From 01318ffdac3c6a40de3ff6bc82bc8419e76600ab Mon Sep 17 00:00:00 2001 From: wycbug <33564918+wycbug@users.noreply.github.com> Date: Sun, 7 Aug 2022 17:15:27 +0800 Subject: [PATCH] chinese version srt files --- README.md | 3 + ...0001 Explore navigation design for iOS.srt | 2202 +++++++ ...Create macOS or Linux virtual machines.srt | 1812 ++++++ zho/2022 Session 10003 Meet WeatherKit.srt | 1088 ++++ zho/2022 Session 10003 Meet WeatherKit2.srt | 1088 ++++ ... Session 10005 What's new in HealthKit.srt | 1854 ++++++ ...sion 10006 Meet Apple Maps Server APIs.srt | 1156 ++++ ... 10007 What's new with in-app purchase.srt | 4362 +++++++++++++ ...10008 What's new in Nearby Interaction.srt | 2347 +++++++ ...t\342\200\231s new in iPad app design.srt" | 1583 +++++ ...Design for Collaboration with Messages.srt | 885 +++ ...e mileage out of your app with CarPlay.srt | 1461 +++++ ...achine learning development experience.srt | 1111 ++++ ...ng Continuity Camera to your macOS app.srt | 1493 +++++ ...10019 Get to know Create ML Components.srt | 2164 +++++++ ...anced models with Create ML Components.srt | 1223 ++++ ...e camera extensions with Core Media IO.srt | 2127 +++++++ ... 10023 What's new in the Photos picker.srt | 1122 ++++ ...022 Session 10024 What's new in Vision.srt | 1546 +++++ ...readable codes and text with VisionKit.srt | 1020 +++ ... Add Live Text interaction to your app.srt | 1323 ++++ ...sion 10027 Optimize your Core ML usage.srt | 2280 +++++++ ...ustom catalogs at scale with ShazamKit.srt | 1397 ++++ ...22 Session 10032 Dive into App Intents.srt | 2768 ++++++++ ...022 Session 10035 What's new in MapKit.srt | 3141 +++++++++ ...sion 10038 What's new with SKAdNetwork.srt | 1299 ++++ ...app purchase integration and migration.srt | 3336 ++++++++++ ...\200\231s new in Wallet and Apple Pay.srt" | 3285 ++++++++++ ... 10043 What's new in App Store Connect.srt | 932 +++ ...4 Discover Benchmarks in App Analytics.srt | 855 +++ ...5 What's new in managing Apple devices.srt | 3430 ++++++++++ ...46 Adopt declarative device management.srt | 2670 ++++++++ ... 10048 What's new in Safari and WebKit.srt | 2566 ++++++++ ... Session 10049 What's new in WKWebView.srt | 701 ++ ...56 Compose custom layouts with SwiftUI.srt | 2130 +++++++ ...ftUI on iPad - Organize your interface.srt | 1477 +++++ ...UI API design - Progressive disclosure.srt | 1057 ++++ ... multiple windows to your SwiftUI app .srt | 1295 ++++ zho/2022 Session 10062 Meet Transferable.srt | 1084 ++++ ...Accelerate machine learning with Metal.srt | 2008 ++++++ ...new players with Game Center dashboard.srt | 708 +++ ...frameworks to your Unity game projects.srt | 2264 +++++++ ...2022 Session 10068 What's new in UIKit.srt | 1440 +++++ ... Session 10069 Meet desktop class iPad.srt | 999 +++ ...n 10070 Build a desktop-class iPad app.srt | 1418 +++++ ...opt desktop class editing interactions.srt | 1416 +++++ ...2 Session 10072 Use SwiftUI with UIKit.srt | 2156 +++++++ ...022 Session 10074 What's new in AppKit.srt | 1738 +++++ ... Session 10075 Use SwiftUI with AppKit.srt | 1592 +++++ ...on 10076 Bring your iOS app to the Mac.srt | 1519 +++++ ...rking delays for a more responsive app.srt | 1189 ++++ ...rove DNS security for apps and servers.srt | 1011 +++ ...ngs with Xcode and on-device detection.srt | 1508 +++++ ...wer down - Improve battery consumption.srt | 1366 ++++ ...022 Session 10089 What's new in PDFKit.srt | 1114 ++++ ...0 What's new in TextKit and text views.srt | 1567 +++++ zho/2022 Session 10092 Meet passkeys.srt | 2596 ++++++++ ...custom collaboration app with Messages.srt | 2283 +++++++ ... 10094 Add Shared with You to your app.srt | 1146 ++++ ...0096 What\342\200\231s new in privacy.srt" | 1372 ++++ ...Session 10098 Meet Web Push for Safari.srt | 1178 ++++ ...200\231s new in Safari Web Extensions.srt" | 1586 +++++ ...Create Safari Web Inspector Extensions.srt | 1260 ++++ ...Session 10101 Go bindless with Metal 3.srt | 2531 ++++++++ ...and optimize GPU binaries with Metal 3.srt | 1128 ++++ ...ost performance with MetalFX Upscaling.srt | 1960 ++++++ ...104 Load resources faster with Metal 3.srt | 1911 ++++++ ...ize your Metal ray tracing performance.srt | 2394 +++++++ ...rofile and optimize your game's memory.srt | 2847 +++++++++ ...2 Session 10107 Get it right (to left).srt | 2823 +++++++++ ...8 Streamline local authorization flows.srt | 1241 ++++ ...231s new in notarization for Mac apps.srt" | 770 +++ ... global apps - Localization by example.srt | 1842 ++++++ ...\342\200\231s new in CloudKit Console.srt" | 633 ++ ... voice communication with Push to Talk.srt | 1905 ++++++ ...ize your use of Core Data and CloudKit.srt | 1868 ++++++ ...ion 10120 Evolve your Core Data schema.srt | 1371 ++++ zho/2022 Session 10121 Meet Focus filters.srt | 1231 ++++ ...sion 10129 Understand USD fundamentals.srt | 1632 +++++ ...0131 Qualities of great AR experiences.srt | 1289 ++++ ...10132 Discover PhotoKit change history.srt | 820 +++ ...ild a productivity app for Apple Watch.srt | 2002 ++++++ ...erts from Bluetooth devices on watchOS.srt | 994 +++ ...0139 Make a great SharePlay experience.srt | 1735 +++++ ... Session 10140 What's new in SharePlay.srt | 1203 ++++ ... 10141 Explore USD tools and rendering.srt | 1436 +++++ ...y awaits - Background tasks in SwiftUI.srt | 1068 ++++ ...43 Discover Managed Device Attestation.srt | 1581 +++++ ...able streams with HLS Content Steering.srt | 1564 +++++ ...342\200\231s new in HLS Interstitials.srt" | 780 +++ ...eate a great video playback experience.srt | 1856 ++++++ ...0148 Meet Apple Music API and MusicKit.srt | 1559 +++++ ...n 10149 What\342\200\231s new in AVQT.srt" | 714 +++ ... Add accessibility to your Unity games.srt | 1001 +++ ... 10153 What's new in web accessibility.srt | 1327 ++++ ...22 Session 10156 Meet ScreenCaptureKit.srt | 1047 +++ ...ssion 10157 What's new in SF Symbols 4.srt | 1283 ++++ ...le compute workloads across Apple GPUs.srt | 1707 +++++ ...60 Program Metal in C++ with metal-cpp.srt | 2222 +++++++ ... your geometry with Metal mesh shaders.srt | 1369 ++++ ...ssion 102 Platforms State of the Union.srt | 5625 +++++++++++++++++ zho/2022 Session 103 Apple Design Awards.srt | 1689 +++++ ...Session 110332 What's new in Create ML.srt | 1304 ++++ ...0335 Explore Apple Business Essentials.srt | 1059 ++++ ...n 110336 What's new in Screen Time API.srt | 799 +++ ...a publishing and playback interactions.srt | 1301 ++++ ...sion 110344 Get to know Developer Mode.srt | 539 ++ ...347 Explore more content with MusicKit.srt | 2022 ++++++ ...ld your first app in Swift Playgrounds.srt | 1030 +++ ...022 Session 110354 What's new in Swift.srt | 3531 +++++++++++ ...ion 110355 Meet Swift Async Algorithms.srt | 1019 +++ ...84 Support multiple users in tvOS apps.srt | 1046 +++ ...on 110401 Create Swift Package plugins.srt | 1498 +++++ ...ment proactive in-app purchase restore.srt | 1664 +++++ ...pture - Depth, focus, and multitasking.srt | 1532 +++++ ...deo in EDR with AVFoundation and Metal.srt | 1710 +++++ zho/2022 Session 110929 Monday@WWDC22.srt | 305 + zho/2022 Session 110930 Tuesday@WWDC22.srt | 145 + zho/2022 Session 110931 Wednesday@WWDC22.srt | 168 + ...2022 Session 110932 WWDC22 Day 4 recap.srt | 146 + ...2022 Session 110933 WWDC22 Day 5 recap.srt | 137 + ...112 Platforms State of the Union (ASL).srt | 5625 +++++++++++++++++ ... Session 113 Apple Design Awards (ASL).srt | 1689 +++++ 123 files changed, 197334 insertions(+) create mode 100644 zho/2022 Session 10001 Explore navigation design for iOS.srt create mode 100644 zho/2022 Session 10002 Create macOS or Linux virtual machines.srt create mode 100644 zho/2022 Session 10003 Meet WeatherKit.srt create mode 100644 zho/2022 Session 10003 Meet WeatherKit2.srt create mode 100644 zho/2022 Session 10005 What's new in HealthKit.srt create mode 100644 zho/2022 Session 10006 Meet Apple Maps Server APIs.srt create mode 100644 zho/2022 Session 10007 What's new with in-app purchase.srt create mode 100644 zho/2022 Session 10008 What's new in Nearby Interaction.srt create mode 100644 "zho/2022 Session 10009 What\342\200\231s new in iPad app design.srt" create mode 100644 zho/2022 Session 10015 Design for Collaboration with Messages.srt create mode 100644 zho/2022 Session 10016 Get more mileage out of your app with CarPlay.srt create mode 100644 zho/2022 Session 10017 Explore the machine learning development experience.srt create mode 100644 zho/2022 Session 10018 Bring Continuity Camera to your macOS app.srt create mode 100644 zho/2022 Session 10019 Get to know Create ML Components.srt create mode 100644 zho/2022 Session 10020 Compose advanced models with Create ML Components.srt create mode 100644 zho/2022 Session 10022 Create camera extensions with Core Media IO.srt create mode 100644 zho/2022 Session 10023 What's new in the Photos picker.srt create mode 100644 zho/2022 Session 10024 What's new in Vision.srt create mode 100644 zho/2022 Session 10025 Capture machine-readable codes and text with VisionKit.srt create mode 100644 zho/2022 Session 10026 Add Live Text interaction to your app.srt create mode 100644 zho/2022 Session 10027 Optimize your Core ML usage.srt create mode 100644 zho/2022 Session 10028 Create custom catalogs at scale with ShazamKit.srt create mode 100644 zho/2022 Session 10032 Dive into App Intents.srt create mode 100644 zho/2022 Session 10035 What's new in MapKit.srt create mode 100644 zho/2022 Session 10038 What's new with SKAdNetwork.srt create mode 100644 zho/2022 Session 10040 Explore in-app purchase integration and migration.srt create mode 100644 "zho/2022 Session 10041 What\342\200\231s new in Wallet and Apple Pay.srt" create mode 100644 zho/2022 Session 10043 What's new in App Store Connect.srt create mode 100644 zho/2022 Session 10044 Discover Benchmarks in App Analytics.srt create mode 100644 zho/2022 Session 10045 What's new in managing Apple devices.srt create mode 100644 zho/2022 Session 10046 Adopt declarative device management.srt create mode 100644 zho/2022 Session 10048 What's new in Safari and WebKit.srt create mode 100644 zho/2022 Session 10049 What's new in WKWebView.srt create mode 100644 zho/2022 Session 10056 Compose custom layouts with SwiftUI.srt create mode 100644 zho/2022 Session 10058 SwiftUI on iPad - Organize your interface.srt create mode 100644 zho/2022 Session 10059 The craft of SwiftUI API design - Progressive disclosure.srt create mode 100644 zho/2022 Session 10061 Bring multiple windows to your SwiftUI app .srt create mode 100644 zho/2022 Session 10062 Meet Transferable.srt create mode 100644 zho/2022 Session 10063 Accelerate machine learning with Metal.srt create mode 100644 zho/2022 Session 10064 Reach new players with Game Center dashboard.srt create mode 100644 zho/2022 Session 10065 Plug-in and play - Add Apple frameworks to your Unity game projects.srt create mode 100644 zho/2022 Session 10068 What's new in UIKit.srt create mode 100644 zho/2022 Session 10069 Meet desktop class iPad.srt create mode 100644 zho/2022 Session 10070 Build a desktop-class iPad app.srt create mode 100644 zho/2022 Session 10071 Adopt desktop class editing interactions.srt create mode 100644 zho/2022 Session 10072 Use SwiftUI with UIKit.srt create mode 100644 zho/2022 Session 10074 What's new in AppKit.srt create mode 100644 zho/2022 Session 10075 Use SwiftUI with AppKit.srt create mode 100644 zho/2022 Session 10076 Bring your iOS app to the Mac.srt create mode 100644 zho/2022 Session 10078 Reduce networking delays for a more responsive app.srt create mode 100644 zho/2022 Session 10079 Improve DNS security for apps and servers.srt create mode 100644 zho/2022 Session 10082 Track down hangs with Xcode and on-device detection.srt create mode 100644 zho/2022 Session 10083 Power down - Improve battery consumption.srt create mode 100644 zho/2022 Session 10089 What's new in PDFKit.srt create mode 100644 zho/2022 Session 10090 What's new in TextKit and text views.srt create mode 100644 zho/2022 Session 10092 Meet passkeys.srt create mode 100644 zho/2022 Session 10093 Integrate your custom collaboration app with Messages.srt create mode 100644 zho/2022 Session 10094 Add Shared with You to your app.srt create mode 100644 "zho/2022 Session 10096 What\342\200\231s new in privacy.srt" create mode 100644 zho/2022 Session 10098 Meet Web Push for Safari.srt create mode 100644 "zho/2022 Session 10099 What\342\200\231s new in Safari Web Extensions.srt" create mode 100644 zho/2022 Session 10100 Create Safari Web Inspector Extensions.srt create mode 100644 zho/2022 Session 10101 Go bindless with Metal 3.srt create mode 100644 zho/2022 Session 10102 Target and optimize GPU binaries with Metal 3.srt create mode 100644 zho/2022 Session 10103 Boost performance with MetalFX Upscaling.srt create mode 100644 zho/2022 Session 10104 Load resources faster with Metal 3.srt create mode 100644 zho/2022 Session 10105 Maximize your Metal ray tracing performance.srt create mode 100644 zho/2022 Session 10106 Profile and optimize your game's memory.srt create mode 100644 zho/2022 Session 10107 Get it right (to left).srt create mode 100644 zho/2022 Session 10108 Streamline local authorization flows.srt create mode 100644 "zho/2022 Session 10109 What\342\200\231s new in notarization for Mac apps.srt" create mode 100644 zho/2022 Session 10110 Build global apps - Localization by example.srt create mode 100644 "zho/2022 Session 10115 What\342\200\231s new in CloudKit Console.srt" create mode 100644 zho/2022 Session 10117 Enhance voice communication with Push to Talk.srt create mode 100644 zho/2022 Session 10119 Optimize your use of Core Data and CloudKit.srt create mode 100644 zho/2022 Session 10120 Evolve your Core Data schema.srt create mode 100644 zho/2022 Session 10121 Meet Focus filters.srt create mode 100644 zho/2022 Session 10129 Understand USD fundamentals.srt create mode 100644 zho/2022 Session 10131 Qualities of great AR experiences.srt create mode 100644 zho/2022 Session 10132 Discover PhotoKit change history.srt create mode 100644 zho/2022 Session 10133 Build a productivity app for Apple Watch.srt create mode 100644 zho/2022 Session 10135 Get timely alerts from Bluetooth devices on watchOS.srt create mode 100644 zho/2022 Session 10139 Make a great SharePlay experience.srt create mode 100644 zho/2022 Session 10140 What's new in SharePlay.srt create mode 100644 zho/2022 Session 10141 Explore USD tools and rendering.srt create mode 100644 zho/2022 Session 10142 Efficiency awaits - Background tasks in SwiftUI.srt create mode 100644 zho/2022 Session 10143 Discover Managed Device Attestation.srt create mode 100644 zho/2022 Session 10144 Deliver reliable streams with HLS Content Steering.srt create mode 100644 "zho/2022 Session 10145 What\342\200\231s new in HLS Interstitials.srt" create mode 100644 zho/2022 Session 10147 Create a great video playback experience.srt create mode 100644 zho/2022 Session 10148 Meet Apple Music API and MusicKit.srt create mode 100644 "zho/2022 Session 10149 What\342\200\231s new in AVQT.srt" create mode 100644 zho/2022 Session 10151 Add accessibility to your Unity games.srt create mode 100644 zho/2022 Session 10153 What's new in web accessibility.srt create mode 100644 zho/2022 Session 10156 Meet ScreenCaptureKit.srt create mode 100644 zho/2022 Session 10157 What's new in SF Symbols 4.srt create mode 100644 zho/2022 Session 10159 Scale compute workloads across Apple GPUs.srt create mode 100644 zho/2022 Session 10160 Program Metal in C++ with metal-cpp.srt create mode 100644 zho/2022 Session 10162 Transform your geometry with Metal mesh shaders.srt create mode 100644 zho/2022 Session 102 Platforms State of the Union.srt create mode 100644 zho/2022 Session 103 Apple Design Awards.srt create mode 100644 zho/2022 Session 110332 What's new in Create ML.srt create mode 100644 zho/2022 Session 110335 Explore Apple Business Essentials.srt create mode 100644 zho/2022 Session 110336 What's new in Screen Time API.srt create mode 100644 zho/2022 Session 110338 Explore media metadata publishing and playback interactions.srt create mode 100644 zho/2022 Session 110344 Get to know Developer Mode.srt create mode 100644 zho/2022 Session 110347 Explore more content with MusicKit.srt create mode 100644 zho/2022 Session 110348 Build your first app in Swift Playgrounds.srt create mode 100644 zho/2022 Session 110354 What's new in Swift.srt create mode 100644 zho/2022 Session 110355 Meet Swift Async Algorithms.srt create mode 100644 zho/2022 Session 110384 Support multiple users in tvOS apps.srt create mode 100644 zho/2022 Session 110401 Create Swift Package plugins.srt create mode 100644 zho/2022 Session 110404 Implement proactive in-app purchase restore.srt create mode 100644 zho/2022 Session 110429 Discover advancements in iOS camera capture - Depth, focus, and multitasking.srt create mode 100644 zho/2022 Session 110565 Display HDR video in EDR with AVFoundation and Metal.srt create mode 100644 zho/2022 Session 110929 Monday@WWDC22.srt create mode 100644 zho/2022 Session 110930 Tuesday@WWDC22.srt create mode 100644 zho/2022 Session 110931 Wednesday@WWDC22.srt create mode 100644 zho/2022 Session 110932 WWDC22 Day 4 recap.srt create mode 100644 zho/2022 Session 110933 WWDC22 Day 5 recap.srt create mode 100644 zho/2022 Session 112 Platforms State of the Union (ASL).srt create mode 100644 zho/2022 Session 113 Apple Design Awards (ASL).srt diff --git a/README.md b/README.md index 9222dc5..b8f7578 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ # wwdc2022-subtitles wwdc2022 substitles, include download links and srt files + + + diff --git a/zho/2022 Session 10001 Explore navigation design for iOS.srt b/zho/2022 Session 10001 Explore navigation design for iOS.srt new file mode 100644 index 0000000..735bf35 --- /dev/null +++ b/zho/2022 Session 10001 Explore navigation design for iOS.srt @@ -0,0 +1,2202 @@ +1 +00:00:00,067 --> 00:00:03,170 +♪ ♪ + +2 +00:00:03,170 --> 00:00:09,676 +♪ + +3 +00:00:09,676 --> 00:00:11,378 +大家好 我叫 +Sarah McClanahan + +4 +00:00:11,378 --> 00:00:14,882 +是布道团队的一名设计师 + +5 +00:00:14,882 --> 00:00:18,085 +今天 我要跟大家分享关于 + +6 +00:00:18,085 --> 00:00:21,021 +如何改善 +iOS 的 App 导航 + +7 +00:00:21,021 --> 00:00:22,890 +以及各种改良的技巧与方法 + +8 +00:00:22,890 --> 00:00:26,827 +导航做得好的 App 往往 +会让大家注意不到导航的存在 + +9 +00:00:26,827 --> 00:00:31,064 +因为好的导航能让人把注意力 +都集中在内容和体验上 + +10 +00:00:31,064 --> 00:00:33,734 +导航会告诉人们 +在您的 App 中 + +11 +00:00:33,734 --> 00:00:36,270 +如何呈现项目 + +12 +00:00:36,270 --> 00:00:38,238 +如何寻找信息 + +13 +00:00:38,238 --> 00:00:40,674 +如何实现目的 + +14 +00:00:40,674 --> 00:00:43,544 +导航的目的就是 + +15 +00:00:43,544 --> 00:00:46,980 +帮助人们尽快熟悉界面 + +16 +00:00:46,980 --> 00:00:50,384 +以轻松发现内容 +并与 App 进行互动 + +17 +00:00:50,384 --> 00:00:53,587 +导航做得太过不符合预期 + +18 +00:00:53,587 --> 00:00:57,291 +或是跟用户的自然认知落差太大 + +19 +00:00:57,291 --> 00:00:59,760 +就会让用户感到无所适从 +并最终感觉这个 App + +20 +00:00:59,760 --> 00:01:01,228 +很不好用 + +21 +00:01:01,228 --> 00:01:05,199 +导航要做好 +需要注意很多细节 + +22 +00:01:05,199 --> 00:01:08,502 +虽然我今天要讲的 +一些理念已经是老生常谈 + +23 +00:01:08,502 --> 00:01:10,370 +但却是重要的基础 + +24 +00:01:10,370 --> 00:01:14,074 +也是一个成功的 +iOS App 所必须的 + +25 +00:01:14,074 --> 00:01:16,710 +因此 不论您是初学者 +还是想进一步寻求 + +26 +00:01:16,710 --> 00:01:20,347 +App 体验的改良方案 +本讲座都适合您 + +27 +00:01:20,347 --> 00:01:23,016 +今天我们要探讨的是底部导航栏 + +28 +00:01:23,016 --> 00:01:27,221 +这是 iOS 上 +一种常见的导航形式 + +29 +00:01:27,221 --> 00:01:30,691 +接下来 我们会探讨 +如何通过层级式及 + +30 +00:01:30,691 --> 00:01:34,127 +以及模态式呈现 + +31 +00:01:34,127 --> 00:01:36,496 +来进行屏幕间的切换 + +32 +00:01:36,496 --> 00:01:39,466 +如您所见 这个讲座只能覆盖 +导航这一大主题下的 + +33 +00:01:39,466 --> 00:01:42,369 +部分内容 + +34 +00:01:42,369 --> 00:01:44,905 +不过 这些都属于关键内容 + +35 +00:01:44,905 --> 00:01:49,042 +能够反映一定的规律 +而这些规律经常被误用 + +36 +00:01:49,042 --> 00:01:51,979 +掌握了这些规律 +能帮助您的 App + +37 +00:01:51,979 --> 00:01:56,016 +成功升级换代 或是适用于更多设备 + +38 +00:01:56,016 --> 00:01:58,485 +首先我们从底部导航栏开始 + +39 +00:01:58,485 --> 00:02:01,121 +底部导航栏属于全局性导航 + +40 +00:02:01,121 --> 00:02:02,956 +始终位于屏幕底部 + +41 +00:02:02,956 --> 00:02:06,793 +将 App 内容进行分区 + +42 +00:02:06,793 --> 00:02:08,896 +可以将底部导航栏看作一种 + +43 +00:02:08,896 --> 00:02:12,199 +分层展示信息的控制手段 + +44 +00:02:12,199 --> 00:02:14,268 +用户控制界面本身 + +45 +00:02:14,268 --> 00:02:17,337 +就应当清晰地展示出 +您的 App 各区间的 + +46 +00:02:17,337 --> 00:02:20,407 +类别与关系 + +47 +00:02:20,407 --> 00:02:23,544 +因此 底部导航栏要反映出 +您的 App 最高层次的 + +48 +00:02:23,544 --> 00:02:26,446 +内容与分类 + +49 +00:02:26,446 --> 00:02:29,783 +每个栏目反映的是 +您的 App 上可选的菜单 + +50 +00:02:29,783 --> 00:02:33,720 +而这些栏目的选择应当 +意义明确 一目了然 + +51 +00:02:33,720 --> 00:02:36,156 +这么听起来可能很简单 + +52 +00:02:36,156 --> 00:02:39,159 +但实际操作中则往往由于各种原因 + +53 +00:02:39,159 --> 00:02:42,996 +在设计中会被忽视 + +54 +00:02:42,996 --> 00:02:45,098 +下面举几个例子 + +55 +00:02:45,098 --> 00:02:47,968 +在不了解 App 内容的情况下 + +56 +00:02:47,968 --> 00:02:51,138 +看看这些导航栏能透露出 +哪些功能信息 + +57 +00:02:51,138 --> 00:02:53,874 +仅仅通过一些简单的标签 +我们就能从中看出 + +58 +00:02:53,874 --> 00:02:56,844 +该 App 的许多功能了 + +59 +00:02:56,844 --> 00:03:00,881 +“马上收听”及“收音机”两项 +提示这个 App 支持的是 + +60 +00:03:00,881 --> 00:03:04,084 +音频媒体的内容 + +61 +00:03:04,084 --> 00:03:08,789 +App 上的“曲库”和“专辑” +暗示该 App 内容丰富 + +62 +00:03:08,789 --> 00:03:13,927 +而“个人专属”则提示了 +强烈的个人风格 + +63 +00:03:13,927 --> 00:03:17,598 +该 App 的导航设计 +十分直截了当 + +64 +00:03:17,598 --> 00:03:20,467 +其功能一目了然 +让我们很清楚自己在 + +65 +00:03:20,467 --> 00:03:23,403 +各个分区可以干些什么 + +66 +00:03:23,403 --> 00:03:26,373 +常见的操作是 +App 最初展示的导航 + +67 +00:03:26,373 --> 00:03:29,409 +着重于功能 + +68 +00:03:29,409 --> 00:03:31,311 +要注意不同界面间导航栏的功能 + +69 +00:03:31,311 --> 00:03:34,381 +分布要平衡 + +70 +00:03:34,381 --> 00:03:36,149 +下面我们举些例子 + +71 +00:03:36,149 --> 00:03:39,486 +帮助大家明白什么样的 +导航栏设计会造成误导 + +72 +00:03:39,486 --> 00:03:41,822 +或让人困惑不解 + +73 +00:03:41,822 --> 00:03:45,058 +想象我手头有个 App +可以帮助人们计划 + +74 +00:03:45,058 --> 00:03:48,695 +城市路线 比如用于骑行 + +75 +00:03:48,695 --> 00:03:51,532 +如果您是来旅游的 +或是刚搬到一个新地方 + +76 +00:03:51,532 --> 00:03:54,334 +又或是刚开始玩骑行 +该 App 可以帮助您 + +77 +00:03:54,334 --> 00:03:57,571 +轻松保存及创建行程路线 + +78 +00:03:57,571 --> 00:03:58,939 +像这样 + +79 +00:03:58,939 --> 00:04:01,708 +既然这个 App 的目的是 +寻找最佳骑行路线 + +80 +00:04:01,708 --> 00:04:07,247 +首先展示的就是 +骑行路线的筛选地图 + +81 +00:04:07,247 --> 00:04:10,184 +接下来的区域可以交互 + +82 +00:04:10,184 --> 00:04:12,853 +可以随着编辑内容或添加好友 + +83 +00:04:12,853 --> 00:04:15,822 +而新增备选路线 + +84 +00:04:15,822 --> 00:04:17,558 +再下来 是分类展示 + +85 +00:04:17,558 --> 00:04:19,092 +各种不同特性的路线 + +86 +00:04:19,092 --> 00:04:22,763 +您会忍不住想把 +所有功能都挤进一个导航栏里 + +87 +00:04:22,763 --> 00:04:26,366 +就像这样 因为这样能一览无余 + +88 +00:04:26,366 --> 00:04:28,669 +也有可能随着 App 更新 + +89 +00:04:28,669 --> 00:04:31,205 +您导航栏上的路线分组 + +90 +00:04:31,205 --> 00:04:33,574 +已经全乱了 + +91 +00:04:33,574 --> 00:04:38,145 +今天呢 我想请您 +重新考虑这个问题 + +92 +00:04:38,145 --> 00:04:41,148 +这样的设计 用户想要找到 +自己想看的内容 + +93 +00:04:41,148 --> 00:04:43,817 +就需要大量翻页 + +94 +00:04:43,817 --> 00:04:47,688 +还要费力地排除各种 +无关的散碎功能干扰 + +95 +00:04:47,688 --> 00:04:50,591 +用户打开一个 App +在地图界面上进行筛选 + +96 +00:04:50,591 --> 00:04:54,061 +与编辑一条路线时 +涉及到的功能乃至思维方式 + +97 +00:04:54,061 --> 00:04:56,864 +是截然不同的 + +98 +00:04:56,864 --> 00:04:59,967 +像这样将不同功能结合 +在一起的做法要谨慎使用 + +99 +00:04:59,967 --> 00:05:02,169 +尤其不要出于担心 生怕用户不愿意 + +100 +00:05:02,169 --> 00:05:03,904 +探索 App 更多界面 + +101 +00:05:03,904 --> 00:05:06,974 +毕竟 如果 App 的功能 +安排合理 + +102 +00:05:06,974 --> 00:05:11,011 +用户才会更容易理解 + +103 +00:05:11,011 --> 00:05:15,015 +一种做法 就是反思一下 + +104 +00:05:15,015 --> 00:05:17,417 +别人为什么会用您的 App? + +105 +00:05:17,417 --> 00:05:20,354 +要记住 好的 App +往往功能集中 + +106 +00:05:20,354 --> 00:05:22,956 +专注于把少数几件事做好 + +107 +00:05:22,956 --> 00:05:25,893 +而不是试图 +用一个 App 解决所有问题 + +108 +00:05:25,893 --> 00:05:28,962 +那我们再回到这个 +骑行 App 的导航栏上 + +109 +00:05:28,962 --> 00:05:30,998 +用这个 App 的人是 +想在自己感兴趣的地方 + +110 +00:05:30,998 --> 00:05:34,034 +找到适合自己的路线 + +111 +00:05:34,034 --> 00:05:36,403 +这才是设计一个 App 时 +最重要的考虑因素 + +112 +00:05:36,403 --> 00:05:39,973 +因为这才是人们最关心的内容 + +113 +00:05:39,973 --> 00:05:43,210 +带着这个认知 我们再来看看 + +114 +00:05:43,210 --> 00:05:45,846 +如何设计导航栏 + +115 +00:05:45,846 --> 00:05:48,415 +来帮助用户设计路线 + +116 +00:05:48,415 --> 00:05:51,885 +以及如何在 App 上 +进行均衡地展示 + +117 +00:05:51,885 --> 00:05:54,421 +这是一条路线的内容细节 + +118 +00:05:54,421 --> 00:05:56,590 +一般人会喜欢先看整体信息 + +119 +00:05:56,590 --> 00:06:00,027 +如距离 海拔变化 + +120 +00:06:00,027 --> 00:06:02,729 +以及全程地图及路面状况 + +121 +00:06:02,729 --> 00:06:06,099 +如人行道和道路等 + +122 +00:06:06,099 --> 00:06:09,837 +而上下陡坡等提醒信息 + +123 +00:06:09,837 --> 00:06:13,473 +能帮助我了解该路线 +是否适合我的水平 + +124 +00:06:13,473 --> 00:06:15,676 +最后 知道沿途是否能 +买到食物和水 + +125 +00:06:15,676 --> 00:06:17,845 +也会大大有助于计划 + +126 +00:06:17,845 --> 00:06:22,549 +好了那么 如何更好地组织这个 + +127 +00:06:22,549 --> 00:06:24,484 +路线查询的核心功能呢? + +128 +00:06:24,484 --> 00:06:29,723 +首先 只有知道路线在哪里 +这条路线才是有用的 + +129 +00:06:29,723 --> 00:06:32,292 +路线与其所属城市 + +130 +00:06:32,292 --> 00:06:35,929 +是密不可分的 + +131 +00:06:35,929 --> 00:06:38,265 +于是 我们需要一个城市界面 + +132 +00:06:38,265 --> 00:06:41,768 +以查询该城市与骑行有关的信息 + +133 +00:06:41,768 --> 00:06:43,203 +从该界面往下翻 + +134 +00:06:43,203 --> 00:06:47,007 +就能看到该城市中所有的骑行路线 + +135 +00:06:47,007 --> 00:06:50,944 +不过这个 App +还支持不同城市的路线 + +136 +00:06:50,944 --> 00:06:56,316 +因此从单个城市往上翻 +会有所有城市的列表 + +137 +00:06:56,316 --> 00:06:59,186 +城市或地方 就可以 +作为路线导航的 + +138 +00:06:59,186 --> 00:07:01,455 +最高层级 + +139 +00:07:01,455 --> 00:07:04,791 +由此可见 单单这一步操作 +就涉及到大量信息 + +140 +00:07:04,791 --> 00:07:09,162 +而且这些信息还是该 App +所提供的内容里非常关键的部分 + +141 +00:07:09,162 --> 00:07:12,232 +这也是底部导航栏设计中 +一个很好的例子 + +142 +00:07:12,232 --> 00:07:14,902 +再看现在这个设计 +是不是就主题分明了 + +143 +00:07:14,902 --> 00:07:17,571 +这个导航界面里不应当出现 + +144 +00:07:17,571 --> 00:07:20,674 +任何跟城市无关的信息 + +145 +00:07:20,674 --> 00:07:24,878 +设计好的底部导航栏要做的 +一个工作就是合理组织内容 + +146 +00:07:24,878 --> 00:07:28,081 +尽可能按照最自然的关系 +来组织不同内容 + +147 +00:07:28,081 --> 00:07:30,851 +要做到这一点 可以结合 +App 中的其他关键功能 + +148 +00:07:30,851 --> 00:07:34,321 +例如“行程” 我可以问自己 + +149 +00:07:34,321 --> 00:07:35,889 +“行程”是什么? + +150 +00:07:35,889 --> 00:07:37,524 +大家一般如何使用“行程”? + +151 +00:07:37,524 --> 00:07:41,128 +在我的 App 里面 把这个功能 +放在哪里最合适? + +152 +00:07:41,128 --> 00:07:44,565 +哪怕别人 +对您的 App 内容并不熟悉 + +153 +00:07:44,565 --> 00:07:47,000 +或者说 越是不熟悉 + +154 +00:07:47,000 --> 00:07:49,303 +就越要将功能和内容的关系 + +155 +00:07:49,303 --> 00:07:51,004 +表达得清楚明白 + +156 +00:07:51,004 --> 00:07:53,207 +准确评估它所属的层级 + +157 +00:07:53,207 --> 00:07:55,409 +以及分析人们会如何使用 + +158 +00:07:55,409 --> 00:07:58,679 +只有这样 才能把一个将所有功能 + +159 +00:07:58,679 --> 00:08:02,349 +塞到首页的 App 升级为 + +160 +00:08:02,349 --> 00:08:05,385 +有着清晰直观导航的 App + +161 +00:08:05,385 --> 00:08:09,156 +现在 底部导航栏上展示的 +核心功能就均衡多了 + +162 +00:08:09,156 --> 00:08:11,892 +因为各个栏目都很直观 + +163 +00:08:11,892 --> 00:08:12,826 +每个栏目相互联系 + +164 +00:08:12,826 --> 00:08:16,864 +却各自有着不同的内容及操作 + +165 +00:08:16,864 --> 00:08:21,001 +这样的导航要自然得多 + +166 +00:08:21,001 --> 00:08:24,238 +接下来 我想讨论一个 +有点关联的主题 + +167 +00:08:24,238 --> 00:08:26,573 +虽然表达得不尽相同 + +168 +00:08:26,573 --> 00:08:28,675 +要避免在同一个页面 + +169 +00:08:28,675 --> 00:08:32,746 +反复强调一个功能 + +170 +00:08:32,746 --> 00:08:34,815 +对于像这样内容丰富的 App + +171 +00:08:34,815 --> 00:08:38,452 +似乎很合适用一个“首页” + +172 +00:08:38,452 --> 00:08:40,954 +来一次性展示 App 内部的 + +173 +00:08:40,954 --> 00:08:43,757 +所有功能 + +174 +00:08:43,757 --> 00:08:46,860 +比如 如果用户似乎对“行程”功能 + +175 +00:08:46,860 --> 00:08:49,763 +不太热衷 而您怀疑这是因为 + +176 +00:08:49,763 --> 00:08:52,766 +用户没意识到 App 有这个功能 + +177 +00:08:54,434 --> 00:08:57,304 +于是 您很自然会想要 +通过在页面中反复展示 + +178 +00:08:57,304 --> 00:09:00,741 +来强调这个功能的存在 + +179 +00:09:00,741 --> 00:09:04,811 +例如在“城市”选项卡上 +加上“新行程” + +180 +00:09:04,811 --> 00:09:07,548 +或是将行程面板 + +181 +00:09:07,548 --> 00:09:09,750 +跟其他功能一起插入醒目的位置 + +182 +00:09:09,750 --> 00:09:12,486 +例如添加好友 + +183 +00:09:12,486 --> 00:09:17,324 +或是在站点列表上 +加上方便的“添加”选项 + +184 +00:09:17,324 --> 00:09:19,326 +如果生怕有些功能会被漏掉 + +185 +00:09:19,326 --> 00:09:23,063 +这种做法无疑具有很大的诱惑力 + +186 +00:09:23,063 --> 00:09:27,234 +这里要澄清一下 +此处反复呈现的并非内容 + +187 +00:09:27,234 --> 00:09:29,303 +很多时候 在不同的界面 + +188 +00:09:29,303 --> 00:09:33,407 +用不同的方式显示同类型内容 +如歌曲或照片 + +189 +00:09:33,407 --> 00:09:36,977 +这种做法是合理的 + +190 +00:09:36,977 --> 00:09:38,712 +但功能就不一样了 + +191 +00:09:38,712 --> 00:09:41,849 +因为功能涉及到人们出于 +某种目的所要采取的行动 + +192 +00:09:41,849 --> 00:09:45,786 +这种时候重复将 +让用户感到困惑 + +193 +00:09:45,786 --> 00:09:49,857 +在实际操作中 一个“首页” +往往会破坏一个 App 的层级 + +194 +00:09:49,857 --> 00:09:54,027 +如果一个 App 不同导航栏 +或分区的功能 + +195 +00:09:54,027 --> 00:09:57,464 +被重复添加到同一个页面上 + +196 +00:09:57,464 --> 00:09:59,333 +同时缺乏足够的内容支持 + +197 +00:09:59,333 --> 00:10:02,202 +会让人感到多余而且杂乱 + +198 +00:10:02,202 --> 00:10:04,771 +“首页”将成为一个 +让人眼花缭乱的地方 + +199 +00:10:04,771 --> 00:10:07,474 +每个功能都在抢地盘 + +200 +00:10:07,474 --> 00:10:10,611 +每个栏目都想得到注意 + +201 +00:10:10,611 --> 00:10:13,447 +而事实却是 这种做法打断了 + +202 +00:10:13,447 --> 00:10:16,884 +内容与相应操作之间的联系 + +203 +00:10:16,884 --> 00:10:18,018 +如果这是您的 App + +204 +00:10:18,018 --> 00:10:20,687 +可以考虑把整个“首页”去掉 + +205 +00:10:20,687 --> 00:10:23,123 +过多重复的功能将使用户无所适从 + +206 +00:10:23,123 --> 00:10:26,960 +弄不清信息在哪里 +又为什么被放置到那里 + +207 +00:10:26,960 --> 00:10:28,629 +“首页”的另一个问题是 + +208 +00:10:28,629 --> 00:10:30,597 +这种功能的重复 + +209 +00:10:30,597 --> 00:10:33,433 +可能导致用户因为 +在其他地方看到该功能 + +210 +00:10:33,433 --> 00:10:35,836 +而直接跳过导航栏操作 + +211 +00:10:35,836 --> 00:10:39,006 +像这样因为碰巧看见某个元素 +而点击切换页面的做法 + +212 +00:10:39,006 --> 00:10:42,242 +会导致用户晕头转向 + +213 +00:10:42,242 --> 00:10:46,747 +这样迫使用户自动 +换页面的做法一定要避免 + +214 +00:10:46,747 --> 00:10:50,284 +接下来 导航栏导航一个最大的好处 + +215 +00:10:50,284 --> 00:10:53,387 +就在于它能在多个顶层内容间切换 + +216 +00:10:53,387 --> 00:10:55,656 +因此在整个导航过程中都要 + +217 +00:10:55,656 --> 00:10:58,659 +保持底部导航栏的存在 + +218 +00:10:58,659 --> 00:11:01,962 +保持底部导航栏的存在能帮助用户 + +219 +00:11:01,962 --> 00:11:03,964 +在不同层次的信息间 + +220 +00:11:03,964 --> 00:11:05,732 +轻松切换 + +221 +00:11:05,732 --> 00:11:08,168 +同时各层级间的关系还能保持清晰 + +222 +00:11:08,168 --> 00:11:11,438 +比如 我可以在“城市”页面 + +223 +00:11:11,438 --> 00:11:15,509 +查看一条新路线 + +224 +00:11:15,509 --> 00:11:17,511 +并与我“行程”页面上 + +225 +00:11:17,511 --> 00:11:20,614 +正在创建的一条行程中 + +226 +00:11:20,614 --> 00:11:23,383 +已储存的路线作比较 + +227 +00:11:23,383 --> 00:11:26,687 +后者在我的层级中要低两层 + +228 +00:11:26,687 --> 00:11:30,190 +要实现这种比较 +不同页面就必须目的明确 + +229 +00:11:30,190 --> 00:11:34,728 +内容的区分也要细致 + +230 +00:11:34,728 --> 00:11:36,997 +最后 您下了这么多工夫 + +231 +00:11:36,997 --> 00:11:39,199 +整理出这么扎实的信息结构 + +232 +00:11:39,199 --> 00:11:42,236 +要配以简明的标签 + +233 +00:11:42,236 --> 00:11:43,670 +我们参考一个今年在 +Apple 设计大奖 + +234 +00:11:43,670 --> 00:11:46,273 +“优越互动”类别获奖的 + +235 +00:11:46,273 --> 00:11:48,208 +这个 App “Slopes” + +236 +00:11:48,208 --> 00:11:50,644 +它最让我欣赏的一点就是 +这个 App 一打开 + +237 +00:11:50,644 --> 00:11:53,013 +默认打开的是中间栏 即您的日志栏 + +238 +00:11:53,013 --> 00:11:55,916 +上面有季节数据 + +239 +00:11:55,916 --> 00:11:57,818 +其他页面的功能更加集中 + +240 +00:11:57,818 --> 00:12:01,255 +全部都很直观 一看就知道 + +241 +00:12:01,255 --> 00:12:03,991 +这个 App 是干什么的 怎么用 + +242 +00:12:03,991 --> 00:12:07,261 +概括地说 这是因为标签的设计 + +243 +00:12:07,261 --> 00:12:08,795 +能直观地反映内容 + +244 +00:12:08,795 --> 00:12:11,098 +记录滑雪日 浏览场地 + +245 +00:12:11,098 --> 00:12:13,967 +与朋友交换数据等 都是用寥寥数语 + +246 +00:12:13,967 --> 00:12:18,438 +就把核心功能讲清楚了 + +247 +00:12:18,438 --> 00:12:21,675 +底部导航栏是一个强大的导航工具 + +248 +00:12:21,675 --> 00:12:24,311 +现在 我们把前面的内容回顾一遍 + +249 +00:12:24,311 --> 00:12:28,749 +利用导航栏来反映您的信息层级 + +250 +00:12:28,749 --> 00:12:31,185 +在导航栏间将不同功能以均衡的方式 + +251 +00:12:31,185 --> 00:12:33,320 +组织起来 + +252 +00:12:33,320 --> 00:12:38,492 +避免在同一个页面出现功能的重复 + +253 +00:12:38,492 --> 00:12:42,396 +在整个 App 中 +始终保持底部导航栏的存在 + +254 +00:12:42,396 --> 00:12:46,934 +最后 导航栏的标签要简洁明了 + +255 +00:12:46,934 --> 00:12:49,970 +好了 下面我们来讲交互xing + +256 +00:12:49,970 --> 00:12:52,973 +一个 App 在不同屏幕间的 +切换方式 + +257 +00:12:52,973 --> 00:12:55,475 +主要有两种 + +258 +00:12:55,475 --> 00:12:57,544 +一种是在不同层级间切换 + +259 +00:12:57,544 --> 00:13:00,247 +我们有时称为 +“推送 (push)” + +260 +00:13:00,247 --> 00:13:02,716 +例如推送更多细节 + +261 +00:13:02,716 --> 00:13:06,453 +另一种切换则称为 +“模态窗 (modal)” + +262 +00:13:06,453 --> 00:13:09,056 +这两种方式我们都很熟悉 + +263 +00:13:09,056 --> 00:13:12,125 +可以帮助我们自然地在一个 +App 的不同层级或界面间跳跃 + +264 +00:13:12,125 --> 00:13:14,161 +下面我给大家举例 + +265 +00:13:14,161 --> 00:13:17,097 +在不同层级间切换时 + +266 +00:13:17,097 --> 00:13:19,333 +出现“推送”页面 就意味着用户 + +267 +00:13:19,333 --> 00:13:21,835 +点击了某个元素 而接下来的页面 + +268 +00:13:21,835 --> 00:13:24,805 +会从右往左滑入 + +269 +00:13:24,805 --> 00:13:27,641 +“推送”界面默认出现于 + +270 +00:13:27,641 --> 00:13:30,811 +由上层往下层信息深入的时候 + +271 +00:13:30,811 --> 00:13:33,280 +这种交互方式很方便 +因为它能直观体现 + +272 +00:13:33,280 --> 00:13:35,082 +信息的层级 + +273 +00:13:35,082 --> 00:13:38,285 +能直接告诉用户 您所看到的内容 + +274 +00:13:38,285 --> 00:13:41,421 +是从一个较高层级 +向下深入所得的细节 + +275 +00:13:41,421 --> 00:13:43,790 +另一方面 模态窗则专门用于 + +276 +00:13:43,790 --> 00:13:46,527 +展示某个界面中的独立任务 + +277 +00:13:46,527 --> 00:13:49,463 +模态窗用于独立操作很方便 + +278 +00:13:49,463 --> 00:13:52,332 +它意味着该界面下 +要进行某种操作所需的 + +279 +00:13:52,332 --> 00:13:55,169 +全部信息都已齐备 + +280 +00:13:55,169 --> 00:13:57,938 +模态窗是一种独特的交互方式 +因为它能隔绝其余层级的信息 + +281 +00:13:57,938 --> 00:14:01,775 +从而帮助用户集中注意 + +282 +00:14:01,775 --> 00:14:04,378 +比如 创建新行程 + +283 +00:14:04,378 --> 00:14:07,714 +就是通过模态窗来呈现的 + +284 +00:14:07,714 --> 00:14:11,985 +用户可以在模态窗里选择 +或输入数据 例如标题 + +285 +00:14:11,985 --> 00:14:16,256 +城市 日期甚至邀请好友 + +286 +00:14:16,256 --> 00:14:18,859 +用模态窗实现这种功能很合适 +因为 UI 的设计要求页面在 + +287 +00:14:18,859 --> 00:14:22,429 +关闭或切换到其他页面前 + +288 +00:14:22,429 --> 00:14:24,765 +完成编辑 + +289 +00:14:24,765 --> 00:14:28,302 +因为信息都是由用户输入 +并不需要参考 + +290 +00:14:28,302 --> 00:14:31,038 +其他页面的信息 + +291 +00:14:31,038 --> 00:14:33,373 +现在 熟悉了两种交互方式以后 + +292 +00:14:33,373 --> 00:14:35,275 +我们再来分别进行进一步探讨 + +293 +00:14:35,275 --> 00:14:37,811 +先从分层导航开始 + +294 +00:14:37,811 --> 00:14:40,480 +下面是几条要考虑的操作指南 + +295 +00:14:40,480 --> 00:14:42,649 +使用推送 +来在 App 的不同层级结构中 + +296 +00:14:42,649 --> 00:14:46,119 +进行切换 + +297 +00:14:46,119 --> 00:14:49,690 +分层导航能够加强 + +298 +00:14:49,690 --> 00:14:52,826 +顶级和下级内容间的关系 + +299 +00:14:52,826 --> 00:14:55,863 +顶级内容具有更高等级 + +300 +00:14:55,863 --> 00:14:59,533 +想要更多的细节时才需要深入下层 + +301 +00:14:59,533 --> 00:15:03,003 +去访问补充界面 + +302 +00:15:03,003 --> 00:15:05,939 +这样在做选择时 范围就小了很多 + +303 +00:15:05,939 --> 00:15:09,576 +且无需访问其他的无关层级 + +304 +00:15:09,576 --> 00:15:11,578 +这就是理想的效果 + +305 +00:15:11,578 --> 00:15:14,081 +内容应当越来越具体 + +306 +00:15:14,081 --> 00:15:16,984 +且随着细节的推进 + +307 +00:15:16,984 --> 00:15:20,187 +选择应当越来越少 + +308 +00:15:20,187 --> 00:15:21,788 +使用推送进行切换时 + +309 +00:15:21,788 --> 00:15:23,590 +要注意导航栏 + +310 +00:15:23,590 --> 00:15:27,861 +必须始终位于屏幕底部 + +311 +00:15:27,861 --> 00:15:29,596 +如之前所说 + +312 +00:15:29,596 --> 00:15:31,231 +这是导航栏导航 + +313 +00:15:31,231 --> 00:15:32,799 +最大的好处 + +314 +00:15:32,799 --> 00:15:34,134 +这样才能保持一致性 + +315 +00:15:34,134 --> 00:15:36,603 +让用户始终能访问 +App 的核心区域 + +316 +00:15:36,603 --> 00:15:38,705 +因为从头到尾都能看见 + +317 +00:15:38,705 --> 00:15:40,541 +这意味着用户能够探索 + +318 +00:15:40,541 --> 00:15:42,609 +不同层级的内容 + +319 +00:15:42,609 --> 00:15:44,978 +随着页面的推进 + +320 +00:15:44,978 --> 00:15:48,615 +用户想要返回原来页面 +很自然地会从左往右扫 + +321 +00:15:48,615 --> 00:15:50,584 +同时还不会打乱其他 +已保存了状态的页面 + +322 +00:15:50,584 --> 00:15:54,888 +及其层级结构 + +323 +00:15:54,888 --> 00:15:57,457 +接下来 还可以使用适当的标签 + +324 +00:15:57,457 --> 00:16:00,194 +通过屏幕的顶部导航栏 + +325 +00:16:00,194 --> 00:16:02,429 +引导用户在层级间切换 + +326 +00:16:02,429 --> 00:16:04,932 +举个例子 + +327 +00:16:04,932 --> 00:16:06,533 +注意 随着我步步深入 + +328 +00:16:06,533 --> 00:16:08,602 +不同层次的信息 + +329 +00:16:08,602 --> 00:16:12,005 +返回按钮在导航栏中出现了变化 + +330 +00:16:12,005 --> 00:16:16,376 +这些变化反映了上一个页面的标题 + +331 +00:16:16,376 --> 00:16:19,746 +这种设计 能帮助我在滚动屏幕 + +332 +00:16:19,746 --> 00:16:22,449 +深入 App 内部层级的同时 +不发生混乱 + +333 +00:16:22,449 --> 00:16:24,852 +让我不用记住自己是从哪里过来的 + +334 +00:16:24,852 --> 00:16:27,454 +要怎么回去 因为返回按钮 + +335 +00:16:27,454 --> 00:16:31,959 +直接告诉我上一个层级的内容 + +336 +00:16:31,959 --> 00:16:34,795 +另一个可以利用分层导航的地方 + +337 +00:16:34,795 --> 00:16:40,033 +是当有用到展示指示器的时候 + +338 +00:16:40,033 --> 00:16:41,435 +展示指示器 + +339 +00:16:41,435 --> 00:16:43,904 +也被称为山形符号 + +340 +00:16:43,904 --> 00:16:47,841 +它会指向您要去的地方 + +341 +00:16:47,841 --> 00:16:50,244 +山形符号所引发的不同切换 + +342 +00:16:50,244 --> 00:16:52,813 +在 UI 表示的内容及相应交互间 + +343 +00:16:52,813 --> 00:16:55,415 +存在分离 + +344 +00:16:55,415 --> 00:16:59,887 +推送符合我们的认知模式 + +345 +00:16:59,887 --> 00:17:02,990 +在西方文化中 阅读习惯是从左往右 + +346 +00:17:02,990 --> 00:17:05,325 +因此这个方向表示下一步 + +347 +00:17:05,325 --> 00:17:08,829 +然而在从右到左的语言中 +如阿拉伯语和希伯来语 + +348 +00:17:08,829 --> 00:17:13,267 +表示下一步的方向正好相反 + +349 +00:17:13,267 --> 00:17:15,836 +如果您的 App 支持 +从右往左的语言 + +350 +00:17:15,836 --> 00:17:17,971 +则推送的方向必须相反 + +351 +00:17:17,971 --> 00:17:22,976 +才能使内容间自然联动 + +352 +00:17:22,976 --> 00:17:26,547 +何时应当使用分层导航 +要考虑的最后一条 + +353 +00:17:26,547 --> 00:17:28,749 +是操作的背景 + +354 +00:17:28,749 --> 00:17:31,018 +比如 当用户频繁地 + +355 +00:17:31,018 --> 00:17:33,754 +在内容之间切换时 + +356 +00:17:33,754 --> 00:17:36,156 +如果某种操作需要用户 + +357 +00:17:36,156 --> 00:17:40,060 +频繁交互 反复切换页面 + +358 +00:17:40,060 --> 00:17:41,929 +操作中需要频繁换 App + +359 +00:17:41,929 --> 00:17:45,899 +或是要花大量时间停留在某个页面 +则应当使用推送 + +360 +00:17:45,899 --> 00:17:48,268 +一个熟悉的例子 +就是“信息”App + +361 +00:17:48,268 --> 00:17:50,637 +虽然该 App 的层级相对扁平 + +362 +00:17:50,637 --> 00:17:53,207 +但我可以在短信间通过推送 + +363 +00:17:53,207 --> 00:17:55,309 +轻松进出 + +364 +00:17:55,309 --> 00:17:58,712 +如果不用推送 而用模态窗 + +365 +00:17:58,712 --> 00:18:00,547 +在不同的聊天窗间无缝切换 + +366 +00:18:00,547 --> 00:18:02,416 +就很难了 + +367 +00:18:02,416 --> 00:18:05,652 +聊天要保持连续性 +但关闭一个无关的模态窗时 + +368 +00:18:05,652 --> 00:18:08,488 +用户会忍不住犹豫 +是否要离开该页面 + +369 +00:18:08,488 --> 00:18:11,658 +这就增加了没必要的负担 + +370 +00:18:11,658 --> 00:18:13,994 +推送则能让用户实现 + +371 +00:18:13,994 --> 00:18:17,264 +App 核心区域之间的平滑转换 + +372 +00:18:17,264 --> 00:18:20,434 +以上就是分层导航的简单概述 + +373 +00:18:20,434 --> 00:18:21,702 +我们复习一下 + +374 +00:18:21,702 --> 00:18:24,438 +首先 推送的切换方式 + +375 +00:18:24,438 --> 00:18:26,807 +可以用于 App 层级间的转换 + +376 +00:18:26,807 --> 00:18:29,209 +底部导航栏应当始终 + +377 +00:18:29,209 --> 00:18:31,912 +保持在屏幕底部 + +378 +00:18:31,912 --> 00:18:34,281 +每个页面的导航栏 +都应当有清晰的标题 + +379 +00:18:34,281 --> 00:18:38,919 +和返回标签 以帮助用户 +清楚自己所在的层级 + +380 +00:18:38,919 --> 00:18:42,456 +有展示指示器存在的时候要用推送 + +381 +00:18:42,456 --> 00:18:44,892 +当操作需要在内容间频繁切换时 + +382 +00:18:44,892 --> 00:18:47,327 +也要用推送 + +383 +00:18:47,327 --> 00:18:49,696 +分层导航是一种非常常见 + +384 +00:18:49,696 --> 00:18:51,798 +以及相对简单的交互方式 + +385 +00:18:51,798 --> 00:18:56,637 +因此您的 App 中 +也可能经常用到 + +386 +00:18:56,637 --> 00:19:00,774 +而模态窗则更多用在 +存在背景转换的情况下 + +387 +00:19:00,774 --> 00:19:03,810 +这种方式重在帮助用户 +专心进行某种单一的操作 + +388 +00:19:03,810 --> 00:19:05,712 +或是独立任务 + +389 +00:19:05,712 --> 00:19:07,714 +在 iOS 上使用模态窗时 + +390 +00:19:07,714 --> 00:19:11,151 +应当始终从屏幕底部呈现 + +391 +00:19:11,151 --> 00:19:13,554 +因为模态窗会打断信息的层级 + +392 +00:19:13,554 --> 00:19:17,824 +从屏幕底部出现 +可以盖住底部导航栏 + +393 +00:19:17,824 --> 00:19:20,527 +这样用户就无法进一步深入 + +394 +00:19:20,527 --> 00:19:23,263 +这种打断操作是故意的 + +395 +00:19:23,263 --> 00:19:27,401 +就为了强化注意力 + +396 +00:19:27,401 --> 00:19:30,737 +现在您可能会想 +那什么叫独立任务? + +397 +00:19:30,737 --> 00:19:34,074 +我们举三个宽泛的例子 + +398 +00:19:34,074 --> 00:19:37,544 +模态窗可以用于简单任务 + +399 +00:19:37,544 --> 00:19:41,448 +多步骤任务 或者用于全屏内容 + +400 +00:19:41,448 --> 00:19:45,552 +下面我会分别举例 + +401 +00:19:45,552 --> 00:19:47,988 +第一个 使用模态窗 + +402 +00:19:47,988 --> 00:19:50,524 +来完成一项简单的任务 + +403 +00:19:50,524 --> 00:19:53,927 +例如创建活动 或设置提醒 + +404 +00:19:53,927 --> 00:19:55,629 +创建提醒要求 + +405 +00:19:55,629 --> 00:19:58,565 +对输入信息进行编辑和修改 + +406 +00:19:58,565 --> 00:20:00,834 +在此过程中锁定注意力可以帮助用户 + +407 +00:20:00,834 --> 00:20:03,670 +心无旁骛地完成任务 + +408 +00:20:03,670 --> 00:20:06,373 +还可以减少因为不小心点到 + +409 +00:20:06,373 --> 00:20:11,912 +其他元素或菜单而报废操作的情况 + +410 +00:20:11,912 --> 00:20:14,882 +第二 使用模态窗来辅助进行 + +411 +00:20:14,882 --> 00:20:16,750 +复杂任务的操作 + +412 +00:20:16,750 --> 00:20:18,785 +这种操作一般涉及多个步骤 + +413 +00:20:18,785 --> 00:20:21,989 +比如在“钱包”App 里 +添加银行卡 + +414 +00:20:21,989 --> 00:20:24,258 +在复杂任务中使用模态窗 + +415 +00:20:24,258 --> 00:20:27,294 +似乎违背我们的直觉 但请记住 + +416 +00:20:27,294 --> 00:20:30,764 +我们的目的是通过隐藏底部导航栏 + +417 +00:20:30,764 --> 00:20:33,367 +来集中注意 并在任务完成或取消前 + +418 +00:20:33,367 --> 00:20:37,337 +防止人们在 App 中移动 + +419 +00:20:37,337 --> 00:20:40,974 +第三 使用模态窗来 +阅读文章 观看视频 + +420 +00:20:40,974 --> 00:20:43,911 +或全屏内容这类 + +421 +00:20:43,911 --> 00:20:45,812 +无需太多页面切换的操作 + +422 +00:20:45,812 --> 00:20:48,215 +一个很好的例子 +就是在“健身”App 中 + +423 +00:20:48,215 --> 00:20:50,117 +通过打开一个健身视频 + +424 +00:20:50,117 --> 00:20:54,721 +来开始锻炼 + +425 +00:20:54,721 --> 00:20:57,457 +在层级交互部分 我们谈到了 + +426 +00:20:57,457 --> 00:20:59,993 +用导航栏来帮助用户定位的重要性 + +427 +00:20:59,993 --> 00:21:03,997 +在模态窗中 这一点同样重要 + +428 +00:21:03,997 --> 00:21:06,099 +剖析模态窗的结构时 + +429 +00:21:06,099 --> 00:21:09,703 +要想想导航栏是如何帮助定位的 + +430 +00:21:09,703 --> 00:21:13,106 +使用标签和交互操作能帮助用户 + +431 +00:21:13,106 --> 00:21:15,909 +对于自身位置以及如何访问其他位置 + +432 +00:21:15,909 --> 00:21:19,146 +产生信心 + +433 +00:21:19,146 --> 00:21:22,583 +标题可以帮助用户 +找到页面中的内容 + +434 +00:21:22,583 --> 00:21:25,619 +例如如“新行程” + +435 +00:21:25,619 --> 00:21:28,488 +右侧的标签则一般用于首选操作 + +436 +00:21:28,488 --> 00:21:33,227 +因此通常用粗体显示以强调重要性 + +437 +00:21:33,227 --> 00:21:36,096 +用简单的动词来作标签 + +438 +00:21:36,096 --> 00:21:39,433 +可以告诉我点击后会发生什么 + +439 +00:21:39,433 --> 00:21:41,635 +首选操作可以关闭模态窗 + +440 +00:21:41,635 --> 00:21:45,572 +同时保存上一步的状态 + +441 +00:21:45,572 --> 00:21:48,609 +如果模态窗上还没有 +输入信息或交互 + +442 +00:21:48,609 --> 00:21:51,378 +则首选操作不会激活 + +443 +00:21:51,378 --> 00:21:53,780 +这样可以让用户明白 + +444 +00:21:53,780 --> 00:21:57,985 +要输入信息才可保存或继续 + +445 +00:21:57,985 --> 00:22:00,787 +如果已经作了首选操作 +则用左边的“取消”按钮 + +446 +00:22:00,787 --> 00:22:03,323 +来关闭模态窗 + +447 +00:22:03,323 --> 00:22:06,026 +可以清楚地表明我要放弃操作了 + +448 +00:22:06,026 --> 00:22:08,996 +如果在点击取消之前 我输入过信息 + +449 +00:22:08,996 --> 00:22:12,099 +这时候就可以出现一个警告 + +450 +00:22:12,099 --> 00:22:14,201 +或一个 Action sheet + +451 +00:22:14,201 --> 00:22:16,737 +以提示用户继续取消的话 + +452 +00:22:16,737 --> 00:22:18,805 +就会丢失数据 + +453 +00:22:18,805 --> 00:22:21,241 +不过 如果我还没有与 UI 交互 + +454 +00:22:21,241 --> 00:22:25,712 +点击取消就会直接关闭模态窗 + +455 +00:22:25,712 --> 00:22:29,249 +尽量少用“关闭”符号 仅当模态窗 + +456 +00:22:29,249 --> 00:22:33,453 +所需的交互很少 +无需文本输入时使用 + +457 +00:22:33,453 --> 00:22:36,123 +有时候可以在模态窗中 +看到一个“X” + +458 +00:22:36,123 --> 00:22:38,859 +作为关闭窗口的首要方式 例如这篇 + +459 +00:22:38,859 --> 00:22:41,361 +在 App Store +“Today”标签页的文章 + +460 +00:22:41,361 --> 00:22:44,798 +“关闭”符号可以用在这里 +是因为这里无需用户输入 + +461 +00:22:44,798 --> 00:22:46,533 +因此简单的关闭动作 + +462 +00:22:46,533 --> 00:22:49,136 +可以帮助用户 +把注意力集中在内容上 + +463 +00:22:49,136 --> 00:22:52,105 +下面举个例子 说明“关闭”符号 + +464 +00:22:52,105 --> 00:22:55,742 +在需要输入和交互的模态窗里 +为何会出问题 + +465 +00:22:55,742 --> 00:22:58,812 +当我选择完一个筛选器后 +如果我点“关闭” + +466 +00:22:58,812 --> 00:23:01,615 +我刚才的选择会被提交还是取消? + +467 +00:23:01,615 --> 00:23:04,751 +没有一个明确的标签提示 +用户就会不确定 + +468 +00:23:04,751 --> 00:23:07,221 +“如果我点了‘关闭’会怎样?” + +469 +00:23:07,221 --> 00:23:10,390 +所以要记住 使用导航栏中的标签 + +470 +00:23:10,390 --> 00:23:12,960 +通常是首选 因为这样更明确 + +471 +00:23:12,960 --> 00:23:15,996 +操作上更明白 + +472 +00:23:15,996 --> 00:23:19,466 +最后 要避免模态窗上 +再叠加模态窗 + +473 +00:23:19,466 --> 00:23:23,604 +因为这样很累赘 且过于复杂 + +474 +00:23:23,604 --> 00:23:25,906 +这里我要提醒大家 模态窗界面本身 + +475 +00:23:25,906 --> 00:23:29,376 +是支持子视图以及切换相关页面的 + +476 +00:23:29,376 --> 00:23:31,979 +我之前提到过 这是一个编辑界面 + +477 +00:23:31,979 --> 00:23:35,315 +其文本字段和表格单元格 + +478 +00:23:35,315 --> 00:23:37,417 +可以进行选择和输入 + +479 +00:23:37,417 --> 00:23:41,121 +因此是可以交互 而不仅仅是阅读的 + +480 +00:23:41,121 --> 00:23:43,724 +例如 我可以点击某个 +添加在行程上的 + +481 +00:23:43,724 --> 00:23:46,860 +好友单元格 + +482 +00:23:46,860 --> 00:23:50,264 +点击后会出现一个推送窗 +因为这里有山形标记 对吧? + +483 +00:23:50,264 --> 00:23:53,467 +点进去后 这个界面可能 +会展示 Kate 的信息 + +484 +00:23:53,467 --> 00:23:57,905 +并允许我将她从行程上移除 + +485 +00:23:57,905 --> 00:24:01,241 +不过 “加好友” +和“上传照片”的标签 + +486 +00:24:01,241 --> 00:24:05,812 +此时都是绿色显示 +表示这些操作都允许 + +487 +00:24:05,812 --> 00:24:07,147 +这几种情况 + +488 +00:24:07,147 --> 00:24:09,449 +都属于操作中的操作 + +489 +00:24:09,449 --> 00:24:11,485 +首先我要添加一份行程表 + +490 +00:24:11,485 --> 00:24:15,289 +然后要在行程表上的添加照片 + +491 +00:24:15,289 --> 00:24:17,724 +上传照片的操作涉及到 + +492 +00:24:17,724 --> 00:24:19,726 +相当多的互动 + +493 +00:24:19,726 --> 00:24:23,797 +比如要在相册中滚动 +并选择一张新照片 + +494 +00:24:23,797 --> 00:24:27,067 +这样的操作也属于独立任务 + +495 +00:24:27,067 --> 00:24:30,103 +选择好照片后 该模态窗就可以关闭 + +496 +00:24:30,103 --> 00:24:34,074 +我又回到了新建行程中 +刚开始的模态窗里 + +497 +00:24:34,074 --> 00:24:36,577 +要尽量减少多个模态窗的叠加 + +498 +00:24:36,577 --> 00:24:38,212 +不过有时候 这也是必要的 + +499 +00:24:38,212 --> 00:24:42,382 +可以帮助在子视图中 +保持一致性和注意力 + +500 +00:24:42,382 --> 00:24:46,386 +以上 就是对 iOS +模态窗展示的概述 + +501 +00:24:46,386 --> 00:24:49,389 +模态窗应从屏幕底部呈现 + +502 +00:24:49,389 --> 00:24:51,825 +可以用于三种类型的任务: + +503 +00:24:51,825 --> 00:24:55,262 +简单任务 多步骤任务及全屏任务 + +504 +00:24:55,262 --> 00:25:00,133 +在导航栏中呈现首选和取消操作 + +505 +00:25:00,133 --> 00:25:04,037 +只在交互很少的内容中 +使用“关闭”符号 + +506 +00:25:04,037 --> 00:25:06,974 +并尽量减少多个模态窗的叠加 + +507 +00:25:06,974 --> 00:25:09,343 +希望这次深入剖析对您有帮助 + +508 +00:25:09,343 --> 00:25:12,045 +当您为自己的 +iOS App 设计导航时 + +509 +00:25:12,045 --> 00:25:14,581 +要考虑如何组织内容 + +510 +00:25:14,581 --> 00:25:16,583 +思考用户与您的功能如何交互 + +511 +00:25:16,583 --> 00:25:20,187 +以及如何将其与您的层级 +完美结合 展示出来 + +512 +00:25:20,187 --> 00:25:23,257 +这样 用户就可以轻松访问 + +513 +00:25:23,257 --> 00:25:25,692 +您的 App 上所有出色的功能 +并享受使用的过程了 + +514 +00:25:25,692 --> 00:25:26,793 +感谢您的收看 + +515 +00:25:26,793 --> 00:25:30,531 +♪ + diff --git a/zho/2022 Session 10002 Create macOS or Linux virtual machines.srt b/zho/2022 Session 10002 Create macOS or Linux virtual machines.srt new file mode 100644 index 0000000..e390cf3 --- /dev/null +++ b/zho/2022 Session 10002 Create macOS or Linux virtual machines.srt @@ -0,0 +1,1812 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,009 --> 00:00:14,014 +大家好 欢迎来到虚拟化课程 + +3 +00:00:14,047 --> 00:00:17,451 +这是我们今天的内容 + +4 +00:00:17,484 --> 00:00:22,222 +我们将了解如何在 Apple 芯片上 + +5 +00:00:22,256 --> 00:00:24,258 +运行 macOS 和 Linux 虚拟机 + +6 +00:00:24,291 --> 00:00:28,896 +在本课程结束时 +你将能够在自己的 Mac 上操作 + +7 +00:00:28,929 --> 00:00:31,798 +这可能有些挑战性 但跟上课程 + +8 +00:00:31,832 --> 00:00:33,567 +我们就能实现 + +9 +00:00:33,600 --> 00:00:35,502 +以下是今天的内容安排 + +10 +00:00:35,536 --> 00:00:38,739 +我们将首先介绍虚拟化技术概述 + +11 +00:00:38,772 --> 00:00:43,744 +并了解如何使用 Virtualization 框架 +构建虚拟机 + +12 +00:00:43,777 --> 00:00:47,114 +然后将深入研究 macOS + +13 +00:00:47,147 --> 00:00:51,919 +我们将了解如何设置 Mac 虚拟机 +并为它安装 macOS + +14 +00:00:51,952 --> 00:00:56,423 +最后 我们再来深入研究 Linux + +15 +00:00:56,456 --> 00:00:58,825 +我们将了解如何运行完整的 +Linux 发行版 + +16 +00:00:58,859 --> 00:01:01,261 +以及一些很酷的新特性 + +17 +00:01:01,295 --> 00:01:03,830 +我们从概述开始 + +18 +00:01:03,864 --> 00:01:08,068 +我们将首先介绍 +支持虚拟化的技术栈 + +19 +00:01:08,101 --> 00:01:10,904 +首先是硬件 + +20 +00:01:10,938 --> 00:01:14,608 +Apple 芯片拥有能够实现 + +21 +00:01:14,641 --> 00:01:16,143 +CPU 和内存虚拟化的特殊硬件 + +22 +00:01:16,176 --> 00:01:20,848 +这表示你可以在单个 SoC 上 +运行多个操作系统 + +23 +00:01:20,881 --> 00:01:24,084 +然后 我们需要软件来利用这个硬件 + +24 +00:01:24,117 --> 00:01:27,421 +这是内置于 macOS 内核中的 + +25 +00:01:27,454 --> 00:01:30,424 +你不再需要编写内核扩展或者 KEXT + +26 +00:01:30,457 --> 00:01:32,993 +一切都是内置的 + +27 +00:01:33,026 --> 00:01:35,162 +要在应用程序中使用这些功能 + +28 +00:01:35,195 --> 00:01:37,698 +你可以使用 Hypervisor 框架 + +29 +00:01:37,731 --> 00:01:43,537 +Hypervisor 框架是一个底层 API +允许你虚拟化 CPU 和内存 + +30 +00:01:43,570 --> 00:01:46,206 +但由于它是一个低级框架 + +31 +00:01:46,240 --> 00:01:50,377 +你需要编写虚拟环境的每一处细节 + +32 +00:01:50,410 --> 00:01:53,547 +通常 我们想要运行完整的操作系统 + +33 +00:01:53,580 --> 00:01:58,919 +因此更高级别的 API +Virtualization 框架应运而生 + +34 +00:01:58,952 --> 00:02:02,022 +Virtualization 框架能够创建虚拟机 + +35 +00:02:02,055 --> 00:02:08,061 +在 Apple 芯片上运行 macOS +或在 Apple 芯片和 Intel 上运行 Linux + +36 +00:02:08,095 --> 00:02:11,064 +我们今天将集中讨论 Virtualization 框架 + +37 +00:02:11,098 --> 00:02:14,668 +在使用 Virtualization 框架时 +我们将处理两类对象 + +38 +00:02:14,701 --> 00:02:17,070 +第一类是配置对象 + +39 +00:02:17,104 --> 00:02:20,107 +它们定义了虚拟机的所有属性 + +40 +00:02:20,140 --> 00:02:22,743 +第二类是虚拟机对象 + +41 +00:02:22,776 --> 00:02:27,548 +它们抽象化了虚拟机 +以及和它们的交互方式 + +42 +00:02:27,581 --> 00:02:31,185 +我们先来看配置 + +43 +00:02:31,218 --> 00:02:34,221 +配置代表着硬件 + +44 +00:02:34,254 --> 00:02:38,425 +创建配置就像在 Apple Store 商店中 +配置 Mac 一样 + +45 +00:02:38,458 --> 00:02:42,863 +我们要定义需要多少 CPU +多少内存和什么样的设备 + +46 +00:02:42,896 --> 00:02:45,532 +我们可以从一个简单的配置开始 + +47 +00:02:45,566 --> 00:02:47,801 +添加一个显示器 用来看到内容 + +48 +00:02:47,835 --> 00:02:50,404 +再加一个键盘 可以打字 + +49 +00:02:50,437 --> 00:02:53,707 +添加一个触控板 就可以与 UI 交互 + +50 +00:02:53,740 --> 00:02:57,211 +配置虚拟机就是这样 + +51 +00:02:57,244 --> 00:02:59,313 +但由于我们处理的是虚拟机 + +52 +00:02:59,346 --> 00:03:01,515 +所以我们将利用代码来完成 + +53 +00:03:01,548 --> 00:03:05,319 +我们来看看如何通过 Swift 编写配置 + +54 +00:03:05,352 --> 00:03:07,921 +定义硬件非常简单 + +55 +00:03:07,955 --> 00:03:12,025 +我们从 VZVirtualMachineConfiguration +这个类型开始 + +56 +00:03:12,059 --> 00:03:15,762 +这是所有配置的根对象 + +57 +00:03:15,796 --> 00:03:19,700 +然后 我们定义机器应该有多少 CPU + +58 +00:03:19,733 --> 00:03:22,102 +这里我们给出 4 个 CPU + +59 +00:03:22,135 --> 00:03:24,571 +然后 我们设置需要多少内存 + +60 +00:03:24,605 --> 00:03:27,975 +这里我们设置为 4GB + +61 +00:03:28,008 --> 00:03:31,578 +最后 我们要定义机器将拥有的设备 + +62 +00:03:31,612 --> 00:03:34,515 +这里我们定义了单个存储设备 + +63 +00:03:34,548 --> 00:03:38,952 +引导磁盘和一个定点设备 如鼠标 + +64 +00:03:38,986 --> 00:03:40,721 +有很多可用的设备 + +65 +00:03:40,754 --> 00:03:44,558 +你设置什么取决于你想解决的问题 + +66 +00:03:44,591 --> 00:03:46,059 +现在我们了解了配置 + +67 +00:03:46,093 --> 00:03:48,629 +它从 VZVirtualMachineConfiguration 开始 + +68 +00:03:48,662 --> 00:03:53,333 +我们在上面添加 CPU 内存和设备 + +69 +00:03:53,367 --> 00:03:56,970 +接下来 我们来研究虚拟机对象 + +70 +00:03:58,205 --> 00:04:00,874 +配置好 Mac 下单之后 +我们通过快递收到它 + +71 +00:04:00,908 --> 00:04:03,677 +下面就可以拆箱并启动它了 + +72 +00:04:03,710 --> 00:04:06,079 +但我们处理的是虚拟机 + +73 +00:04:06,113 --> 00:04:08,515 +需要利用代码来完成 + +74 +00:04:08,549 --> 00:04:11,585 +我们来看看如何通过 Swift 完成 + +75 +00:04:11,618 --> 00:04:14,688 +首先 我们通过配置 + +76 +00:04:14,721 --> 00:04:16,223 +创建 VZVirtualMachine 实例 + +77 +00:04:16,256 --> 00:04:20,627 +VZVirtualMachine 抽象了 +虚拟硬件实例 + +78 +00:04:20,661 --> 00:04:23,397 +现在我们有了虚拟机 +就可以对其进行操作了 + +79 +00:04:23,430 --> 00:04:27,901 +例如在本例中 我们调用 start() +来启动它 + +80 +00:04:27,935 --> 00:04:30,237 +我们经常想要与虚拟机交互 + +81 +00:04:30,270 --> 00:04:33,507 +因此我们需要其它对象的协助 + +82 +00:04:33,540 --> 00:04:36,410 +例如 如果我们想要展示虚拟显示器 + +83 +00:04:36,443 --> 00:04:39,680 +可以使用 VZVirtualMachineView +类型的对象 + +84 +00:04:39,713 --> 00:04:41,648 +我们先创建一个视图 + +85 +00:04:41,682 --> 00:04:45,619 +然后将视图上的 virtualMachine 属性 +设置为我们的虚拟机 + +86 +00:04:45,652 --> 00:04:47,154 +这样就大功告成了 + +87 +00:04:47,187 --> 00:04:51,525 +现在我们可以像使用任何 NSView 一样 +使用 VZVirtualMachineView + +88 +00:04:51,558 --> 00:04:55,395 +我们可以将它集成到 App 中 +以查看虚拟机的内容 + +89 +00:04:56,964 --> 00:04:59,967 +总结一下 我们已经看过了配置 + +90 +00:05:00,000 --> 00:05:03,770 +配置是从 +VZVirtualMachineConfiguration 开始 + +91 +00:05:03,804 --> 00:05:08,208 +我们从中定义 CPU 内存和设备 + +92 +00:05:08,242 --> 00:05:10,878 +通过配置 我们创建一个虚拟机 + +93 +00:05:10,911 --> 00:05:13,480 +并使用虚拟机对象 + +94 +00:05:13,514 --> 00:05:17,651 +我们已经了解了 +VZVirtualMachine 抽象了虚拟机本身 + +95 +00:05:17,684 --> 00:05:20,554 +VZVirtualMachineView 显示内容 + +96 +00:05:20,587 --> 00:05:23,624 +还有其它对象可以协助我们 +使用虚拟机 + +97 +00:05:23,657 --> 00:05:26,927 +我们已经了解到 +该配置为定义虚拟机 + +98 +00:05:26,960 --> 00:05:29,162 +提供了很大的灵活性 + +99 +00:05:29,196 --> 00:05:33,667 +遗憾的是 +没法在一节课涉及太多功能 + +100 +00:05:33,700 --> 00:05:37,437 +在本节课中 +我们会研究一些核心能力 + +101 +00:05:37,471 --> 00:05:39,873 +其它的内容均在文档中 + +102 +00:05:39,907 --> 00:05:42,943 +我希望大家查看一下 + +103 +00:05:42,976 --> 00:05:46,647 +我们在概述中了解了如何构建虚拟机 + +104 +00:05:46,680 --> 00:05:50,684 +现在来研究如何在其中运行 +完整的操作系统 + +105 +00:05:50,717 --> 00:05:52,953 +我们将从 macOS 开始 + +106 +00:05:52,986 --> 00:05:56,790 +Virtualization 框架 +在 Apple 芯片上支持 macOS + +107 +00:05:56,823 --> 00:05:59,126 +当我们在 Apple 芯片上 +构建 Virtualization 框架时 + +108 +00:05:59,159 --> 00:06:03,163 +我们同时开发了 +macOS 和 Virtualization 框架 + +109 +00:06:03,197 --> 00:06:05,966 +这使得 +在虚拟机中运行 macOS 时 + +110 +00:06:05,999 --> 00:06:08,735 +效率十分惊人 + +111 +00:06:08,769 --> 00:06:11,038 +以下是我们将要了解的内容 + +112 +00:06:11,071 --> 00:06:12,973 +首先 我们会研究如何 + +113 +00:06:13,006 --> 00:06:16,376 +将虚拟机变成 Mac 虚拟机 + +114 +00:06:16,410 --> 00:06:20,914 +然后 我们将研究 +在 Mac 虚拟机上安装 macOS 的步骤 + +115 +00:06:20,948 --> 00:06:25,352 +接下来 我们还将了解到 macOS 的 +一些特殊设备 + +116 +00:06:25,385 --> 00:06:28,822 +最后 我们将学习一个 +非常重要的实例 + +117 +00:06:28,856 --> 00:06:32,826 +在主机系统和 Mac 虚拟机之间 +共享文件 + +118 +00:06:34,261 --> 00:06:36,830 +我们先从配置开始 + +119 +00:06:36,864 --> 00:06:40,167 +我们已经了解了如何搭建通用虚拟机 + +120 +00:06:40,200 --> 00:06:45,706 +现在我们想添加一些特殊属性 +让其成为 Mac 虚拟机 + +121 +00:06:45,739 --> 00:06:48,976 +那么我们如何配置 Mac 虚拟机呢 + +122 +00:06:49,009 --> 00:06:51,879 +首先 我们要定义一个特殊的平台 + +123 +00:06:51,912 --> 00:06:55,315 +平台是一个对象 + +124 +00:06:55,349 --> 00:06:57,684 +它拥有特定类型虚拟机的所有属性 + +125 +00:06:57,718 --> 00:07:02,122 +Mac 虚拟机硬件有三个独特的属性 + +126 +00:07:02,155 --> 00:07:04,358 +第一个是硬件模型 + +127 +00:07:04,391 --> 00:07:09,196 +硬件模型决定了我们需要的 +Mac 虚拟机的版本 + +128 +00:07:09,229 --> 00:07:11,265 +其次是辅助存储器 + +129 +00:07:11,298 --> 00:07:15,969 +它是系统使用的一种非易失性存储器 + +130 +00:07:16,003 --> 00:07:19,239 +第三个是虚拟机标识符 + +131 +00:07:19,273 --> 00:07:22,676 +它是代表机器的唯一数字 + +132 +00:07:22,709 --> 00:07:26,113 +就像每台 Mac 都有 +唯一的序列号一样 + +133 +00:07:26,146 --> 00:07:29,883 +一旦我们有了平台 +就有了所有这些硬件 + +134 +00:07:29,917 --> 00:07:34,621 +但还差一点 +那就是引导 macOS 的方法 + +135 +00:07:34,655 --> 00:07:36,890 +为此 我们将使用一个 +特殊的引导加载程序 + +136 +00:07:36,924 --> 00:07:39,126 +macOS 引导加载程序 + +137 +00:07:39,159 --> 00:07:43,063 +我们来看看 +如何在在 Swift 中做到这一切 + +138 +00:07:43,096 --> 00:07:44,932 +我们还是从最基本的开始 + +139 +00:07:44,965 --> 00:07:48,635 +这段代码是我们在概述中见过的 + +140 +00:07:48,669 --> 00:07:52,506 +然后我们创建一个 +VZMacPlatformConfiguration + +141 +00:07:52,539 --> 00:07:56,043 +这是我们的虚拟 Mac 平台对象 + +142 +00:07:56,076 --> 00:07:58,011 +我们需要一个 Mac 的硬件模型 + +143 +00:07:58,045 --> 00:08:01,315 +这里我们使用之前保存的一个 + +144 +00:08:01,348 --> 00:08:03,650 +在虚拟机中 辅助存储器 + +145 +00:08:03,684 --> 00:08:06,119 +由本地文件系统上的某个文件支持 + +146 +00:08:06,153 --> 00:08:09,957 +在这里 我们通过 +文件 URL 来初始化辅助存储器 + +147 +00:08:09,990 --> 00:08:13,760 +我们从之前保存的一个标识符中 + +148 +00:08:13,794 --> 00:08:15,762 +初始化 VZMacMachineIdentifier + +149 +00:08:15,796 --> 00:08:19,633 +对于新的安装 +我们还可以创建一个新的标识符 + +150 +00:08:19,666 --> 00:08:23,470 +我们已经设置好了三个属性 +平台已准备就绪 + +151 +00:08:23,504 --> 00:08:27,107 +我们所要做的就是 +在配置对象上设置它 + +152 +00:08:27,140 --> 00:08:31,011 +得到了硬件 +接下来我们要找方法来启动它 + +153 +00:08:31,912 --> 00:08:36,383 +为此 我们使用 VZMacBootLoader +来设置引导加载程序 + +154 +00:08:36,416 --> 00:08:38,719 +现在我们的机器已准备好启动了 + +155 +00:08:38,752 --> 00:08:43,123 +到目前为止 我们所做的 +是如何定义虚拟 Mac 以及启动它 + +156 +00:08:43,156 --> 00:08:45,125 +但我们仍需要在上面安装软件 + +157 +00:08:45,158 --> 00:08:48,395 +这就涉及到安装 + +158 +00:08:48,428 --> 00:08:51,265 +安装 macOS 需要三个步骤 + +159 +00:08:51,298 --> 00:08:54,501 +首先 我们需要下载一个 +带有要安装的 + +160 +00:08:54,535 --> 00:08:56,703 +macOS 版本的恢复映像 + +161 +00:08:56,737 --> 00:08:58,939 +然后 我们需要创建一个 + +162 +00:08:58,972 --> 00:09:01,942 +与 macOS 版本兼容的配置 + +163 +00:09:01,975 --> 00:09:04,645 +最后 我们将在兼容的 + +164 +00:09:04,678 --> 00:09:07,114 +虚拟机中安装我们的恢复映像 + +165 +00:09:07,147 --> 00:09:10,117 +首先 我们需要下载一个恢复映像 + +166 +00:09:10,150 --> 00:09:12,753 +你可以从开发者网站下载 + +167 +00:09:12,786 --> 00:09:15,989 +但 Virtualization 也可以帮到我们 + +168 +00:09:16,023 --> 00:09:19,927 +你可以调用 +VZMacOSRestoreImage.latestSupported + +169 +00:09:19,960 --> 00:09:25,032 +为最新稳定版本的 macOS 获取 +恢复映像对象 + +170 +00:09:25,065 --> 00:09:29,570 +这个对象有我们可以用来 +下载文件的 URL 属性 + +171 +00:09:29,603 --> 00:09:32,739 +然后 我们希望创建一个 +与我们下载的 + +172 +00:09:32,773 --> 00:09:35,409 +macOS 版本兼容的虚拟机 + +173 +00:09:35,442 --> 00:09:37,811 +这里 Virtualization 也可以帮到我们 + +174 +00:09:37,845 --> 00:09:42,249 +我们可以向恢复映像对象询问配置要求 + +175 +00:09:42,282 --> 00:09:44,985 +如果恢复映像可以在当前系统上运行 + +176 +00:09:45,018 --> 00:09:47,888 +我们会得到一个可以列出需求的对象 + +177 +00:09:47,921 --> 00:09:50,858 +从需求中 +我们可以得到运行该版本的 macOS + +178 +00:09:50,891 --> 00:09:52,993 +所需的硬件模型 + +179 +00:09:53,026 --> 00:09:55,929 +我们已经看过了如何恢复硬件模型 + +180 +00:09:55,963 --> 00:09:58,665 +这就是我们如何获得新模型 + +181 +00:09:59,800 --> 00:10:03,470 +需求中还包含两个有用的属性 + +182 +00:10:03,504 --> 00:10:07,808 +该对象可以告诉我们运行 +这个版本的 macOS + +183 +00:10:07,841 --> 00:10:10,410 +需要多少 CPU 和内存 + +184 +00:10:11,345 --> 00:10:14,348 +最后 我们准备好开始安装了 + +185 +00:10:14,381 --> 00:10:18,218 +我们先从配置中创建一个新的虚拟机 + +186 +00:10:18,252 --> 00:10:20,354 +然后创建一个安装程序 + +187 +00:10:20,387 --> 00:10:22,789 +安装程序有两个参数 + +188 +00:10:22,823 --> 00:10:25,392 +我们创建的兼容虚拟机 + +189 +00:10:25,425 --> 00:10:28,662 +和下载恢复映像的路径 + +190 +00:10:28,695 --> 00:10:32,933 +现在我们只需调用安装即可 +看 我们准备好运行 macOS 了 + +191 +00:10:33,901 --> 00:10:37,104 +现在我们可以设置 +一个虚拟 Mac 并安装 macOS + +192 +00:10:37,137 --> 00:10:41,241 +我们来看看 Mac 的一些特殊设备 + +193 +00:10:41,275 --> 00:10:44,912 +第一个很酷的功能是 GPU 加速 + +194 +00:10:44,945 --> 00:10:48,582 +我们创建了一个图像设备 +将 GPU 功能 + +195 +00:10:48,615 --> 00:10:50,184 +暴露给虚拟 Mac 的 + +196 +00:10:50,217 --> 00:10:53,020 +这表示你可以在虚拟机中运行 Metal + +197 +00:10:53,053 --> 00:10:56,156 +并在 macOS 中获得出色的图形性能 + +198 +00:10:56,190 --> 00:10:58,125 +我们来看看如何设置它 + +199 +00:10:59,626 --> 00:11:02,496 +我们首先创建图形设备配置 + +200 +00:11:02,529 --> 00:11:06,333 +在这里 我们将使用 +VZMacGraphicsDeviceConfiguration + +201 +00:11:06,366 --> 00:11:08,402 +然后我们要给它一个显示器 + +202 +00:11:08,435 --> 00:11:13,040 +我们通过定义其大小 +和像素密度来设置显示器 + +203 +00:11:13,073 --> 00:11:15,342 +现在我们的设备已经设置好了 + +204 +00:11:15,375 --> 00:11:18,712 +像往常一样 +我们在主配置对象上设置它 + +205 +00:11:18,745 --> 00:11:22,249 +我们将它设置为虚拟机的图形设备 + +206 +00:11:23,383 --> 00:11:26,553 +接下来 我们来了解 +与 Mac 互动的新设备 + +207 +00:11:26,587 --> 00:11:29,890 +在 macOS Ventura 中 +我们将 Mac 触控板支持 + +208 +00:11:29,923 --> 00:11:31,558 +添加到了虚拟 Mac 中 + +209 +00:11:31,592 --> 00:11:34,127 +新的触控板支持 + +210 +00:11:34,161 --> 00:11:37,431 +旋转 缩放等手势 + +211 +00:11:37,464 --> 00:11:40,300 +这个新设备 +采用 macOS 中新的驱动程序 + +212 +00:11:40,334 --> 00:11:42,236 +所以要想使用它 +在主机系统 + +213 +00:11:42,269 --> 00:11:45,572 +和虚拟机中均需要 macOS 13 + +214 +00:11:45,606 --> 00:11:48,208 +我们来看看如何设置 + +215 +00:11:48,242 --> 00:11:50,210 +很简单 + +216 +00:11:50,244 --> 00:11:54,181 +我们创建一个 VZMacTrackpadConfiguration +类型的新对象 + +217 +00:11:54,214 --> 00:11:58,218 +然后将其设置为虚拟机上的定点设备 + +218 +00:11:58,252 --> 00:12:03,557 +当我们在虚拟 Mac 中使用视图时 +可以使用手势 + +219 +00:12:03,590 --> 00:12:06,627 +最后 我们来研究一下 +大多数人的常见用例 + +220 +00:12:06,660 --> 00:12:10,998 +即在主机系统和虚拟机之间共享文件 + +221 +00:12:11,031 --> 00:12:14,635 +在 macOS 12 中 +我们推出了 Virtio 文件系统设备 + +222 +00:12:14,668 --> 00:12:16,637 +在 Linux 上共享文件 + +223 +00:12:16,670 --> 00:12:20,407 +在 macOS Ventura 中 +我们增加了对 macOS 的支持 + +224 +00:12:20,440 --> 00:12:23,744 +你可以选择 +想要与虚拟机共享的文件夹 + +225 +00:12:23,777 --> 00:12:26,980 +你在主机系统中所做的任何更改 + +226 +00:12:27,014 --> 00:12:29,850 +都会立即反应在虚拟机中 反之亦然 + +227 +00:12:29,883 --> 00:12:32,152 +我们来看看如何设置 + +228 +00:12:32,186 --> 00:12:37,324 +首先 我们创建一个带有我们想要 +共享的目录的 VZShareDirectory + +229 +00:12:37,357 --> 00:12:39,726 +然后我们创建一个共享对象 + +230 +00:12:39,760 --> 00:12:43,931 +这里我们使用 VZSingleDirectoryShare +来共享单个目录 + +231 +00:12:43,964 --> 00:12:48,802 +您也可以用 VZMultipleDirectoryShare +来共享多个目录 + +232 +00:12:48,836 --> 00:12:51,438 +现在有了共享 +我们需要创建一个设备 + +233 +00:12:51,471 --> 00:12:54,241 +但我们将从一个特殊的东西开始 + +234 +00:12:54,274 --> 00:12:56,810 +文件系统设备由标记标识 + +235 +00:12:56,844 --> 00:12:59,913 +在 macOS Ventura 中 +我们添加了一个特殊标记 + +236 +00:12:59,947 --> 00:13:03,217 +告诉虚拟机自动装载这个设备 + +237 +00:13:03,250 --> 00:13:07,521 +这里 我们使用这个特殊标记 +即 macOSGuestAutomountTag + +238 +00:13:07,554 --> 00:13:11,325 +然后我们创建设备 +并使用我们的特殊标记 + +239 +00:13:11,358 --> 00:13:14,995 +我们从所配置的单个目录设置共享 + +240 +00:13:15,028 --> 00:13:19,266 +最后 像往常一样 +将设备添加到配置中 + +241 +00:13:19,299 --> 00:13:23,737 +最后 我们一起在演示中 +查看所有内容 + +242 +00:13:23,770 --> 00:13:26,273 +我们从基本配置开始 + +243 +00:13:26,306 --> 00:13:28,342 +我们有 +VZVirtualMachineConfiguration + +244 +00:13:28,375 --> 00:13:33,814 +它包含 CPU 内存 键盘和磁盘 + +245 +00:13:33,847 --> 00:13:35,449 +我们想要一个虚拟 Mac + +246 +00:13:35,482 --> 00:13:39,086 +因此 我们需要从设置平台开始 + +247 +00:13:39,119 --> 00:13:43,524 +我们将使用上面定义的 +createMacPlatform 来做到这一点 + +248 +00:13:43,557 --> 00:13:46,426 +创建虚拟 Mac 的第二步是 +引导加载程序 + +249 +00:13:46,460 --> 00:13:49,997 +我们需要知道如何启动 macOS 的 +引导加载程序 + +250 +00:13:50,030 --> 00:13:52,699 +为此 我们将平台的 +引导加载程序设置为 + +251 +00:13:52,733 --> 00:13:55,536 +VZMacOSBootLoader + +252 +00:13:55,569 --> 00:13:58,238 +接下来 我们要设置设备 + +253 +00:13:58,272 --> 00:14:00,507 +我们需要加速图形端口 + +254 +00:14:00,541 --> 00:14:04,711 +因此 我们设置一个 +VZMacGraphicsConfiguration + +255 +00:14:04,745 --> 00:14:06,413 +我们创建对象 + +256 +00:14:06,446 --> 00:14:09,383 +定义显示大小和像素密度 + +257 +00:14:09,416 --> 00:14:12,186 +并将其添加到配置中 + +258 +00:14:12,219 --> 00:14:14,755 +然后 我们想使用新的触控板 + +259 +00:14:14,788 --> 00:14:17,224 +我们所要做的就是将定点设备 + +260 +00:14:17,257 --> 00:14:19,426 +设置为 VZMacTrackpadConfiguration + +261 +00:14:19,459 --> 00:14:20,694 +以上就是全部 + +262 +00:14:20,727 --> 00:14:24,765 +现在 我们可以启动虚拟机了 +但是我们最后再添加一些东西 + +263 +00:14:24,798 --> 00:14:27,134 +我们已经看到了如何共享目录 + +264 +00:14:27,167 --> 00:14:29,169 +我们来演示一遍 + +265 +00:14:29,203 --> 00:14:32,406 +我们首先创建文件系统设备配置 + +266 +00:14:32,439 --> 00:14:37,010 +这里 请注意 我们使用特殊标记 +将它自动装载到 macOS 中 + +267 +00:14:37,044 --> 00:14:38,879 +然后定义我们的共享 + +268 +00:14:38,912 --> 00:14:42,649 +这里 使用文件系统上的 +路径的单个目录共享 + +269 +00:14:42,683 --> 00:14:46,019 +这里 我们将共享 +正在编辑的这个项目 + +270 +00:14:47,254 --> 00:14:50,457 +将设备添加到配置中 +这样就完成了 + +271 +00:14:51,391 --> 00:14:55,128 +一切就绪 我们来启动应用程序 + +272 +00:14:55,162 --> 00:14:57,598 +因为我们配置了 MacGraphics 设备 + +273 +00:14:57,631 --> 00:15:01,101 +VZVirtualMachineView +就会显示内容 + +274 +00:15:01,134 --> 00:15:04,271 +这就是我们在窗口中所看到的内容 + +275 +00:15:04,304 --> 00:15:08,008 +就是它 +我们从头开始配置 macOS + +276 +00:15:08,041 --> 00:15:11,678 +我们可以看到共享目录 +和此刻正在编辑的项目 + +277 +00:15:11,712 --> 00:15:14,915 +最后 我们来看一下 Linux + +278 +00:15:14,948 --> 00:15:17,150 +Virtualization 框架 +早在 macOS Big Sur 中 + +279 +00:15:17,184 --> 00:15:20,020 +就已支持 Linux + +280 +00:15:20,053 --> 00:15:23,357 +在 macOS Ventura 中 +我们增加了一些非常酷的新特性 + +281 +00:15:23,390 --> 00:15:25,359 +我们想和大家分享其中的一些 + +282 +00:15:26,660 --> 00:15:29,830 +首先 我们将看到如何在虚拟机中 + +283 +00:15:29,863 --> 00:15:33,066 +安装完整的未经修改的 +Linux 发行版 + +284 +00:15:33,100 --> 00:15:37,604 +然后我们将看到在 Linux 中 +添加的显示界面的新设备 + +285 +00:15:37,638 --> 00:15:41,375 +最后 我们将看看如何利用 Rosetta 2 + +286 +00:15:41,408 --> 00:15:44,878 +在虚拟机中运行 Linux 二进制文件 + +287 +00:15:44,912 --> 00:15:47,181 +我们从安装开始 + +288 +00:15:47,214 --> 00:15:49,616 +如果我们想在实体机上安装 Linux + +289 +00:15:49,650 --> 00:15:52,819 +首先要下载自带安装程序的 ISO 文件 + +290 +00:15:52,853 --> 00:15:55,923 +然后用 ISO 覆盖一个U盘 + +291 +00:15:55,956 --> 00:15:59,893 +最后 我们将U盘插入电脑 +然后启动 + +292 +00:15:59,927 --> 00:16:03,363 +在处理虚拟机时 +我们将采用相同的步骤 + +293 +00:16:03,397 --> 00:16:07,868 +但我们将使用虚拟U盘 +而不是实际U盘 + +294 +00:16:07,901 --> 00:16:09,970 +我们来看看它是如何工作的 + +295 +00:16:10,003 --> 00:16:14,775 +我们首先从下载的 ISO 文件路径 +创建 URL + +296 +00:16:14,808 --> 00:16:18,779 +然后 我们从该文件创建一个 +磁盘映像附件 + +297 +00:16:18,812 --> 00:16:24,651 +磁盘映像附件代表我们可以 +连接到设备上的一块存储 + +298 +00:16:24,685 --> 00:16:28,155 +接下来 我们配置一个虚拟存储设备 + +299 +00:16:28,188 --> 00:16:30,624 +这里 我们需要 USB 存储 + +300 +00:16:30,657 --> 00:16:35,028 +所以我们使用 +VZUSBMassStorageDeviceConfiguration + +301 +00:16:35,062 --> 00:16:37,030 +最后 一如既往地 + +302 +00:16:37,064 --> 00:16:39,533 +我们在主配置中添加设备 + +303 +00:16:39,566 --> 00:16:42,736 +这里 USB 设备出现在 +另一个存储设备一旁 + +304 +00:16:42,769 --> 00:16:45,706 +也就是我们安装 Linux 的主磁盘 + +305 +00:16:45,739 --> 00:16:49,343 +现在我们有了 USB 驱动器 +但我们需要启动方法 + +306 +00:16:50,310 --> 00:16:54,081 +在 macOS Ventura 中 +我们增加了对 EFI 的支持 + +307 +00:16:54,114 --> 00:16:58,952 +EFI 是引导 ARM +和 Intel 硬件的行业标准 + +308 +00:16:58,986 --> 00:17:02,556 +我们正在为虚拟机提供同样的支持 + +309 +00:17:02,589 --> 00:17:05,259 +EFI 具有启动发现机制 + +310 +00:17:05,292 --> 00:17:09,496 +能够发现 USB 驱动器上的安装程序 + +311 +00:17:09,530 --> 00:17:13,100 +EFI 可以查看每个驱动器 +以寻找可以启动的驱动器 + +312 +00:17:13,133 --> 00:17:16,003 +它会识别出安装程序 +并以此作为开始 + +313 +00:17:16,036 --> 00:17:19,373 +安装程序会告诉 EFI +接下来使用什么驱动程序 + +314 +00:17:19,406 --> 00:17:23,577 +安装完成后 EFI 就可以 +启动 Linux 发行版了 + +315 +00:17:23,610 --> 00:17:26,847 +我们来看看 +如何在代码中设置 EFI + +316 +00:17:26,880 --> 00:17:31,018 +首先 我们创建一个 +VZEFIBootLoader 类型的引导加载程序 + +317 +00:17:31,051 --> 00:17:35,355 +EFI 需要非易失性存储器 +来存储启动间的信息 + +318 +00:17:35,389 --> 00:17:38,258 +这就是所谓的 EFI 可变存储器 + +319 +00:17:38,292 --> 00:17:40,761 +有了虚拟机 +我们可以通过文件系统上的 + +320 +00:17:40,794 --> 00:17:42,863 +某个文件来支持这样的存储器 + +321 +00:17:42,896 --> 00:17:46,033 +这里 我们重新创建一个 +新的可变存储器 + +322 +00:17:46,066 --> 00:17:47,568 +现在 EFI 准备好了 + +323 +00:17:47,601 --> 00:17:51,705 +我们只需要在配置中将它设置为 +引导加载程序 + +324 +00:17:51,738 --> 00:17:57,010 +接下来 我们将研究 Linux 虚拟机的 +新功能 图形 + +325 +00:17:57,044 --> 00:18:01,515 +在 macOS Ventura 中 我们增加了 +对 Virtio GPU 2D 的支持 + +326 +00:18:01,548 --> 00:18:05,285 +Virtio GPU 2D 是一个半虚拟化的设备 +允许 Linux + +327 +00:18:05,319 --> 00:18:08,455 +为宿主 macOS 提供界面 + +328 +00:18:08,488 --> 00:18:11,325 +Linux 呈现内容 将渲染帧提供给 + +329 +00:18:11,358 --> 00:18:14,494 +Virtualization 框架 +以便可以显示它 + +330 +00:18:14,528 --> 00:18:18,765 +你现在可以用 VZVirtualMachineView +在你的 App 中显示这些内容 + +331 +00:18:18,799 --> 00:18:21,201 +就像在 macOS 上一样 + +332 +00:18:21,235 --> 00:18:23,237 +我们来看看如何设置它 + +333 +00:18:24,571 --> 00:18:28,542 +设备设置与我们设置 +macOS 时所做的类似 + +334 +00:18:28,575 --> 00:18:32,946 +我们首先创建一个 +VZVirtioGraphicsDeviceConfiguration + +335 +00:18:32,980 --> 00:18:36,149 +我们需要定义虚拟显示器的大小 + +336 +00:18:36,183 --> 00:18:39,953 +在 Virtio 术语中 +虚拟显示器是一个 “scanout” + +337 +00:18:39,987 --> 00:18:44,892 +所以我们创建了一个 +显示器大小的 scanout + +338 +00:18:44,925 --> 00:18:48,262 +最后 我们将新设备设置为 + +339 +00:18:48,295 --> 00:18:49,963 +配置的图形设备 + +340 +00:18:49,997 --> 00:18:54,168 +现在我们的虚拟机已经准备好 +用 VZVirtualMachineView 来显示内容了 + +341 +00:18:54,201 --> 00:18:58,405 +接下来 我们通过演示 +来查看所有内容 + +342 +00:18:58,438 --> 00:19:00,040 +我们从中断的地方开始 + +343 +00:19:00,073 --> 00:19:03,143 +先删除 Mac 特有的代码 + +344 +00:19:03,177 --> 00:19:05,479 +然后更改引导的磁盘 + +345 +00:19:05,512 --> 00:19:09,950 +我们将路径从 Mac 驱动器 +换为 Linux 驱动器 + +346 +00:19:09,983 --> 00:19:12,386 +接下来 需要一个引导加载程序 + +347 +00:19:12,419 --> 00:19:16,156 +我们用 VZEFIBootLoader +来设置 EFI + +348 +00:19:16,924 --> 00:19:19,326 +首先创建 +EFI 引导加载程序对象 + +349 +00:19:19,359 --> 00:19:22,129 +然后我们从它的文件中 +加载可变存储器 + +350 +00:19:22,162 --> 00:19:27,401 +最后 我们在配置中将 EFI +设置为引导加载程序 + +351 +00:19:27,434 --> 00:19:31,238 +现在我们可以启动了 +不过最好能显示 UI + +352 +00:19:31,271 --> 00:19:35,008 +让我们将 Virtio GPU 添加到配置中 + +353 +00:19:35,042 --> 00:19:36,643 +只需创建一个 +VZVirtioGraphicsDeviceConfiguration + +354 +00:19:36,677 --> 00:19:40,013 +类型的图形设备 + +355 +00:19:40,047 --> 00:19:43,884 +然后我们用虚拟显示器的 +大小定义 scanout + +356 +00:19:43,917 --> 00:19:49,389 +我们在配置上将 Virtio GPU +设置为 graphicsDevice + +357 +00:19:49,423 --> 00:19:52,993 +最后就是让鼠标工作 + +358 +00:19:53,026 --> 00:19:56,330 +我们只需使用虚拟的 +USB 屏幕坐标指示设备 + +359 +00:19:56,363 --> 00:19:58,665 +在 Linux 中会出现一个鼠标 + +360 +00:19:58,699 --> 00:20:01,335 +好了 这样我们就可以 +运行这个项目了 + +361 +00:20:01,368 --> 00:20:04,471 +EFI 可以查看磁盘 +识别是否可以引导 + +362 +00:20:04,505 --> 00:20:09,977 +然后 Linux 通过 Virtio GPU 设备 +显示界面内容 + +363 +00:20:10,010 --> 00:20:12,946 +我们可以用鼠标与 Linux 交互 + +364 +00:20:12,980 --> 00:20:15,983 +最重要的是 我们来看看如何 + +365 +00:20:16,016 --> 00:20:19,119 +在 Linux 中使用 Rosetta 2 技术 + +366 +00:20:20,053 --> 00:20:23,490 +对于许多人来说 +我们喜欢在 Mac 上开发服务 + +367 +00:20:23,524 --> 00:20:25,025 +但一旦我们的工作就绪 + +368 +00:20:25,058 --> 00:20:29,162 +我们创建的二进制文件 +可能需要在 x86 服务器上运行 + +369 +00:20:29,196 --> 00:20:32,332 +x86 指令模拟在这方面做得很好 + +370 +00:20:32,366 --> 00:20:35,035 +但我们可以做得更好 + +371 +00:20:35,068 --> 00:20:37,204 +在 macOS Ventura 中 +我们将 Rosetta 2 的强大功能 + +372 +00:20:37,237 --> 00:20:39,673 +引入到 Linux 二进制中 + +373 +00:20:40,807 --> 00:20:44,378 +Rosetta 2 所做的是在虚拟机中 + +374 +00:20:44,411 --> 00:20:46,446 +转译 Linux x86-64 二进制 + +375 +00:20:46,480 --> 00:20:49,750 +这表示你可以运行你喜欢的 +ARM Linux 发行版 + +376 +00:20:49,783 --> 00:20:53,253 +它的 x86-64 App +可以通过 Rosetta 运行 + +377 +00:20:53,287 --> 00:20:54,755 +而且很快 + +378 +00:20:54,788 --> 00:20:57,658 +这和我们在 Mac 上使用的技术 +是一样的 + +379 +00:20:57,691 --> 00:21:00,460 +这意味着我们拥有惊人的性能 + +380 +00:21:00,494 --> 00:21:03,530 +让我们看看如何使用它 + +381 +00:21:03,564 --> 00:21:07,000 +首先 我们需要让 Linux +可以访问 Rosetta + +382 +00:21:07,034 --> 00:21:11,705 +为此 我们使用了与 macOS +相同的文件共享技术 + +383 +00:21:11,738 --> 00:21:15,175 +我们使用了一种特殊的对象 +而非共享文件夹 + +384 +00:21:15,209 --> 00:21:18,912 +也就是 +VZLinuxRosettaDirectoryShare + +385 +00:21:18,946 --> 00:21:24,151 +然后我们创建一个共享设备 +并设置 Rosetta 目录共享 + +386 +00:21:24,184 --> 00:21:28,455 +最后 我们像往常一样 +在配置上设置我们的设备 + +387 +00:21:28,488 --> 00:21:32,059 +现在我们的虚拟机可以 +使用 Rosetta 了 + +388 +00:21:32,092 --> 00:21:35,696 +接下来 让我们看看 Linux +如何利用它 + +389 +00:21:36,930 --> 00:21:41,335 +在 Linux 中 我们首先 +在文件系统中装载共享目录 + +390 +00:21:41,368 --> 00:21:46,240 +我们从 Linux 中看到的是可以 +转译应用程序的 Rosetta 二进制文件 + +391 +00:21:46,273 --> 00:21:50,511 +然后 我们可以使用 update-binfmts +告诉系统使用 Rosetta + +392 +00:21:50,544 --> 00:21:53,847 +处理任何 x86-64 二进制文件 + +393 +00:21:53,881 --> 00:21:55,849 +不要担心记不住这个命令 + +394 +00:21:55,883 --> 00:21:58,685 +这些全都在文档中 + +395 +00:21:58,719 --> 00:22:00,921 +现在 Linux 已经准备就绪 + +396 +00:22:00,954 --> 00:22:05,926 +Rosetta 会转译每一个 +启动运行的 x86-64 二进制文件 + +397 +00:22:07,361 --> 00:22:11,832 +在结束 Linux 部分之前 +我们来进行一个大汇总 + +398 +00:22:11,865 --> 00:22:15,602 +这里 我们重新安装了一个 +完整的 Linux 发行版 + +399 +00:22:15,636 --> 00:22:18,705 +我们可以用 Virtio GPU 2D +来显示它的界面 + +400 +00:22:18,739 --> 00:22:22,776 +在虚拟机中 +我们通过 Rosetta 运行了一个 PHP 服务器 + +401 +00:22:22,809 --> 00:22:26,079 +我们可以从 macOS 主机与它连接 + +402 +00:22:27,381 --> 00:22:31,518 +我们已经看到 +创建虚拟机从未如此简单 + +403 +00:22:31,552 --> 00:22:34,488 +利用 Virtualization 框架 +你只需要写几行代码 + +404 +00:22:34,521 --> 00:22:37,191 +就可以运行虚拟机 + +405 +00:22:37,224 --> 00:22:42,062 +我们还看到 虚拟机 +在 macOS 上的速度非常快 + +406 +00:22:42,095 --> 00:22:43,931 +为了更进一步了解虚拟化 + +407 +00:22:43,964 --> 00:22:47,534 +请大家查看代码示例和文档 + +408 +00:22:47,568 --> 00:22:49,603 +我和我们的团队迫不及待地 + +409 +00:22:49,636 --> 00:22:51,772 +想看到你们如何利用这项技术 + +410 +00:22:51,805 --> 00:22:57,110 +[欢快的音乐] + diff --git a/zho/2022 Session 10003 Meet WeatherKit.srt b/zho/2022 Session 10003 Meet WeatherKit.srt new file mode 100644 index 0000000..75c9383 --- /dev/null +++ b/zho/2022 Session 10003 Meet WeatherKit.srt @@ -0,0 +1,1088 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ ♪ + +2 +00:00:03,003 --> 00:00:10,077 +♪ + +3 +00:00:10,077 --> 00:00:13,914 +欢迎来到 WWDC22 的 +“WeatherKit 简介” + +4 +00:00:13,914 --> 00:00:15,182 +我叫 Novall + +5 +00:00:15,182 --> 00:00:17,885 +是天气团队的工程师 + +6 +00:00:17,885 --> 00:00:20,721 +我们对天气数据的依赖与日俱增 + +7 +00:00:20,721 --> 00:00:23,557 +所以从哪里获得天气数据 +变得非常重要 + +8 +00:00:23,557 --> 00:00:25,459 +从出门前 +在 Apple Watch 上查看天气 + +9 +00:00:25,459 --> 00:00:27,094 +来决定是否 + +10 +00:00:27,094 --> 00:00:29,329 +携带雨伞 + +11 +00:00:29,329 --> 00:00:32,733 +到通过预测降雨和霜雪以便于 + +12 +00:00:32,733 --> 00:00:35,836 +协助农民规划轮作的 +可持续农业工作 + +13 +00:00:35,836 --> 00:00:39,573 +为冬季风暴中的旅行 +保证安全并做好准备 + +14 +00:00:39,573 --> 00:00:42,176 +天气影响每个人 + +15 +00:00:42,176 --> 00:00:44,778 +准确的天气信息在如今 + +16 +00:00:44,778 --> 00:00:48,315 +深受天气变化影响的世界中 +变的比以往更重要 + +17 +00:00:48,315 --> 00:00:50,517 +而获得准确的预测 + +18 +00:00:50,517 --> 00:00:53,287 +也比在以往任何时候都重要 + +19 +00:00:53,287 --> 00:00:55,923 +这就是我们创建 +WeatherKit 的原因 + +20 +00:00:55,923 --> 00:00:59,693 +WeatherKit 由全新的 +Apple Weather Service 提供支持 + +21 +00:00:59,693 --> 00:01:02,863 +这是一个顶级的全球天气预报系统 + +22 +00:01:02,863 --> 00:01:05,832 +它使用高分辨率气象模型 + +23 +00:01:05,832 --> 00:01:08,802 +以及机器学习和预测算法 + +24 +00:01:08,802 --> 00:01:11,038 +为您提供超本地化 + +25 +00:01:11,038 --> 00:01:13,307 +的全球天气预测 + +26 +00:01:13,307 --> 00:01:16,944 +借助 Apple Weather Service +我们可以访问大量数据 + +27 +00:01:16,944 --> 00:01:20,948 +所有这些信息都可以通过 +WeatherKit 提供给您 + +28 +00:01:20,948 --> 00:01:24,284 +准确的天气数据 +需要用户的位置信息 + +29 +00:01:24,284 --> 00:01:28,522 +而对这些数据保密 +是一项共同的责任 + +30 +00:01:28,522 --> 00:01:30,824 +为了遵守我们对隐私的承诺 + +31 +00:01:30,824 --> 00:01:34,027 +WeatherKit 旨在 +不泄露用户信息的情况下 + +32 +00:01:34,027 --> 00:01:37,130 +提供超本地化天气预报 + +33 +00:01:37,130 --> 00:01:40,601 +位置信息仅用于提供天气预报 + +34 +00:01:40,601 --> 00:01:41,768 +这个信息不会关联 + +35 +00:01:41,768 --> 00:01:45,105 +任何个人识别信息 + +36 +00:01:45,105 --> 00:01:48,008 +且这些数据永远不会共享或出售 + +37 +00:01:48,008 --> 00:01:49,943 +我们会让您 +在 Wea​​therKit 中轻松的 + +38 +00:01:49,943 --> 00:01:52,279 +完成对用户信息的保密 + +39 +00:01:52,279 --> 00:01:55,516 +今天我将深入介绍 +有关 WeatherKit 的更多细节 + +40 +00:01:55,516 --> 00:01:58,919 +这样您就可以 +充分利用了解我们的新 API + +41 +00:01:58,919 --> 00:02:00,888 +首先我将介绍 +通过 WeatherKit 提供的 + +42 +00:02:00,888 --> 00:02:02,356 +可用的数据集 + +43 +00:02:02,356 --> 00:02:05,526 +该数据集由我们的 +Apple Weather Service 提供支持 + +44 +00:02:05,526 --> 00:02:08,362 +接下来我将分别向您展示 + +45 +00:02:08,362 --> 00:02:10,330 +如何使用 WeatherKit 框架 +获取天气信息 + +46 +00:02:10,330 --> 00:02:13,133 +以及一个可以在任意系统平台上 + +47 +00:02:13,133 --> 00:02:15,435 +获取天气信息的 REST API + +48 +00:02:15,435 --> 00:02:16,370 +最后 + +49 +00:02:16,370 --> 00:02:18,839 +我将介绍一些额外的实现要求 + +50 +00:02:18,839 --> 00:02:21,341 +和必备条件 + +51 +00:02:21,341 --> 00:02:25,746 +让我先概述一下可用的天气数据集 + +52 +00:02:25,746 --> 00:02:29,983 +正如我所提到的 您可以访问 +WeatherKit 中的大量数据 + +53 +00:02:29,983 --> 00:02:33,187 +那么让我们来谈谈每个数据集 + +54 +00:02:33,187 --> 00:02:36,156 +当前天气数据集提供 + +55 +00:02:36,156 --> 00:02:38,659 +请求位置在“现在”条件下的数据 + +56 +00:02:38,659 --> 00:02:40,794 +它表示一个时间点下的条件数据 + +57 +00:02:40,794 --> 00:02:46,333 +包括紫外线指数、温度和风力等信息 + +58 +00:02:46,333 --> 00:02:48,669 +分钟预报包含在可用区域内的 + +59 +00:02:48,669 --> 00:02:51,138 +下一个小时里每分钟的 + +60 +00:02:51,138 --> 00:02:53,073 +降雨情况预测 + +61 +00:02:53,073 --> 00:02:55,475 +该数据集对于您决定出门前是否带伞 + +62 +00:02:55,475 --> 00:02:58,846 +非常有帮助 + +63 +00:02:58,846 --> 00:03:01,281 +小时预报提供 + +64 +00:03:01,281 --> 00:03:03,183 +从当前时间开始 +到未来 240 小时之间 + +65 +00:03:03,183 --> 00:03:07,154 +的数据预测集合 + +66 +00:03:07,154 --> 00:03:09,957 +在这里会提供每个小时的预测信息 + +67 +00:03:09,957 --> 00:03:15,362 +包含如湿度 能见度 +压力和露点等信息 + +68 +00:03:15,362 --> 00:03:19,867 +每日预测 +提供未来 10 天的预测信息 + +69 +00:03:19,867 --> 00:03:21,468 +每一天的预测均提供 + +70 +00:03:21,468 --> 00:03:24,371 +有关全天的预测信息 + +71 +00:03:24,371 --> 00:03:26,540 +比如高温和低温 + +72 +00:03:26,540 --> 00:03:29,042 +日出和日落 + +73 +00:03:29,042 --> 00:03:31,445 +气象警报提供 + +74 +00:03:31,445 --> 00:03:34,248 +所请求位置的恶劣天气警告 + +75 +00:03:34,248 --> 00:03:37,017 +该数据集所包含重要信息 + +76 +00:03:37,017 --> 00:03:41,455 +可以确保您用户的安全 +对天气状况充分了解并做好准备 + +77 +00:03:41,455 --> 00:03:45,259 +最后 历史气象提供 + +78 +00:03:45,259 --> 00:03:46,627 +保存的历史气象数据 + +79 +00:03:46,627 --> 00:03:49,530 +这样您就可以看到天气数据的趋势 + +80 +00:03:49,530 --> 00:03:51,164 +您可以通过指定开始和结束日期 + +81 +00:03:51,164 --> 00:03:53,667 +访问每日和每小时的 + +82 +00:03:53,667 --> 00:03:56,770 +历史天气数据 + +83 +00:03:56,770 --> 00:03:59,773 +这让您可以访问大量数据 + +84 +00:03:59,773 --> 00:04:03,010 +我们相信您会利用历史天气数据 + +85 +00:04:03,010 --> 00:04:05,779 +实现利用很多 +重要且有效的功能方法 + +86 +00:04:05,779 --> 00:04:09,283 +既然您已经看到了 +所有可用的天气数据数据 + +87 +00:04:09,283 --> 00:04:11,585 +现在我将向您介绍 + +88 +00:04:11,585 --> 00:04:14,821 +如何使用 WeatherKit API +请求天气数据 + +89 +00:04:14,821 --> 00:04:18,392 +Apple Weather 数据 +可通过原生框架 (WeatherKit) + +90 +00:04:18,392 --> 00:04:21,562 +和 REST API 获得 + +91 +00:04:21,562 --> 00:04:23,697 +首先 让我向您展示 + +92 +00:04:23,697 --> 00:04:27,201 +使用我们的 Swift 框架 +访问天气数据有多容易 + +93 +00:04:27,201 --> 00:04:29,603 +几行代码就足够了 + +94 +00:04:29,603 --> 00:04:33,540 +使用 Swift 的并发功能 +请求天气数据非常简单 + +95 +00:04:33,540 --> 00:04:37,778 +首先 您需要导入 +WeatherKit 和 CoreLocation 库 + +96 +00:04:37,778 --> 00:04:40,047 +然后您需要 +实例化一个 weatherService 对象 + +97 +00:04:40,047 --> 00:04:43,383 +作为天气服务的入口 + +98 +00:04:43,383 --> 00:04:45,719 +您需要为您感兴趣的位置 + +99 +00:04:45,719 --> 00:04:48,288 +创建一个描述坐标的 +CLLocation 变量 + +100 +00:04:48,288 --> 00:04:52,226 +在这里 我使用的是 +我的家乡 New York Syracuse 的坐标 + +101 +00:04:52,226 --> 00:04:55,662 +然后在 weatherService 实例上 +调用 weather(for:) 方法 + +102 +00:04:55,662 --> 00:04:59,333 +并传入上面创建的位置变量 + +103 +00:04:59,333 --> 00:05:00,767 +当请求结束后 + +104 +00:05:00,767 --> 00:05:04,171 +您即可在 App 中 +访问所需的天气数据 + +105 +00:05:04,171 --> 00:05:08,575 +就像这个例子中的 +当前温度和紫外线指数一样 + +106 +00:05:08,575 --> 00:05:10,410 +现在我已经向您展示了 + +107 +00:05:10,410 --> 00:05:12,779 +使用 Swift +请求天气数据有多容易 + +108 +00:05:12,779 --> 00:05:14,681 +让我再举一个例子 + +109 +00:05:14,681 --> 00:05:18,485 +我正在使用我在 Swift UI +框架中构建的旅行 App + +110 +00:05:18,485 --> 00:05:20,521 +您可以从本教程关联的描述中 + +111 +00:05:20,521 --> 00:05:22,789 +获取该讲座的链接 + +112 +00:05:22,789 --> 00:05:25,058 +因为我真的很期待再次旅行 + +113 +00:05:25,058 --> 00:05:27,094 +我决定创建一个飞行计划 App + +114 +00:05:27,094 --> 00:05:29,663 +来计划我的下一次旅行 + +115 +00:05:29,663 --> 00:05:32,866 +我已经完成了 +旅行 App 的设计逻辑 + +116 +00:05:32,866 --> 00:05:34,768 +但是当我点击 +旅途中的任意一个航班时 + +117 +00:05:34,768 --> 00:05:37,337 +我想以列的形式 +显示包含每个目的地的 + +118 +00:05:37,337 --> 00:05:43,110 +环境 降水 风力和温度的信息 + +119 +00:05:43,110 --> 00:05:45,379 +第一步是启用 Wea​​therKit + +120 +00:05:45,379 --> 00:05:48,348 +在开发者门户中注册 App ID + +121 +00:05:48,348 --> 00:05:51,084 +然后选择功能 +和 App 服务选项卡 + +122 +00:05:51,084 --> 00:05:53,387 +启用 Wea​​therKit + +123 +00:05:53,387 --> 00:05:55,756 +然后在 Xcode 中的对应项目内 + +124 +00:05:55,756 --> 00:05:57,958 +添加 WeatherKit 功能 + +125 +00:05:57,958 --> 00:05:59,626 +有了这些准备工作 + +126 +00:05:59,626 --> 00:06:01,862 +下面让我介绍一下 + +127 +00:06:01,862 --> 00:06:04,765 +如何为每一个目的地获取天气数据 + +128 +00:06:04,765 --> 00:06:07,100 +在这里我已经构建了 +一个名为 Airport 的结构体 + +129 +00:06:07,100 --> 00:06:08,869 +包含经纬度 + +130 +00:06:08,869 --> 00:06:11,438 +和我的目的地机场的信息 + +131 +00:06:11,438 --> 00:06:14,374 +我会通过 weather(for:) 方法 +包含机场位置信息 + +132 +00:06:14,374 --> 00:06:15,609 +来请求我们的共享天气服务 + +133 +00:06:15,609 --> 00:06:18,979 +以获得每小时的天气数据 + +134 +00:06:22,983 --> 00:06:24,751 +因为我只想要一个数据子集 + +135 +00:06:24,751 --> 00:06:27,788 +我还需要在请求中 + +136 +00:06:27,788 --> 00:06:29,823 +指定包括每小时预测的信息 + +137 +00:06:29,823 --> 00:06:32,726 +现在 我将构建 +并运行我的 App + +138 +00:06:36,530 --> 00:06:38,565 +现在我可以看到 +我的自定义视图已更新 + +139 +00:06:38,565 --> 00:06:41,602 +会显示每个机场的天气情况 + +140 +00:06:41,602 --> 00:06:43,604 +构建这个 App 时 +我需要做的下一件事 + +141 +00:06:43,604 --> 00:06:48,342 +是在我的 App 中 +显示数据源的归属 + +142 +00:06:48,342 --> 00:06:51,678 +[按键] + +143 +00:06:51,678 --> 00:06:53,580 +首先 我需要从 +attribution.legalPageURL + +144 +00:06:53,580 --> 00:06:57,084 +获得归属链接 + +145 +00:06:57,084 --> 00:06:59,586 +这是指向法律归属页面的链接 + +146 +00:06:59,586 --> 00:07:01,388 +包含关于天气数据源 + +147 +00:07:01,388 --> 00:07:03,724 +的版权信息 + +148 +00:07:03,724 --> 00:07:05,425 +我还需要获取用于合并 + +149 +00:07:05,425 --> 00:07:07,494 +Apple Weather 标记的链接 + +150 +00:07:07,494 --> 00:07:11,598 +[按键] + +151 +00:07:11,598 --> 00:07:14,101 +它有浅色和深色两种版本 + +152 +00:07:14,101 --> 00:07:16,336 +所以我会检查 +colorScheme 环境值 + +153 +00:07:16,336 --> 00:07:18,906 +查看当前显示的深色或浅色外观 + +154 +00:07:18,906 --> 00:07:22,209 +是否在 SwiftUI 中 +得到正确的显示 + +155 +00:07:22,209 --> 00:07:24,811 +最后 我将再次构建并运行 + +156 +00:07:29,816 --> 00:07:32,286 +请注意 Apple Weather +标记和归属链接 + +157 +00:07:32,286 --> 00:07:36,256 +在 SFSafariViewController 中打开 + +158 +00:07:36,256 --> 00:07:38,058 +这就是获取天气信息所需的一切 + +159 +00:07:38,058 --> 00:07:40,761 +使用 Wea​​therKit API +您可以有很多办法 + +160 +00:07:40,761 --> 00:07:43,263 +在您的飞行 App 中 + +161 +00:07:43,263 --> 00:07:45,265 +添加天气数据 + +162 +00:07:45,265 --> 00:07:48,135 +但这只是原生框架 + +163 +00:07:48,135 --> 00:07:51,038 +REST API 提供 +同样丰富的天气数据 + +164 +00:07:51,038 --> 00:07:55,209 +并且作为 Swift 框架 +他可以在任何平台上使用 + +165 +00:07:55,209 --> 00:07:58,679 +在此示例中 我将展示 + +166 +00:07:58,679 --> 00:08:02,382 +如何通过 weatherkit.apple.com 接口 +请求天气警报 + +167 +00:08:02,382 --> 00:08:04,651 +首先 您需要请求一个验证令牌 + +168 +00:08:04,651 --> 00:08:07,020 +这个我们稍后再讨论 + +169 +00:08:07,020 --> 00:08:10,457 +然后 要获取天气对象 +首先需要创建一个 + +170 +00:08:10,457 --> 00:08:14,494 +标示给定位置的 +所需天气数据集的 URL + +171 +00:08:14,494 --> 00:08:16,630 +为了适应软件的本地化 + +172 +00:08:16,630 --> 00:08:19,032 +一定要设置合适的语言 + +173 +00:08:19,032 --> 00:08:21,502 +然后提供 + +174 +00:08:21,502 --> 00:08:24,037 +所需位置的经纬度 + +175 +00:08:24,037 --> 00:08:26,473 +指明所需的数据集 + +176 +00:08:26,473 --> 00:08:29,243 +您可能会注意到此参数是复数 + +177 +00:08:29,243 --> 00:08:33,313 +所以您可以使用逗号分割多次请求 + +178 +00:08:33,313 --> 00:08:36,917 +最后 请求位置的国家代码 + +179 +00:08:36,917 --> 00:08:39,186 +但请注意 仅在请求天气警报时 + +180 +00:08:39,186 --> 00:08:43,156 +国家代码才是必须的 + +181 +00:08:43,156 --> 00:08:44,725 +接下来 您将获取天气数据 + +182 +00:08:44,725 --> 00:08:48,328 +使用上面的 URL +和您的验证令牌 + +183 +00:08:48,328 --> 00:08:51,231 +将结果转换为 JSON 格式 + +184 +00:08:51,231 --> 00:08:53,367 +您可以用这个变量访问天气警报信息 + +185 +00:08:53,367 --> 00:08:55,669 +以及他们的详细信息 + +186 +00:08:55,669 --> 00:08:58,539 +再说一次 另一个例子对您来说 +访问天气数据已经如此简单 + +187 +00:08:58,539 --> 00:09:02,943 +只是这次是通过 REST API + +188 +00:09:02,943 --> 00:09:05,746 +要更深入地了解您需要的设置 + +189 +00:09:05,746 --> 00:09:08,815 +让我们重温一下如何进行验证 + +190 +00:09:08,815 --> 00:09:10,517 +对于 WeatherKit REST API + +191 +00:09:10,517 --> 00:09:14,821 +还有一些额外的 +步骤来处理身份验证 + +192 +00:09:14,821 --> 00:09:16,957 +在开发者门户中 +您需要创建 + +193 +00:09:16,957 --> 00:09:20,227 +为 WeatherKit 验证密钥 +和相关联的服务 ID + +194 +00:09:20,227 --> 00:09:24,531 +来启用对 WeatherKit 请求权限 + +195 +00:09:24,531 --> 00:09:25,999 +在开发者门户的 +“Keys”(密钥) 部分中 + +196 +00:09:25,999 --> 00:09:29,269 +可以创建私钥 + +197 +00:09:29,269 --> 00:09:32,172 +WeatherKit 需要在每次请求中 + +198 +00:09:32,172 --> 00:09:33,707 +用令牌来验证授权 + +199 +00:09:33,707 --> 00:09:36,243 +因此 您需要 +在您的服务器上部署一个 + +200 +00:09:36,243 --> 00:09:40,814 +用于使用您的私钥的 +已签名 JSON Web Token (JWT) + +201 +00:09:40,814 --> 00:09:43,884 +对于那些熟悉 +JSON Web Token 验证的人 + +202 +00:09:43,884 --> 00:09:46,854 +这是一个相当标准的授权流程 + +203 +00:09:46,854 --> 00:09:48,021 +但如果您是第一次使用它 + +204 +00:09:48,021 --> 00:09:51,291 +那么请听我分享一些这里的细节 + +205 +00:09:51,291 --> 00:09:52,593 +要生成签名令牌 + +206 +00:09:52,593 --> 00:09:55,762 +您需要按照开发者文档中所述 + +207 +00:09:55,762 --> 00:09:59,166 +创建包含键名和值的Header + +208 +00:09:59,166 --> 00:10:02,069 +然后创建 +专用于 WeatherKit Rest API + +209 +00:10:02,069 --> 00:10:06,106 +和您的 App 的有效信息 + +210 +00:10:06,106 --> 00:10:08,809 +包括发行人 主题 + +211 +00:10:08,809 --> 00:10:11,311 +和到期时间 + +212 +00:10:11,311 --> 00:10:13,247 +最后 您需要签署令牌 + +213 +00:10:13,247 --> 00:10:17,618 +以便于随后调用 +Wea​​therKit REST API + +214 +00:10:17,618 --> 00:10:20,087 +回到我的天气警报示例 + +215 +00:10:20,087 --> 00:10:24,191 +在这里 +您将从您的签名服务中请求令牌 + +216 +00:10:24,191 --> 00:10:26,593 +并为您的天气数据 HTTP 请求 + +217 +00:10:26,593 --> 00:10:31,031 +添加 Authorization 令牌 Header + +218 +00:10:31,031 --> 00:10:33,634 +这就是通过 +WeatherKit REST API + +219 +00:10:33,634 --> 00:10:36,270 +从 Apple Weather Service 获取 + +220 +00:10:36,270 --> 00:10:38,438 +天气数据的两种好方法之一 + +221 +00:10:38,438 --> 00:10:41,008 +最后 我将介绍 +一些不论在 App Store + +222 +00:10:41,008 --> 00:10:44,111 +或其他平台发布 App 之前 + +223 +00:10:44,111 --> 00:10:47,915 +使用 REST API 时的额外要求 + +224 +00:10:47,915 --> 00:10:50,050 +这些要求全都对您适用 + +225 +00:10:50,050 --> 00:10:54,388 +无论您使用的是 +原生 Swift 还是 REST API + +226 +00:10:54,388 --> 00:10:57,090 +第一个要求是标注服务归属 + +227 +00:10:57,090 --> 00:10:58,859 +正如您在我的演示中看到的 + +228 +00:10:58,859 --> 00:11:01,528 +不论是在本地 App +或是网络 App 中 + +229 +00:11:01,528 --> 00:11:04,164 +您都需要显示 +服务来源的 API 链接 + +230 +00:11:04,164 --> 00:11:07,234 +第二个要求是归属标志 + +231 +00:11:07,234 --> 00:11:10,304 +WeatherKit API +可以为您在 App 中 + +232 +00:11:10,304 --> 00:11:15,042 +提供很便捷的图片资源 + +233 +00:11:15,042 --> 00:11:17,644 +最后 如果您要显示天气警报 + +234 +00:11:17,644 --> 00:11:19,513 +您还需要链接到 + +235 +00:11:19,513 --> 00:11:21,849 +提供活动信息的页面 + +236 +00:11:21,849 --> 00:11:24,284 +就是如此容易 +无论您是准备把 App + +237 +00:11:24,284 --> 00:11:27,554 +发布到 App Store 还是网上 + +238 +00:11:27,554 --> 00:11:28,889 +这就是 WeatherKit + +239 +00:11:28,889 --> 00:11:32,559 +Apple Weather Service +提供支持的超本地预报 + +240 +00:11:32,559 --> 00:11:36,663 +通过我们的 Swift 框架 +和 REST API 访问 + +241 +00:11:36,663 --> 00:11:38,732 +两者都为您提供了无限可能 + +242 +00:11:38,732 --> 00:11:40,934 +帮助您将天气数据 +应用于您的 App + +243 +00:11:40,934 --> 00:11:43,670 +以及任何平台 +或设备之中 + +244 +00:11:43,670 --> 00:11:45,806 +我们希望您喜欢本次讲座 + +245 +00:11:45,806 --> 00:11:48,742 +除了查看与本次讲座相关的链接 + +246 +00:11:48,742 --> 00:11:51,311 +阅读文档并下载项目之外 + +247 +00:11:51,311 --> 00:11:53,647 +我们还希望能得到您的反馈 + +248 +00:11:53,647 --> 00:11:57,117 +我们迫不及待地想看到 +您在使用 WeatherKit 时 + +249 +00:11:57,117 --> 00:11:58,819 +展现的所有创造性 +和有影响力的方式 + +250 +00:11:58,819 --> 00:12:01,622 +谢谢您 祝您 WWDC 愉快! + +251 +00:12:01,622 --> 00:12:05,726 +♪ + diff --git a/zho/2022 Session 10003 Meet WeatherKit2.srt b/zho/2022 Session 10003 Meet WeatherKit2.srt new file mode 100644 index 0000000..75c9383 --- /dev/null +++ b/zho/2022 Session 10003 Meet WeatherKit2.srt @@ -0,0 +1,1088 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ ♪ + +2 +00:00:03,003 --> 00:00:10,077 +♪ + +3 +00:00:10,077 --> 00:00:13,914 +欢迎来到 WWDC22 的 +“WeatherKit 简介” + +4 +00:00:13,914 --> 00:00:15,182 +我叫 Novall + +5 +00:00:15,182 --> 00:00:17,885 +是天气团队的工程师 + +6 +00:00:17,885 --> 00:00:20,721 +我们对天气数据的依赖与日俱增 + +7 +00:00:20,721 --> 00:00:23,557 +所以从哪里获得天气数据 +变得非常重要 + +8 +00:00:23,557 --> 00:00:25,459 +从出门前 +在 Apple Watch 上查看天气 + +9 +00:00:25,459 --> 00:00:27,094 +来决定是否 + +10 +00:00:27,094 --> 00:00:29,329 +携带雨伞 + +11 +00:00:29,329 --> 00:00:32,733 +到通过预测降雨和霜雪以便于 + +12 +00:00:32,733 --> 00:00:35,836 +协助农民规划轮作的 +可持续农业工作 + +13 +00:00:35,836 --> 00:00:39,573 +为冬季风暴中的旅行 +保证安全并做好准备 + +14 +00:00:39,573 --> 00:00:42,176 +天气影响每个人 + +15 +00:00:42,176 --> 00:00:44,778 +准确的天气信息在如今 + +16 +00:00:44,778 --> 00:00:48,315 +深受天气变化影响的世界中 +变的比以往更重要 + +17 +00:00:48,315 --> 00:00:50,517 +而获得准确的预测 + +18 +00:00:50,517 --> 00:00:53,287 +也比在以往任何时候都重要 + +19 +00:00:53,287 --> 00:00:55,923 +这就是我们创建 +WeatherKit 的原因 + +20 +00:00:55,923 --> 00:00:59,693 +WeatherKit 由全新的 +Apple Weather Service 提供支持 + +21 +00:00:59,693 --> 00:01:02,863 +这是一个顶级的全球天气预报系统 + +22 +00:01:02,863 --> 00:01:05,832 +它使用高分辨率气象模型 + +23 +00:01:05,832 --> 00:01:08,802 +以及机器学习和预测算法 + +24 +00:01:08,802 --> 00:01:11,038 +为您提供超本地化 + +25 +00:01:11,038 --> 00:01:13,307 +的全球天气预测 + +26 +00:01:13,307 --> 00:01:16,944 +借助 Apple Weather Service +我们可以访问大量数据 + +27 +00:01:16,944 --> 00:01:20,948 +所有这些信息都可以通过 +WeatherKit 提供给您 + +28 +00:01:20,948 --> 00:01:24,284 +准确的天气数据 +需要用户的位置信息 + +29 +00:01:24,284 --> 00:01:28,522 +而对这些数据保密 +是一项共同的责任 + +30 +00:01:28,522 --> 00:01:30,824 +为了遵守我们对隐私的承诺 + +31 +00:01:30,824 --> 00:01:34,027 +WeatherKit 旨在 +不泄露用户信息的情况下 + +32 +00:01:34,027 --> 00:01:37,130 +提供超本地化天气预报 + +33 +00:01:37,130 --> 00:01:40,601 +位置信息仅用于提供天气预报 + +34 +00:01:40,601 --> 00:01:41,768 +这个信息不会关联 + +35 +00:01:41,768 --> 00:01:45,105 +任何个人识别信息 + +36 +00:01:45,105 --> 00:01:48,008 +且这些数据永远不会共享或出售 + +37 +00:01:48,008 --> 00:01:49,943 +我们会让您 +在 Wea​​therKit 中轻松的 + +38 +00:01:49,943 --> 00:01:52,279 +完成对用户信息的保密 + +39 +00:01:52,279 --> 00:01:55,516 +今天我将深入介绍 +有关 WeatherKit 的更多细节 + +40 +00:01:55,516 --> 00:01:58,919 +这样您就可以 +充分利用了解我们的新 API + +41 +00:01:58,919 --> 00:02:00,888 +首先我将介绍 +通过 WeatherKit 提供的 + +42 +00:02:00,888 --> 00:02:02,356 +可用的数据集 + +43 +00:02:02,356 --> 00:02:05,526 +该数据集由我们的 +Apple Weather Service 提供支持 + +44 +00:02:05,526 --> 00:02:08,362 +接下来我将分别向您展示 + +45 +00:02:08,362 --> 00:02:10,330 +如何使用 WeatherKit 框架 +获取天气信息 + +46 +00:02:10,330 --> 00:02:13,133 +以及一个可以在任意系统平台上 + +47 +00:02:13,133 --> 00:02:15,435 +获取天气信息的 REST API + +48 +00:02:15,435 --> 00:02:16,370 +最后 + +49 +00:02:16,370 --> 00:02:18,839 +我将介绍一些额外的实现要求 + +50 +00:02:18,839 --> 00:02:21,341 +和必备条件 + +51 +00:02:21,341 --> 00:02:25,746 +让我先概述一下可用的天气数据集 + +52 +00:02:25,746 --> 00:02:29,983 +正如我所提到的 您可以访问 +WeatherKit 中的大量数据 + +53 +00:02:29,983 --> 00:02:33,187 +那么让我们来谈谈每个数据集 + +54 +00:02:33,187 --> 00:02:36,156 +当前天气数据集提供 + +55 +00:02:36,156 --> 00:02:38,659 +请求位置在“现在”条件下的数据 + +56 +00:02:38,659 --> 00:02:40,794 +它表示一个时间点下的条件数据 + +57 +00:02:40,794 --> 00:02:46,333 +包括紫外线指数、温度和风力等信息 + +58 +00:02:46,333 --> 00:02:48,669 +分钟预报包含在可用区域内的 + +59 +00:02:48,669 --> 00:02:51,138 +下一个小时里每分钟的 + +60 +00:02:51,138 --> 00:02:53,073 +降雨情况预测 + +61 +00:02:53,073 --> 00:02:55,475 +该数据集对于您决定出门前是否带伞 + +62 +00:02:55,475 --> 00:02:58,846 +非常有帮助 + +63 +00:02:58,846 --> 00:03:01,281 +小时预报提供 + +64 +00:03:01,281 --> 00:03:03,183 +从当前时间开始 +到未来 240 小时之间 + +65 +00:03:03,183 --> 00:03:07,154 +的数据预测集合 + +66 +00:03:07,154 --> 00:03:09,957 +在这里会提供每个小时的预测信息 + +67 +00:03:09,957 --> 00:03:15,362 +包含如湿度 能见度 +压力和露点等信息 + +68 +00:03:15,362 --> 00:03:19,867 +每日预测 +提供未来 10 天的预测信息 + +69 +00:03:19,867 --> 00:03:21,468 +每一天的预测均提供 + +70 +00:03:21,468 --> 00:03:24,371 +有关全天的预测信息 + +71 +00:03:24,371 --> 00:03:26,540 +比如高温和低温 + +72 +00:03:26,540 --> 00:03:29,042 +日出和日落 + +73 +00:03:29,042 --> 00:03:31,445 +气象警报提供 + +74 +00:03:31,445 --> 00:03:34,248 +所请求位置的恶劣天气警告 + +75 +00:03:34,248 --> 00:03:37,017 +该数据集所包含重要信息 + +76 +00:03:37,017 --> 00:03:41,455 +可以确保您用户的安全 +对天气状况充分了解并做好准备 + +77 +00:03:41,455 --> 00:03:45,259 +最后 历史气象提供 + +78 +00:03:45,259 --> 00:03:46,627 +保存的历史气象数据 + +79 +00:03:46,627 --> 00:03:49,530 +这样您就可以看到天气数据的趋势 + +80 +00:03:49,530 --> 00:03:51,164 +您可以通过指定开始和结束日期 + +81 +00:03:51,164 --> 00:03:53,667 +访问每日和每小时的 + +82 +00:03:53,667 --> 00:03:56,770 +历史天气数据 + +83 +00:03:56,770 --> 00:03:59,773 +这让您可以访问大量数据 + +84 +00:03:59,773 --> 00:04:03,010 +我们相信您会利用历史天气数据 + +85 +00:04:03,010 --> 00:04:05,779 +实现利用很多 +重要且有效的功能方法 + +86 +00:04:05,779 --> 00:04:09,283 +既然您已经看到了 +所有可用的天气数据数据 + +87 +00:04:09,283 --> 00:04:11,585 +现在我将向您介绍 + +88 +00:04:11,585 --> 00:04:14,821 +如何使用 WeatherKit API +请求天气数据 + +89 +00:04:14,821 --> 00:04:18,392 +Apple Weather 数据 +可通过原生框架 (WeatherKit) + +90 +00:04:18,392 --> 00:04:21,562 +和 REST API 获得 + +91 +00:04:21,562 --> 00:04:23,697 +首先 让我向您展示 + +92 +00:04:23,697 --> 00:04:27,201 +使用我们的 Swift 框架 +访问天气数据有多容易 + +93 +00:04:27,201 --> 00:04:29,603 +几行代码就足够了 + +94 +00:04:29,603 --> 00:04:33,540 +使用 Swift 的并发功能 +请求天气数据非常简单 + +95 +00:04:33,540 --> 00:04:37,778 +首先 您需要导入 +WeatherKit 和 CoreLocation 库 + +96 +00:04:37,778 --> 00:04:40,047 +然后您需要 +实例化一个 weatherService 对象 + +97 +00:04:40,047 --> 00:04:43,383 +作为天气服务的入口 + +98 +00:04:43,383 --> 00:04:45,719 +您需要为您感兴趣的位置 + +99 +00:04:45,719 --> 00:04:48,288 +创建一个描述坐标的 +CLLocation 变量 + +100 +00:04:48,288 --> 00:04:52,226 +在这里 我使用的是 +我的家乡 New York Syracuse 的坐标 + +101 +00:04:52,226 --> 00:04:55,662 +然后在 weatherService 实例上 +调用 weather(for:) 方法 + +102 +00:04:55,662 --> 00:04:59,333 +并传入上面创建的位置变量 + +103 +00:04:59,333 --> 00:05:00,767 +当请求结束后 + +104 +00:05:00,767 --> 00:05:04,171 +您即可在 App 中 +访问所需的天气数据 + +105 +00:05:04,171 --> 00:05:08,575 +就像这个例子中的 +当前温度和紫外线指数一样 + +106 +00:05:08,575 --> 00:05:10,410 +现在我已经向您展示了 + +107 +00:05:10,410 --> 00:05:12,779 +使用 Swift +请求天气数据有多容易 + +108 +00:05:12,779 --> 00:05:14,681 +让我再举一个例子 + +109 +00:05:14,681 --> 00:05:18,485 +我正在使用我在 Swift UI +框架中构建的旅行 App + +110 +00:05:18,485 --> 00:05:20,521 +您可以从本教程关联的描述中 + +111 +00:05:20,521 --> 00:05:22,789 +获取该讲座的链接 + +112 +00:05:22,789 --> 00:05:25,058 +因为我真的很期待再次旅行 + +113 +00:05:25,058 --> 00:05:27,094 +我决定创建一个飞行计划 App + +114 +00:05:27,094 --> 00:05:29,663 +来计划我的下一次旅行 + +115 +00:05:29,663 --> 00:05:32,866 +我已经完成了 +旅行 App 的设计逻辑 + +116 +00:05:32,866 --> 00:05:34,768 +但是当我点击 +旅途中的任意一个航班时 + +117 +00:05:34,768 --> 00:05:37,337 +我想以列的形式 +显示包含每个目的地的 + +118 +00:05:37,337 --> 00:05:43,110 +环境 降水 风力和温度的信息 + +119 +00:05:43,110 --> 00:05:45,379 +第一步是启用 Wea​​therKit + +120 +00:05:45,379 --> 00:05:48,348 +在开发者门户中注册 App ID + +121 +00:05:48,348 --> 00:05:51,084 +然后选择功能 +和 App 服务选项卡 + +122 +00:05:51,084 --> 00:05:53,387 +启用 Wea​​therKit + +123 +00:05:53,387 --> 00:05:55,756 +然后在 Xcode 中的对应项目内 + +124 +00:05:55,756 --> 00:05:57,958 +添加 WeatherKit 功能 + +125 +00:05:57,958 --> 00:05:59,626 +有了这些准备工作 + +126 +00:05:59,626 --> 00:06:01,862 +下面让我介绍一下 + +127 +00:06:01,862 --> 00:06:04,765 +如何为每一个目的地获取天气数据 + +128 +00:06:04,765 --> 00:06:07,100 +在这里我已经构建了 +一个名为 Airport 的结构体 + +129 +00:06:07,100 --> 00:06:08,869 +包含经纬度 + +130 +00:06:08,869 --> 00:06:11,438 +和我的目的地机场的信息 + +131 +00:06:11,438 --> 00:06:14,374 +我会通过 weather(for:) 方法 +包含机场位置信息 + +132 +00:06:14,374 --> 00:06:15,609 +来请求我们的共享天气服务 + +133 +00:06:15,609 --> 00:06:18,979 +以获得每小时的天气数据 + +134 +00:06:22,983 --> 00:06:24,751 +因为我只想要一个数据子集 + +135 +00:06:24,751 --> 00:06:27,788 +我还需要在请求中 + +136 +00:06:27,788 --> 00:06:29,823 +指定包括每小时预测的信息 + +137 +00:06:29,823 --> 00:06:32,726 +现在 我将构建 +并运行我的 App + +138 +00:06:36,530 --> 00:06:38,565 +现在我可以看到 +我的自定义视图已更新 + +139 +00:06:38,565 --> 00:06:41,602 +会显示每个机场的天气情况 + +140 +00:06:41,602 --> 00:06:43,604 +构建这个 App 时 +我需要做的下一件事 + +141 +00:06:43,604 --> 00:06:48,342 +是在我的 App 中 +显示数据源的归属 + +142 +00:06:48,342 --> 00:06:51,678 +[按键] + +143 +00:06:51,678 --> 00:06:53,580 +首先 我需要从 +attribution.legalPageURL + +144 +00:06:53,580 --> 00:06:57,084 +获得归属链接 + +145 +00:06:57,084 --> 00:06:59,586 +这是指向法律归属页面的链接 + +146 +00:06:59,586 --> 00:07:01,388 +包含关于天气数据源 + +147 +00:07:01,388 --> 00:07:03,724 +的版权信息 + +148 +00:07:03,724 --> 00:07:05,425 +我还需要获取用于合并 + +149 +00:07:05,425 --> 00:07:07,494 +Apple Weather 标记的链接 + +150 +00:07:07,494 --> 00:07:11,598 +[按键] + +151 +00:07:11,598 --> 00:07:14,101 +它有浅色和深色两种版本 + +152 +00:07:14,101 --> 00:07:16,336 +所以我会检查 +colorScheme 环境值 + +153 +00:07:16,336 --> 00:07:18,906 +查看当前显示的深色或浅色外观 + +154 +00:07:18,906 --> 00:07:22,209 +是否在 SwiftUI 中 +得到正确的显示 + +155 +00:07:22,209 --> 00:07:24,811 +最后 我将再次构建并运行 + +156 +00:07:29,816 --> 00:07:32,286 +请注意 Apple Weather +标记和归属链接 + +157 +00:07:32,286 --> 00:07:36,256 +在 SFSafariViewController 中打开 + +158 +00:07:36,256 --> 00:07:38,058 +这就是获取天气信息所需的一切 + +159 +00:07:38,058 --> 00:07:40,761 +使用 Wea​​therKit API +您可以有很多办法 + +160 +00:07:40,761 --> 00:07:43,263 +在您的飞行 App 中 + +161 +00:07:43,263 --> 00:07:45,265 +添加天气数据 + +162 +00:07:45,265 --> 00:07:48,135 +但这只是原生框架 + +163 +00:07:48,135 --> 00:07:51,038 +REST API 提供 +同样丰富的天气数据 + +164 +00:07:51,038 --> 00:07:55,209 +并且作为 Swift 框架 +他可以在任何平台上使用 + +165 +00:07:55,209 --> 00:07:58,679 +在此示例中 我将展示 + +166 +00:07:58,679 --> 00:08:02,382 +如何通过 weatherkit.apple.com 接口 +请求天气警报 + +167 +00:08:02,382 --> 00:08:04,651 +首先 您需要请求一个验证令牌 + +168 +00:08:04,651 --> 00:08:07,020 +这个我们稍后再讨论 + +169 +00:08:07,020 --> 00:08:10,457 +然后 要获取天气对象 +首先需要创建一个 + +170 +00:08:10,457 --> 00:08:14,494 +标示给定位置的 +所需天气数据集的 URL + +171 +00:08:14,494 --> 00:08:16,630 +为了适应软件的本地化 + +172 +00:08:16,630 --> 00:08:19,032 +一定要设置合适的语言 + +173 +00:08:19,032 --> 00:08:21,502 +然后提供 + +174 +00:08:21,502 --> 00:08:24,037 +所需位置的经纬度 + +175 +00:08:24,037 --> 00:08:26,473 +指明所需的数据集 + +176 +00:08:26,473 --> 00:08:29,243 +您可能会注意到此参数是复数 + +177 +00:08:29,243 --> 00:08:33,313 +所以您可以使用逗号分割多次请求 + +178 +00:08:33,313 --> 00:08:36,917 +最后 请求位置的国家代码 + +179 +00:08:36,917 --> 00:08:39,186 +但请注意 仅在请求天气警报时 + +180 +00:08:39,186 --> 00:08:43,156 +国家代码才是必须的 + +181 +00:08:43,156 --> 00:08:44,725 +接下来 您将获取天气数据 + +182 +00:08:44,725 --> 00:08:48,328 +使用上面的 URL +和您的验证令牌 + +183 +00:08:48,328 --> 00:08:51,231 +将结果转换为 JSON 格式 + +184 +00:08:51,231 --> 00:08:53,367 +您可以用这个变量访问天气警报信息 + +185 +00:08:53,367 --> 00:08:55,669 +以及他们的详细信息 + +186 +00:08:55,669 --> 00:08:58,539 +再说一次 另一个例子对您来说 +访问天气数据已经如此简单 + +187 +00:08:58,539 --> 00:09:02,943 +只是这次是通过 REST API + +188 +00:09:02,943 --> 00:09:05,746 +要更深入地了解您需要的设置 + +189 +00:09:05,746 --> 00:09:08,815 +让我们重温一下如何进行验证 + +190 +00:09:08,815 --> 00:09:10,517 +对于 WeatherKit REST API + +191 +00:09:10,517 --> 00:09:14,821 +还有一些额外的 +步骤来处理身份验证 + +192 +00:09:14,821 --> 00:09:16,957 +在开发者门户中 +您需要创建 + +193 +00:09:16,957 --> 00:09:20,227 +为 WeatherKit 验证密钥 +和相关联的服务 ID + +194 +00:09:20,227 --> 00:09:24,531 +来启用对 WeatherKit 请求权限 + +195 +00:09:24,531 --> 00:09:25,999 +在开发者门户的 +“Keys”(密钥) 部分中 + +196 +00:09:25,999 --> 00:09:29,269 +可以创建私钥 + +197 +00:09:29,269 --> 00:09:32,172 +WeatherKit 需要在每次请求中 + +198 +00:09:32,172 --> 00:09:33,707 +用令牌来验证授权 + +199 +00:09:33,707 --> 00:09:36,243 +因此 您需要 +在您的服务器上部署一个 + +200 +00:09:36,243 --> 00:09:40,814 +用于使用您的私钥的 +已签名 JSON Web Token (JWT) + +201 +00:09:40,814 --> 00:09:43,884 +对于那些熟悉 +JSON Web Token 验证的人 + +202 +00:09:43,884 --> 00:09:46,854 +这是一个相当标准的授权流程 + +203 +00:09:46,854 --> 00:09:48,021 +但如果您是第一次使用它 + +204 +00:09:48,021 --> 00:09:51,291 +那么请听我分享一些这里的细节 + +205 +00:09:51,291 --> 00:09:52,593 +要生成签名令牌 + +206 +00:09:52,593 --> 00:09:55,762 +您需要按照开发者文档中所述 + +207 +00:09:55,762 --> 00:09:59,166 +创建包含键名和值的Header + +208 +00:09:59,166 --> 00:10:02,069 +然后创建 +专用于 WeatherKit Rest API + +209 +00:10:02,069 --> 00:10:06,106 +和您的 App 的有效信息 + +210 +00:10:06,106 --> 00:10:08,809 +包括发行人 主题 + +211 +00:10:08,809 --> 00:10:11,311 +和到期时间 + +212 +00:10:11,311 --> 00:10:13,247 +最后 您需要签署令牌 + +213 +00:10:13,247 --> 00:10:17,618 +以便于随后调用 +Wea​​therKit REST API + +214 +00:10:17,618 --> 00:10:20,087 +回到我的天气警报示例 + +215 +00:10:20,087 --> 00:10:24,191 +在这里 +您将从您的签名服务中请求令牌 + +216 +00:10:24,191 --> 00:10:26,593 +并为您的天气数据 HTTP 请求 + +217 +00:10:26,593 --> 00:10:31,031 +添加 Authorization 令牌 Header + +218 +00:10:31,031 --> 00:10:33,634 +这就是通过 +WeatherKit REST API + +219 +00:10:33,634 --> 00:10:36,270 +从 Apple Weather Service 获取 + +220 +00:10:36,270 --> 00:10:38,438 +天气数据的两种好方法之一 + +221 +00:10:38,438 --> 00:10:41,008 +最后 我将介绍 +一些不论在 App Store + +222 +00:10:41,008 --> 00:10:44,111 +或其他平台发布 App 之前 + +223 +00:10:44,111 --> 00:10:47,915 +使用 REST API 时的额外要求 + +224 +00:10:47,915 --> 00:10:50,050 +这些要求全都对您适用 + +225 +00:10:50,050 --> 00:10:54,388 +无论您使用的是 +原生 Swift 还是 REST API + +226 +00:10:54,388 --> 00:10:57,090 +第一个要求是标注服务归属 + +227 +00:10:57,090 --> 00:10:58,859 +正如您在我的演示中看到的 + +228 +00:10:58,859 --> 00:11:01,528 +不论是在本地 App +或是网络 App 中 + +229 +00:11:01,528 --> 00:11:04,164 +您都需要显示 +服务来源的 API 链接 + +230 +00:11:04,164 --> 00:11:07,234 +第二个要求是归属标志 + +231 +00:11:07,234 --> 00:11:10,304 +WeatherKit API +可以为您在 App 中 + +232 +00:11:10,304 --> 00:11:15,042 +提供很便捷的图片资源 + +233 +00:11:15,042 --> 00:11:17,644 +最后 如果您要显示天气警报 + +234 +00:11:17,644 --> 00:11:19,513 +您还需要链接到 + +235 +00:11:19,513 --> 00:11:21,849 +提供活动信息的页面 + +236 +00:11:21,849 --> 00:11:24,284 +就是如此容易 +无论您是准备把 App + +237 +00:11:24,284 --> 00:11:27,554 +发布到 App Store 还是网上 + +238 +00:11:27,554 --> 00:11:28,889 +这就是 WeatherKit + +239 +00:11:28,889 --> 00:11:32,559 +Apple Weather Service +提供支持的超本地预报 + +240 +00:11:32,559 --> 00:11:36,663 +通过我们的 Swift 框架 +和 REST API 访问 + +241 +00:11:36,663 --> 00:11:38,732 +两者都为您提供了无限可能 + +242 +00:11:38,732 --> 00:11:40,934 +帮助您将天气数据 +应用于您的 App + +243 +00:11:40,934 --> 00:11:43,670 +以及任何平台 +或设备之中 + +244 +00:11:43,670 --> 00:11:45,806 +我们希望您喜欢本次讲座 + +245 +00:11:45,806 --> 00:11:48,742 +除了查看与本次讲座相关的链接 + +246 +00:11:48,742 --> 00:11:51,311 +阅读文档并下载项目之外 + +247 +00:11:51,311 --> 00:11:53,647 +我们还希望能得到您的反馈 + +248 +00:11:53,647 --> 00:11:57,117 +我们迫不及待地想看到 +您在使用 WeatherKit 时 + +249 +00:11:57,117 --> 00:11:58,819 +展现的所有创造性 +和有影响力的方式 + +250 +00:11:58,819 --> 00:12:01,622 +谢谢您 祝您 WWDC 愉快! + +251 +00:12:01,622 --> 00:12:05,726 +♪ + diff --git a/zho/2022 Session 10005 What's new in HealthKit.srt b/zho/2022 Session 10005 What's new in HealthKit.srt new file mode 100644 index 0000000..3446f90 --- /dev/null +++ b/zho/2022 Session 10005 What's new in HealthKit.srt @@ -0,0 +1,1854 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,610 +♪ + +3 +00:00:09,610 --> 00:00:13,080 +您好 欢迎来到 WWDC + +4 +00:00:13,080 --> 00:00:16,850 +我是 Karim +一名 HealthKit 工程师 + +5 +00:00:16,850 --> 00:00:19,753 +HealthKit 框架为提供 + +6 +00:00:19,753 --> 00:00:22,322 +良好的健康体验打下基础 + +7 +00:00:22,322 --> 00:00:24,124 +而 Apple Watch 拥有 + +8 +00:00:24,124 --> 00:00:26,860 +许多健康和安全功能 + +9 +00:00:26,860 --> 00:00:29,429 +为您监测数据 保驾护航 + +10 +00:00:29,429 --> 00:00:33,567 +睡眠跟踪是广受欢迎的功能之一 + +11 +00:00:33,567 --> 00:00:35,235 +我们升级了睡眠跟踪 + +12 +00:00:35,235 --> 00:00:38,839 +以捕捉更细致的睡眠数据 + +13 +00:00:38,839 --> 00:00:41,875 +今年 +HealthKit 还新增了 + +14 +00:00:41,875 --> 00:00:44,478 +许多出色功能 + +15 +00:00:44,478 --> 00:00:47,281 +我们优化了 API + +16 +00:00:47,281 --> 00:00:51,885 +使用 Swift async 查询数据 +更为便捷 + +17 +00:00:51,885 --> 00:00:57,558 +我们提升了体能训练功能 +呈现出更多元的体能训练 + +18 +00:00:57,558 --> 00:01:02,029 +我们完善了保存 +视力处方的方法 + +19 +00:01:02,029 --> 00:01:07,668 +其中包括保存纸质处方的数字副本 + +20 +00:01:07,668 --> 00:01:10,971 +我很高兴能向您介绍 +更多有关升级的信息 + +21 +00:01:10,971 --> 00:01:14,041 +以及在您的 App +中运用它们的方法 + +22 +00:01:14,041 --> 00:01:17,244 +让我们开始吧 + +23 +00:01:17,244 --> 00:01:20,080 +睡眠起着 + +24 +00:01:20,080 --> 00:01:23,884 +放松身心的重要作用 + +25 +00:01:23,884 --> 00:01:27,955 +我个人喜欢用 Apple Watch +来记录我的睡眠时间 + +26 +00:01:27,955 --> 00:01:30,757 +然后获取建议 + +27 +00:01:30,757 --> 00:01:33,393 +用以理解和改善睡眠质量 + +28 +00:01:33,393 --> 00:01:37,397 +今年我们再次优化睡眠追踪 + +29 +00:01:37,397 --> 00:01:41,001 +引入睡眠阶段的分析记录 + +30 +00:01:41,001 --> 00:01:43,704 +Apple Watch 会自动追踪 + +31 +00:01:43,704 --> 00:01:46,173 +您入睡后的 + +32 +00:01:46,173 --> 00:01:47,574 +各个睡眠阶段 + +33 +00:01:47,574 --> 00:01:51,478 +这些数据可以在 +健康 App 中查看 + +34 +00:01:51,478 --> 00:01:53,947 +数据也会存到 +HealthKit 里 + +35 +00:01:53,947 --> 00:01:57,417 +当然 您的 App 也能够读取 + +36 +00:01:57,417 --> 00:02:01,455 +并保存睡眠阶段数据 + +37 +00:02:01,455 --> 00:02:04,691 +通过 Apple Watch 或您的 App +存储的睡眠数据 + +38 +00:02:04,691 --> 00:02:08,262 +在 HealthKit 中 +以 sleepAnalysis 标识符 + +39 +00:02:08,262 --> 00:02:12,833 +存储为类别样本 + +40 +00:02:12,833 --> 00:02:15,802 +我们将睡眠阶段分成三类 + +41 +00:02:15,802 --> 00:02:20,374 +快速眼动睡眠 (REM) +核心睡眠和深度睡眠 + +42 +00:02:20,374 --> 00:02:22,576 +将睡眠数据 +保存到 HealthKit 时 + +43 +00:02:22,576 --> 00:02:25,546 +您应当给 + +44 +00:02:25,546 --> 00:02:31,752 +目标睡眠阶段的每一段 +持续时间创建样本 + +45 +00:02:31,752 --> 00:02:35,522 +这是睡眠样本值枚举的示例 + +46 +00:02:35,522 --> 00:02:41,128 +我们添加了三个枚举值 +来代表睡眠阶段 + +47 +00:02:41,128 --> 00:02:43,730 +第一个是 asleepCore + +48 +00:02:43,730 --> 00:02:48,268 +这对应 +美国睡眠医学会 (AASM) + +49 +00:02:48,268 --> 00:02:54,708 +评分模型的第一和第二阶段 + +50 +00:02:54,708 --> 00:02:58,712 +然后是 asleepDeep +对应的是 + +51 +00:02:58,712 --> 00:03:02,349 +AASM 评分模型第三阶段 + +52 +00:03:02,349 --> 00:03:04,785 +最后是 asleepREM + +53 +00:03:04,785 --> 00:03:09,556 +这对应的是快速眼动期 + +54 +00:03:09,556 --> 00:03:11,825 +因为添加了睡眠阶段 + +55 +00:03:11,825 --> 00:03:14,761 +我们废弃了原 asleep 枚举值 + +56 +00:03:14,761 --> 00:03:18,265 +添加了 asleepUnspecified 枚举值 + +57 +00:03:18,265 --> 00:03:21,134 +用于表明 + +58 +00:03:21,134 --> 00:03:24,071 +睡着但未指定的睡眠阶段 + +59 +00:03:24,071 --> 00:03:26,707 +有了更新好的睡眠样本枚举 + +60 +00:03:26,707 --> 00:03:30,511 +现在可以保存和读取 HealthKit + +61 +00:03:30,511 --> 00:03:32,045 +里的睡眠阶段数据了 + +62 +00:03:32,045 --> 00:03:36,416 +我们添加了一个新谓词 +使得读取指定睡眠阶段的样本 + +63 +00:03:36,416 --> 00:03:38,685 +更为方便 + +64 +00:03:38,685 --> 00:03:42,022 +比如我想读取快速眼动睡眠 +阶段 (REM) 的 + +65 +00:03:42,022 --> 00:03:44,191 +睡眠样本 + +66 +00:03:44,191 --> 00:03:46,260 +首先 我用新的 +predicateForSamples 方法 + +67 +00:03:46,260 --> 00:03:49,530 +传入 asleepREM + +68 +00:03:49,530 --> 00:03:52,533 +创建一个谓词 + +69 +00:03:52,533 --> 00:03:55,769 +现在 我可以开始 +创建查询了 + +70 +00:03:55,769 --> 00:03:57,871 +我为我的查询创建一个谓词 + +71 +00:03:57,871 --> 00:04:00,340 +把 sleepAnalysis +作为样本类型 + +72 +00:04:00,340 --> 00:04:02,643 +再传入睡眠阶段的谓词 + +73 +00:04:02,643 --> 00:04:07,381 +有了这个查询谓词 +我现在可以创建查询了 + +74 +00:04:07,381 --> 00:04:09,616 +运行查询就会得到 + +75 +00:04:09,616 --> 00:04:13,554 +快速眼动睡眠阶段 (REM) +的睡眠样本数组 + +76 +00:04:13,554 --> 00:04:16,857 +但是 如果您想读取 +所有睡眠阶段的样本 + +77 +00:04:16,857 --> 00:04:20,827 +包括未指定的 + +78 +00:04:20,827 --> 00:04:23,163 +请务必更新您的 App + +79 +00:04:23,163 --> 00:04:28,669 +在构建谓词时使用全新的 +.allAsleepValues + +80 +00:04:28,669 --> 00:04:31,805 +如果您在去年之后 +没有关注过 HealthKit + +81 +00:04:31,805 --> 00:04:36,877 +可能不熟悉这种较短的查询语法 + +82 +00:04:36,877 --> 00:04:39,179 +自 iOS 15.4 起 + +83 +00:04:39,179 --> 00:04:44,518 +我们就更新了查询 API +以支持 Swift async + +84 +00:04:44,518 --> 00:04:47,888 +查询是 HealthKit +的重要组成部分 + +85 +00:04:47,888 --> 00:04:51,124 +有了 Swift async 的支持 + +86 +00:04:51,124 --> 00:04:54,161 +查询的语法更简洁 使用更方便 + +87 +00:04:54,161 --> 00:04:57,464 +查询能让您从 +HealthKit 读取各种数据 + +88 +00:04:57,464 --> 00:04:59,933 +使用谓词筛选结果 + +89 +00:04:59,933 --> 00:05:03,871 +还能监测到新进来的数据 + +90 +00:05:03,871 --> 00:05:08,442 +所有查询都是 +HKQuery 的子类 + +91 +00:05:08,442 --> 00:05:12,045 +如果我想知道某个时期 + +92 +00:05:12,045 --> 00:05:14,014 +消耗的卡路里总额 + +93 +00:05:14,014 --> 00:05:17,217 +用 HKStatisticsCollectionQuery + +94 +00:05:17,217 --> 00:05:20,554 +进行查询以获取计算 +好的统计数据是个好办法 + +95 +00:05:20,554 --> 00:05:23,223 +要想获得初始查询结果 + +96 +00:05:23,223 --> 00:05:27,895 +需要设置 +initialResultsHandler 闭包 + +97 +00:05:27,895 --> 00:05:31,398 +如果想获取之后的更新 + +98 +00:05:31,398 --> 00:05:33,100 +另外设置 + +99 +00:05:33,100 --> 00:05:36,403 +statisticsUpdateHandler 闭包 + +100 +00:05:36,403 --> 00:05:38,105 +开始查询后 + +101 +00:05:38,105 --> 00:05:41,842 +闭包会被调用 +带有查询结果 + +102 +00:05:41,842 --> 00:05:46,313 +有了 Swift async +查询起来更加方便 + +103 +00:05:46,313 --> 00:05:49,883 +每个查询都有 +相匹配的查询描述符 + +104 +00:05:49,883 --> 00:05:53,187 +HKStatisticsCollectionQuery 有 + +105 +00:05:53,187 --> 00:05:56,990 +HKStatisticsCollectionQueryDescriptor + +106 +00:05:56,990 --> 00:05:58,425 +要得到初始查询结果 + +107 +00:05:58,425 --> 00:06:02,696 +只需调用 +async result(for:) 方法 + +108 +00:06:02,696 --> 00:06:06,333 +如果您想获取初始查询结果及后续更新 + +109 +00:06:06,333 --> 00:06:10,270 +可以调用 +results(for:) 方法 + +110 +00:06:10,270 --> 00:06:14,341 +得到 AsyncSequence + +111 +00:06:14,341 --> 00:06:16,677 +使用循环来读取结果 + +112 +00:06:16,677 --> 00:06:20,214 +HealthKit 很适合跟踪体能训练 + +113 +00:06:20,214 --> 00:06:24,318 +以及相关指标 +例如消耗的卡路里 + +114 +00:06:24,318 --> 00:06:28,021 +要想知道我这周消耗了多少卡路里 + +115 +00:06:28,021 --> 00:06:32,125 +我可以使用 +统计数据收集查询描述符 + +116 +00:06:32,125 --> 00:06:35,028 +首先 我创建查询描述符 + +117 +00:06:35,028 --> 00:06:38,732 +传入匹配卡路里样本的谓词 + +118 +00:06:38,732 --> 00:06:44,404 +传入 cumulativeSum 选项 +因为我想要得到总和 + +119 +00:06:44,404 --> 00:06:46,507 +我想知道这周的数据 + +120 +00:06:46,507 --> 00:06:50,844 +所以我用 thisSunday +作为 anchorDate + +121 +00:06:50,844 --> 00:06:54,114 +最后 我想要计算一周时间的 + +122 +00:06:54,114 --> 00:06:58,685 +卡路里消耗总和 + +123 +00:06:58,685 --> 00:07:00,988 +查询描述符创建后 + +124 +00:07:00,988 --> 00:07:04,224 +要做的就是调用 +result(for:) 方法 + +125 +00:07:04,224 --> 00:07:07,127 +传入 healthStore 对象 + +126 +00:07:07,127 --> 00:07:09,563 +返回的 statisticsCollection 对象 + +127 +00:07:09,563 --> 00:07:13,400 +会给我当前数据的快照 + +128 +00:07:13,400 --> 00:07:16,770 +如果想要在卡路里变化时 +获取到更新 + +129 +00:07:16,770 --> 00:07:20,474 +只要调用 +results(for:) + +130 +00:07:20,474 --> 00:07:23,043 +在返回的异步序列中 + +131 +00:07:23,043 --> 00:07:25,879 +循环读取结果就可以了 + +132 +00:07:25,879 --> 00:07:28,048 +当我不再需要获取更新时 + +133 +00:07:28,048 --> 00:07:32,986 +只要跳出循环 就能结束查询 + +134 +00:07:32,986 --> 00:07:36,590 +接下来 让我们谈谈体能训练功能 + +135 +00:07:36,590 --> 00:07:40,227 +HealthKit 是 +保存体能训练数据 + +136 +00:07:40,227 --> 00:07:42,496 +及所有相关指标的好地方 + +137 +00:07:42,496 --> 00:07:45,332 +无论您是要悠闲地骑个自行车 + +138 +00:07:45,332 --> 00:07:48,702 +还是在比赛中挑战突破自身极限 +都能很好地记录下来 + +139 +00:07:48,702 --> 00:07:49,970 +通常来说 + +140 +00:07:49,970 --> 00:07:53,874 +体能训练一般不限于单个活动 + +141 +00:07:53,874 --> 00:07:58,378 +您可能会在间歇训练中 +重复相同的活动 + +142 +00:07:58,378 --> 00:08:01,181 +也有可能参加铁人三项比赛 + +143 +00:08:01,181 --> 00:08:05,686 +铁人三项包括游泳自行车和跑步 + +144 +00:08:05,686 --> 00:08:10,657 +在 iOS 16 和 watchOS 9 中 +我们更新了体能训练 API + +145 +00:08:10,657 --> 00:08:14,361 +能够捕获这类体能训练 + +146 +00:08:14,361 --> 00:08:19,266 +以及关联的每个活动的统计数据 + +147 +00:08:19,266 --> 00:08:22,836 +这是我最近一次做的 + +148 +00:08:22,836 --> 00:08:24,771 +游泳-自行车-跑步 +体能训练时间轴 + +149 +00:08:24,771 --> 00:08:26,607 +我先游泳 + +150 +00:08:26,607 --> 00:08:28,976 +然后花些许时间准备 + +151 +00:08:28,976 --> 00:08:32,246 +才开始自行车部分 + +152 +00:08:32,246 --> 00:08:34,147 +最后再跑步 + +153 +00:08:34,147 --> 00:08:41,154 +每项活动都由一个 +HKWorkoutActivity 对象表示 + +154 +00:08:41,154 --> 00:08:42,756 +创建每项体能训练活动 + +155 +00:08:42,756 --> 00:08:45,959 +都带有各自的体能训练配置 + +156 +00:08:45,959 --> 00:08:49,730 +其中涵盖活动类型 + +157 +00:08:49,730 --> 00:08:52,866 +一个体能训练活动包含期间 + +158 +00:08:52,866 --> 00:08:56,937 +发生的所有事件 + +159 +00:08:56,937 --> 00:09:01,275 +您能够读取每一项活动的统计数据 + +160 +00:09:01,275 --> 00:09:03,944 +在您只想要 + +161 +00:09:03,944 --> 00:09:08,949 +分析某一项活动时 +很有帮助 + +162 +00:09:08,949 --> 00:09:10,751 +说回我的时间轴 + +163 +00:09:10,751 --> 00:09:12,853 +我的三项活动都配置了 + +164 +00:09:12,853 --> 00:09:16,590 +对应的活动类型 + +165 +00:09:16,590 --> 00:09:19,693 +活动在时间上不能重叠 + +166 +00:09:19,693 --> 00:09:22,296 +而且因为每次活动之间 + +167 +00:09:22,296 --> 00:09:24,264 +可能会有过渡期 + +168 +00:09:24,264 --> 00:09:27,835 +它们不需要紧连在一起 + +169 +00:09:27,835 --> 00:09:30,337 +如果我想分析过渡时期 + +170 +00:09:30,337 --> 00:09:32,539 +发生了什么 + +171 +00:09:32,539 --> 00:09:35,676 +我可以给每一个过渡期创建 +HKWorkoutActivity + +172 +00:09:35,676 --> 00:09:39,613 +活动类型是过渡期 + +173 +00:09:39,613 --> 00:09:44,451 +所有活动都将存到 +HKWorkout 对象下的 + +174 +00:09:44,451 --> 00:09:47,721 +workoutActivities 属性中 + +175 +00:09:47,721 --> 00:09:52,092 +如果您用 HKWorkoutBuilder +把体能训练添加到 HealthKit 中 + +176 +00:09:52,092 --> 00:09:55,696 +添加活动只要创建 +HKWorkoutActivity 对象 + +177 +00:09:55,696 --> 00:10:00,634 +传入 workoutConfiguration + +178 +00:10:00,634 --> 00:10:04,171 +开始和结束日期 以及 +可选的元数据 + +179 +00:10:04,171 --> 00:10:08,141 +然后 您只需在体能训练构建器上 + +180 +00:10:08,141 --> 00:10:10,477 +调用 addWorkoutActivity +添加即可 + +181 +00:10:10,477 --> 00:10:14,214 +在 Apple Watch 上 +您可以使用体能训练会话 + +182 +00:10:14,214 --> 00:10:16,617 +来跟踪 游泳-自行车-跑步 体能训练 + +183 +00:10:16,617 --> 00:10:18,652 +及相关的体能训练构建器 + +184 +00:10:18,652 --> 00:10:21,455 +把体能训练保存到 HealthKit 中 + +185 +00:10:21,455 --> 00:10:23,524 +我们继续回到体能训练时间轴 + +186 +00:10:23,524 --> 00:10:26,593 +要在 Apple Watch 上 +跟踪这次体能训练 + +187 +00:10:26,593 --> 00:10:31,598 +我需要设置一个 +体能训练会话和构建器 + +188 +00:10:31,598 --> 00:10:35,102 +我首先创建一个体能训练配置 + +189 +00:10:35,102 --> 00:10:38,172 +类型为 +swimBikeRun + +190 +00:10:38,172 --> 00:10:41,475 +然后用我的配置创建一个 + +191 +00:10:41,475 --> 00:10:43,944 +HKWorkoutSession + +192 +00:10:43,944 --> 00:10:45,812 +在体能训练的起始点 + +193 +00:10:45,812 --> 00:10:48,982 +我只是简单地在会话中 +调用 startActivity + +194 +00:10:48,982 --> 00:10:53,287 +并在相关的体能训练构建器上 +调用 beginCollection + +195 +00:10:53,287 --> 00:10:55,923 +会话和构建器准备就绪后 + +196 +00:10:55,923 --> 00:10:58,458 +我可以使用 +beginNewActivity 方法 + +197 +00:10:58,458 --> 00:11:01,128 +添加我的第一个活动 + +198 +00:11:01,128 --> 00:11:05,766 +第一个是游泳体能训练配置 +并附上开始日期 + +199 +00:11:05,766 --> 00:11:08,368 +每项活动开始前 + +200 +00:11:08,368 --> 00:11:11,438 +请确保您更新体能训练 +构建器数据源 + +201 +00:11:11,438 --> 00:11:15,676 +只收集您想要的数据类型 + +202 +00:11:15,676 --> 00:11:17,978 +由于这是个游泳活动 + +203 +00:11:17,978 --> 00:11:21,181 +我想收集游泳里程 + +204 +00:11:21,181 --> 00:11:22,983 +活动结束后 + +205 +00:11:22,983 --> 00:11:28,589 +我调用 endCurrentActivity +加上结束日期 + +206 +00:11:28,589 --> 00:11:32,092 +因为我想要分析 + +207 +00:11:32,092 --> 00:11:34,394 +游泳和骑行之间的过渡期 + +208 +00:11:34,394 --> 00:11:37,064 +我会在游泳结束后马上 + +209 +00:11:37,064 --> 00:11:40,667 +开始一个新的过渡活动 + +210 +00:11:40,667 --> 00:11:44,705 +然后 由于这也是一个活动的始点 + +211 +00:11:44,705 --> 00:11:46,540 +我会更新构建器数据源 + +212 +00:11:46,540 --> 00:11:49,676 +来停止游泳里程的收集 + +213 +00:11:49,676 --> 00:11:53,680 +因为游泳不再相关了 + +214 +00:11:53,680 --> 00:11:58,385 +在骑行开始前 +结束过渡活动 + +215 +00:11:58,385 --> 00:12:01,154 +跟踪其余的活动 + +216 +00:12:01,154 --> 00:12:03,857 +也是用同样的方式 + +217 +00:12:03,857 --> 00:12:05,459 +在体能训练结束时 + +218 +00:12:05,459 --> 00:12:10,130 +结束会话也会结束 +任何进行中的活动 + +219 +00:12:10,130 --> 00:12:12,432 +然后我就完成体能训练构建器 + +220 +00:12:12,432 --> 00:12:16,803 +这会保存并返回一个 +HKWorkout 对象 + +221 +00:12:16,803 --> 00:12:19,039 +我可以从返回的体能训练数据 + +222 +00:12:19,039 --> 00:12:21,675 +读取一些相关的指标 + +223 +00:12:21,675 --> 00:12:25,312 +例如 totalEnergyBurned +和 totalDistance + +224 +00:12:25,312 --> 00:12:29,950 +然后在我的 App 中 +显示体能训练总结 + +225 +00:12:29,950 --> 00:12:32,920 +但是 这一小部分属性 + +226 +00:12:32,920 --> 00:12:35,122 +已经不够用了 + +227 +00:12:35,122 --> 00:12:39,426 +totalSwimmingStrokeCount +并不是跟所有体能训练都有关 + +228 +00:12:39,426 --> 00:12:43,163 +个别体能训练可能会收集更多指标 + +229 +00:12:43,163 --> 00:12:45,732 +为了所以种类的体能训练指标 + +230 +00:12:45,732 --> 00:12:47,501 +读取都起来更方便 + +231 +00:12:47,501 --> 00:12:49,803 +我们弃用了这些属性 + +232 +00:12:49,803 --> 00:12:53,874 +新增了对指定的数量类型 + +233 +00:12:53,874 --> 00:12:56,643 +返回统计数据的方法 + +234 +00:12:56,643 --> 00:12:59,847 +顺便说下 新方法也可在 + +235 +00:12:59,847 --> 00:13:03,750 +HKWorkoutActivity 上使用 + +236 +00:13:03,750 --> 00:13:08,188 +这个方法能让您专注于 +活动期间发生的数据 + +237 +00:13:08,188 --> 00:13:11,758 +这些统计数据会被自动计算 + +238 +00:13:11,758 --> 00:13:14,328 +根据体能训练中收集的所有样本 + +239 +00:13:14,328 --> 00:13:20,033 +但前提是用了 HKWorkoutBuilder 或 +HKLiveWorkoutBuilder + +240 +00:13:20,033 --> 00:13:23,103 +除了更丰富的体能训练 +数据呈现以外 + +241 +00:13:23,103 --> 00:13:26,273 +我们还新增了一组谓词 + +242 +00:13:26,273 --> 00:13:28,876 +在您进行分析或可视化时 + +243 +00:13:28,876 --> 00:13:32,980 +用于只查询您感兴趣的 +体能训练 + +244 +00:13:32,980 --> 00:13:34,848 +举个例子 + +245 +00:13:34,848 --> 00:13:38,452 +这是我最近的体能训练 + +246 +00:13:38,452 --> 00:13:42,623 +每个活动都带有平均心率 + +247 +00:13:42,623 --> 00:13:47,060 +我想找出体能训练中平均心率 + +248 +00:13:47,060 --> 00:13:50,931 +高于 150 的高强度活动 + +249 +00:13:50,931 --> 00:13:54,568 +首先 我用新的 +predicateForWorkoutActivity + +250 +00:13:54,568 --> 00:13:57,171 +方法创建一个谓词 + +251 +00:13:57,171 --> 00:14:00,574 +作用于体能训练活动 + +252 +00:14:00,574 --> 00:14:02,109 +我要找平均心率 + +253 +00:14:02,109 --> 00:14:05,579 +高于每分钟 150 次 + +254 +00:14:05,579 --> 00:14:08,582 +接下来 因为我想查询体能训练 + +255 +00:14:08,582 --> 00:14:13,287 +所以我把心率谓词放在 +体能训练谓词里 + +256 +00:14:13,287 --> 00:14:17,391 +然后 我用该谓词创建查询 + +257 +00:14:17,391 --> 00:14:20,060 +我调用了查询描述符上的 + +258 +00:14:20,060 --> 00:14:23,397 +result(for: healthStore) 方法 + +259 +00:14:23,397 --> 00:14:26,099 +以获取符合我谓词的体能训练列表 + +260 +00:14:26,099 --> 00:14:27,935 +通过这种方式 + +261 +00:14:27,935 --> 00:14:31,271 +我可以只查询我感兴趣的体能训练 + +262 +00:14:31,271 --> 00:14:33,073 +我最近的一个体能训练 + +263 +00:14:33,073 --> 00:14:36,476 +包含四个跑步区间 + +264 +00:14:36,476 --> 00:14:40,247 +用 HKWorkoutActivity + +265 +00:14:40,247 --> 00:14:42,616 +是捕捉这些区间的好方法 + +266 +00:14:42,616 --> 00:14:45,419 +您只要确保 +间歇性体能训练里的 + +267 +00:14:45,419 --> 00:14:49,022 +所有活动的活动类型 + +268 +00:14:49,022 --> 00:14:50,858 +跟体能训练的类型相同 + +269 +00:14:50,858 --> 00:14:54,461 +因此 就跑步体能训练来说 +所有活动要配置 + +270 +00:14:54,461 --> 00:14:57,064 +.running 类型 + +271 +00:14:57,064 --> 00:15:01,034 +使用体能训练活动来跟踪 +间歇性体能训练的好处 + +272 +00:15:01,034 --> 00:15:04,972 +是您可以获得每个区间的统计数据 + +273 +00:15:04,972 --> 00:15:07,741 +有了这些更新 + +274 +00:15:07,741 --> 00:15:11,545 +体能训练更丰富地呈现了 + +275 +00:15:11,545 --> 00:15:14,615 +活动以及活动前后的情况 + +276 +00:15:14,615 --> 00:15:18,051 +为了提供更丰富的信息 + +277 +00:15:18,051 --> 00:15:21,188 +我们引入了新的跑步指标 + +278 +00:15:21,188 --> 00:15:23,390 +在 Apple Watch Series 6 +SE 及更新机型上 + +279 +00:15:23,390 --> 00:15:28,061 +会自动收集 + +280 +00:15:28,061 --> 00:15:33,700 +包括跑步步幅 步长 +或以瓦特为单位的功率等指标 + +281 +00:15:33,700 --> 00:15:37,604 +对于游泳体能训练 +我们添加了 SWOLF 分数 + +282 +00:15:37,604 --> 00:15:40,374 +SWOLF 通过给定距离下的划水数 + +283 +00:15:40,374 --> 00:15:42,509 +和所用时间 + +284 +00:15:42,509 --> 00:15:45,812 +来计算 + +285 +00:15:45,812 --> 00:15:49,550 +将为在 Apple Watch 上 + +286 +00:15:49,550 --> 00:15:52,219 +采集的游泳体能训练数据中的 + +287 +00:15:52,219 --> 00:15:55,589 +每一圈和每个分区 +都进行计算 + +288 +00:15:55,589 --> 00:15:58,759 +虽然这些指标 +丰富了您的体能训练数据 + +289 +00:15:58,759 --> 00:16:02,696 +并让您更好地了解您的表现 + +290 +00:16:02,696 --> 00:16:05,299 +但是记录体能训练结束后的 + +291 +00:16:05,299 --> 00:16:09,403 +另一个指标也很重要 +那就是心率恢复 + +292 +00:16:09,403 --> 00:16:13,473 +该指标是对您运动后 +心率降低速度的估计 + +293 +00:16:13,473 --> 00:16:17,878 +可以用来了解 + +294 +00:16:17,878 --> 00:16:20,214 +心脏负荷后的恢复情况 + +295 +00:16:20,214 --> 00:16:23,283 +并揭示可能潜在的健康问题 + +296 +00:16:23,283 --> 00:16:28,722 +在 iOS 16 我们引入了一种 +新的 Cardio Recovery 数据类型 + +297 +00:16:28,722 --> 00:16:31,325 +可在健康 App 访问 + +298 +00:16:31,325 --> 00:16:34,761 +您的 App 将能够从 HealthKit 中 + +299 +00:16:34,761 --> 00:16:37,364 +读取和保存该数据 + +300 +00:16:37,364 --> 00:16:41,068 +心率恢复是数量类型 + +301 +00:16:41,068 --> 00:16:46,173 +标识符为 +.heartRateRecoveryOneMinute + +302 +00:16:46,173 --> 00:16:48,275 +有关每个心率恢复样本的 + +303 +00:16:48,275 --> 00:16:50,711 +附加上下文信息 + +304 +00:16:50,711 --> 00:16:54,114 +可以添加为元数据 + +305 +00:16:54,114 --> 00:16:56,650 +在我最近的 +游泳-自行车-跑步体能训练中 + +306 +00:16:56,650 --> 00:16:59,152 +我达到了运动极限 + +307 +00:16:59,152 --> 00:17:03,056 +然后观察我的心率恢复速率 + +308 +00:17:03,056 --> 00:17:05,492 +我花了大约三个半小时 + +309 +00:17:05,492 --> 00:17:08,295 +来完成体能训练 + +310 +00:17:08,295 --> 00:17:12,733 +当我跑步时我达到了 +每分钟 184 次的 + +311 +00:17:12,733 --> 00:17:14,535 +最大心率 + +312 +00:17:14,535 --> 00:17:16,803 +体能训练后的一分钟里 + +313 +00:17:16,803 --> 00:17:20,507 +我的心率下降了 50 次 + +314 +00:17:20,507 --> 00:17:24,178 +在 Apple Watch 上使用 +HKLiveWorkoutBuilder 时 + +315 +00:17:24,178 --> 00:17:26,280 +心率恢复样本 + +316 +00:17:26,280 --> 00:17:28,749 +连同其上下文信息 + +317 +00:17:28,749 --> 00:17:33,320 +在体能训练后会 +自动保存在 HealthKit 中 + +318 +00:17:33,320 --> 00:17:37,024 +除此之外 要保存心率恢复样本 + +319 +00:17:37,024 --> 00:17:39,426 +我使用 +.heartRateRecoveryOneMinute 类型 + +320 +00:17:39,426 --> 00:17:42,729 +创建了一个数量样本 + +321 +00:17:42,729 --> 00:17:44,531 +我的心率在体能训练后的一分钟里 + +322 +00:17:44,531 --> 00:17:46,333 +下降了 50 次 + +323 +00:17:46,333 --> 00:17:50,504 +所以我将其设置为我的样本数量 + +324 +00:17:50,504 --> 00:17:54,074 +我还为样本设置了开始和结束日期 + +325 +00:17:54,074 --> 00:17:57,945 +然后 我将附加上下文信息添加到了 + +326 +00:17:57,945 --> 00:18:00,614 +元数据字典中 + +327 +00:18:00,614 --> 00:18:03,450 +以恢复测试类型开始 + +328 +00:18:03,450 --> 00:18:06,186 +由于我的体能训练达到了极限 + +329 +00:18:06,186 --> 00:18:09,723 +所以测试类型为 +.maxExercise + +330 +00:18:09,723 --> 00:18:12,259 +我的体能训练 +是 swimBikeRun + +331 +00:18:12,259 --> 00:18:15,996 +所以我将其设置为活动类型 + +332 +00:18:15,996 --> 00:18:19,233 +我还可以使用 +HeartRateRecoveryActivityDuration 键 + +333 +00:18:19,233 --> 00:18:23,170 +添加体能训练持续时间 + +334 +00:18:23,170 --> 00:18:27,307 +最后 我添加体能训练期间 + +335 +00:18:27,307 --> 00:18:32,846 +观察到的最大心率 +为每分钟 184 次 + +336 +00:18:32,846 --> 00:18:35,916 +有了这些更新 现在将更加容易 + +337 +00:18:35,916 --> 00:18:39,953 +跟踪游泳-自行车-跑步和 +间歇性体能训练 + +338 +00:18:39,953 --> 00:18:43,457 +此外 新指标的引入 + +339 +00:18:43,457 --> 00:18:47,427 +为您的体能训练提供了更全面的信息 + +340 +00:18:47,427 --> 00:18:52,432 +以及评估过程的新方法 + +341 +00:18:52,432 --> 00:18:57,070 +虽然活动和健身会影响到每一个人 + +342 +00:18:57,070 --> 00:18:59,473 +还有其他方面的健康问题会 + +343 +00:18:59,473 --> 00:19:03,277 +涉及到我们许多人 比如视觉 + +344 +00:19:03,277 --> 00:19:07,047 +实际上 根据美国视力协会表示 + +345 +00:19:07,047 --> 00:19:11,952 +美国大约 75% 的成年人 + +346 +00:19:11,952 --> 00:19:15,322 +依靠处方眼镜或隐形眼镜 + +347 +00:19:15,322 --> 00:19:17,724 +矫正视力 + +348 +00:19:17,724 --> 00:19:20,961 +但是 这些处方很容易丢失 + +349 +00:19:20,961 --> 00:19:23,630 +而且 在订购处方眼镜或隐形眼镜时 + +350 +00:19:23,630 --> 00:19:27,968 +要随身携带处方 显得十分累赘 + +351 +00:19:27,968 --> 00:19:31,104 +所以让我们将其放在我们的手机里 + +352 +00:19:31,104 --> 00:19:34,141 +从 iOS 16 开始 +您的 App 现在可以将 + +353 +00:19:34,141 --> 00:19:39,713 +眼镜和隐形眼镜处方 +保存到 HealthKit 中 + +354 +00:19:39,713 --> 00:19:42,349 +视力处方是一个带有 + +355 +00:19:42,349 --> 00:19:45,686 +visionPrescriptionType 类型的样本 + +356 +00:19:45,686 --> 00:19:47,721 +样本的开始日期对应 + +357 +00:19:47,721 --> 00:19:50,424 +处方的发放日期 + +358 +00:19:50,424 --> 00:19:54,661 +而结束日期对应于处方的到期日期 + +359 +00:19:54,661 --> 00:19:59,066 +实体处方的数字副本 + +360 +00:19:59,066 --> 00:20:02,836 +可以选择性地附在样本上 + +361 +00:20:02,836 --> 00:20:06,006 +眼镜或隐形眼镜处方样本 + +362 +00:20:06,006 --> 00:20:10,711 +是 HKVisionPrescription 的子类 + +363 +00:20:10,711 --> 00:20:15,349 +对于眼镜 +您使用 HKGlassesPrescription 子类 + +364 +00:20:15,349 --> 00:20:20,454 +对于隐形眼镜 +使用 HKContactsPrescription 子类 + +365 +00:20:20,454 --> 00:20:22,756 +使用两个眼镜镜片规格对象 + +366 +00:20:22,756 --> 00:20:26,560 +创建每个眼镜处方 + +367 +00:20:26,560 --> 00:20:29,396 +每只眼睛一个 + +368 +00:20:29,396 --> 00:20:32,766 +同样 隐形眼镜处方由 + +369 +00:20:32,766 --> 00:20:36,770 +两个隐形眼镜镜片规格对象创建 + +370 +00:20:36,770 --> 00:20:40,240 +现在 我们将阅读眼镜处方 + +371 +00:20:40,240 --> 00:20:42,276 +保存到 HealthKit + +372 +00:20:42,276 --> 00:20:46,580 +第一步是对每只眼睛创建一个 + +373 +00:20:46,580 --> 00:20:48,682 +HKGlassesLensSpecification + +374 +00:20:48,682 --> 00:20:52,619 +像顶点距离和棱镜等参数 + +375 +00:20:52,619 --> 00:20:54,821 +是可选的 + +376 +00:20:54,821 --> 00:21:00,928 +我可以用同样的方法 +创建右眼镜片规格 + +377 +00:21:00,928 --> 00:21:04,565 +接下来 我用右眼和左眼的镜片规格 + +378 +00:21:04,565 --> 00:21:09,169 +创建了一个眼镜处方样本 + +379 +00:21:09,169 --> 00:21:12,206 +该处方是为我的阅读眼镜创建的 + +380 +00:21:12,206 --> 00:21:16,310 +所以我在描述中添加了备注 + +381 +00:21:16,310 --> 00:21:18,946 +然后 我只需在 healthStore 上 + +382 +00:21:18,946 --> 00:21:20,881 +调用保存方法 +来保存处方 + +383 +00:21:20,881 --> 00:21:25,819 +这样 我的处方已 +保存到 HealthKit 中 + +384 +00:21:25,819 --> 00:21:27,688 +同时 我给处方拍了张照 + +385 +00:21:27,688 --> 00:21:31,892 +想将其附加到我刚刚保存的样本中 + +386 +00:21:31,892 --> 00:21:37,898 +文件附件由 HKAttachment 对象表示 + +387 +00:21:37,898 --> 00:21:43,904 +使用 HKAttachmentStore 来 +保存和读取文件附件 + +388 +00:21:43,904 --> 00:21:47,074 +仅静态图像或 PDF 文件 + +389 +00:21:47,074 --> 00:21:50,911 +可以附在处方上 + +390 +00:21:50,911 --> 00:21:55,415 +要将我图片附在处方样本上 + +391 +00:21:55,415 --> 00:21:59,453 +我首先使用 +healthStore 创建一个 + +392 +00:21:59,453 --> 00:22:01,722 +HKAttachmentStore 对象 + +393 +00:22:01,722 --> 00:22:07,127 +然后调用 addAttachment(to:) +传入处方样本 + +394 +00:22:07,127 --> 00:22:09,963 +我为附件设置了一个名称 + +395 +00:22:09,963 --> 00:22:13,333 +在这里 我附上了 +一个 PNG 文件 + +396 +00:22:13,333 --> 00:22:17,871 +最后 传递文件的 URL + +397 +00:22:17,871 --> 00:22:22,709 +我刚刚附上的处方包含更多信息 + +398 +00:22:22,709 --> 00:22:25,512 +不只是镜头规格 + +399 +00:22:25,512 --> 00:22:30,784 +还包括敏感信息 +例如我的全名和出生日期 + +400 +00:22:30,784 --> 00:22:33,020 +HealthKit 的 +核心原则之一 + +401 +00:22:33,020 --> 00:22:36,356 +是为了保护您的隐私并确保 + +402 +00:22:36,356 --> 00:22:40,494 +您可以始终掌控您分享的数据 + +403 +00:22:40,494 --> 00:22:44,498 +因为在分享包含附件的处方时 + +404 +00:22:44,498 --> 00:22:47,100 +很容易无心分享出更多的数据 + +405 +00:22:47,100 --> 00:22:50,304 +我们为处方引入了一种 + +406 +00:22:50,304 --> 00:22:52,406 +新的授权模式 + +407 +00:22:52,406 --> 00:22:54,641 +每个处方对象的读取权限 + +408 +00:22:54,641 --> 00:22:57,945 +是单独授权的 + +409 +00:22:57,945 --> 00:23:00,714 +用户可以授权 App + +410 +00:23:00,714 --> 00:23:03,550 +读取特定的处方 + +411 +00:23:03,550 --> 00:23:07,254 +并可随时更新这些授权 + +412 +00:23:07,254 --> 00:23:10,924 +对于视力处方对象 + +413 +00:23:10,924 --> 00:23:14,161 +我们有新的 API +用于请求授权 + +414 +00:23:14,161 --> 00:23:16,196 +就像其他数据类型一样 + +415 +00:23:16,196 --> 00:23:19,166 +您可以使用查询来读取 + +416 +00:23:19,166 --> 00:23:22,035 +您的 App 有权访问的处方 + +417 +00:23:22,035 --> 00:23:25,539 +如果您只对某些处方感兴趣 + +418 +00:23:25,539 --> 00:23:27,875 +您可以使用谓词 + +419 +00:23:27,875 --> 00:23:31,011 +要请求授权 +只需调用 healthStore 的 + +420 +00:23:31,011 --> 00:23:34,248 +requestPerObjectRead 授权方法 + +421 +00:23:34,248 --> 00:23:37,885 +传入 visionType + +422 +00:23:37,885 --> 00:23:42,890 +这样将始终在您的 App 中显示 + +423 +00:23:42,890 --> 00:23:45,559 +处方授权弹出窗口 + +424 +00:23:45,559 --> 00:23:48,595 +展示所有与您的谓词 +相匹配的处方列表 + +425 +00:23:48,595 --> 00:23:51,365 +确保您在适当的环境中请求授权 + +426 +00:23:51,365 --> 00:23:56,370 +以确保最佳的用户体验 + +427 +00:23:56,370 --> 00:24:00,574 +以上只是我们添加到 +HealthKit 的一些新内容 + +428 +00:24:00,574 --> 00:24:03,510 +使您的 App 能够提供更好的 + +429 +00:24:03,510 --> 00:24:05,979 +健康和健身体验 + +430 +00:24:05,979 --> 00:24:09,950 +非常期待看到您接下来的创造 + +431 +00:24:09,950 --> 00:24:13,754 +祝您有一个愉快的 WWDC +如果您有任何问题 + +432 +00:24:13,754 --> 00:24:17,357 +我们很乐意在 +开发者论坛中为您提供帮助 + +433 +00:24:17,357 --> 00:24:21,461 +♪ + diff --git a/zho/2022 Session 10006 Meet Apple Maps Server APIs.srt b/zho/2022 Session 10006 Meet Apple Maps Server APIs.srt new file mode 100644 index 0000000..4781ff3 --- /dev/null +++ b/zho/2022 Session 10006 Meet Apple Maps Server APIs.srt @@ -0,0 +1,1156 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ ♪ + +2 +00:00:03,003 --> 00:00:09,276 +♪ + +3 +00:00:09,276 --> 00:00:12,079 +大家好! +我叫 Ankur Soni + +4 +00:00:12,079 --> 00:00:14,882 +我是 Apple 地图服务团队的 + +5 +00:00:14,882 --> 00:00:16,416 +工程经理 + +6 +00:00:16,416 --> 00:00:19,353 +今天 我们要看一下即将进入 +地图开发者生态系统的 + +7 +00:00:19,353 --> 00:00:21,255 +一些令人兴奋的新功能 + +8 +00:00:21,255 --> 00:00:23,223 +让我们现在开始吧 + +9 +00:00:23,223 --> 00:00:26,326 +我们的“地图”App +可以为全球 Apple 用户 + +10 +00:00:26,326 --> 00:00:28,195 +提供多样的终端用户体验 + +11 +00:00:28,195 --> 00:00:30,264 +我们授权开发者 +通过 MapKit 和 MapKit JS + +12 +00:00:30,264 --> 00:00:33,534 +去搭建属于他们的 + +13 +00:00:33,534 --> 00:00:38,205 +体验优秀的 +地理定位 App 和网站 + +14 +00:00:38,205 --> 00:00:41,108 +并且 我们的 +Apple 地图开发者服务 + +15 +00:00:41,108 --> 00:00:43,911 +一直坚持以用户为中心 + +16 +00:00:43,911 --> 00:00:47,214 +我们会悉心聆听所有反馈和建议 + +17 +00:00:47,214 --> 00:00:50,817 +您会希望在不影响性能 +或增加功耗的前提下 + +18 +00:00:50,817 --> 00:00:54,388 +在 MapKit 上扩充您的数据 + +19 +00:00:54,388 --> 00:00:56,156 +因此 为了完善我们的生态系统 + +20 +00:00:56,156 --> 00:01:01,128 +我现在很高兴向您介绍 +Apple Maps Server API + +21 +00:01:01,128 --> 00:01:04,398 +我们正在增加 +四个新的 Server API + +22 +00:01:04,398 --> 00:01:08,335 +分别是 Geocode (地理编码) +Reverse Geocoding (反向地理编码) + +23 +00:01:08,335 --> 00:01:12,306 +Search (搜索) +以及 ETA (预计到达时间) + +24 +00:01:12,306 --> 00:01:15,843 +在把地图合并 +导入到您的 App 中时 + +25 +00:01:15,843 --> 00:01:20,047 +这些 API +将帮助您处理各种用例 + +26 +00:01:20,047 --> 00:01:23,150 +使用 Geocode API +您可以将地址 + +27 +00:01:23,150 --> 00:01:26,486 +转换为地理坐标 纬度和经度 + +28 +00:01:26,486 --> 00:01:28,956 +同理 使用 Reverse Geocoding API + +29 +00:01:28,956 --> 00:01:30,257 +您可以通过一个逆向的过程 + +30 +00:01:30,257 --> 00:01:33,861 +得到从地理坐标到地址的信息 + +31 +00:01:33,861 --> 00:01:37,431 +借助 Search API +您可以为用户提供 + +32 +00:01:37,431 --> 00:01:40,367 +输入企业名称 兴趣点等关键词 + +33 +00:01:40,367 --> 00:01:43,637 +查找地点的功能 + +34 +00:01:43,637 --> 00:01:45,672 +也许您想覆盖一些您自己的数据 + +35 +00:01:45,672 --> 00:01:47,774 +并将其呈现给用户 + +36 +00:01:47,774 --> 00:01:51,078 +通过 ETA API +您可以帮助您的用户 + +37 +00:01:51,078 --> 00:01:53,680 +了解您的业务离他们有多远 + +38 +00:01:53,680 --> 00:01:56,717 +或进行一些计算以找到最近的商店 + +39 +00:01:56,717 --> 00:02:00,287 +可能性是无限的! + +40 +00:02:00,287 --> 00:02:05,526 +您很可能会因为三个重要原因 +而喜欢上我们的 Server API + +41 +00:02:05,526 --> 00:02:08,862 +首先 您现在可以 +体验到 MapKit、MapKit JS + +42 +00:02:08,862 --> 00:02:13,367 +和全新的 Apple Maps Server API +实现功能上的无缝衔接 + +43 +00:02:13,367 --> 00:02:15,736 +这在简化您的 App 架构的同时 + +44 +00:02:15,736 --> 00:02:18,572 +还能为您提供 +更多的 Apple Maps 堆栈 + +45 +00:02:18,572 --> 00:02:20,574 +这将使您的生活更轻松 + +46 +00:02:20,574 --> 00:02:21,909 +当然 它也帮助了我 + +47 +00:02:21,909 --> 00:02:24,611 +但是 嘿 可能我 +对它有偏爱滤镜 + +48 +00:02:24,611 --> 00:02:27,881 +其次 我们的 Server API +可以减少网络调用 + +49 +00:02:27,881 --> 00:02:30,651 +很多时候 我们经常 +会陷入这样一种情况 + +50 +00:02:30,651 --> 00:02:33,086 +我们在诸如 +iPad、iPhone 和网站等 + +51 +00:02:33,086 --> 00:02:36,790 +用户设备上不断地提出 + +52 +00:02:36,790 --> 00:02:38,692 +重复和冗余的请求 + +53 +00:02:38,692 --> 00:02:41,862 +也许您也曾经试过 +在不同的设备的同一个 App 上 + +54 +00:02:41,862 --> 00:02:44,798 +一遍又一遍地查找同一个地址 + +55 +00:02:44,798 --> 00:02:48,268 +这大大增加了网络调用 +造成带宽浪费 + +56 +00:02:48,268 --> 00:02:51,171 +但如果将此常见操作 +委托给您的服务器 + +57 +00:02:51,171 --> 00:02:55,242 +并且只在后端 +使用 Server API 执行一次 + +58 +00:02:55,242 --> 00:02:58,812 +那么就能实现 +减少 App 带宽消耗的目的 + +59 +00:02:58,812 --> 00:03:02,082 +并且 通过委托 +使用 Apple Maps Server API + +60 +00:03:02,082 --> 00:03:05,786 +实现您的 App 的一些功能 + +61 +00:03:05,786 --> 00:03:09,223 +就能进一步减少 +您 App 的功耗了 + +62 +00:03:09,223 --> 00:03:12,292 +现在让我们来看看 +其中一些 API 的接口吧 + +63 +00:03:12,292 --> 00:03:14,828 +假设我们正在为您的定位 App + +64 +00:03:14,828 --> 00:03:17,397 +创建地图名片 + +65 +00:03:17,397 --> 00:03:20,300 +这里我们看到三个商店及其地址 + +66 +00:03:20,300 --> 00:03:22,736 +以及与用户位置的距离 + +67 +00:03:22,736 --> 00:03:25,772 +在本例中 我们假设用户 + +68 +00:03:25,772 --> 00:03:29,109 +提供了他们的位置 + +69 +00:03:29,109 --> 00:03:32,846 +现在 让我们开始着手 +创建其中一张地图名片 + +70 +00:03:32,846 --> 00:03:35,415 +我们假设 +包括这家漫画书店在内的地址信息 + +71 +00:03:35,415 --> 00:03:41,121 +已经储存在服务器上 +并且可以随时进行调用 + +72 +00:03:41,121 --> 00:03:44,191 +我们现在有很多方法 +可以创建 但等一下 + +73 +00:03:44,191 --> 00:03:47,261 +假设我们现在 +没有这些新的 Server API + +74 +00:03:47,261 --> 00:03:49,763 +那么 App 的基本架构 +会是什么样子? + +75 +00:03:49,763 --> 00:03:52,666 +您的 App +将如何获取这些数据? + +76 +00:03:52,666 --> 00:03:56,570 +在此图中 我们的 +App 先向服务器发送请求 + +77 +00:03:56,570 --> 00:03:58,972 +以获取漫画书店地址列表 + +78 +00:03:58,972 --> 00:04:01,742 +后端服务器返回漫画书店地址列表 + +79 +00:04:01,742 --> 00:04:04,511 +到您的客户端设备 + +80 +00:04:04,511 --> 00:04:07,514 +由于我们在此示例中 +没有新的 Server API + +81 +00:04:07,514 --> 00:04:10,717 +所以我们的 App +在创建一张地图名片 + +82 +00:04:10,717 --> 00:04:13,520 +就必须执行大量操作 + +83 +00:04:13,520 --> 00:04:15,355 +每执行一次任务 + +84 +00:04:15,355 --> 00:04:17,758 +用户可能都需要多次 + +85 +00:04:17,758 --> 00:04:20,127 +向后端服务器发送请求 + +86 +00:04:20,127 --> 00:04:23,697 +在这里您可以看到客户端正在 + +87 +00:04:23,697 --> 00:04:25,866 +直接向 Apple Maps Server +发送请求 + +88 +00:04:25,866 --> 00:04:29,570 +或者通过 MapKit +或 MapKit JS + +89 +00:04:29,570 --> 00:04:32,773 +客户端和后端服务器之间的这种互动 + +90 +00:04:32,773 --> 00:04:35,075 +会对 App 的性能和大小 + +91 +00:04:35,075 --> 00:04:36,643 +产生负面影响 + +92 +00:04:36,643 --> 00:04:39,780 +在通常具有高延迟的蜂窝网络上 + +93 +00:04:39,780 --> 00:04:43,517 +以这种方式使用单个请求 + +94 +00:04:43,517 --> 00:04:45,586 +效率很低 甚至可能导致连接中断 + +95 +00:04:45,586 --> 00:04:47,487 +或数据丢失 + +96 +00:04:47,487 --> 00:04:50,190 +当每个请求可以并行完成时 + +97 +00:04:50,190 --> 00:04:53,093 +App 必须 +在单独的连接上发送 等待 + +98 +00:04:53,093 --> 00:04:55,896 +和处理每个请求的数据 + +99 +00:04:55,896 --> 00:04:58,232 +而这将增加失败的可能 + +100 +00:04:58,232 --> 00:05:02,436 +最后 您将必须 +合并客户端上的所有响应 + +101 +00:05:02,436 --> 00:05:04,738 +当所有这些调用发生时 + +102 +00:05:04,738 --> 00:05:07,341 +您正在向用户展示一个微调器 + +103 +00:05:07,341 --> 00:05:10,077 +另外 客户端设备 +需要为这些额外的调用 + +104 +00:05:10,077 --> 00:05:12,079 +使用更多的带宽和功耗 + +105 +00:05:12,079 --> 00:05:14,848 +这样的用户体验并不好 + +106 +00:05:14,848 --> 00:05:17,284 +现在 让我们来看一下使用了 + +107 +00:05:17,284 --> 00:05:20,120 +Apple Maps Server API +的模型架构 + +108 +00:05:20,120 --> 00:05:23,156 +您可以开始使用后端服务器作为网关 + +109 +00:05:23,156 --> 00:05:27,895 +以减少客户端和服务器之间的互动 + +110 +00:05:27,895 --> 00:05:31,198 +和以前一样 这里我们从您的客户端 + +111 +00:05:31,198 --> 00:05:34,368 +向后端服务器发送一个 +显示漫画店列表的请求 + +112 +00:05:34,368 --> 00:05:39,740 +接下来 我们 +从服务器发出请求以进行地理编码 + +113 +00:05:39,740 --> 00:05:42,843 +然后我们会收到 +来自 Apple Maps Server 的 + +114 +00:05:42,843 --> 00:05:45,846 +每个 API 的响应 + +115 +00:05:45,846 --> 00:05:50,217 +漫画书服务器组合 +来自每个服务的响应 + +116 +00:05:50,217 --> 00:05:52,920 +并将响应发送给 App + +117 +00:05:52,920 --> 00:05:55,656 +此模式可以减少 App + +118 +00:05:55,656 --> 00:05:58,458 +对后端服务的请求数量 + +119 +00:05:58,458 --> 00:06:00,093 +并在高延迟网络上 + +120 +00:06:00,093 --> 00:06:02,162 +提高 App 的性能 + +121 +00:06:02,162 --> 00:06:05,899 +总而言之 +您的客户端仅向您的服务器 + +122 +00:06:05,899 --> 00:06:07,868 +发送了一次获取存储列表的请求 + +123 +00:06:07,868 --> 00:06:10,337 +然后您的服务器完成繁重的工作 + +124 +00:06:10,337 --> 00:06:13,941 +进行了相应的 API 调用并组成 + +125 +00:06:13,941 --> 00:06:16,810 +最符合用户需求的响应呈现给用户 + +126 +00:06:16,810 --> 00:06:19,780 +所以 让我们回到 +这里的案例研究示例 + +127 +00:06:19,780 --> 00:06:22,249 +我们将使用地理编码 +和 ETA API + +128 +00:06:22,249 --> 00:06:24,918 +来获取到商店的距离 + +129 +00:06:24,918 --> 00:06:29,256 +我们可以使用地理编码 +API 来查找纬度和经度 + +130 +00:06:29,256 --> 00:06:31,825 +我们稍后将使用商店地址 + +131 +00:06:31,825 --> 00:06:33,627 +用于预计到达时间计算 + +132 +00:06:33,627 --> 00:06:36,430 +在这个例子中 首先 我们将采取 + +133 +00:06:36,430 --> 00:06:42,102 +漫画书店的地址 +和 URL 对其进行编码 + +134 +00:06:42,102 --> 00:06:45,339 +接下来 我们将使用 +Geocode API + +135 +00:06:45,339 --> 00:06:50,077 +并将这个 URL 编码的地址 +作为查询参数传递 + +136 +00:06:50,077 --> 00:06:52,746 +我们现在暂时跳过认证的细节 + +137 +00:06:52,746 --> 00:06:55,749 +在几张幻灯片中再来讨论它 + +138 +00:06:55,749 --> 00:06:58,852 +在响应中 可以看到 + +139 +00:06:58,852 --> 00:07:01,555 +返回的地址的经纬度 + +140 +00:07:01,555 --> 00:07:03,724 +我们将重复相同的流程来找到 + +141 +00:07:03,724 --> 00:07:06,994 +客户地址的经纬度 + +142 +00:07:06,994 --> 00:07:10,063 +这将在稍后用于预计到达时间计算 + +143 +00:07:10,063 --> 00:07:13,600 +如您所见 响应中有更多字段 + +144 +00:07:13,600 --> 00:07:15,269 +我会在下方的资源部分 + +145 +00:07:15,269 --> 00:07:18,438 +链接详细的文档 + +146 +00:07:18,438 --> 00:07:23,110 +现在 我们可以 +用从 Geocode API 获得的数据 + +147 +00:07:23,110 --> 00:07:26,947 +在 ETA API 上 +设置起点和终点 + +148 +00:07:26,947 --> 00:07:31,585 +正如我之前提到的 +我们有起点纬度 经度 + +149 +00:07:31,585 --> 00:07:34,121 +以及目的地的纬度 经度 + +150 +00:07:34,121 --> 00:07:38,125 +如果需要 我们最多可以 +在此处指定 10 个目的地 + +151 +00:07:38,125 --> 00:07:41,628 +我们以 URL 编码的格式 + +152 +00:07:41,628 --> 00:07:45,299 +把起点信息和终点信息 + +153 +00:07:45,299 --> 00:07:47,701 +提供给 ETA API + +154 +00:07:47,701 --> 00:07:50,971 +我们可以通过 API +输出每个目的地 + +155 +00:07:50,971 --> 00:07:53,040 +的预计到达时间列表 + +156 +00:07:53,040 --> 00:07:55,142 +在这个案例中 +因为我们只提供了一个目的地 + +157 +00:07:55,142 --> 00:07:58,679 +所以我们只有 +一个预计到达时间反馈信息 + +158 +00:07:58,679 --> 00:08:02,416 +这是我们的示例 假设我们 + +159 +00:08:02,416 --> 00:08:04,918 +想使用 distanceMeters +计算到商店的距离 + +160 +00:08:04,918 --> 00:08:07,921 +有了这些 我们就有了所需的 + +161 +00:08:07,921 --> 00:08:10,757 +所有信息:商店地址和 + +162 +00:08:10,757 --> 00:08:12,626 +用户与商店的距离 + +163 +00:08:12,626 --> 00:08:15,829 +您还可以选择使用个性化的商店信息 + +164 +00:08:15,829 --> 00:08:19,666 +扩充或修改此数据 如商店营业时间 + +165 +00:08:19,666 --> 00:08:23,136 +通过这种方式 +您可以利用不同的 Server API + +166 +00:08:23,136 --> 00:08:25,239 +构建您的 App + +167 +00:08:25,239 --> 00:08:28,041 +其他 API 请参考 + +168 +00:08:28,041 --> 00:08:29,910 +在本视频下方的文档链接 + +169 +00:08:29,910 --> 00:08:33,814 +我们尚未讨论的 +一个关键部分是身份验证 + +170 +00:08:33,814 --> 00:08:37,451 +所有 Apple Maps Server API +都经过了身份验证 + +171 +00:08:37,451 --> 00:08:41,154 +如果您使用的是 MapKit JS +那么您已经完成了一半 + +172 +00:08:41,154 --> 00:08:45,225 +Apple Maps Server API +使用与 MapKit JS 相同的机制 + +173 +00:08:45,225 --> 00:08:47,327 +进行身份验证 + +174 +00:08:47,327 --> 00:08:49,630 +首先 您将从您的开发者帐户 + +175 +00:08:49,630 --> 00:08:51,565 +下载您的私钥 + +176 +00:08:51,565 --> 00:08:53,300 +然后 您将使用此私钥 + +177 +00:08:53,300 --> 00:08:56,703 +生成 JWT 格式的地图身份 +验证令牌 + +178 +00:08:56,703 --> 00:08:59,039 +下方链接有如何生成 + +179 +00:08:59,039 --> 00:09:00,874 +该令牌的详细文档 + +180 +00:09:00,874 --> 00:09:03,076 +然后 您可以 +使用令牌 API 交换这个 + +181 +00:09:03,076 --> 00:09:06,713 +地图认证令牌来获得地图访问令牌 + +182 +00:09:06,713 --> 00:09:10,417 +我们将在后端验证地图身份验证令牌 + +183 +00:09:10,417 --> 00:09:13,053 +并发回地图访问令牌 + +184 +00:09:13,053 --> 00:09:15,422 +这是 JWT 格式 + +185 +00:09:15,422 --> 00:09:18,792 +将用于所有 API 交互 + +186 +00:09:18,792 --> 00:09:22,329 +此访问令牌需要通过重复此处 + +187 +00:09:22,329 --> 00:09:25,632 +突出显示的过程 +每 30 分钟刷新一次 + +188 +00:09:25,632 --> 00:09:29,236 +现在我们看到了 +身份验证流程是什么样的 + +189 +00:09:29,236 --> 00:09:33,106 +这是一个如何使用令牌 API + +190 +00:09:33,106 --> 00:09:35,776 +来获取访问令牌的简单示例 + +191 +00:09:35,776 --> 00:09:39,079 +我们在这里使用的是令牌 API + +192 +00:09:39,079 --> 00:09:43,050 +我们将地图认证令牌 +作为头文件传递 + +193 +00:09:43,050 --> 00:09:46,019 +您将收到一个地图访问令牌 + +194 +00:09:46,019 --> 00:09:48,555 +可用于访问 API + +195 +00:09:48,555 --> 00:09:52,159 +它将采用 JWT 格式 +并具有标准字段 + +196 +00:09:52,159 --> 00:09:55,562 +如 expiry、issuedAt 等 + +197 +00:09:55,562 --> 00:09:58,298 +为方便起见 +expiresInSeconds 字段 + +198 +00:09:58,298 --> 00:10:01,001 +显示令牌的有效时间 + +199 +00:10:01,001 --> 00:10:04,738 +在这种情况下 +有效时间是 30 分钟 + +200 +00:10:04,738 --> 00:10:07,207 +请记住地图身份验证令牌 + +201 +00:10:07,207 --> 00:10:10,310 +与地图访问令牌不同 + +202 +00:10:10,310 --> 00:10:12,713 +您交换地图认证令牌 + +203 +00:10:12,713 --> 00:10:15,649 +以获得一个 +时效为 30 分钟的地图访问令牌 + +204 +00:10:15,649 --> 00:10:18,252 +来访问 Server API + +205 +00:10:18,252 --> 00:10:21,054 +让我们快速看看有地图访问令牌的 + +206 +00:10:21,054 --> 00:10:24,958 +API 交互是怎么样的 + +207 +00:10:24,958 --> 00:10:29,096 +我们将通过 Server API 调用 +传递地图访问令牌 + +208 +00:10:29,096 --> 00:10:31,932 +它作为头文件 +添加到 API 调用中 + +209 +00:10:31,932 --> 00:10:34,368 +就像我们之前 +看到的几张幻灯片一样 + +210 +00:10:34,368 --> 00:10:37,971 +Apple Maps Server +将验证地图访问令牌 + +211 +00:10:37,971 --> 00:10:40,073 +验证成功后 + +212 +00:10:40,073 --> 00:10:44,578 +Apple Maps Server +将会响应 API 的请求 + +213 +00:10:44,578 --> 00:10:47,848 +现在我已经 +介绍了 API 和身份验证 + +214 +00:10:47,848 --> 00:10:50,417 +让我谈谈使用限制 + +215 +00:10:50,417 --> 00:10:53,153 +能力越大 责任越大 + +216 +00:10:53,153 --> 00:10:55,389 +所以请明智地使用您的配额 + +217 +00:10:55,389 --> 00:10:59,359 +每天可以进行的 API 调用 +是有上限的 + +218 +00:10:59,359 --> 00:11:01,094 +但这个上限值很高 + +219 +00:11:01,094 --> 00:11:05,632 +每天您总共将获得 +25,000 个请求配额 + +220 +00:11:05,632 --> 00:11:09,736 +请记住 通过 MapKit JS +和 Server API + +221 +00:11:09,736 --> 00:11:11,371 +调用服务都使用相同的配额 + +222 +00:11:11,371 --> 00:11:14,508 +如果您需要更多配额 请与我们联系 + +223 +00:11:14,508 --> 00:11:18,011 +那么 您如何跟踪这一切呢? + +224 +00:11:18,011 --> 00:11:23,083 +您可以在地图开发者主页中 +查看使用情况 + +225 +00:11:23,083 --> 00:11:24,885 +有人正在使用 MapKit JS 吗? + +226 +00:11:24,885 --> 00:11:27,788 +这对您来说会很熟悉 + +227 +00:11:27,788 --> 00:11:31,191 +Server API 的使用 +被归类为服务 + +228 +00:11:31,191 --> 00:11:34,962 +您可以在此处突出显示 + +229 +00:11:34,962 --> 00:11:37,431 +当超过每日配额时 + +230 +00:11:37,431 --> 00:11:41,869 +也就是超过 25,000 个 +Server API 调用 + +231 +00:11:41,869 --> 00:11:44,371 +我们将开始拒绝新的服务调用 + +232 +00:11:44,371 --> 00:11:47,407 +并以 HTTP 429 状态响应 + +233 +00:11:47,407 --> 00:11:50,177 +这表示有太多的请求 + +234 +00:11:50,177 --> 00:11:52,446 +在这种情况下 您应该确保 + +235 +00:11:52,446 --> 00:11:55,382 +App 产生的数据 +可以被有效地压缩 + +236 +00:11:55,382 --> 00:11:57,484 +在极少数情况下 当您的服务 + +237 +00:11:57,484 --> 00:12:00,521 +发出不寻常的请求量时 + +238 +00:12:00,521 --> 00:12:03,490 +可能是由于代码 +或基础结构中的一些 Bug + +239 +00:12:03,490 --> 00:12:07,227 +也可能是 +得到 HTTP 429 状态 + +240 +00:12:07,227 --> 00:12:10,397 +当您接收 +HTTP 429 状态时 + +241 +00:12:10,397 --> 00:12:13,667 +请尽量避免 +再重复机械地继续发送请求 + +242 +00:12:13,667 --> 00:12:16,570 +更好的方法是 + +243 +00:12:16,570 --> 00:12:18,105 +稍后再进行重试 + +244 +00:12:18,105 --> 00:12:21,775 +这种方法称为指数避退 + +245 +00:12:21,775 --> 00:12:24,878 +那么 我们今天了解到了什么? + +246 +00:12:24,878 --> 00:12:27,548 +我们发布了 +四个新的 Server API + +247 +00:12:27,548 --> 00:12:30,784 +这些 API 分别是 +Geocode、Reverse Geocoding + +248 +00:12:30,784 --> 00:12:33,687 +Search 和 ETA + +249 +00:12:33,687 --> 00:12:38,025 +将这些 API 与 MapKit +和 MapKit JS 结合使用 + +250 +00:12:38,025 --> 00:12:40,027 +将帮助您更好地 +使用 Apple Maps 堆栈 + +251 +00:12:40,027 --> 00:12:42,896 +构建您的 App + +252 +00:12:42,896 --> 00:12:45,866 +您可以通过 +使用 Apple Maps Server API + +253 +00:12:45,866 --> 00:12:48,335 +将这些任务委派给您的后端服务器 + +254 +00:12:48,335 --> 00:12:51,872 +以此优化冗余 减少重复调用 + +255 +00:12:51,872 --> 00:12:55,542 +这些 API 的每日配额 +为 25,000 次 + +256 +00:12:55,542 --> 00:12:58,745 +并与您的 MapKit JS 服务 +使用共享 + +257 +00:12:58,745 --> 00:13:01,849 +这就是为您而设的 +全新 Apple Maps Server API + +258 +00:13:01,849 --> 00:13:04,551 +请务必观看我们提及的 +关联讲座 + +259 +00:13:04,551 --> 00:13:07,020 +以及下面链接的详细文档 + +260 +00:13:07,020 --> 00:13:10,123 +我们期待看到您 +充分利用这些 API + +261 +00:13:10,123 --> 00:13:11,458 +感谢收看! + +262 +00:13:11,458 --> 00:13:15,462 +♪ + diff --git a/zho/2022 Session 10007 What's new with in-app purchase.srt b/zho/2022 Session 10007 What's new with in-app purchase.srt new file mode 100644 index 0000000..353169c --- /dev/null +++ b/zho/2022 Session 10007 What's new with in-app purchase.srt @@ -0,0 +1,4362 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,576 +♪ + +3 +00:00:09,576 --> 00:00:10,978 +Dani Chootong:大家好 欢迎收看 + +4 +00:00:10,978 --> 00:00:13,213 +“App 内购买的新功能” + +5 +00:00:13,213 --> 00:00:16,550 +我是 Dani +StoreKit 团队的工程师 + +6 +00:00:16,550 --> 00:00:19,186 +今天将由我和同事 lan 一起 + +7 +00:00:19,186 --> 00:00:20,854 +为大家介绍 +今年在 App 内购买中 + +8 +00:00:20,854 --> 00:00:23,657 +添加的新功能 + +9 +00:00:23,657 --> 00:00:26,126 +去年 我们推出了 StoreKit 2 + +10 +00:00:26,126 --> 00:00:29,096 +这是一组全新设计的 API + +11 +00:00:29,096 --> 00:00:32,032 +用于简化 App 内购买的步骤 + +12 +00:00:32,032 --> 00:00:34,902 +StoreKit 2 使用现代语言功能 + +13 +00:00:34,902 --> 00:00:38,539 +包括使用了 async/await +模式的 Swift 并发 + +14 +00:00:38,539 --> 00:00:39,573 +在服务器端 + +15 +00:00:39,573 --> 00:00:41,608 +我们用一组全新 +App Store Server 端点 + +16 +00:00:41,608 --> 00:00:45,078 +补充了这些新的 StoreKit 功能 + +17 +00:00:45,078 --> 00:00:47,214 +这些服务器端点方便您在服务器上 + +18 +00:00:47,214 --> 00:00:49,917 +检索交易信息 + +19 +00:00:49,917 --> 00:00:52,219 +查看订阅状态 + +20 +00:00:52,219 --> 00:00:55,822 +我们还发布了第 2 版 +App Store Server Notifications + +21 +00:00:55,822 --> 00:00:57,691 +方便您在服务器上 + +22 +00:00:57,691 --> 00:01:00,227 +跟踪订阅周期 + +23 +00:01:00,227 --> 00:01:02,996 +以上 API 以及 +新版 StoreKit 模型的 + +24 +00:01:02,996 --> 00:01:04,598 +增强功能 + +25 +00:01:04,598 --> 00:01:07,467 +将由我来为大家介绍 + +26 +00:01:07,467 --> 00:01:09,303 +之后 将由 Ian 为大家介绍 + +27 +00:01:09,303 --> 00:01:11,205 +一些超赞的服务器更新 + +28 +00:01:11,205 --> 00:01:13,707 +包括 +App Store Server API 增强功能 + +29 +00:01:13,707 --> 00:01:17,611 +以及用于 App Store +Server Notifications 的全新 API + +30 +00:01:17,611 --> 00:01:20,514 +首先 我将介绍用于 +验证 App 购买的 + +31 +00:01:20,514 --> 00:01:23,584 +全新 App Transaction API + +32 +00:01:23,584 --> 00:01:26,420 +其次 我将深入介绍 +StoreKit 模型的 + +33 +00:01:26,420 --> 00:01:28,989 +新增属性 + +34 +00:01:28,989 --> 00:01:32,226 +即全新 SwiftUI 友好型 API + +35 +00:01:32,226 --> 00:01:34,127 +用于兑换订阅优惠代码 + +36 +00:01:34,127 --> 00:01:37,231 +并要求用户评价 App + +37 +00:01:37,231 --> 00:01:39,967 +再次 我将为您 +介绍 StoreKit Messages + +38 +00:01:39,967 --> 00:01:41,735 +该 API 用于向用户显示 + +39 +00:01:41,735 --> 00:01:44,171 +App Store 的消息 + +40 +00:01:44,171 --> 00:01:46,740 +最后 我将介绍 +即将新增的增强功能 + +41 +00:01:46,740 --> 00:01:49,343 +该功能从旧版 +StoreKit API 迁移到新版时 + +42 +00:01:49,343 --> 00:01:52,880 +能保留您的 applicationUsername + +43 +00:01:52,880 --> 00:01:55,949 +讲解过程中 +我将用我常用的 App + +44 +00:01:55,949 --> 00:01:57,017 +Food Truck 为大家演示 + +45 +00:01:57,017 --> 00:01:59,987 +在 Food Truck 这款 App 中 +我经营着一个虚拟甜甜圈餐车 + +46 +00:01:59,987 --> 00:02:02,789 +走遍各个城市售卖甜甜圈 + +47 +00:02:02,789 --> 00:02:05,392 +那我们现在就开始吧! + +48 +00:02:05,392 --> 00:02:06,960 +先来看看 App Transaction + +49 +00:02:06,960 --> 00:02:09,196 +App Transaction +是我们新推出的 API + +50 +00:02:09,196 --> 00:02:12,432 +用于验证 App 购买 + +51 +00:02:12,432 --> 00:02:14,968 +App 交易相当于为设备上 + +52 +00:02:14,968 --> 00:02:18,939 +运行的 App 购买签名信息 + +53 +00:02:18,939 --> 00:02:21,508 +该 API 使用 JWS 签名 + +54 +00:02:21,508 --> 00:02:24,444 +取代了原先 +StoreKit API 中 App 收据的 + +55 +00:02:24,444 --> 00:02:27,247 +App 详情 + +56 +00:02:27,247 --> 00:02:29,416 +如交易验证一样 + +57 +00:02:29,416 --> 00:02:31,585 +StoreKit 为您的 App 交易 + +58 +00:02:31,585 --> 00:02:34,888 +执行自动验证 + +59 +00:02:34,888 --> 00:02:37,457 +但如果您愿意 您也可 + +60 +00:02:37,457 --> 00:02:39,326 +自行验证 + +61 +00:02:39,326 --> 00:02:43,230 +验证 JWS 签名有据可查 + +62 +00:02:43,230 --> 00:02:45,065 +您可参考公共文档 + +63 +00:02:45,065 --> 00:02:48,335 +执行验证 + +64 +00:02:48,335 --> 00:02:50,370 +StoreKit 在必要时可自动更新 + +65 +00:02:50,370 --> 00:02:52,673 +App 交易 + +66 +00:02:52,673 --> 00:02:54,775 +但在极少数情况下 用户 + +67 +00:02:54,775 --> 00:02:57,978 +认为交易出现问题 也可手动刷新 + +68 +00:02:57,978 --> 00:02:59,613 +您应在 App 中提供 UI + +69 +00:02:59,613 --> 00:03:03,417 +允许用户刷新 App 交易 + +70 +00:03:03,417 --> 00:03:06,186 +该方法仅用于响应用户操作 + +71 +00:03:06,186 --> 00:03:07,988 +因为刷新 App 交易 + +72 +00:03:07,988 --> 00:03:11,091 +会提示用户进行身份验证 + +73 +00:03:11,091 --> 00:03:15,362 +App Transaction +受欢迎的原因并非只有防止诈骗 + +74 +00:03:15,362 --> 00:03:18,599 +如果您希望把 +商业模式从付费 App 转换成 + +75 +00:03:18,599 --> 00:03:21,368 +提供 App 内购买项目的免费 App + +76 +00:03:21,368 --> 00:03:23,170 +如果您好奇哪些客户 + +77 +00:03:23,170 --> 00:03:25,172 +预购了您的 App + +78 +00:03:25,172 --> 00:03:27,875 +或想了解您 App 的购买时段 + +79 +00:03:27,875 --> 00:03:31,879 +均可在 +App Transaction 中实现 + +80 +00:03:31,879 --> 00:03:33,747 +在 App 收据中 收据有效负载 + +81 +00:03:33,747 --> 00:03:36,383 +结合了您的 App 购买数据 + +82 +00:03:36,383 --> 00:03:39,786 +以及所有发起的 App 内购买 + +83 +00:03:39,786 --> 00:03:41,989 +这在 StoreKit 中 + +84 +00:03:41,989 --> 00:03:43,290 +分为两个独立组件 + +85 +00:03:43,290 --> 00:03:46,393 +第一个组件是交易历史 + +86 +00:03:46,393 --> 00:03:48,495 +StoreKit 的交易 API +可以让您在设备上 + +87 +00:03:48,495 --> 00:03:51,064 +查看用户所有的 App 内购买 + +88 +00:03:51,064 --> 00:03:52,933 +历史记录 + +89 +00:03:52,933 --> 00:03:56,270 +该 API 可以查找 +您所需要的确切信息 + +90 +00:03:56,270 --> 00:03:58,672 +包括用户最新交易 + +91 +00:03:58,672 --> 00:04:02,476 +未完成的交易和当前授权的交易 + +92 +00:04:02,476 --> 00:04:05,279 +如您倾向于 +在自己的服务器上执行运算 + +93 +00:04:05,279 --> 00:04:07,347 +还可从 +App Store Server API 中 + +94 +00:04:07,347 --> 00:04:09,516 +获取用户的购买历史记录 + +95 +00:04:09,516 --> 00:04:11,652 +Ian 稍后将对该功能的亮点 + +96 +00:04:11,652 --> 00:04:13,687 +进行补充 + +97 +00:04:13,687 --> 00:04:16,089 +第二个组件是 App Transaction + +98 +00:04:16,089 --> 00:04:18,058 +包含让您的 +App 在设备上有效运行 + +99 +00:04:18,058 --> 00:04:20,861 +所需的数据 + +100 +00:04:20,861 --> 00:04:23,063 +使用 App Transaction 能轻松 + +101 +00:04:23,063 --> 00:04:25,599 +验证您的 App 购买 + +102 +00:04:25,599 --> 00:04:28,869 +稍后我将举例说明使用方法 + +103 +00:04:28,869 --> 00:04:30,537 +但在此之前 我先来向您介绍一下 + +104 +00:04:30,537 --> 00:04:32,239 +我常用的这款 App 的背景 + +105 +00:04:32,239 --> 00:04:34,508 +在 Food Truck 上 +我可以配送甜甜圈 + +106 +00:04:34,508 --> 00:04:36,777 +查阅基础社交信息流 + +107 +00:04:36,777 --> 00:04:39,046 +查看销售历史 + +108 +00:04:39,046 --> 00:04:41,048 +将所有这些信息保存在数据库中 + +109 +00:04:41,048 --> 00:04:45,219 +需要持续支付费用 +那么为了便于支付 + +110 +00:04:45,219 --> 00:04:47,487 +我要一次性购买 + +111 +00:04:47,487 --> 00:04:49,523 +年度销售记录表 + +112 +00:04:49,523 --> 00:04:52,793 +此外 我还想增强社交信息流推送 + +113 +00:04:52,793 --> 00:04:54,628 +这样不仅能看到他人如何评价 + +114 +00:04:54,628 --> 00:04:56,630 +我的餐车 我还能提供工具 + +115 +00:04:56,630 --> 00:04:59,299 +和客户展开互动 + +116 +00:04:59,299 --> 00:05:00,968 +这就涉及到订阅服务 + +117 +00:05:00,968 --> 00:05:04,505 +可以按月度或年度订阅 + +118 +00:05:04,505 --> 00:05:07,508 +Food Truck 起初是一款付费 App +我打算将其转变为 + +119 +00:05:07,508 --> 00:05:10,310 +支持 App 内购买的免费 App + +120 +00:05:10,310 --> 00:05:11,912 +但我又不希望忽略 + +121 +00:05:11,912 --> 00:05:15,782 +当前已经购买了 Food Truck 的用户 + +122 +00:05:15,782 --> 00:05:17,751 +所以 我会使用 App Transaction + +123 +00:05:17,751 --> 00:05:20,220 +保证已购买 Food Truck 的用户 + +124 +00:05:20,220 --> 00:05:24,157 +继续访问其支付的高级内容 + +125 +00:05:24,157 --> 00:05:26,994 +这是 Food Truck 的时间线 + +126 +00:05:26,994 --> 00:05:29,263 +在最初的版本中 + +127 +00:05:29,263 --> 00:05:31,965 +Food Truck 是一款 +售价 4.99 美元的付费 App + +128 +00:05:31,965 --> 00:05:34,401 +1.0 版本提供甜甜圈配送 + +129 +00:05:34,401 --> 00:05:37,938 +基础社交动态和销售记录表 + +130 +00:05:37,938 --> 00:05:39,907 +后来 在发布 8.0 版本时 + +131 +00:05:39,907 --> 00:05:42,009 +我改变了商业模式 + +132 +00:05:42,009 --> 00:05:43,810 +现在 Food Truck +虽然免费 但包含 + +133 +00:05:43,810 --> 00:05:47,347 +各类解锁高级功能 +的 App 内购买项目 + +134 +00:05:47,347 --> 00:05:50,284 +年度销售记录表现在是一次性购买的 + +135 +00:05:50,284 --> 00:05:52,486 +非消耗型订阅项目 现在还有 + +136 +00:05:52,486 --> 00:05:55,255 +全新的获取高级 +社交动态的订阅服务 + +137 +00:05:55,255 --> 00:05:58,125 +为您提供高级体验工具 + +138 +00:05:58,125 --> 00:06:00,761 +现在让我们来看看会受此影响的 + +139 +00:06:00,761 --> 00:06:03,263 +两类不同的用户 + +140 +00:06:03,263 --> 00:06:06,633 +Alice 发现了 +Food Truck 2.5 版本的 App + +141 +00:06:06,633 --> 00:06:09,069 +决定在虚拟世界中分享 + +142 +00:06:09,069 --> 00:06:11,138 +她对甜甜圈的热情 + +143 +00:06:11,138 --> 00:06:13,507 +所以 她以 4.99 美元的 +价格购买了这款 App + +144 +00:06:13,507 --> 00:06:16,476 +开启了甜甜圈售卖之旅 + +145 +00:06:16,476 --> 00:06:19,513 +第二位用户 Bob +通过朋友知道了 Food Truck + +146 +00:06:19,513 --> 00:06:21,014 +并在 8.2 版的 App Store 中 + +147 +00:06:21,014 --> 00:06:23,684 +免费下载了这款 App + +148 +00:06:23,684 --> 00:06:26,220 +在此情况下 在这款 App 免费前 + +149 +00:06:26,220 --> 00:06:28,522 +购买了该 App 的 Alice +仍可以访问 + +150 +00:06:28,522 --> 00:06:33,093 +其已经支付的所有高级内容 + +151 +00:06:33,093 --> 00:06:35,095 +仍可以选择订阅购买 + +152 +00:06:35,095 --> 00:06:37,764 +高级的社交动态信息流 但不可否认 + +153 +00:06:37,764 --> 00:06:42,569 +年度销售记录表已经包含在 +她的付费版 App 中了 + +154 +00:06:42,569 --> 00:06:44,872 +而 Bob 则是免费下载了该 App + +155 +00:06:44,872 --> 00:06:47,307 +两位都要完成 App 内购买 + +156 +00:06:47,307 --> 00:06:49,510 +才可使用其中的解锁功能和内容 + +157 +00:06:49,510 --> 00:06:51,345 +那么 让我们看看如何 +通过代码中的 App Transaction + +158 +00:06:51,345 --> 00:06:53,881 +实现这一目标 + +159 +00:06:53,881 --> 00:06:55,816 +首先 我将调用 +AppTransaction.shared + +160 +00:06:55,816 --> 00:06:59,353 +发起 App 交易 + +161 +00:06:59,353 --> 00:07:01,722 +通过该操作得到 +一个含有我的 App 交易的 + +162 +00:07:01,722 --> 00:07:03,991 +VerificationResult + +163 +00:07:03,991 --> 00:07:05,993 +在结果中 AppTransaction 类型 + +164 +00:07:05,993 --> 00:07:09,296 +包含 JWS 有效负载 + +165 +00:07:09,296 --> 00:07:11,865 +接下来 我将打开结果 + +166 +00:07:11,865 --> 00:07:14,134 +如果结果未经验证 那就要 + +167 +00:07:14,134 --> 00:07:16,136 +提醒用户 其 App 购买 + +168 +00:07:16,136 --> 00:07:18,105 +可能未经 App Store 验证 + +169 +00:07:18,105 --> 00:07:22,142 +然后 我就可以 +提示用户刷新 App 交易 + +170 +00:07:22,142 --> 00:07:26,046 +与此同时 我将为用户 +提供 App 短时体验机会 + +171 +00:07:26,046 --> 00:07:28,282 +如果结果已经验证 那我将借此机会 + +172 +00:07:28,282 --> 00:07:31,885 +检查用户是否购买了我的 App + +173 +00:07:31,885 --> 00:07:33,153 +购买了我的 App 的用户 + +174 +00:07:33,153 --> 00:07:36,290 +有权获取其所支付的服务 + +175 +00:07:36,290 --> 00:07:39,493 +为此 我将利用原始 +App 版本的属性 + +176 +00:07:39,493 --> 00:07:41,762 +该属性可让我了解用户首次下载 + +177 +00:07:41,762 --> 00:07:46,099 +该 App 时的版本 + +178 +00:07:46,099 --> 00:07:49,069 +8.0 版本是包含了 +App 内购买项目选项的 + +179 +00:07:49,069 --> 00:07:51,572 +免费版本 + +180 +00:07:51,572 --> 00:07:53,941 +我将把用户下载的 +原始 App 版本导入函数 + +181 +00:07:53,941 --> 00:07:57,010 +检查用户是否在 8.0 版本发行前 + +182 +00:07:57,010 --> 00:07:58,812 +就购买了我的 App + +183 +00:07:58,812 --> 00:08:01,081 +以此为依据 我就可以决定 + +184 +00:08:01,081 --> 00:08:05,919 +如何为用户提供高级内容 + +185 +00:08:05,919 --> 00:08:08,155 +对于像 Alice 这类 +购买 App 的用户 + +186 +00:08:08,155 --> 00:08:10,490 +我将向其提供购买时 + +187 +00:08:10,490 --> 00:08:13,093 +有权获得的内容 + +188 +00:08:13,093 --> 00:08:15,996 +为其解锁甜甜圈售卖的 + +189 +00:08:15,996 --> 00:08:18,332 +年度销售记录表 + +190 +00:08:18,332 --> 00:08:20,901 +我还想查看 +两位在 App 内购买中的 + +191 +00:08:20,901 --> 00:08:25,172 +其他行为记录 +以便为他们提供相关内容 + +192 +00:08:25,172 --> 00:08:27,908 +此外我同时也可以确定 +某用户 (比如 Bob) 是在 + +193 +00:08:27,908 --> 00:08:31,044 +我转变商业模式后 +才下载了我的 App + +194 +00:08:31,044 --> 00:08:32,079 +这正好可以 + +195 +00:08:32,079 --> 00:08:33,780 +检查用户当前授权的交易 + +196 +00:08:33,780 --> 00:08:37,651 +如此我就可以 +解锁其付费的功能和内容 + +197 +00:08:37,651 --> 00:08:39,152 +只需几行代码 + +198 +00:08:39,152 --> 00:08:41,755 +我就能验证我的 App 购买 + +199 +00:08:41,755 --> 00:08:43,323 +检查用户是否下载了 + +200 +00:08:43,323 --> 00:08:44,925 +该 App 的付费版本 + +201 +00:08:44,925 --> 00:08:47,494 +并且不论用户 +是否购买了我的 App + +202 +00:08:47,494 --> 00:08:52,032 +我都能立即提供高级内容 + +203 +00:08:52,032 --> 00:08:54,201 +使用 App Transaction +您可轻松为用户 + +204 +00:08:54,201 --> 00:08:56,403 +提供支持 无论其是老用户 + +205 +00:08:56,403 --> 00:08:59,473 +还是刚刚下载 App 的新用户 + +206 +00:08:59,473 --> 00:09:01,441 +现在我来为大家讲解 + +207 +00:09:01,441 --> 00:09:04,344 +StoreKit 模型中的新增属性 + +208 +00:09:04,344 --> 00:09:07,414 +首先是价格区域设置 + +209 +00:09:07,414 --> 00:09:10,684 +价格区域设置 +如今包含在 StoreKit 产品中 + +210 +00:09:10,684 --> 00:09:12,586 +您在使用原先购买的 API 时 + +211 +00:09:12,586 --> 00:09:16,423 +可能对此已有所了解 + +212 +00:09:16,423 --> 00:09:19,593 +接下来 我将深入 +介绍服务器的环境属性 + +213 +00:09:19,593 --> 00:09:21,662 +现在 您可以知道交易或续订 + +214 +00:09:21,662 --> 00:09:25,132 +发生时处于的服务器环境 + +215 +00:09:25,132 --> 00:09:27,334 +然后 我会谈谈 + +216 +00:09:27,334 --> 00:09:28,902 +最近订阅开始日期属性 + +217 +00:09:28,902 --> 00:09:31,471 +它能帮助您根据用户的订阅模式 + +218 +00:09:31,471 --> 00:09:35,242 +明智地决定如何为其提供服务 + +219 +00:09:35,242 --> 00:09:37,845 +最后 我将介绍利用上述属性 + +220 +00:09:37,845 --> 00:09:39,546 +在 Xcode 中使用 +StoreKit Testing 时的 + +221 +00:09:39,546 --> 00:09:41,882 +特别注意事项 + +222 +00:09:41,882 --> 00:09:43,650 +上述属性在较旧的操作系统中 + +223 +00:09:43,650 --> 00:09:46,520 +会返回标记值 对此我来 + +224 +00:09:46,520 --> 00:09:48,522 +稍作一点解释 + +225 +00:09:48,522 --> 00:09:51,692 +StoreKit API +的设计考虑了灵活性 + +226 +00:09:51,692 --> 00:09:53,026 +所以我可以很自豪地说 + +227 +00:09:53,026 --> 00:09:55,295 +以上新属性就算是在去年 + +228 +00:09:55,295 --> 00:09:58,432 +未曾配备类似属性的操作系统上 + +229 +00:09:58,432 --> 00:10:01,902 +也可以使用 + +230 +00:10:01,902 --> 00:10:04,304 +要做到这一点 您只需要使用 + +231 +00:10:04,304 --> 00:10:07,074 +Xcode 14 来构建 +您的 App 您可在 + +232 +00:10:07,074 --> 00:10:10,177 +先前的操作系统中 +获取上述新增属性 + +233 +00:10:10,177 --> 00:10:12,179 +之所以能如此 是因为 + +234 +00:10:12,179 --> 00:10:14,515 +上述新增属性 +被编译到您的 App 中 + +235 +00:10:14,515 --> 00:10:16,984 +因此 用户在更新版本后 + +236 +00:10:16,984 --> 00:10:19,186 +就能够使用这些增强功能 + +237 +00:10:19,186 --> 00:10:21,955 +无需更新其操作系统 + +238 +00:10:21,955 --> 00:10:23,790 +但是 在使用新增属性时 + +239 +00:10:23,790 --> 00:10:26,360 +要牢记一件事 + +240 +00:10:26,360 --> 00:10:28,328 +当您在旧版操作系统中的 + +241 +00:10:28,328 --> 00:10:30,397 +Xcode 中使用 +StoreKit 测试时 + +242 +00:10:30,397 --> 00:10:32,533 +新增属性会返回标记值 + +243 +00:10:32,533 --> 00:10:33,967 +这里说的标记值 + +244 +00:10:33,967 --> 00:10:36,069 +指的是占位符值 + +245 +00:10:36,069 --> 00:10:38,539 +不是您使用的实际值 + +246 +00:10:38,539 --> 00:10:41,308 +我来解释一下原因 + +247 +00:10:41,308 --> 00:10:43,544 +沙盒和生产环境 + +248 +00:10:43,544 --> 00:10:45,812 +通过提取 App Store +服务器响应的值 + +249 +00:10:45,812 --> 00:10:48,081 +来利用这些属性 + +250 +00:10:48,081 --> 00:10:50,083 +不过 Xcode 中的 +StoreKit 测试 + +251 +00:10:50,083 --> 00:10:52,786 +是独立于 App Store 服务器 + +252 +00:10:52,786 --> 00:10:54,821 +运行的本地测试环境 + +253 +00:10:54,821 --> 00:10:57,157 +这意味着我们无法将这些属性的值 + +254 +00:10:57,157 --> 00:11:00,527 +回传到先前的操作系统中 + +255 +00:11:00,527 --> 00:11:02,396 +您可将测试设备 +更新到新的操作系统中 + +256 +00:11:02,396 --> 00:11:05,232 +从而轻松绕过此限制 + +257 +00:11:05,232 --> 00:11:07,100 +随后即可在本地环境中 + +258 +00:11:07,100 --> 00:11:08,735 +测试上述值 + +259 +00:11:08,735 --> 00:11:10,971 +我们来讨论一下几种 + +260 +00:11:10,971 --> 00:11:13,340 +利用新增属性的情况 + +261 +00:11:13,340 --> 00:11:15,776 +首先是价格区域设置 + +262 +00:11:15,776 --> 00:11:18,478 +StoreKit 产品已经 +具备了显示价格属性 + +263 +00:11:18,478 --> 00:11:21,281 +用以标记购买价格 +但利用价格区域设置 + +264 +00:11:21,281 --> 00:11:22,716 +您可将产品十进制价格中得出的 + +265 +00:11:22,716 --> 00:11:25,986 +数字格式化 + +266 +00:11:25,986 --> 00:11:27,721 +如果您有年度订阅功能 + +267 +00:11:27,721 --> 00:11:29,756 +即可以此为契机 + +268 +00:11:29,756 --> 00:11:32,726 +向用户展示每月的费用 + +269 +00:11:32,726 --> 00:11:35,329 +在此示例中 +您可以看到年度订阅服务 + +270 +00:11:35,329 --> 00:11:38,599 +每月费用为 4.17 美元 + +271 +00:11:38,599 --> 00:11:40,200 +或者您想向用户展示 + +272 +00:11:40,200 --> 00:11:42,469 +订阅您的年度服务比订阅月度服务 + +273 +00:11:42,469 --> 00:11:44,404 +节省了多少开支 + +274 +00:11:44,404 --> 00:11:46,607 +利用以上信息 您的用户可以 + +275 +00:11:46,607 --> 00:11:48,475 +在考虑您的购买选项时 + +276 +00:11:48,475 --> 00:11:51,144 +做出明智的决定 + +277 +00:11:51,144 --> 00:11:54,014 +我们继续来讨论环境属性 + +278 +00:11:54,014 --> 00:11:55,516 +环境属性可以 + +279 +00:11:55,516 --> 00:11:57,918 +在交易和续订信息中找到 + +280 +00:11:57,918 --> 00:11:59,920 +该属性能让您了解交易或续订信息 + +281 +00:11:59,920 --> 00:12:02,990 +源于哪个服务器环境 + +282 +00:12:02,990 --> 00:12:06,093 +例如 Xcode、沙盒或生产环境 + +283 +00:12:06,093 --> 00:12:07,327 +您的 App 会在用户购买后 + +284 +00:12:07,327 --> 00:12:09,730 +将交易信息发送到您的服务器 + +285 +00:12:09,730 --> 00:12:13,133 +以便记账和分析 + +286 +00:12:13,133 --> 00:12:15,302 +当您的 App 生成交易时 + +287 +00:12:15,302 --> 00:12:18,172 +交易可能来自任何服务器环境 + +288 +00:12:18,172 --> 00:12:19,673 +和您一样 我也不想让 + +289 +00:12:19,673 --> 00:12:22,843 +不相关的测试数据干扰分析 + +290 +00:12:22,843 --> 00:12:25,045 +因此 了解环境可帮助您 + +291 +00:12:25,045 --> 00:12:27,614 +过滤掉发送至服务器的 + +292 +00:12:27,614 --> 00:12:29,149 +不必要的信息 + +293 +00:12:29,149 --> 00:12:30,350 +最后 我们来看看 + +294 +00:12:30,350 --> 00:12:32,786 +最近订阅开始日期 + +295 +00:12:32,786 --> 00:12:34,955 +最近订阅开始日期可在 + +296 +00:12:34,955 --> 00:12:37,624 +产品订阅信息中查看 + +297 +00:12:37,624 --> 00:12:39,326 +指的是连续订阅 + +298 +00:12:39,326 --> 00:12:41,595 +最近开始的日期 + +299 +00:12:41,595 --> 00:12:44,231 +如果任何两个订阅期 +之间没有超过 60 天 + +300 +00:12:44,231 --> 00:12:48,235 +则视为连续订阅 + +301 +00:12:48,235 --> 00:12:50,270 +请记住 该期间可能包含 + +302 +00:12:50,270 --> 00:12:53,240 +用户未订阅您产品的时间 + +303 +00:12:53,240 --> 00:12:54,875 +因此不可将其作为 + +304 +00:12:54,875 --> 00:12:59,213 +用户已订阅天数的指标 + +305 +00:12:59,213 --> 00:13:01,515 +最近订阅开始日期可帮助您 + +306 +00:13:01,515 --> 00:13:05,485 +确定您和用户之间的粘度 + +307 +00:13:05,485 --> 00:13:07,955 +对于忠实用户 您可为其提供奖励 + +308 +00:13:07,955 --> 00:13:10,891 +鼓励其继续使用您的产品 + +309 +00:13:10,891 --> 00:13:12,292 +或者 若您注意到用户 + +310 +00:13:12,292 --> 00:13:14,194 +已取消订阅您的服务 + +311 +00:13:14,194 --> 00:13:16,997 +您可以借此机会 +激励用户再次使用您的产品 + +312 +00:13:16,997 --> 00:13:21,635 +赢回流失的顾客 + +313 +00:13:21,635 --> 00:13:23,704 +之前我提到过 我们要仔细查看 + +314 +00:13:23,704 --> 00:13:26,573 +新增属性的标记值 + +315 +00:13:26,573 --> 00:13:28,842 +请注意 这里说的标记值 + +316 +00:13:28,842 --> 00:13:30,511 +指的是占位符值 + +317 +00:13:30,511 --> 00:13:34,781 +用于指示缺失的实际值 + +318 +00:13:34,781 --> 00:13:38,252 +新增属性的标记值很容易识别 + +319 +00:13:38,252 --> 00:13:39,987 +当您处理价格区域设置时 + +320 +00:13:39,987 --> 00:13:45,526 +标记值是带有 +标识符 xx_XX 的区域设置 + +321 +00:13:45,526 --> 00:13:49,062 +对环境属性而言 +标记值是一个空字符串 + +322 +00:13:49,062 --> 00:13:51,698 +最后 就最近订阅开始日期而言 + +323 +00:13:51,698 --> 00:13:54,301 +此值为 Date.distantPast + +324 +00:13:54,301 --> 00:13:56,503 +所幸 标记值的出现 + +325 +00:13:56,503 --> 00:13:58,739 +是可预测的—— +您只会在较老的操作系统中的 + +326 +00:13:58,739 --> 00:14:00,707 +Xcode 中使用 StoreKit 测试时 + +327 +00:14:00,707 --> 00:14:02,442 +遇到该值 + +328 +00:14:02,442 --> 00:14:05,879 +您可通过更新测试设备解决该问题 + +329 +00:14:05,879 --> 00:14:07,514 +现在您已经了解了 +我们在 StoreKit 模型中 + +330 +00:14:07,514 --> 00:14:09,650 +添加的增强功能 + +331 +00:14:09,650 --> 00:14:11,685 +我最喜欢一点是 新增属性 + +332 +00:14:11,685 --> 00:14:13,720 +可以一直向后兼容到 + +333 +00:14:13,720 --> 00:14:15,822 +推出该模型的操作系统 + +334 +00:14:15,822 --> 00:14:17,824 +这样您的用户只需更新 App + +335 +00:14:17,824 --> 00:14:19,560 +就可立即使用新增属性 + +336 +00:14:19,560 --> 00:14:22,196 +当您对价格值执行算法时 + +337 +00:14:22,196 --> 00:14:24,431 +价格区域设置可帮助您正确格式化 + +338 +00:14:24,431 --> 00:14:26,800 +使其与 App Store 的 +区域设置相匹配 + +339 +00:14:26,800 --> 00:14:29,269 +对于交易和订阅信息 + +340 +00:14:29,269 --> 00:14:30,504 +环境会准确告知您 + +341 +00:14:30,504 --> 00:14:32,272 +具体来源 + +342 +00:14:32,272 --> 00:14:33,974 +因此若您将 +这些数据存储在服务器上 + +343 +00:14:33,974 --> 00:14:37,377 +您就可以根据环境 +对其采取相应措施 + +344 +00:14:37,377 --> 00:14:40,013 +最近订阅开始日期可助您了解 + +345 +00:14:40,013 --> 00:14:42,482 +用户忠诚度 因此您可为长期用户 + +346 +00:14:42,482 --> 00:14:45,085 +定制具体优惠 或者您可以 + +347 +00:14:45,085 --> 00:14:49,423 +为已退订的用户提供激励 + +348 +00:14:49,423 --> 00:14:52,693 +若您想知道环境 + +349 +00:14:52,693 --> 00:14:55,529 +以及最近订阅开始日期 + +350 +00:14:55,529 --> 00:14:59,032 +可在 App Store Server API 和 +App Store Server Notifications 中查看 + +351 +00:14:59,032 --> 00:15:01,101 +这是 Ian 之后要讨论的内容 + +352 +00:15:01,101 --> 00:15:04,471 +现在我来介绍一下 +我们为兑换优惠代码和请求评价 + +353 +00:15:04,471 --> 00:15:08,108 +提供的全新 SwiftUI API + +354 +00:15:08,108 --> 00:15:11,245 +优惠代码可帮助您 + +355 +00:15:11,245 --> 00:15:14,081 +通过提供折扣或限时免费订阅 + +356 +00:15:14,081 --> 00:15:16,984 +获取、巩固并赢回订阅者 + +357 +00:15:16,984 --> 00:15:19,453 +在 App Store Connect 中 +您可以创建唯一命名的 + +358 +00:15:19,453 --> 00:15:20,821 +自定义代码 + +359 +00:15:20,821 --> 00:15:23,490 +然后您可设置最大赎回限额 + +360 +00:15:23,490 --> 00:15:26,527 +选择是否设置截止时间 + +361 +00:15:26,527 --> 00:15:28,996 +我们来看 SwiftUI 在 + +362 +00:15:28,996 --> 00:15:32,366 +您的 App 中呈现 +优惠代码兑换表的方式 + +363 +00:15:32,366 --> 00:15:34,034 +这是一个 SwiftUI 视图 + +364 +00:15:34,034 --> 00:15:36,837 +带有可触发优惠代码兑换表的按钮 + +365 +00:15:36,837 --> 00:15:38,672 +优惠代码兑换表 + +366 +00:15:38,672 --> 00:15:42,843 +在 SwiftUI 中 +有自己的视图修饰符 + +367 +00:15:42,843 --> 00:15:44,645 +视图修饰符使用简单 + +368 +00:15:44,645 --> 00:15:47,915 +只需绑定布尔值便可启动程序 + +369 +00:15:47,915 --> 00:15:49,883 +一旦解除优惠代码表 + +370 +00:15:49,883 --> 00:15:51,051 +您就会得到显示 + +371 +00:15:51,051 --> 00:15:54,955 +该表是否成功呈现的结果 + +372 +00:15:54,955 --> 00:15:57,558 +当用户为您的 App +兑换优惠代码时 + +373 +00:15:57,558 --> 00:15:58,592 +最终交易结果 + +374 +00:15:58,592 --> 00:16:02,062 +就被发送到事务监听器 + +375 +00:16:02,062 --> 00:16:04,231 +因此 一定要在您的 App 启动后 + +376 +00:16:04,231 --> 00:16:06,233 +设置一个事务监听器 使其在 + +377 +00:16:06,233 --> 00:16:09,970 +App 运行时接收和更新事务 + +378 +00:16:09,970 --> 00:16:14,842 +优惠代码视图修饰符 +将从 iOS 16 起 + +379 +00:16:14,842 --> 00:16:18,478 +接下来 我来介绍一下 +对请求评价的更新 + +380 +00:16:18,478 --> 00:16:21,281 +获取用户反馈尤为重要 + +381 +00:16:21,281 --> 00:16:23,550 +评价可能是潜在新用户 + +382 +00:16:23,550 --> 00:16:27,154 +下载 App 的决定性因素 + +383 +00:16:27,154 --> 00:16:29,356 +其他用户或许也想通过评价来提供 + +384 +00:16:29,356 --> 00:16:32,159 +反馈或建议 + +385 +00:16:32,159 --> 00:16:34,761 +无论哪种情况 +我们都希望为您提供有利工具 + +386 +00:16:34,761 --> 00:16:37,297 +便于您向用户请求评分 + +387 +00:16:37,297 --> 00:16:39,066 +让用户知道您在倾听他们的意见 + +388 +00:16:39,066 --> 00:16:41,468 +方便您继续与其互动 + +389 +00:16:41,468 --> 00:16:44,071 +我们再来看一下代码 + +390 +00:16:44,071 --> 00:16:45,272 +这个简单的视图 + +391 +00:16:45,272 --> 00:16:48,275 +演示了请求评价的 API + +392 +00:16:48,275 --> 00:16:50,744 +在 SwiftUI 中 有一个环境值 + +393 +00:16:50,744 --> 00:16:52,513 +名为 requestReview + +394 +00:16:52,513 --> 00:16:54,314 +您可使用此值来获取 + +395 +00:16:54,314 --> 00:16:56,550 +RequestReviewAction 的实例 + +396 +00:16:56,550 --> 00:16:58,418 +当您准备好请求评分时 + +397 +00:16:58,418 --> 00:17:00,420 +只需将实例作为函数调用 + +398 +00:17:00,420 --> 00:17:03,524 +请求显示评价提示 + +399 +00:17:03,524 --> 00:17:05,192 +您可选择恰当时机请求用户 + +400 +00:17:05,192 --> 00:17:06,827 +对您的 App 进行评价 + +401 +00:17:06,827 --> 00:17:09,429 +不过 您需了解 该提示 + +402 +00:17:09,429 --> 00:17:12,032 +在 365 天内最多只会 + +403 +00:17:12,032 --> 00:17:14,902 +向用户展示 3 次 + +404 +00:17:14,902 --> 00:17:16,503 +您也不应请求用户 + +405 +00:17:16,503 --> 00:17:19,740 +对同一版本的 App +进行多次评价 + +406 +00:17:19,740 --> 00:17:22,543 +避免评价提示打扰用户 + +407 +00:17:22,543 --> 00:17:24,811 +请求评价的良好时机应在用户 + +408 +00:17:24,811 --> 00:17:27,814 +进行良性互动之后 +例如在电子商务 App 上 + +409 +00:17:27,814 --> 00:17:31,118 +完成购买 或在游戏中完成关卡 + +410 +00:17:31,118 --> 00:17:33,854 +最后 用户可禁止在其设备上 + +411 +00:17:33,854 --> 00:17:35,923 +发送请求 因此您不应 + +412 +00:17:35,923 --> 00:17:39,927 +再次向用户发送评价请求 + +413 +00:17:39,927 --> 00:17:42,196 +以上 API 一定会 +让您的 SwiftUI App + +414 +00:17:42,196 --> 00:17:43,664 +使用便捷 + +415 +00:17:43,664 --> 00:17:45,566 +接下来 我为大家介绍一下 + +416 +00:17:45,566 --> 00:17:48,468 +适用 StoreKit 消息的新 API + +417 +00:17:48,468 --> 00:17:51,071 +StoreKit 消息是在您的 App 上 + +418 +00:17:51,071 --> 00:17:54,808 +显示的一张表格 +用于向用户展示重要信息 + +419 +00:17:54,808 --> 00:17:57,244 +信息由 App Store 出售 + +420 +00:17:57,244 --> 00:17:58,745 +每一条消息的出现都有原因 + +421 +00:17:58,745 --> 00:18:01,882 +包含在消息元数据中 + +422 +00:18:01,882 --> 00:18:03,717 +当您的 App 在前台运行时 + +423 +00:18:03,717 --> 00:18:05,586 +就能检索到 StoreKit 消息 + +424 +00:18:05,586 --> 00:18:07,321 +举个例子 我们看一下 + +425 +00:18:07,321 --> 00:18:10,858 +其中一条消息原因——同意涨价 + +426 +00:18:10,858 --> 00:18:13,227 +当您提高订阅价格时 + +427 +00:18:13,227 --> 00:18:15,963 +需要经过用户同意 +App Store 就会通过 + +428 +00:18:15,963 --> 00:18:19,833 +电子邮件、推送通知 +和 App 内价格同意书的方式 + +429 +00:18:19,833 --> 00:18:21,869 +通知受影响的订阅者 + +430 +00:18:21,869 --> 00:18:23,971 +在此情况下 App Store 需要用户 + +431 +00:18:23,971 --> 00:18:25,906 +在以更高的价格续订之前 + +432 +00:18:25,906 --> 00:18:28,442 +同意您新制定的价格 + +433 +00:18:28,442 --> 00:18:30,978 +因此 如果您决定 +向用户收取更多订阅费用 + +434 +00:18:30,978 --> 00:18:32,980 +且若用户尚未回应涨价 + +435 +00:18:32,980 --> 00:18:36,316 +那么当其打开您的 App 时 + +436 +00:18:36,316 --> 00:18:38,285 +就会出现涨价同意书 + +437 +00:18:38,285 --> 00:18:40,654 +默认情况下 StoreKit 消息 + +438 +00:18:40,654 --> 00:18:42,990 +会在用户前台运行 +您的 App 时显示 + +439 +00:18:42,990 --> 00:18:44,892 +要求用户就您的 App + +440 +00:18:44,892 --> 00:18:46,693 +进行某些操作 + +441 +00:18:46,693 --> 00:18:48,495 +我们来回顾一下 + +442 +00:18:48,495 --> 00:18:51,298 +以您的 App 为起点 + +443 +00:18:51,298 --> 00:18:53,467 +当您的 App 进入前台时 + +444 +00:18:53,467 --> 00:18:54,635 +StoreKit 会检查 + +445 +00:18:54,635 --> 00:18:56,904 +有无待显示的消息 + +446 +00:18:56,904 --> 00:19:00,007 +如果有 StoreKit 会在 +App Store 中记录 + +447 +00:19:00,007 --> 00:19:01,909 +App Store 会将相关信息 + +448 +00:19:01,909 --> 00:19:03,677 +返回到 StoreKit + +449 +00:19:03,677 --> 00:19:05,579 +这时 StoreKit +会检查您的 App 是否 + +450 +00:19:05,579 --> 00:19:07,614 +设置为接收消息 + +451 +00:19:07,614 --> 00:19:10,651 +您可通过在 App 上 +设置消息监听器来实现 + +452 +00:19:10,651 --> 00:19:12,486 +这一点我很快就会讲到 + +453 +00:19:12,486 --> 00:19:14,721 +如果您的 App +设置了消息监听器 + +454 +00:19:14,721 --> 00:19:17,925 +StoreKit 会将 +有关信息发送到您的 App + +455 +00:19:17,925 --> 00:19:20,761 +然后由您决定是否 + +456 +00:19:20,761 --> 00:19:22,796 +让您的 App 显示消息 + +457 +00:19:22,796 --> 00:19:25,499 +或者推迟显示 + +458 +00:19:25,499 --> 00:19:28,135 +若您未设置消息监听器 + +459 +00:19:28,135 --> 00:19:29,837 +StoreKit 通过在您的 App 上 + +460 +00:19:29,837 --> 00:19:32,339 +显示消息表来立即显示消息 + +461 +00:19:32,339 --> 00:19:34,408 +我来介绍如何在代码中执行此操作 + +462 +00:19:34,408 --> 00:19:36,410 +但在这之前 我先解释一种情况 + +463 +00:19:36,410 --> 00:19:38,779 +在这种情况下 +控制 App Store 消息的呈现 + +464 +00:19:38,779 --> 00:19:41,148 +非常有用 + +465 +00:19:41,148 --> 00:19:43,450 +在 Food Truck 这款 App 中 +我可以自定义 + +466 +00:19:43,450 --> 00:19:45,485 +送往不同城市的甜甜圈 + +467 +00:19:45,485 --> 00:19:48,088 +在此期间 +若有消息发送到我的 App 上 + +468 +00:19:48,088 --> 00:19:50,290 +那么消息表的突然出现 会扰乱用户 + +469 +00:19:50,290 --> 00:19:53,460 +所以我要利用消息 API + +470 +00:19:53,460 --> 00:19:56,129 +控制消息出现的时间 + +471 +00:19:56,129 --> 00:19:59,333 +来避免此类情况 + +472 +00:19:59,333 --> 00:20:01,535 +现在来看代码 + +473 +00:20:01,535 --> 00:20:04,304 +这是一个甜甜圈编辑器的简单视图 + +474 +00:20:04,304 --> 00:20:06,607 +之前提到过 待处理消息 + +475 +00:20:06,607 --> 00:20:09,142 +会在您每次 +前台运行 App 时发送 + +476 +00:20:09,142 --> 00:20:12,012 +所以 我想在 +每个视图中设置一个消息监听器 + +477 +00:20:12,012 --> 00:20:15,782 +来推迟消息的呈现 + +478 +00:20:15,782 --> 00:20:17,985 +在位于编辑视图时 +我将添加一个绑定数组来收集 + +479 +00:20:17,985 --> 00:20:20,921 +传送至我 App 的所有消息 + +480 +00:20:20,921 --> 00:20:24,091 +这个步骤很重要 +因为若不设置消息监听器 + +481 +00:20:24,091 --> 00:20:26,760 +StoreKit 将在 +我前台运行 App 时 + +482 +00:20:26,760 --> 00:20:28,962 +立即显示消息表 + +483 +00:20:28,962 --> 00:20:32,533 +视图一出现 我就设置了消息监听器 + +484 +00:20:32,533 --> 00:20:34,668 +为此 我将设置一个任务 + +485 +00:20:34,668 --> 00:20:37,504 +该任务会在 +消息类型上迭代一个静态属性 + +486 +00:20:37,504 --> 00:20:39,540 +该属性是一个异步序列 + +487 +00:20:39,540 --> 00:20:42,676 +而且我可以在消息进来时立刻接收 + +488 +00:20:42,676 --> 00:20:44,444 +就我的用途而言 我将在待处理的 + +489 +00:20:44,444 --> 00:20:46,747 +消息数组中保存消息 + +490 +00:20:46,747 --> 00:20:48,649 +由于每次在前台运行 App 时 + +491 +00:20:48,649 --> 00:20:50,751 +都会发送待处理消息 您的 App + +492 +00:20:50,751 --> 00:20:53,487 +会多次接收同一条消息 因此我可以 + +493 +00:20:53,487 --> 00:20:56,757 +避免将重复的消息添加到数组中 + +494 +00:20:56,757 --> 00:20:58,759 +然后 一旦该视图消失 + +495 +00:20:58,759 --> 00:21:01,762 +父视图中就可显示消息 + +496 +00:21:01,762 --> 00:21:03,730 +这是包含甜甜圈编辑器链接的 + +497 +00:21:03,730 --> 00:21:05,499 +父视图 + +498 +00:21:05,499 --> 00:21:07,434 +在这里 我收集了 +需要在待处理消息数组中 + +499 +00:21:07,434 --> 00:21:10,671 +显示的所有待处理消息 + +500 +00:21:10,671 --> 00:21:13,507 +那么 如何显示以上待处理消息呢? + +501 +00:21:13,507 --> 00:21:15,175 +现在有一个 +displayStoreKitMessage + +502 +00:21:15,175 --> 00:21:17,244 +环境值 + +503 +00:21:17,244 --> 00:21:19,880 +该值为您提供 +DisplayMessageAction 的实例 + +504 +00:21:19,880 --> 00:21:23,383 +您可以利用其显示特定消息 + +505 +00:21:23,383 --> 00:21:24,418 +视图出现时 + +506 +00:21:24,418 --> 00:21:25,986 +我将循环访问待处理消息 + +507 +00:21:25,986 --> 00:21:27,855 +并调用 displayStoreKitMessage + +508 +00:21:27,855 --> 00:21:30,390 +传递我要显示的消息 + +509 +00:21:30,390 --> 00:21:34,695 +StoreKit 负责呈现消息表 + +510 +00:21:34,695 --> 00:21:36,196 +之前 我提到过相同的消息 + +511 +00:21:36,196 --> 00:21:38,799 +可能会多次传送到您的 App + +512 +00:21:38,799 --> 00:21:40,868 +那是因为消息在呈现给用户后 + +513 +00:21:40,868 --> 00:21:42,936 +才被标记为已读 + +514 +00:21:42,936 --> 00:21:45,639 +因此 StoreKit 会确保 +每条不同的消息 + +515 +00:21:45,639 --> 00:21:48,442 +只呈现一次 + +516 +00:21:48,442 --> 00:21:50,477 +这一点是 Messages API 的 + +517 +00:21:50,477 --> 00:21:52,613 +快速实现 + +518 +00:21:52,613 --> 00:21:55,849 +再次提醒 StoreKit 消息 +会在您前台运行 App 时 + +519 +00:21:55,849 --> 00:21:58,352 +发送给您 所以您需要 + +520 +00:21:58,352 --> 00:22:01,188 +给每一个视图设置 +消息侦听器 以便控制 + +521 +00:22:01,188 --> 00:22:04,258 +消息显示的时间 + +522 +00:22:04,258 --> 00:22:07,294 +您可确保消息在恰当的时机出现 + +523 +00:22:07,294 --> 00:22:10,797 +保证用户的良好体验 + +524 +00:22:10,797 --> 00:22:12,566 +或者您也可以为某些消息类型 + +525 +00:22:12,566 --> 00:22:14,368 +自定义逻辑 + +526 +00:22:14,368 --> 00:22:16,370 +在向用户发送涨价同意书前 + +527 +00:22:16,370 --> 00:22:17,804 +您可能想利用涨价同意信息 + +528 +00:22:17,804 --> 00:22:19,673 +告知用户 + +529 +00:22:19,673 --> 00:22:23,076 +您提供的附加价值 + +530 +00:22:23,076 --> 00:22:25,712 +最后 我们来看一下用户购买后 + +531 +00:22:25,712 --> 00:22:28,282 +StoreKit 将 +applicationUsername 保存为 + +532 +00:22:28,282 --> 00:22:31,185 +appAccountToken 的方式 + +533 +00:22:31,185 --> 00:22:34,087 +如果您的服务器上有用户帐户系统 + +534 +00:22:34,087 --> 00:22:35,889 +您可能已经在使用 + +535 +00:22:35,889 --> 00:22:38,425 +applicationUsername 属性了 + +536 +00:22:38,425 --> 00:22:41,361 +applicationUsername +是您创建的字符串 + +537 +00:22:41,361 --> 00:22:45,832 +用于将交易与您服务中的 +用户帐户相关联 + +538 +00:22:45,832 --> 00:22:48,235 +在 App 内购买的原始 API 中 + +539 +00:22:48,235 --> 00:22:50,938 +您在向支付队列添加付款时 + +540 +00:22:50,938 --> 00:22:53,340 +会设置 applicationUsername 值 + +541 +00:22:53,340 --> 00:22:56,810 +尽管 applicationUsername +接受任何字符串 + +542 +00:22:56,810 --> 00:22:59,213 +但我们建议您提供 + +543 +00:22:59,213 --> 00:23:01,815 +UUID 的字符串表现形式 + +544 +00:23:01,815 --> 00:23:04,184 +在提供 UUID 字符串后 + +545 +00:23:04,184 --> 00:23:06,086 +StoreKit 会保留该值 您会在 + +546 +00:23:06,086 --> 00:23:08,522 +队列更新的交易中看到它 + +547 +00:23:08,522 --> 00:23:10,457 +如果您未向 applicationUsername + +548 +00:23:10,457 --> 00:23:13,794 +提供 UUID 字符串 +StoreKit 可能不会保留该值 + +549 +00:23:13,794 --> 00:23:15,896 +无法保证在您将支付交易添加到 + +550 +00:23:15,896 --> 00:23:18,699 +队列和队列更新交易之间 + +551 +00:23:18,699 --> 00:23:21,935 +该值将保持不变 + +552 +00:23:21,935 --> 00:23:25,072 +您提供 UUID 字符串表现形式后 + +553 +00:23:25,072 --> 00:23:27,307 +就能识别哪些用户帐户 + +554 +00:23:27,307 --> 00:23:30,410 +开始并完成了一笔交易 + +555 +00:23:30,410 --> 00:23:33,313 +在现代 StoreKit API 中 +我们将此概念实现为 + +556 +00:23:33,313 --> 00:23:35,883 +appAccountToken 的购买选项 + +557 +00:23:35,883 --> 00:23:39,386 +并需要 UUID 格式 + +558 +00:23:39,386 --> 00:23:41,622 +现在 当您在付款期间将 +applicationUsername + +559 +00:23:41,622 --> 00:23:44,525 +设置为 UUID 字符串时 + +560 +00:23:44,525 --> 00:23:47,761 +App Store 服务器就会将其 +存储为 appAccountToken + +561 +00:23:47,761 --> 00:23:51,031 +所以您会看到其 UUID 出现在 + +562 +00:23:51,031 --> 00:23:53,267 +App Store Server API +返回的签名交易信息 + +563 +00:23:53,267 --> 00:23:57,337 +和 V2 App Store +Server Notifications 中 + +564 +00:23:57,337 --> 00:24:00,541 +并且其作为 UUID +在现代 StoreKit 交易 API 中 + +565 +00:24:00,541 --> 00:24:03,911 +可与 appAccountToken 兼容 + +566 +00:24:03,911 --> 00:24:06,446 +因此 您可确定在将代码库 + +567 +00:24:06,446 --> 00:24:08,248 +更新到现代 StoreKit API 时 + +568 +00:24:08,248 --> 00:24:11,084 +您用于 +applicationUsername 的 UUID + +569 +00:24:11,084 --> 00:24:12,986 +在 StoreKit 交易中 + +570 +00:24:12,986 --> 00:24:15,789 +保存为 appAccountToken + +571 +00:24:15,789 --> 00:24:18,125 +我们今天接触了很多概念 + +572 +00:24:18,125 --> 00:24:20,427 +在讲解服务器更新之前 + +573 +00:24:20,427 --> 00:24:24,264 +我们先来回顾一下 +今年 StoreKit 的更新内容 + +574 +00:24:24,264 --> 00:24:26,400 +我们讨论了用 App Transaction + +575 +00:24:26,400 --> 00:24:28,035 +验证您的 App 购买 + +576 +00:24:28,035 --> 00:24:31,605 +在 SwiftUI 中 +兑换优惠代码并请求评价 + +577 +00:24:31,605 --> 00:24:35,409 +以及控制 StoreKit 的消息呈现 + +578 +00:24:35,409 --> 00:24:38,579 +我们谈到价格区域设置、环境 + +579 +00:24:38,579 --> 00:24:41,715 +以及最近订阅开始日期等新增属性 + +580 +00:24:41,715 --> 00:24:43,784 +还讲述了将 applicationUsername + +581 +00:24:43,784 --> 00:24:48,088 +设置为 UUID 字符串以 + +582 +00:24:48,088 --> 00:24:50,924 +将其保留 +为 App 帐户令牌的重要性 + +583 +00:24:50,924 --> 00:24:53,660 +我强烈推荐您观看接下来的讲解 + +584 +00:24:53,660 --> 00:24:56,063 +“StoreKit 测试中的新功能” + +585 +00:24:56,063 --> 00:24:58,899 +如果您需要重新了解 +StoreKit 2 API + +586 +00:24:58,899 --> 00:25:01,935 +请查看去年的 +“Meet StoreKit 2”一期 + +587 +00:25:01,935 --> 00:25:03,637 +接下来就交给 Ian + +588 +00:25:03,637 --> 00:25:06,673 +由他为您介绍 +App Store 服务器的更新内容 + +589 +00:25:06,673 --> 00:25:07,975 +Ian Zanger :谢谢 Dani + +590 +00:25:07,975 --> 00:25:09,776 +大家好 我是 Ian + +591 +00:25:09,776 --> 00:25:12,913 +App Store Server +团队的工程师 + +592 +00:25:12,913 --> 00:25:14,181 +既然您已经了解了 + +593 +00:25:14,181 --> 00:25:16,416 +使用 StoreKit 进行 +App 内购买的最新消息 + +594 +00:25:16,416 --> 00:25:19,253 +那么我就换个角度来谈谈服务器 + +595 +00:25:19,253 --> 00:25:23,223 +首先 我来回顾一下 +过去一年的最新进展 + +596 +00:25:23,223 --> 00:25:25,559 +然后再介绍 +App Store Server API + +597 +00:25:25,559 --> 00:25:27,861 +和 App Store Server Notifications V2 的 + +598 +00:25:27,861 --> 00:25:32,299 +新增亮点 + +599 +00:25:32,299 --> 00:25:34,535 +我们开始吧 + +600 +00:25:34,535 --> 00:25:36,069 +去年收获颇丰 + +601 +00:25:36,069 --> 00:25:39,039 +我们为您带来了一整套 + +602 +00:25:39,039 --> 00:25:41,008 +搭载 App Store Server API + +603 +00:25:41,008 --> 00:25:44,344 +和 App Store Server Notifications V2 +的全新端点 + +604 +00:25:44,344 --> 00:25:46,580 +包括支持以上所有新功能的 + +605 +00:25:46,580 --> 00:25:48,815 +完整的沙盒测试 + +606 +00:25:48,815 --> 00:25:52,653 +我们分享了如何使用 +Get Transaction History 端点 + +607 +00:25:52,653 --> 00:25:55,889 +获取用户 App 内 +购买的完整历史记录 + +608 +00:25:55,889 --> 00:25:59,092 +或 Get All +Subscription Statuses 端点 + +609 +00:25:59,092 --> 00:26:01,061 +以便随时了解 + +610 +00:26:01,061 --> 00:26:03,497 +用户订阅状态 + +611 +00:26:03,497 --> 00:26:05,899 +上述两个端点都可便于切断 + +612 +00:26:05,899 --> 00:26:09,169 +用户的 originalTransactionId + +613 +00:26:09,169 --> 00:26:11,605 +这样您只需存储这一简单的值 + +614 +00:26:11,605 --> 00:26:14,808 +就可以访问数据宝库 + +615 +00:26:14,808 --> 00:26:16,777 +我们还涉猎到 + +616 +00:26:16,777 --> 00:26:19,012 +App Store Server Notifications V2 + +617 +00:26:19,012 --> 00:26:22,082 +简化服务器上​​的事件处理 + +618 +00:26:22,082 --> 00:26:25,385 +并补足 +App Store Server API 的方式 + +619 +00:26:25,385 --> 00:26:27,387 +利用版本 2 通知 + +620 +00:26:27,387 --> 00:26:30,524 +App Store 服务器 +会直接调用您的服务器 + +621 +00:26:30,524 --> 00:26:33,894 +在有新版本时 +通知您更新 App 内购买 + +622 +00:26:33,894 --> 00:26:37,264 +简化后的通知类型和子类型 + +623 +00:26:37,264 --> 00:26:40,267 +便于您理解具体情况 + +624 +00:26:40,267 --> 00:26:42,135 +您可借此跟踪 App 内订阅 + +625 +00:26:42,135 --> 00:26:45,939 +和其他事件相关的变动 + +626 +00:26:45,939 --> 00:26:47,574 +利用所有这些数据源 + +627 +00:26:47,574 --> 00:26:51,411 +我们想让数据尽可能便于解析 + +628 +00:26:51,411 --> 00:26:53,680 +收据现在已成为历史 + +629 +00:26:53,680 --> 00:26:56,583 +因为新增服务以签名的 JSON 格式 + +630 +00:26:56,583 --> 00:27:00,487 +提供 App 内数据 +您因此可以轻松解析 + +631 +00:27:00,487 --> 00:27:04,091 +并相信其来自 +App Store 服务器 + +632 +00:27:04,091 --> 00:27:07,628 +去年对于 App Store +服务器来说是重要的一年 + +633 +00:27:07,628 --> 00:27:10,063 +如果您致力于更新服务器代码 + +634 +00:27:10,063 --> 00:27:12,432 +以便使用所有新增功能 + +635 +00:27:12,432 --> 00:27:15,068 +那么这一年对您或许同样重要 + +636 +00:27:15,068 --> 00:27:18,238 +请放心 努力将继续得到回报 + +637 +00:27:18,238 --> 00:27:21,341 +因为我们为 +App Store Server API 和 + +638 +00:27:21,341 --> 00:27:27,181 +App Store Server Notifications V2 +带来了强大的增强功能特性 + +639 +00:27:27,181 --> 00:27:28,749 +这就是我们一年的历程 + +640 +00:27:28,749 --> 00:27:30,484 +如果您在听完今年的更新后 + +641 +00:27:30,484 --> 00:27:32,519 +想复习一下 + +642 +00:27:32,519 --> 00:27:36,990 +请务必查看 WWDC21 演讲 + +643 +00:27:36,990 --> 00:27:40,127 +“管理服务器上的 App 内购买”、 + +644 +00:27:40,127 --> 00:27:42,262 +“认识 StoreKit 2” + +645 +00:27:42,262 --> 00:27:45,832 +以及“支持顾客和处理退款” + +646 +00:27:45,832 --> 00:27:48,468 +现在我们继续讲解为 WWDC22 的 + +647 +00:27:48,468 --> 00:27:53,207 +App Store 服务器做的全新升级 + +648 +00:27:53,207 --> 00:27:56,143 +首先 我来分享一些关于交易 + +649 +00:27:56,143 --> 00:27:58,378 +和续订信息字段的更新 + +650 +00:27:58,378 --> 00:28:01,148 +接下来我为您讲述 +App Store Server API 中 + +651 +00:28:01,148 --> 00:28:03,917 +新的增强功能 + +652 +00:28:03,917 --> 00:28:06,587 +最后 我将分享即将用于 +App Store Server Notifications V2 + +653 +00:28:06,587 --> 00:28:11,191 +的亮点新功能 + +654 +00:28:11,191 --> 00:28:14,461 +现在我们来深入探讨第一个话题 + +655 +00:28:14,461 --> 00:28:18,498 +交易和续订信息中的新字段 + +656 +00:28:18,498 --> 00:28:21,735 +此前 您从 Dani 那里 +了解到 App 内购买中 + +657 +00:28:21,735 --> 00:28:24,137 +交易和续订信息的 + +658 +00:28:24,137 --> 00:28:26,039 +新字段 + +659 +00:28:26,039 --> 00:28:30,077 +上述字段 即环境和 +recentSubscriptionStartDate + +660 +00:28:30,077 --> 00:28:32,079 +也会出现在您从 +App Store Server API + +661 +00:28:32,079 --> 00:28:33,514 +和 V2 App Store Server Notifications 中 + +662 +00:28:33,514 --> 00:28:36,316 +收到的交易和续订信息的 + +663 +00:28:36,316 --> 00:28:40,687 +有效载荷中 + +664 +00:28:40,687 --> 00:28:44,391 +让我们重新审视一下 +您希望从包含以上新字段的 + +665 +00:28:44,391 --> 00:28:48,395 +App Store 服务器中收到的数据 + +666 +00:28:48,395 --> 00:28:50,931 +首先是交易信息有效载荷 + +667 +00:28:50,931 --> 00:28:53,734 +解码后我们可以在这里看到 + +668 +00:28:53,734 --> 00:28:57,804 +在底部 您可以看到 +我们的新字段:环境 + +669 +00:28:57,804 --> 00:28:59,773 +您可以清晰地知道 + +670 +00:28:59,773 --> 00:29:01,575 +交易是否发生 + +671 +00:29:01,575 --> 00:29:04,878 +在生产或沙盒环境中 + +672 +00:29:04,878 --> 00:29:07,247 +接下来是续订信息有效载荷 + +673 +00:29:07,247 --> 00:29:10,017 +解码后仍可在这里看到 + +674 +00:29:10,017 --> 00:29:13,620 +如您所见 环境字段也出现在这里 + +675 +00:29:13,620 --> 00:29:15,656 +以供您参考 + +676 +00:29:15,656 --> 00:29:18,192 +此外 recentSubscriptionStartDate + +677 +00:29:18,192 --> 00:29:21,428 +现在将出现在 +每个续订信息有效载荷中 + +678 +00:29:21,428 --> 00:29:23,797 +这是用户在最近的续订字段中 + +679 +00:29:23,797 --> 00:29:27,801 +首次订阅购买的开始日期 + +680 +00:29:27,801 --> 00:29:32,105 +它会忽略 60 天及以内的时间间隔 + +681 +00:29:32,105 --> 00:29:35,542 +recentSubscriptionStartDate 是了解 + +682 +00:29:35,542 --> 00:29:38,512 +用户忠诚度的简单方法 + +683 +00:29:38,512 --> 00:29:40,047 +但如果您想了解更多细节 + +684 +00:29:40,047 --> 00:29:43,750 +包括服务订阅间隙的时间和长度 + +685 +00:29:43,750 --> 00:29:47,020 +您可调用 +Get Transaction History 端点 + +686 +00:29:47,020 --> 00:29:48,622 +并检查用户 + +687 +00:29:48,622 --> 00:29:51,925 +续订购买的完整历史记录 + +688 +00:29:51,925 --> 00:29:54,094 +若想进一步了解细节 + +689 +00:29:54,094 --> 00:29:56,964 +使用 App Store Server Notifications V2 + +690 +00:29:56,964 --> 00:29:59,867 +App Store 服务器就会自动 + +691 +00:29:59,867 --> 00:30:03,070 +向您的服务器发送用户订阅更新 + +692 +00:30:03,070 --> 00:30:05,939 +这些通知可让您最大限度了解 + +693 +00:30:05,939 --> 00:30:09,710 +更新偏好变化、优惠代码兑换 + +694 +00:30:09,710 --> 00:30:14,548 +计费失败等事件的时间 + +695 +00:30:14,548 --> 00:30:17,351 +如您所见 +recentSubscriptionStartDate + +696 +00:30:17,351 --> 00:30:19,152 +为确定用户忠诚度 + +697 +00:30:19,152 --> 00:30:21,588 +完善了一系列选项 + +698 +00:30:21,588 --> 00:30:23,757 +利用这些工具可定制优惠 + +699 +00:30:23,757 --> 00:30:27,060 +奖励您最忠实的用户 + +700 +00:30:27,060 --> 00:30:30,497 +现在让我们来看 +Get Transaction History + +701 +00:30:30,497 --> 00:30:33,734 +端点中便利的增强功能 + +702 +00:30:33,734 --> 00:30:36,003 +利用 Get Transaction History 端点 + +703 +00:30:36,003 --> 00:30:39,206 +您可以在 App 上获取用户购买的 + +704 +00:30:39,206 --> 00:30:41,008 +完整历史记录 + +705 +00:30:41,008 --> 00:30:43,377 +端点响应是分页的 + +706 +00:30:43,377 --> 00:30:46,947 +因此您可在合理的 +区块中处理这些数据 + +707 +00:30:46,947 --> 00:30:49,983 +每个响应都包含一个 +修订令牌 您在下一个请求中 + +708 +00:30:49,983 --> 00:30:53,921 +提供该令牌即可获取下一页 + +709 +00:30:53,921 --> 00:30:56,623 +页面按修改日期排序 + +710 +00:30:56,623 --> 00:30:59,693 +这就意味着每个后续页面都包含 + +711 +00:30:59,693 --> 00:31:02,930 +最近修改的交易 + +712 +00:31:02,930 --> 00:31:05,299 +我们看看其工作模式 + +713 +00:31:05,299 --> 00:31:08,268 +您调用 +Get Transaction History 端点 + +714 +00:31:08,268 --> 00:31:12,105 +并提供 originalTransactionId + +715 +00:31:12,105 --> 00:31:16,410 +App Store 服务器 +将为该用户返回至多 + +716 +00:31:16,410 --> 00:31:18,045 +20 个签名交易 + +717 +00:31:18,045 --> 00:31:21,181 +还会返回一个更新的修订值 + +718 +00:31:21,181 --> 00:31:25,519 +您将在下一页请求中 +为该用户提供此值 + +719 +00:31:25,519 --> 00:31:27,688 +您会看到 +当响应中的 hasMore 字段 + +720 +00:31:27,688 --> 00:31:31,725 +为真时 还有更多可用数据 + +721 +00:31:31,725 --> 00:31:32,926 +假设在这种情况下 + +722 +00:31:32,926 --> 00:31:35,863 +还有另一页可用数据 + +723 +00:31:35,863 --> 00:31:37,998 +您向端点发出另一个请求 + +724 +00:31:37,998 --> 00:31:41,635 +其中包含了第一个响应中的修订值 + +725 +00:31:41,635 --> 00:31:43,537 +那您收到的下一页数据 + +726 +00:31:43,537 --> 00:31:46,406 +其中就包括更新的修订值 + +727 +00:31:46,406 --> 00:31:49,743 +hasMore 现在是错误的 +因此您就知道了 + +728 +00:31:49,743 --> 00:31:52,513 +最新的交易数据 + +729 +00:31:52,513 --> 00:31:54,181 +此外 您注意到 + +730 +00:31:54,181 --> 00:31:56,683 +响应中的最终交易 + +731 +00:31:56,683 --> 00:31:58,485 +好像之前见过 + +732 +00:31:58,485 --> 00:32:01,288 +这就是您在第一次请求时收到的 + +733 +00:32:01,288 --> 00:32:03,891 +20 个签名交易中的一个 + +734 +00:32:03,891 --> 00:32:06,593 +这意味着交易一定已被修改 + +735 +00:32:06,593 --> 00:32:10,497 +所以它被放回了排序首位 + +736 +00:32:10,497 --> 00:32:13,467 +现在您可以检查该交易的数据 + +737 +00:32:13,467 --> 00:32:15,702 +看看发生了什么变化 + +738 +00:32:15,702 --> 00:32:18,639 +这时 您会注意到 revocationDate + +739 +00:32:18,639 --> 00:32:21,808 +和 revocationReason 字段已被填充 + +740 +00:32:21,808 --> 00:32:24,211 +这意味着交易被撤销 + +741 +00:32:24,211 --> 00:32:26,847 +您可以撤消任何与购买相关的内容 + +742 +00:32:26,847 --> 00:32:29,616 +来采取行动 + +743 +00:32:29,616 --> 00:32:32,152 +最好的办法是将最终响应的修订值 + +744 +00:32:32,152 --> 00:32:34,521 +与您用于识别用户的 + +745 +00:32:34,521 --> 00:32:39,326 +originalTransactionId 一同存储 + +746 +00:32:39,326 --> 00:32:41,862 +这样下一次您为该用户调用端点时 + +747 +00:32:41,862 --> 00:32:44,064 +就可以提供该修订并了解 + +748 +00:32:44,064 --> 00:32:47,201 +只取回自您上次请求后被修改的 + +749 +00:32:47,201 --> 00:32:50,971 +新交易数据 + +750 +00:32:50,971 --> 00:32:54,074 +如您所见 +Get Transaction History 端点 + +751 +00:32:54,074 --> 00:32:57,811 +为您提供了一种检索 +一套全面 App 内购买数据的 + +752 +00:32:57,811 --> 00:33:00,013 +简单方法 + +753 +00:33:00,013 --> 00:33:03,851 +但有时它或许过于全面 + +754 +00:33:03,851 --> 00:33:06,286 +某些用户购买历史较长 + +755 +00:33:06,286 --> 00:33:09,056 +有好几年 + +756 +00:33:09,056 --> 00:33:12,092 +对于这些用户 此端点可能会返回 + +757 +00:33:12,092 --> 00:33:16,897 +数百种类型的购买数据 + +758 +00:33:16,897 --> 00:33:20,234 +即使有页面 处理起来也较繁琐 + +759 +00:33:20,234 --> 00:33:22,803 +这就是今年我们 +要用各种新的排序和过滤选项 + +760 +00:33:22,803 --> 00:33:27,307 +增强该端点的原因 + +761 +00:33:27,307 --> 00:33:31,111 +现在您可以告知我们 +您想要的确切初始数据 + +762 +00:33:31,111 --> 00:33:33,514 +节省服务器处理时间 + +763 +00:33:33,514 --> 00:33:35,449 +并减少所有可用页面 + +764 +00:33:35,449 --> 00:33:39,319 +所需的网络调用次数 + +765 +00:33:39,319 --> 00:33:41,889 +如果您想在第一页看到 + +766 +00:33:41,889 --> 00:33:43,891 +最近修改的购买数据 + +767 +00:33:43,891 --> 00:33:47,794 +可按修改日期降序排列 + +768 +00:33:47,794 --> 00:33:50,597 +您还可以按几个 +有用的字段进行过滤 + +769 +00:33:50,597 --> 00:33:54,201 +例如产品类型、产品 ID + +770 +00:33:54,201 --> 00:33:56,970 +家庭共享状态等 + +771 +00:33:56,970 --> 00:33:59,706 +要应用上述排序和过滤选项 + +772 +00:33:59,706 --> 00:34:03,143 +只需将其作为查询参数附加到您对 + +773 +00:34:03,143 --> 00:34:06,346 +Get Transaction History 端点的请求中 + +774 +00:34:06,346 --> 00:34:09,183 +我们进一步来看看其工作方式 + +775 +00:34:09,183 --> 00:34:12,686 +在这里您可以 +看到新增的全部参数选项 + +776 +00:34:12,686 --> 00:34:15,455 +可能看起来很熟悉 因为大多数都 + +777 +00:34:15,455 --> 00:34:18,625 +来自交易信息有效负载 + +778 +00:34:18,625 --> 00:34:20,394 +您可以混合匹配这些参数 + +779 +00:34:20,394 --> 00:34:22,596 +以得到具体结果 + +780 +00:34:22,596 --> 00:34:24,865 +例如 我们或许只想获取 + +781 +00:34:24,865 --> 00:34:28,335 +一位用户自今年年初以来的 + +782 +00:34:28,335 --> 00:34:31,004 +非消费性购买数据 + +783 +00:34:31,004 --> 00:34:34,741 +并希望排除任何已撤销的购买 + +784 +00:34:34,741 --> 00:34:36,510 +那么我们构建自定义请求 + +785 +00:34:36,510 --> 00:34:39,446 +将 productType +设置为 NON_CONSUMABLE + +786 +00:34:39,446 --> 00:34:43,116 +并将 startDate +指定为今年年初 + +787 +00:34:43,116 --> 00:34:45,185 +以毫秒为单位显示 + +788 +00:34:45,185 --> 00:34:49,189 +最后 我们将 +excludeRevoked 设置为 true + +789 +00:34:49,189 --> 00:34:50,891 +请求就构建完成了! + +790 +00:34:50,891 --> 00:34:53,093 +由于我们没有选择排序顺序 + +791 +00:34:53,093 --> 00:34:55,095 +响应将默认为 + +792 +00:34:55,095 --> 00:34:58,131 +按升序修改日期排序 + +793 +00:34:58,131 --> 00:35:00,934 +即便请求已十分具体 + +794 +00:35:00,934 --> 00:35:04,338 +也可能有多个购买页面需要检索 + +795 +00:35:04,338 --> 00:35:06,673 +对于后续请求 我们应该确保 + +796 +00:35:06,673 --> 00:35:09,343 +除了先前响应的修订 + +797 +00:35:09,343 --> 00:35:12,980 +包含完全相同的查询参数 + +798 +00:35:12,980 --> 00:35:14,781 +为了更加灵活 + +799 +00:35:14,781 --> 00:35:18,185 +其中有三个过滤器字段支持多个值 + +800 +00:35:18,185 --> 00:35:20,587 +因此您可以过滤与所提供值 + +801 +00:35:20,587 --> 00:35:24,691 +至少有一个相匹配的购买数据 + +802 +00:35:24,691 --> 00:35:28,962 +该字段为 +productType、productId + +803 +00:35:28,962 --> 00:35:32,199 +和 subscriptionGroupIdentifier + +804 +00:35:32,199 --> 00:35:35,369 +要为这些参数提供多个值 + +805 +00:35:35,369 --> 00:35:39,173 +只需多次对其定义 + +806 +00:35:39,173 --> 00:35:44,378 +接下来我们继续讨论 +App Store Server Notification 更新 + +807 +00:35:44,378 --> 00:35:47,314 +使用 App Store Server Notifications V2 + +808 +00:35:47,314 --> 00:35:50,417 +您可将服务器提升至更高水平 + +809 +00:35:50,417 --> 00:35:53,487 +V2 通知提供了 + +810 +00:35:53,487 --> 00:35:55,088 +关于 App 内购买的详细内容 + +811 +00:35:55,088 --> 00:35:57,824 +使其独树一帜 + +812 +00:35:57,824 --> 00:36:01,161 +这尤其方便您跟踪 App 中提供的 + +813 +00:36:01,161 --> 00:36:05,032 +自动更新订阅生命周期 + +814 +00:36:05,032 --> 00:36:08,569 +您可以利用该内容巩固用户 + +815 +00:36:08,569 --> 00:36:10,804 +赢回流失用户 + +816 +00:36:10,804 --> 00:36:15,108 +解决用户支持请求等 + +817 +00:36:15,108 --> 00:36:19,446 +了解了以上妙用 +您可能想知道究竟如何开始 + +818 +00:36:19,446 --> 00:36:21,181 +与其他新功能一样 + +819 +00:36:21,181 --> 00:36:24,852 +最好以沙盒测试环境为起点 + +820 +00:36:24,852 --> 00:36:26,086 +这就是为什么去年 + +821 +00:36:26,086 --> 00:36:29,423 +我们要在 +App Store Connect 中添加 + +822 +00:36:29,423 --> 00:36:31,792 +设置单独服务器 URL 的功能 + +823 +00:36:31,792 --> 00:36:35,262 +以便在沙盒中接收 +App Store Server Notifications + +824 +00:36:35,262 --> 00:36:37,865 +注册您的服务器 URL 后 + +825 +00:36:37,865 --> 00:36:39,600 +您需要确认您的服务器 + +826 +00:36:39,600 --> 00:36:43,403 +正在接收来自 +App Store 服务器的通知 + +827 +00:36:43,403 --> 00:36:45,272 +您可以设置一个沙盒帐户 + +828 +00:36:45,272 --> 00:36:49,276 +以便通过用户操作触发通知 + +829 +00:36:49,276 --> 00:36:52,779 +例如 假设您使用该沙盒帐户 + +830 +00:36:52,779 --> 00:36:56,216 +首次购买订阅服务 + +831 +00:36:56,216 --> 00:37:00,687 +您会收到 +SUBSCRIBED 类型 V2 通知 + +832 +00:37:00,687 --> 00:37:03,257 +和 INITIAL_BUY 子类型 + +833 +00:37:03,257 --> 00:37:05,626 +若没有收到通知怎么办? + +834 +00:37:05,626 --> 00:37:08,262 +您或许会怀疑是否是服务器 + +835 +00:37:08,262 --> 00:37:12,099 +或您为触发通知 +而操作的步骤出现了问题 + +836 +00:37:12,099 --> 00:37:15,169 +刚开始时 这种情况会产生 + +837 +00:37:15,169 --> 00:37:16,803 +很多不确定性 + +838 +00:37:16,803 --> 00:37:19,573 +我们希望简化设置 便于您 + +839 +00:37:19,573 --> 00:37:23,043 +轻松验证 +App Store Server Notifications + +840 +00:37:23,043 --> 00:37:25,345 +是否发送至您的服务器 + +841 +00:37:25,345 --> 00:37:27,981 +因此在今年 我们推出新的 + +842 +00:37:27,981 --> 00:37:31,151 +Request a Test Notification 端点 + +843 +00:37:31,151 --> 00:37:32,886 +通过调用这个简单的端点 + +844 +00:37:32,886 --> 00:37:37,691 +您可要求我们发送 +TEST 类型的 V2 Notification + +845 +00:37:37,691 --> 00:37:42,429 +至 App Store Connect 中 +为您的 App 注册的服务器 URL + +846 +00:37:42,429 --> 00:37:45,899 +新的 TEST 通知类型为 + +847 +00:37:45,899 --> 00:37:47,935 +该端点专用 + +848 +00:37:47,935 --> 00:37:51,038 +您可以在沙盒或生产环境中调用端点 + +849 +00:37:51,038 --> 00:37:55,342 +为任一环境测试您保存的 URL + +850 +00:37:55,342 --> 00:37:59,346 +使用这个新端点 +可以快速测试新的服务器 URL + +851 +00:37:59,346 --> 00:38:01,748 +和配置 + +852 +00:38:01,748 --> 00:38:04,918 +我们来看看如何简化首次设置 + +853 +00:38:04,918 --> 00:38:08,555 +如果您只是想触发第一个通知 + +854 +00:38:08,555 --> 00:38:10,924 +那么无需设置沙盒帐户 + +855 +00:38:10,924 --> 00:38:12,960 +或执行购买 + +856 +00:38:12,960 --> 00:38:14,328 +只需在您要测试的环境中 + +857 +00:38:14,328 --> 00:38:16,964 +调用新端点 + +858 +00:38:16,964 --> 00:38:20,634 +即可收到一个确认您请求的 + +859 +00:38:20,634 --> 00:38:22,736 +HTTP 200 响应 + +860 +00:38:22,736 --> 00:38:25,138 +该响应包含一个新字段 + +861 +00:38:25,138 --> 00:38:29,610 +testNotificationToken +识别您的服务器 + +862 +00:38:29,610 --> 00:38:31,712 +收到的测试通知 + +863 +00:38:31,712 --> 00:38:34,381 +我们稍后会再次提到这个新字段 + +864 +00:38:34,381 --> 00:38:38,819 +片刻后 您的服务器 +就会在 App Store Connect + +865 +00:38:38,819 --> 00:38:43,624 +保存的 URL 中收到 +类型为 TEST 的 V2 通知 + +866 +00:38:43,624 --> 00:38:46,493 +现在来看如何调用该端点 + +867 +00:38:46,493 --> 00:38:49,530 +只需向 App Store +服务器上的这个新路径 + +868 +00:38:49,530 --> 00:38:52,032 +发送一个简单的 POST 请求 + +869 +00:38:52,032 --> 00:38:55,235 +您就会收到 HTTP 200 响应 + +870 +00:38:55,235 --> 00:38:58,572 +并了解您的请求已被提交 + +871 +00:38:58,572 --> 00:39:01,441 +响应将包含我提到的新字段 + +872 +00:39:01,441 --> 00:39:03,810 +testNotificationToken + +873 +00:39:03,810 --> 00:39:06,146 +请留意这一点以备后用 + +874 +00:39:06,146 --> 00:39:10,317 +很快您就会收到一份 +签好名的 TEST 通知 + +875 +00:39:10,317 --> 00:39:12,519 +这是该通知 + +876 +00:39:12,519 --> 00:39:14,488 +解码后的样子 + +877 +00:39:14,488 --> 00:39:17,491 +您会注意到它包含 V2 通知中 + +878 +00:39:17,491 --> 00:39:19,526 +所有常见的顶级字段 + +879 +00:39:19,526 --> 00:39:23,230 +包括新的 notificationType TEST + +880 +00:39:23,230 --> 00:39:26,099 +数据对象的内容 + +881 +00:39:26,099 --> 00:39:27,901 +比正常通知稍短 + +882 +00:39:27,901 --> 00:39:29,636 +由于这只是一个测试 + +883 +00:39:29,636 --> 00:39:32,840 +未包含交易相关数据 + +884 +00:39:32,840 --> 00:39:35,642 +因此我们省略了特定于交易的字段 + +885 +00:39:35,642 --> 00:39:40,080 +最常见的就是 +signedTransactionInfo + +886 +00:39:40,080 --> 00:39:43,684 +调用新的 +Request a Test Notification 端点时 + +887 +00:39:43,684 --> 00:39:46,186 +请记住 +App Store Server Notifications + +888 +00:39:46,186 --> 00:39:48,655 +是异步发送的 + +889 +00:39:48,655 --> 00:39:50,824 +您对端点的成功调用 + +890 +00:39:50,824 --> 00:39:55,462 +将返回一个 HTTP 200 +但实际的测试通知 + +891 +00:39:55,462 --> 00:39:59,466 +稍后将单独到达 + +892 +00:39:59,466 --> 00:40:01,368 +由于该端点是为 + +893 +00:40:01,368 --> 00:40:03,704 +测试您的服务器配置 + +894 +00:40:03,704 --> 00:40:07,107 +您或许好奇该测试若失败了该怎么办 + +895 +00:40:07,107 --> 00:40:12,112 +换句话说 +如果测试通知没有到达怎么办? + +896 +00:40:12,112 --> 00:40:14,982 +为进一步提高您的测试能力 + +897 +00:40:14,982 --> 00:40:18,752 +我们将发布 +Get Test Notification Status 端点 + +898 +00:40:18,752 --> 00:40:20,521 +您将其与 + +899 +00:40:20,521 --> 00:40:24,091 +Request a Test Notification 端点结合使用 + +900 +00:40:24,091 --> 00:40:26,793 +利用该端点 您可以检查先前请求的 + +901 +00:40:26,793 --> 00:40:30,631 +TEST 通知状态 + +902 +00:40:30,631 --> 00:40:33,534 +端点响应将告知您 +App Store 服务器是否 + +903 +00:40:33,534 --> 00:40:35,369 +能够访问您的服务器 + +904 +00:40:35,369 --> 00:40:39,173 +并成功发送 TEST 通知 + +905 +00:40:39,173 --> 00:40:42,342 +如果发送失败 它也会告诉您原因 + +906 +00:40:42,342 --> 00:40:46,480 +这样您就可以更好地 +对服务器配置进行故障排除 + +907 +00:40:46,480 --> 00:40:50,284 +我们来看使用该端点的方法 + +908 +00:40:50,284 --> 00:40:54,888 +向 App Store 服务器上的 +此路径发送 GET 请求 + +909 +00:40:54,888 --> 00:40:58,091 +在此路径中 包含了您从 + +910 +00:40:58,091 --> 00:41:02,462 +Request a Test Notification 端点 +收到的 testNotificationToken + +911 +00:41:02,462 --> 00:41:04,865 +这会告诉我们您想检查 + +912 +00:41:04,865 --> 00:41:07,234 +哪个测试通知的状态 + +913 +00:41:07,234 --> 00:41:09,169 +再来看响应 + +914 +00:41:09,169 --> 00:41:13,073 +signedPayload 字段 +包含了App Store 服务器 + +915 +00:41:13,073 --> 00:41:15,542 +尝试向您的服务器发送的 + +916 +00:41:15,542 --> 00:41:17,377 +TEST 通知有效负载 + +917 +00:41:17,377 --> 00:41:21,281 +并且 +firstSendAttemptResult 字段表明了 + +918 +00:41:21,281 --> 00:41:23,851 +发送尝试的结果 + +919 +00:41:23,851 --> 00:41:27,654 +这里 SUCCESS 表示发送成功 + +920 +00:41:27,654 --> 00:41:31,725 +意味着 App Store 服务器 +收到了您的服务器做出的 + +921 +00:41:31,725 --> 00:41:34,127 +HTTP 200 响应 + +922 +00:41:34,127 --> 00:41:36,530 +如果未发送成功 + +923 +00:41:36,530 --> 00:41:40,667 +您将看到以下几个不同的错误值 + +924 +00:41:40,667 --> 00:41:44,505 +这些值表示 +App Store 服务器在尝试 + +925 +00:41:44,505 --> 00:41:48,008 +通过测试通知 +访问您的服务器时遇到的错误 + +926 +00:41:48,008 --> 00:41:51,812 +有了这些信息 +您可以解决服务器问题 + +927 +00:41:51,812 --> 00:41:54,748 +根据需要请求新的测试通知 + +928 +00:41:54,748 --> 00:41:58,118 +让您的服务器平稳运行 + +929 +00:41:58,118 --> 00:42:00,921 +总得来说 以上测试通知端点 + +930 +00:42:00,921 --> 00:42:03,724 +使用简单 在设置或重新配置服务器 + +931 +00:42:03,724 --> 00:42:06,593 +以接收 +V2 App Store 服务器通知时 + +932 +00:42:06,593 --> 00:42:11,698 +可以为您省去很多麻烦 + +933 +00:42:11,698 --> 00:42:13,133 +在上述端点的帮助下 + +934 +00:42:13,133 --> 00:42:17,004 +您可以设置 +您的服务器确保其顺利运行 + +935 +00:42:17,004 --> 00:42:20,207 +但服务器并不完美 有时还会中断 + +936 +00:42:20,207 --> 00:42:23,043 +那当您的服务器 +出现故障 导致您错过 + +937 +00:42:23,043 --> 00:42:26,914 +App Store Server Notifications 时 +您如何恢复? + +938 +00:42:26,914 --> 00:42:30,484 +目前的解决方案就是重试系统 + +939 +00:42:30,484 --> 00:42:33,453 +当 App Store 服务器 +无法访问您的服务器时 + +940 +00:42:33,453 --> 00:42:36,089 +它会启动重试程序 + +941 +00:42:36,089 --> 00:42:40,360 +最多重试发送五次相同通知 + +942 +00:42:40,360 --> 00:42:43,363 +每次尝试间隔递增 + +943 +00:42:43,363 --> 00:42:47,701 +重试仅发生在生产环境中 + +944 +00:42:47,701 --> 00:42:50,637 +可帮助您最终从中断中恢复 + +945 +00:42:50,637 --> 00:42:53,740 +但并非适合所有情况 + +946 +00:42:53,740 --> 00:42:57,110 +例如 有些中断可能范围较大 + +947 +00:42:57,110 --> 00:42:58,979 +如果您的服务器停机时间长到 + +948 +00:42:58,979 --> 00:43:02,482 +错过了 App Store +服务器发送的最终重试尝试 + +949 +00:43:02,482 --> 00:43:05,319 +那该通知将丢失 + +950 +00:43:05,319 --> 00:43:06,587 +或者还有更常见的情况 + +951 +00:43:06,587 --> 00:43:09,590 +您的服务器可能遇到了 +一个非常简短的问题 + +952 +00:43:09,590 --> 00:43:13,560 +而在此期间它只错过了少量通知 + +953 +00:43:13,560 --> 00:43:16,196 +但错过哪怕一个通知 + +954 +00:43:16,196 --> 00:43:18,832 +都意味着您的客户记录 + +955 +00:43:18,832 --> 00:43:20,567 +至少有一个小时未更新 + +956 +00:43:20,567 --> 00:43:23,437 +而您却不知道未更新的是哪些记录! + +957 +00:43:23,437 --> 00:43:26,240 +显然 服务器中断压力很大 + +958 +00:43:26,240 --> 00:43:29,309 +从中恢复是一项复杂的任务 + +959 +00:43:29,309 --> 00:43:31,845 +所以我们才想尽可能简单地 + +960 +00:43:31,845 --> 00:43:35,182 +恢复错过的 +App Store Server Notifications + +961 +00:43:35,182 --> 00:43:39,887 +以便您的服务器尽快重回正轨 + +962 +00:43:39,887 --> 00:43:42,689 +这也是今年我们推出新的 + +963 +00:43:42,689 --> 00:43:45,325 +Get Notification History 端点的原因 + +964 +00:43:45,325 --> 00:43:46,994 +有了该端点 + +965 +00:43:46,994 --> 00:43:51,331 +您可以获取您的 App 生成的 + +966 +00:43:51,331 --> 00:43:53,767 +V2 App Store Server Notifications + +967 +00:43:53,767 --> 00:43:58,238 +无论您的服务器是否成功收到通知 + +968 +00:43:58,238 --> 00:44:02,743 +该通知都会出现在该端点的响应中 + +969 +00:44:02,743 --> 00:44:04,111 +调用该端点时 + +970 +00:44:04,111 --> 00:44:08,515 +您要指定获取通知的日期范围 + +971 +00:44:08,515 --> 00:44:11,919 +通过 WWDC +我们已经开始记录这些数据 + +972 +00:44:11,919 --> 00:44:15,422 +累积最近六个月的 + +973 +00:44:15,422 --> 00:44:18,192 +滚动历史上线 + +974 +00:44:18,192 --> 00:44:22,296 +您可以选择 +按类型和子类型过滤您的请求 + +975 +00:44:22,296 --> 00:44:25,699 +或通过提供 originalTransactionId + +976 +00:44:25,699 --> 00:44:29,036 +仅获取单个用户的通知 + +977 +00:44:29,036 --> 00:44:31,905 +现有的重试系统仍然可用 + +978 +00:44:31,905 --> 00:44:35,843 +因此您可以将其与该新端点结合使用 + +979 +00:44:35,843 --> 00:44:39,046 +我们来看一下如何调用该端点 + +980 +00:44:39,046 --> 00:44:41,849 +您向 App Store +服务器上的这个新路径 + +981 +00:44:41,849 --> 00:44:43,684 +发送一个简单的 POST 请求 + +982 +00:44:43,684 --> 00:44:48,822 +在请求正文中包含 +startDate 和 endDate + +983 +00:44:48,822 --> 00:44:51,425 +响应将仅包含我们首次尝试 + +984 +00:44:51,425 --> 00:44:54,795 +在此窗口中发送的通知 + +985 +00:44:54,795 --> 00:44:58,065 +请记住 最早可用的通知 + +986 +00:44:58,065 --> 00:45:02,970 +是在您提出请求前 +六个月发送的通知 + +987 +00:45:02,970 --> 00:45:06,473 +或者 您可指定一个 +notificationType + +988 +00:45:06,473 --> 00:45:08,609 +和 notificationSubtype + +989 +00:45:08,609 --> 00:45:12,513 +若采用此方法 +历史记录将被过滤为仅 + +990 +00:45:12,513 --> 00:45:15,148 +匹配这两个值的通知 + +991 +00:45:15,148 --> 00:45:19,486 +请记住 某些通知没有子类型 + +992 +00:45:19,486 --> 00:45:21,321 +又或者 您可提供 + +993 +00:45:21,321 --> 00:45:23,991 +某个用户的 +originalTransactionId + +994 +00:45:23,991 --> 00:45:28,662 +仅获取该用户的通知历史记录 + +995 +00:45:28,662 --> 00:45:31,632 +最后 您要提供 +一个 paginationToken + +996 +00:45:31,632 --> 00:45:34,768 +作为每个后续请求的查询参数 + +997 +00:45:34,768 --> 00:45:37,171 +以便获取下一页 + +998 +00:45:37,171 --> 00:45:39,740 +确保您在后续请求中 + +999 +00:45:39,740 --> 00:45:41,341 +使用相同的请求正文 + +1000 +00:45:41,341 --> 00:45:44,511 +仅更改此 paginationToken + +1001 +00:45:44,511 --> 00:45:47,447 +现在让我们来看响应 + +1002 +00:45:47,447 --> 00:45:51,752 +notificationHistory 数组 +最多包含 20 个通知 + +1003 +00:45:51,752 --> 00:45:55,622 +首先是最久远的通知 + +1004 +00:45:55,622 --> 00:45:59,860 +该数组中的每个条目代表一个通知 + +1005 +00:45:59,860 --> 00:46:02,930 +在其中您会找到 signedPayload + +1006 +00:46:02,930 --> 00:46:07,434 +您可像往常一样 +对其解码以查看交易数据 + +1007 +00:46:07,434 --> 00:46:10,337 +其中的数据与 App Store 服务器 + +1008 +00:46:10,337 --> 00:46:14,575 +在原始通知中发送的有效负载相同 + +1009 +00:46:14,575 --> 00:46:16,610 +您会看到我们 +为该还端点响应带来了新的 + +1010 +00:46:16,610 --> 00:46:20,848 +firstSendAttemptResult 字段 + +1011 +00:46:20,848 --> 00:46:24,151 +使用此字段您可查找超时序列 + +1012 +00:46:24,151 --> 00:46:27,487 +以及其他错误 +以更好了解您的服务器 + +1013 +00:46:27,487 --> 00:46:30,858 +错过历史通知的原因 + +1014 +00:46:30,858 --> 00:46:33,627 +若有更多页面需要检索 + +1015 +00:46:33,627 --> 00:46:36,196 +响应还包含一个 paginationToken + +1016 +00:46:36,196 --> 00:46:38,265 +您应该在下一个请求中提供此信息 + +1017 +00:46:38,265 --> 00:46:41,802 +以获得下一页通知 + +1018 +00:46:41,802 --> 00:46:43,937 +只要 hasMore 字段为 true + +1019 +00:46:43,937 --> 00:46:47,708 +您就有更多页面需要检索 + +1020 +00:46:47,708 --> 00:46:49,243 +以上就是该新端点的 + +1021 +00:46:49,243 --> 00:46:52,546 +所有介绍 + +1022 +00:46:52,546 --> 00:46:56,116 +今天我们的 App Store +服务器更新讲座就到此结束了 + +1023 +00:46:56,116 --> 00:46:59,152 +讲座中提及的服务器功能现在均可 + +1024 +00:46:59,152 --> 00:47:02,389 +在沙盒和生产中使用 + +1025 +00:47:02,389 --> 00:47:04,758 +我们希望您能利用以上新功能 + +1026 +00:47:04,758 --> 00:47:07,761 +让您的服务器达到最佳状态 + +1027 +00:47:07,761 --> 00:47:11,465 +有关针对 App 内购买使用服务器 +的更多精彩内容 + +1028 +00:47:11,465 --> 00:47:13,700 +包括如何在支持旧版客户端的同时 + +1029 +00:47:13,700 --> 00:47:15,802 +使用最新功能 + +1030 +00:47:15,802 --> 00:47:20,374 +建议您观看 WWDC22 的另一场讲座 + +1031 +00:47:20,374 --> 00:47:24,211 +“探索 App 内购买集成和迁移” + +1032 +00:47:24,211 --> 00:47:27,548 +两位:感谢您加入 WWDC22! + +1033 +00:47:27,548 --> 00:47:31,585 +♪ + diff --git a/zho/2022 Session 10008 What's new in Nearby Interaction.srt b/zho/2022 Session 10008 What's new in Nearby Interaction.srt new file mode 100644 index 0000000..77a30e0 --- /dev/null +++ b/zho/2022 Session 10008 What's new in Nearby Interaction.srt @@ -0,0 +1,2347 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,910 +♪ + +3 +00:00:09,910 --> 00:00:12,713 +嗨 我是 Jon Schoenberg +是一名工程师 + +4 +00:00:12,713 --> 00:00:15,082 +就职于 Apple 的 +定位技术团队 + +5 +00:00:15,082 --> 00:00:18,018 +本期讲座 我将介绍 +Nearby Interaction 中的 + +6 +00:00:18,018 --> 00:00:20,721 +一项新功能这项功能会为您 + +7 +00:00:20,721 --> 00:00:23,123 +打造更丰富 更多样化 + +8 +00:00:23,123 --> 00:00:25,259 +且具有空间感知效果的体验 + +9 +00:00:25,259 --> 00:00:27,928 +Nearby Interaction 框架使得 + +10 +00:00:27,928 --> 00:00:31,398 +充分利用 U1 的能力更加容易 + +11 +00:00:31,398 --> 00:00:34,935 +U1 是 Apple 的 +超宽带技术芯片 + +12 +00:00:34,935 --> 00:00:39,139 +这一框架能够 +在附近的 Apple 设备 + +13 +00:00:39,139 --> 00:00:42,276 +或与 U1 超宽带芯片 +兼容的配件之间 + +14 +00:00:42,276 --> 00:00:47,014 +创建精确的空间感知交互 + +15 +00:00:47,014 --> 00:00:48,749 +我们先快速回顾一下 + +16 +00:00:48,749 --> 00:00:52,519 +过去两年来为您提供的功能 + +17 +00:00:52,519 --> 00:00:56,190 +当 Nearby Interaction +在 WWDC 2020 上首次亮相时 + +18 +00:00:56,190 --> 00:00:58,258 +这项功能专注于的是利用 U1 + +19 +00:00:58,258 --> 00:01:02,462 +在两台 iPhone 之间 +创造并运行会话 + +20 +00:01:02,462 --> 00:01:06,333 +在 WWDC 2021 上 +这项功能得到了扩展 + +21 +00:01:06,333 --> 00:01:09,570 +支持与 Apple Watch +和第三方超宽带兼容配件 + +22 +00:01:09,570 --> 00:01:13,240 +运行会话 + +23 +00:01:13,240 --> 00:01:14,875 +如果您有兴趣深入了解 + +24 +00:01:14,875 --> 00:01:17,511 +Nearby Interaction 框架的 API + +25 +00:01:17,511 --> 00:01:20,848 +请查看 WWDC 2020 年 + +26 +00:01:20,848 --> 00:01:22,082 +“了解 Nearby Interaction”演讲 + +27 +00:01:22,082 --> 00:01:25,285 +和 2021 年的 + +28 +00:01:25,285 --> 00:01:27,354 +“探索与第三方配件的 +Nearby Interaction” + +29 +00:01:27,354 --> 00:01:29,489 +用户社区对 Nearby Interaction +的反响 令我们非常兴奋 + +30 +00:01:29,489 --> 00:01:31,992 +在本期讲座中 + +31 +00:01:31,992 --> 00:01:34,228 +我很高兴能为您介绍新功能 + +32 +00:01:34,228 --> 00:01:36,530 +和新功能改进 + +33 +00:01:36,530 --> 00:01:39,099 +我将围绕两个主题展开 + +34 +00:01:39,099 --> 00:01:42,135 +使用 ARKit 增强 +Nearby Interaction + +35 +00:01:42,135 --> 00:01:44,404 +和后台会话 + +36 +00:01:44,404 --> 00:01:46,573 +同时 我将分享一些 + +37 +00:01:46,573 --> 00:01:50,611 +能简化 Nearby Interaction +框架使用的改进 + +38 +00:01:50,611 --> 00:01:54,314 +而作为总结 +我会聊一聊对去年宣布的 + +39 +00:01:54,314 --> 00:01:56,450 +第三方硬件支持的更新 + +40 +00:01:56,450 --> 00:01:58,018 +我们兴奋地期待着 + +41 +00:01:58,018 --> 00:01:59,520 +您会如何使用这些新功能 + +42 +00:01:59,520 --> 00:02:02,556 +那我们来深入了解一下细节吧 + +43 +00:02:02,556 --> 00:02:04,992 +我先从令人振奋的新功能开始说起 + +44 +00:02:04,992 --> 00:02:09,062 +这项新功能将 ARKit 与 +Nearby Interaction 紧密集成 + +45 +00:02:09,062 --> 00:02:12,533 +这项新功能 +通过利用 ARKit 计算的设备轨迹 + +46 +00:02:12,533 --> 00:02:17,371 +增强了 Nearby Interaction + +47 +00:02:17,371 --> 00:02:19,406 +有 ARKit 增强的 +Nearby Interaction 利用了 + +48 +00:02:19,406 --> 00:02:22,109 +与实现 AirTag 的 +Precision Finding + +49 +00:02:22,109 --> 00:02:25,345 +相同的底层技术 + +50 +00:02:25,345 --> 00:02:29,783 +而我们通过 Nearby Interaction +将这种技术提供给您 + +51 +00:02:29,783 --> 00:02:32,619 +最佳用例是引导用户 + +52 +00:02:32,619 --> 00:02:36,190 +找到附近特定对象的体验 +例如放错地方的物品 + +53 +00:02:36,190 --> 00:02:37,524 +感兴趣的对象 + +54 +00:02:37,524 --> 00:02:41,461 +或用户想要与之交互的对象 + +55 +00:02:41,461 --> 00:02:44,231 +通过集成 ARKit 和 +Nearby Interaction + +56 +00:02:44,231 --> 00:02:46,366 +距离和方向的信息 + +57 +00:02:46,366 --> 00:02:48,235 +比单独使用 Nearby Interaction + +58 +00:02:48,235 --> 00:02:50,537 +更稳定可用 + +59 +00:02:50,537 --> 00:02:55,342 +能有效拓宽超宽带视场 + +60 +00:02:55,342 --> 00:02:58,245 +最后 这个新功能 + +61 +00:02:58,245 --> 00:03:02,049 +最适合于与固定设备交互之用 + +62 +00:03:02,049 --> 00:03:04,384 +我们现在就演示一下 + +63 +00:03:04,384 --> 00:03:07,688 +ARKit 和 +Nearby Interaction 的新集成 + +64 +00:03:07,688 --> 00:03:11,358 +在您 App 中的可能性 + +65 +00:03:11,358 --> 00:03:14,428 +我手头有一个用于 +喷气发动机博物馆的 App + +66 +00:03:14,428 --> 00:03:16,430 +博物馆中具有超宽带配件 + +67 +00:03:16,430 --> 00:03:18,532 +帮助引导用户参观展品 + +68 +00:03:18,532 --> 00:03:21,969 +我们去找下一个喷气发动机吧 + +69 +00:03:21,969 --> 00:03:24,271 +当用户选择前往下一个展览时 + +70 +00:03:24,271 --> 00:03:27,307 +App 发现超宽带配件 + +71 +00:03:27,307 --> 00:03:29,142 +并进行必要的信息交换 + +72 +00:03:29,142 --> 00:03:31,645 +从而开始使用 Nearby Interaction + +73 +00:03:31,645 --> 00:03:33,914 +然后 App 指示用户 + +74 +00:03:33,914 --> 00:03:37,584 +将手机左右移动 通过 ARKit + +75 +00:03:37,584 --> 00:03:40,387 +使用增强的 Nearby Interaction 模式 + +76 +00:03:40,387 --> 00:03:45,058 +App 开始寻找 +下一个展览的物理位置 + +77 +00:03:45,058 --> 00:03:47,728 +现在 App 确定了 + +78 +00:03:47,728 --> 00:03:49,997 +下一个展览的方向 + +79 +00:03:49,997 --> 00:03:52,499 +一个简单的箭头图标告诉用户 + +80 +00:03:52,499 --> 00:03:55,869 +去查看箭头指向位置出现的东西 + +81 +00:03:55,869 --> 00:03:58,505 +这种丰富的空间感知信息 + +82 +00:03:58,505 --> 00:04:02,576 +利用 ARKit 和 +Nearby Interaction 的结合 + +83 +00:04:02,576 --> 00:04:06,313 +甚至可以指向 +与用户行进方向相反的 + +84 +00:04:06,313 --> 00:04:10,250 +在用户背后的展品 + +85 +00:04:10,250 --> 00:04:12,719 +最后 App 会在 + +86 +00:04:12,719 --> 00:04:16,690 +AR 世界中 +显示下一个展览位置的叠加层 + +87 +00:04:16,690 --> 00:04:19,159 +而 App 会提示用户 +稍微上下移动 iPhone + +88 +00:04:19,159 --> 00:04:22,262 +从而在 AR 世界中 + +89 +00:04:22,262 --> 00:04:23,964 +找到展品的位置 + +90 +00:04:23,964 --> 00:04:26,567 +将 AR 内容放入场景中后 + +91 +00:04:26,567 --> 00:04:29,770 +Nearby Interaction +超宽带测量值 + +92 +00:04:29,770 --> 00:04:31,705 +与 ARKit 的强大组合 + +93 +00:04:31,705 --> 00:04:35,642 +能让用户轻松地前往 + +94 +00:04:35,642 --> 00:04:38,111 +下一个喷气发动机的位置 + +95 +00:04:38,111 --> 00:04:42,349 +我虽然没有找到喷气发动机 +但我找到了皇后 + +96 +00:04:42,349 --> 00:04:44,818 +现在我们再看看 + +97 +00:04:44,818 --> 00:04:47,287 +如何启用这种增强的 +Nearby Interaction 模式 + +98 +00:04:47,287 --> 00:04:50,757 +使用 ARKit 启用增强模式很简单 +在 iOS 15 中 您可以通过在您的 App 中 + +99 +00:04:50,757 --> 00:04:52,559 +从附近的对等点 +接受 NIDiscoveryToken + +100 +00:04:52,559 --> 00:04:55,829 +创建一个会话配置 + +101 +00:04:55,829 --> 00:04:57,965 +并运行 NISession + +102 +00:04:57,965 --> 00:05:01,068 +在新的和现有的 +Nearby Interaction 用例上 + +103 +00:05:01,068 --> 00:05:04,938 +只需启用新的 +isCameraAssistanceEnabled 属性 + +104 +00:05:04,938 --> 00:05:08,375 +这一属性位于 +NIConfiguration 子类下 + +105 +00:05:08,375 --> 00:05:11,245 +就可以很轻松地 +用 ARKit 启用增强模式 + +106 +00:05:11,245 --> 00:05:13,080 +若要使用 ARKit 的增强模式 + +107 +00:05:13,080 --> 00:05:16,650 +只需要设置 + +108 +00:05:16,650 --> 00:05:18,452 +isCameraAssistanceEnabled 属性 + +109 +00:05:18,452 --> 00:05:20,354 +当两台 Apple 设备交互时 + +110 +00:05:20,354 --> 00:05:23,724 +或一台 Apple 设备 +与第三方超宽带配件交互时 + +111 +00:05:23,724 --> 00:05:27,694 +相机辅助是可用的 + +112 +00:05:27,694 --> 00:05:30,063 +我们来看看 +当 NISession 在启用 + +113 +00:05:30,063 --> 00:05:34,401 +相机辅助的情况下运行时 +会发生什么 + +114 +00:05:34,401 --> 00:05:35,903 +启用相机辅助功能后 + +115 +00:05:35,903 --> 00:05:38,872 +会在 Nearby Interaction 框架内 + +116 +00:05:38,872 --> 00:05:41,808 +自动创建一个 ARSessionan + +117 +00:05:41,808 --> 00:05:46,413 +您不需要手动创建此 ARSession + +118 +00:05:46,413 --> 00:05:49,082 +在启用了相机辅助的情况下 +运行 NISession + +119 +00:05:49,082 --> 00:05:52,819 +也会在 Nearby Interaction 框架中 +自动创建 ARSession + +120 +00:05:52,819 --> 00:05:56,423 +并运行 ARSession 框架 + +121 +00:05:56,423 --> 00:06:00,394 +ARSession 在 App 进程中运行 + +122 +00:06:00,394 --> 00:06:01,795 +因此 + +123 +00:06:01,795 --> 00:06:06,200 +App 必须 +在它的 Info.plist 中 + +124 +00:06:06,200 --> 00:06:09,336 +提供 CameraUsageDescription +目的字符串 + +125 +00:06:09,336 --> 00:06:13,674 +确保字符串要有用 +从而告诉你的用户 + +126 +00:06:13,674 --> 00:06:19,379 +为什么想要获得良好使用体验 +必须要使用相机 + +127 +00:06:19,379 --> 00:06:23,717 +对于给定的 App +只能运行一个 ARSession + +128 +00:06:23,717 --> 00:06:26,620 +也就是说 如果您的 App 中 + +129 +00:06:26,620 --> 00:06:31,425 +已经拥有 ARKit +就需要向 NISession 共享 + +130 +00:06:31,425 --> 00:06:34,161 +您创建的 ARSession + +131 +00:06:34,161 --> 00:06:36,430 +要向 NISession +共享 ARSession + +132 +00:06:36,430 --> 00:06:39,466 +可以使用 NISession 类上 + +133 +00:06:39,466 --> 00:06:41,602 +的一个新的 setARSession 方法 + +134 +00:06:41,602 --> 00:06:46,306 +在 NISession 上运行之前 + +135 +00:06:46,306 --> 00:06:49,943 +调用 setARSession 时 + +136 +00:06:49,943 --> 00:06:51,979 +在 Nearby Interaction 框架内 + +137 +00:06:51,979 --> 00:06:54,248 +不会自动创建 ARSessionan + +138 +00:06:54,248 --> 00:06:57,284 +这确保了可以在 App 中 + +139 +00:06:57,284 --> 00:07:00,554 +在拥有 ARKit 体验的同时 +能够获得 + +140 +00:07:00,554 --> 00:07:02,723 +Nearby Interaction 中的 +相机辅助 + +141 +00:07:02,723 --> 00:07:06,894 +在这个 SwiftUI 示例中 +作为 makeUIView 函数的一部分 + +142 +00:07:06,894 --> 00:07:09,997 +ARView 中的底层 ARSession + +143 +00:07:09,997 --> 00:07:16,303 +通过新的 setARSession 方法 +向 NISession 共享 + +144 +00:07:16,303 --> 00:07:19,072 +如果您直接使用 ARSession + +145 +00:07:19,072 --> 00:07:22,476 +那么就需要 +在 ARSession 上调用运行 + +146 +00:07:22,476 --> 00:07:26,313 +ARWorldTrackingConfiguration + +147 +00:07:26,313 --> 00:07:29,449 +此外 还必须在 +这个 ARConfiguration 中 + +148 +00:07:29,449 --> 00:07:32,953 +以特定的方式配置几个属性 + +149 +00:07:32,953 --> 00:07:35,189 +以确保相机辅助的 + +150 +00:07:35,189 --> 00:07:37,925 +高质量性能 + +151 +00:07:37,925 --> 00:07:41,128 +把 worldAlignment +设置为 .gravity + +152 +00:07:41,128 --> 00:07:44,698 +禁用协作和 userFaceTracking + +153 +00:07:44,698 --> 00:07:47,768 +initialWorldMap 为 nil +还有一个委托 + +154 +00:07:47,768 --> 00:07:50,671 +其 +sessionShouldAttemptRelocalization 方法 + +155 +00:07:50,671 --> 00:07:52,673 +返回值应为 false + +156 +00:07:52,673 --> 00:07:54,241 +我们再来看一些 + +157 +00:07:54,241 --> 00:07:57,277 +共享您创建的 +ARSession 时的最优方法 + +158 +00:07:57,277 --> 00:08:01,014 +在您的 NISessionDelegate +didInvalidateWith 错误方法中 + +159 +00:08:01,014 --> 00:08:04,785 +请一直检查错误代码 + +160 +00:08:04,785 --> 00:08:08,856 +如果用于运行共享 ARSession +的 ARConfiguration + +161 +00:08:08,856 --> 00:08:11,725 +不符合概要属性 + +162 +00:08:11,725 --> 00:08:14,695 +NISession 将会失效 + +163 +00:08:14,695 --> 00:08:18,665 +将会返回一个新的 NIError 码 + +164 +00:08:18,665 --> 00:08:21,535 +invalidARConfiguration + +165 +00:08:21,535 --> 00:08:24,471 +若要在 App 中 +接收附近的对象更新 + +166 +00:08:24,471 --> 00:08:28,141 +请继续在您的 +NISessionDelegate 中 + +167 +00:08:28,141 --> 00:08:30,577 +使用 +didUpdateNearbyObjects 方法 + +168 +00:08:30,577 --> 00:08:32,946 +在您的 +didUpdateNearbyObjects 方法中 + +169 +00:08:32,946 --> 00:08:36,617 +您可能会检查附近的对象 +以找到所需的对等方 + +170 +00:08:36,617 --> 00:08:38,852 +并根据 NINearbyObject 的 + +171 +00:08:38,852 --> 00:08:43,323 +距离和方向属性更新 UI + +172 +00:08:43,323 --> 00:08:47,461 +调用它的时候要时刻小心 +因为可能是 nil + +173 +00:08:47,461 --> 00:08:49,496 +启用相机辅助功能后 + +174 +00:08:49,496 --> 00:08:54,401 +NINearbyObject 中 +有两个新属性可用 + +175 +00:08:54,401 --> 00:08:57,704 +第一个是 horizontalAngle + +176 +00:08:57,704 --> 00:08:59,640 +这是以弧度表示的一维角 + +177 +00:08:59,640 --> 00:09:03,377 +指示到附近物体的方位角方向 + +178 +00:09:03,377 --> 00:09:07,447 +当不可用时 这个值将为 nil + +179 +00:09:07,447 --> 00:09:10,017 +第二 verticalDirectionEstimate + +180 +00:09:10,017 --> 00:09:13,220 +是垂直维度中 + +181 +00:09:13,220 --> 00:09:14,955 +与邻近对象的位置关系 + +182 +00:09:14,955 --> 00:09:19,526 +这是一个新的 +VerticalDirectionEstimate 类型 + +183 +00:09:19,526 --> 00:09:23,497 +距离和方向表示用户设备 + +184 +00:09:23,497 --> 00:09:27,067 +和附近物体之间的关键空间关系 + +185 +00:09:27,067 --> 00:09:31,305 +距离以米为单位 方向是从您的设备 + +186 +00:09:31,305 --> 00:09:34,975 +到附近物体的一个三维矢量 + +187 +00:09:34,975 --> 00:09:38,478 +水平角是指 + +188 +00:09:38,478 --> 00:09:41,215 +运行 NISession +的设备与附近物体 + +189 +00:09:41,215 --> 00:09:44,251 +在局部水平面上的夹角 + +190 +00:09:44,251 --> 00:09:46,420 +水平角包括了两个设备之间的 + +191 +00:09:46,420 --> 00:09:50,591 +任何垂直位移偏移 和设备本身的 + +192 +00:09:50,591 --> 00:09:52,926 +任何水平旋转 + +193 +00:09:52,926 --> 00:09:55,963 +尽管物体方向是三维 + +194 +00:09:55,963 --> 00:10:02,469 +水平角是用一维的方式 +表示了两个设备之间的朝向 + +195 +00:10:02,469 --> 00:10:04,471 +这个水平角属性 + +196 +00:10:04,471 --> 00:10:07,574 +与方向属性互补 + +197 +00:10:07,574 --> 00:10:09,710 +而如果方向无法识别 + +198 +00:10:09,710 --> 00:10:12,212 +水平角可以帮助您 + +199 +00:10:12,212 --> 00:10:16,717 +将用户引导至附近的对象 + +200 +00:10:16,717 --> 00:10:20,254 +垂直方向估计 + +201 +00:10:20,254 --> 00:10:22,823 +是对垂直位置信息的定性评估 + +202 +00:10:22,823 --> 00:10:27,160 +您可以利用它 引导用户前往不同层 + +203 +00:10:27,160 --> 00:10:32,599 +我们再来看看新的 +VerticalDirectionEstimate 类型 + +204 +00:10:32,599 --> 00:10:35,702 +VerticalDirectionEstimate 是 + +205 +00:10:35,702 --> 00:10:38,705 +NINearbyObject 内嵌套的枚举 + +206 +00:10:38,705 --> 00:10:41,808 +表示与附近对象 + +207 +00:10:41,808 --> 00:10:44,611 +垂直关系的定性评估 + +208 +00:10:44,611 --> 00:10:47,147 +在使用 +VerticalDirectionEstimate 前 + +209 +00:10:47,147 --> 00:10:50,517 +请确保检查 +这项属性的值为 unknown + +210 +00:10:50,517 --> 00:10:55,756 +垂直关系可以是 +相同 (same) 上 (above) 下 (below) + +211 +00:10:55,756 --> 00:10:58,926 +还有上或 +下 (aboveOrBelow) 这样的特殊值 + +212 +00:10:58,926 --> 00:11:02,996 +这一特殊值表示 +附近物体不在同一水平面上 + +213 +00:11:02,996 --> 00:11:07,968 +但位置不明显 +可能在设备上方或下方 + +214 +00:11:07,968 --> 00:11:11,071 +超宽带测量值受 + +215 +00:11:11,071 --> 00:11:12,506 +视场和障碍物的影响 + +216 +00:11:12,506 --> 00:11:14,575 +用于方向信息的视场 + +217 +00:11:14,575 --> 00:11:19,746 +对应于从设备后部投射的锥形 + +218 +00:11:19,746 --> 00:11:22,316 +当启用相机辅助时 + +219 +00:11:22,316 --> 00:11:26,086 +从 ARKit 计算出的设备轨迹 + +220 +00:11:26,086 --> 00:11:30,390 +可以在更多场景中提供 + +221 +00:11:30,390 --> 00:11:35,495 +距离 方向 水平角度 +和垂直方向估计 + +222 +00:11:35,495 --> 00:11:39,099 +有效扩展超宽带传感器的视场 + +223 +00:11:39,099 --> 00:11:42,936 +我们再来看利用 +ARKit 和 Nearby Interaction 的集成 + +224 +00:11:42,936 --> 00:11:48,475 +在场景中放置 AR 对象 + +225 +00:11:48,475 --> 00:11:52,579 +为了让您更容易地将 + +226 +00:11:52,579 --> 00:11:54,548 +表示附近物体的三维虚拟内容 + +227 +00:11:54,548 --> 00:11:56,783 +覆盖到摄像头源可视化上 + +228 +00:11:56,783 --> 00:12:02,389 +我们添加了一个辅助方法 +NISession 上的 worldTransform + +229 +00:12:02,389 --> 00:12:05,058 +这个方法在 ARKit 的坐标空间中 + +230 +00:12:05,058 --> 00:12:07,861 +会返回一个 worldTransform + +231 +00:12:07,861 --> 00:12:10,330 +它表示给定的附近物体 + +232 +00:12:10,330 --> 00:12:13,467 +在物理环境中可用的位置 + +233 +00:12:13,467 --> 00:12:18,272 +当不可用时 +这种方法会返回 nil + +234 +00:12:18,272 --> 00:12:20,174 +我们在演示视频中使用了这种方法 + +235 +00:12:20,174 --> 00:12:23,844 +将浮动的球体置于 +下一个展品的上方 + +236 +00:12:23,844 --> 00:12:26,513 +我们想让您尽可能容易地 + +237 +00:12:26,513 --> 00:12:29,917 +利用 Nearby Interaction 位置输出 + +238 +00:12:29,917 --> 00:12:34,221 +用您的应用来操纵 +AR 世界中的内容 + +239 +00:12:34,221 --> 00:12:38,859 +iOS 中 +两个强大的系统结合在一起 + +240 +00:12:38,859 --> 00:12:42,429 +您的用户必须在垂直和水平方向 + +241 +00:12:42,429 --> 00:12:46,033 +充分扫动设备 从而让相机辅助 + +242 +00:12:46,033 --> 00:12:49,403 +充分计算周围世界变换 + +243 +00:12:49,403 --> 00:12:52,472 +当用户扫动设备不充分时 + +244 +00:12:52,472 --> 00:12:55,542 +相机辅助无法完全覆盖到 + +245 +00:12:55,542 --> 00:12:59,947 +ARKit 世界变换 +这个方法就会返回 nil + +246 +00:12:59,947 --> 00:13:04,251 +如果世界变换对您的 +App 体验很重要 + +247 +00:13:04,251 --> 00:13:07,888 +就要注意引导用户充分扫动设备 + +248 +00:13:07,888 --> 00:13:11,291 +从而生成这种变换 + +249 +00:13:11,291 --> 00:13:14,027 +再来看看我们对 + +250 +00:13:14,027 --> 00:13:17,064 +NISessionDelegate +所做的一些补充 + +251 +00:13:17,064 --> 00:13:20,400 +以使您能够像在演示中看到的那样 + +252 +00:13:20,400 --> 00:13:22,035 +指导用户 + +253 +00:13:22,035 --> 00:13:24,505 +要帮助引导用户朝向指定对象 + +254 +00:13:24,505 --> 00:13:27,441 +一个 NISessionDelegate +回调函数 + +255 +00:13:27,441 --> 00:13:30,978 +会通过新的 +didUpdateAlgorithmConvergence 委托方法 + +256 +00:13:30,978 --> 00:13:33,881 +提供关于 Nearby Interaction + +257 +00:13:33,881 --> 00:13:36,149 +算法收敛的信息 + +258 +00:13:36,149 --> 00:13:39,286 +算法收敛可以帮助你理解为什么 + +259 +00:13:39,286 --> 00:13:42,389 +水平角度 垂直方向估计 + +260 +00:13:42,389 --> 00:13:45,025 +和 worldTransform 是不可用的 + +261 +00:13:45,025 --> 00:13:47,728 +以及用户可以做些什么 + +262 +00:13:47,728 --> 00:13:50,130 +来解决这些属性 + +263 +00:13:50,130 --> 00:13:51,231 +委托会提供 + +264 +00:13:51,231 --> 00:13:54,735 +一个新的 +NIAlgorithmConvergence 对象 + +265 +00:13:54,735 --> 00:13:58,605 +和一个可选的 NINearbyObject + +266 +00:13:58,605 --> 00:14:02,976 +只有当您在 NIConfiguration 中 +启用相机辅助时 + +267 +00:14:02,976 --> 00:14:07,047 +才会调用此委托方法 + +268 +00:14:07,047 --> 00:14:11,518 +让我们看看新的 +NIAlgorithmConvergence 类型 + +269 +00:14:11,518 --> 00:14:15,055 +NIAlgorithmConvergence +具有单一状态属性 + +270 +00:14:15,055 --> 00:14:18,792 +这种属性是 +NIAlgorithmConvergenceStatus 类型 + +271 +00:14:18,792 --> 00:14:22,796 +NIAlgorithmConvergenceStatus +是一个枚举类型 + +272 +00:14:22,796 --> 00:14:26,233 +表示算法是否收敛 + +273 +00:14:26,233 --> 00:14:28,435 +如果算法不收敛 + +274 +00:14:28,435 --> 00:14:30,270 +关联值的数组 + +275 +00:14:30,270 --> 00:14:36,109 +就会提供 +NIAlgorithmConvergenceStatus.Reasons + +276 +00:14:36,109 --> 00:14:38,178 +我们回到新的委托方法 + +277 +00:14:38,178 --> 00:14:39,413 +假如您要给用户更新 + +278 +00:14:39,413 --> 00:14:43,016 +相机辅助状态 + +279 +00:14:43,016 --> 00:14:44,985 +您可以打开收敛状态 + +280 +00:14:44,985 --> 00:14:46,520 +如果未知或收敛 + +281 +00:14:46,520 --> 00:14:49,857 +将该信息显示给用户 + +282 +00:14:49,857 --> 00:14:53,460 +请务必检查 NINearbyObject + +283 +00:14:53,460 --> 00:14:54,895 +当对象为 nil 时 + +284 +00:14:54,895 --> 00:14:59,733 +NIAlgorithmConvergence 状态 +适用于会话本身 + +285 +00:14:59,733 --> 00:15:04,271 +而不是特定的 NINearbyObject + +286 +00:15:04,271 --> 00:15:06,473 +当状态未收敛时 + +287 +00:15:06,473 --> 00:15:10,611 +它会还包含一个相关值 + +288 +00:15:10,611 --> 00:15:13,113 +描述算法不收敛的原因 + +289 +00:15:13,113 --> 00:15:16,016 +因此 可以使用本地化的描述 + +290 +00:15:16,016 --> 00:15:19,620 +来帮助您更好地与用户进行交流 + +291 +00:15:19,620 --> 00:15:23,390 +接下来让我们看看如何使用这些值 + +292 +00:15:23,390 --> 00:15:26,126 +一定要仔细检查 +notConverged 这个 case + +293 +00:15:26,126 --> 00:15:28,028 +和相关的 reason 值 + +294 +00:15:28,028 --> 00:15:31,265 +这样可以引导用户采取 + +295 +00:15:31,265 --> 00:15:33,767 +有助于生成关于附近对象 + +296 +00:15:33,767 --> 00:15:36,537 +所需信息的操作 + +297 +00:15:36,537 --> 00:15:38,906 +关联值是一个 + +298 +00:15:38,906 --> 00:15:41,942 +NIAlgorithmConvergence +StatusReasons 数组 + +299 +00:15:41,942 --> 00:15:45,345 +reason 值可以表明总体运动不足 + +300 +00:15:45,345 --> 00:15:48,649 +水平或垂直扫动中的运动不足 + +301 +00:15:48,649 --> 00:15:51,051 +和照明不足 + +302 +00:15:51,051 --> 00:15:56,089 +请注意 可能同时存在多种原因 + +303 +00:15:56,089 --> 00:15:59,593 +请根据对 App 中 +最重要的操作顺序 + +304 +00:15:59,593 --> 00:16:03,764 +指导用户完成每个操作 + +305 +00:16:03,764 --> 00:16:06,767 +回想一下我在演示中 +是如何移动手机的 + +306 +00:16:06,767 --> 00:16:09,469 +需要在水平和垂直方向上进行扫动 + +307 +00:16:09,469 --> 00:16:13,407 +以解析世界变换 + +308 +00:16:13,407 --> 00:16:15,175 +这是带有相机辅助的 + +309 +00:16:15,175 --> 00:16:18,712 +增强的 Nearby Interaction 模式 +最重要的一点 + +310 +00:16:18,712 --> 00:16:20,380 +我们做了一些额外的改变 + +311 +00:16:20,380 --> 00:16:23,317 +来帮助您更好地利用此模式 + +312 +00:16:23,317 --> 00:16:27,955 +以前 NISession 上的 +单个 isSupported 类变量 + +313 +00:16:27,955 --> 00:16:31,391 +就可以用来检查给定设备上 + +314 +00:16:31,391 --> 00:16:33,827 +是否支持 Nearby Interaction + +315 +00:16:33,827 --> 00:16:36,196 +现在这种方式已弃用 + +316 +00:16:36,196 --> 00:16:38,165 +随着相机辅助功能的增加 + +317 +00:16:38,165 --> 00:16:40,100 +我们通过在 NISession 中 + +318 +00:16:40,100 --> 00:16:43,670 +能返回一个新的 +NIDeviceCapability 对象的 + +319 +00:16:43,670 --> 00:16:48,041 +新的 deviceCapabilities 类成员 + +320 +00:16:48,041 --> 00:16:52,880 +使 Nearby Interaction +支持的设备功能更加具有描述性 + +321 +00:16:52,880 --> 00:16:54,581 +检查 + +322 +00:16:54,581 --> 00:16:57,451 +supportsPreciseDistanceMeasurement 属性 + +323 +00:16:57,451 --> 00:16:59,987 +在最低程度上相当于现在已弃用的 + +324 +00:16:59,987 --> 00:17:03,223 +isSupported 类变量 + +325 +00:17:03,223 --> 00:17:05,893 +当您确定了设备支持 + +326 +00:17:05,893 --> 00:17:07,961 +精确的距离测量 + +327 +00:17:07,961 --> 00:17:10,397 +你应该使用 NIDeviceCapability + +328 +00:17:10,397 --> 00:17:13,567 +来充分了解设备 App 中 + +329 +00:17:13,567 --> 00:17:18,505 +Nearby Interaction 的可用功能 + +330 +00:17:18,505 --> 00:17:22,075 +建议您通过检查 +NIDeviceCapability 对象的 + +331 +00:17:22,075 --> 00:17:23,977 +附加 supportsDirectionMeasurement + +332 +00:17:23,977 --> 00:17:27,881 +和 supportsCameraAssistance 属性 + +333 +00:17:27,881 --> 00:17:30,350 +来定制您的 App 体验 + +334 +00:17:30,350 --> 00:17:33,987 +以适应设备的功能 + +335 +00:17:33,987 --> 00:17:36,924 +并不是所有的设备都支持方向测量 + +336 +00:17:36,924 --> 00:17:39,092 +或相机辅助 + +337 +00:17:39,092 --> 00:17:41,962 +所以请确应用体验 + +338 +00:17:41,962 --> 00:17:45,132 +适合设备功能 + +339 +00:17:45,132 --> 00:17:48,368 +特别要注意的是 + +340 +00:17:48,368 --> 00:17:50,637 +为了更好地支持 Apple Watch + +341 +00:17:50,637 --> 00:17:53,807 +要加入仅限距离的体验 + +342 +00:17:53,807 --> 00:17:56,476 +以上就是将相机辅助作为 + +343 +00:17:56,476 --> 00:18:00,581 +通过 Nearby Interaction 增强 ARKit 的方式 +现在让我们把注意力转向 + +344 +00:18:00,581 --> 00:18:03,650 +辅助后台会话 + +345 +00:18:03,650 --> 00:18:07,187 +现在您可以在 App 中 +使用 Nearby Interaction + +346 +00:18:07,187 --> 00:18:11,325 +让用户指向其他设备 寻找朋友 + +347 +00:18:11,325 --> 00:18:13,360 +并根据距离和方向 + +348 +00:18:13,360 --> 00:18:16,830 +显示控件或其他 UI + +349 +00:18:16,830 --> 00:18:20,300 +然而 当 App 切换到后台 + +350 +00:18:20,300 --> 00:18:24,238 +或者当用户在 iOS +和 watchOS 上锁定屏幕时 + +351 +00:18:24,238 --> 00:18:27,074 +所有正在运行的 +NISession 都会被暂停 + +352 +00:18:27,074 --> 00:18:30,444 +直到 App 返回前台运行 + +353 +00:18:30,444 --> 00:18:34,715 +这意味着当你与你的配件交互时 + +354 +00:18:34,715 --> 00:18:38,018 +需要专注于实际的用户体验 + +355 +00:18:38,018 --> 00:18:43,423 +从 iOS 16 开始 +Nearby Interaction 已经实现免手持 + +356 +00:18:43,423 --> 00:18:45,659 +现在 当您走进有智能音箱的房间时 + +357 +00:18:45,659 --> 00:18:47,861 +你可以使用 +Nearby Interaction 来播放音乐 + +358 +00:18:47,861 --> 00:18:51,732 +Nearby Interaction +能帮您打开电动自行车 + +359 +00:18:51,732 --> 00:18:56,170 +或触发其他配件上的免手持操作 + +360 +00:18:56,170 --> 00:18:58,372 +即使用户没有通过辅助后台会话 + +361 +00:18:58,372 --> 00:19:00,607 +积极使用您的 App + +362 +00:19:00,607 --> 00:19:03,911 +Nearby Interaction 也能使用 + +363 +00:19:03,911 --> 00:19:05,946 +让我们看看如何实现这个 + +364 +00:19:05,946 --> 00:19:09,616 +振奋人心的的新功能 + +365 +00:19:09,616 --> 00:19:11,885 +我们先来回顾一下这个序列 + +366 +00:19:11,885 --> 00:19:15,923 +如何配置和运行 +一个带有配件的 NISession + +367 +00:19:15,923 --> 00:19:17,591 +你可能认出了这个序列 + +368 +00:19:17,591 --> 00:19:20,894 +去年的 WWDC 演讲中出现过 + +369 +00:19:20,894 --> 00:19:23,063 +配件通过数据通道 + +370 +00:19:23,063 --> 00:19:26,400 +发送其超宽带配件配置数据 +到您的 App + +371 +00:19:26,400 --> 00:19:29,169 +用这个数据 您可以创建一个 + +372 +00:19:29,169 --> 00:19:33,106 +NINearbyAccessoryConfiguration + +373 +00:19:33,106 --> 00:19:36,877 +创建一个 NISession +设置一个 NISessionDelegate + +374 +00:19:36,877 --> 00:19:40,280 +从配件获得超宽带测量值 + +375 +00:19:40,280 --> 00:19:43,050 +使用您的配置运行 NISession + +376 +00:19:43,050 --> 00:19:46,687 +会话将返回 +可共享的配置数据来设置配件 + +377 +00:19:46,687 --> 00:19:48,922 +以便与 App + +378 +00:19:48,922 --> 00:19:51,024 +进行互操作 + +379 +00:19:51,024 --> 00:19:53,560 +将此共享配置数据 + +380 +00:19:53,560 --> 00:19:55,195 +发送回配件后 + +381 +00:19:55,195 --> 00:19:58,265 +就可以在 App 和配件中 + +382 +00:19:58,265 --> 00:20:01,902 +接收超宽带测量数据 + +383 +00:20:01,902 --> 00:20:04,037 +有关配置和运行的所有详细信息 + +384 +00:20:04,037 --> 00:20:06,874 +与第三方配件的 +Nearby Interaction + +385 +00:20:06,874 --> 00:20:10,511 +请回顾去年的 WWDC 讲座 + +386 +00:20:10,511 --> 00:20:14,515 +接下来看看如何设置新的后台会话 + +387 +00:20:14,515 --> 00:20:17,584 +前面的序列图显示了 + +388 +00:20:17,584 --> 00:20:21,154 +App 和配件之间的数据流 + +389 +00:20:21,154 --> 00:20:24,091 +在配件和 App 之间 +使用低功耗蓝牙 + +390 +00:20:24,091 --> 00:20:29,263 +建立通信通道是很常见的做法 + +391 +00:20:29,263 --> 00:20:32,299 +当使用低功耗蓝牙与配件配对时 + +392 +00:20:32,299 --> 00:20:34,067 +您可以启用 Nearby Interaction + +393 +00:20:34,067 --> 00:20:37,905 +在后台启动和继续会话 + +394 +00:20:37,905 --> 00:20:40,574 +让我们仔细看看这是怎么做到的 + +395 +00:20:40,574 --> 00:20:43,977 +现在 您可以配置 App + +396 +00:20:43,977 --> 00:20:46,780 +来使用 Core Bluetooth +在后台时就能 + +397 +00:20:46,780 --> 00:20:48,682 +发现 连接到低功耗蓝牙配件 + +398 +00:20:48,682 --> 00:20:51,418 +并与低功耗蓝牙交换数据 + +399 +00:20:51,418 --> 00:20:54,388 +欲了解更多详情 请查看现有的 +《Core Bluetooth 编程指南》 + +400 +00:20:54,388 --> 00:20:59,426 +或 2017 年的 WWDC 讲座 + +401 +00:20:59,426 --> 00:21:02,296 +利用强大的后台操作从 + +402 +00:21:02,296 --> 00:21:05,432 +从 CoreBluetooth 高效发现配件 + +403 +00:21:05,432 --> 00:21:08,869 +并在后台运行您的 App + +404 +00:21:08,869 --> 00:21:12,306 +您的 App +可以启动一个 NISession + +405 +00:21:12,306 --> 00:21:14,074 +与低功耗蓝牙配件 + +406 +00:21:14,074 --> 00:21:18,345 +在后台也支持超宽带 + +407 +00:21:18,345 --> 00:21:21,381 +现在让我们看看序列图是如何更新 + +408 +00:21:21,381 --> 00:21:24,284 +以反映这种新模式 + +409 +00:21:24,284 --> 00:21:25,953 +要与这个配件交互 + +410 +00:21:25,953 --> 00:21:29,890 +首先 确保它与低功耗蓝牙配对 + +411 +00:21:29,890 --> 00:21:32,693 +然后 连接到配件 + +412 +00:21:32,693 --> 00:21:34,261 +当配件生成 + +413 +00:21:34,261 --> 00:21:37,831 +配件超宽带配置数据时 + +414 +00:21:37,831 --> 00:21:40,801 +应该能既发送到您的 App + +415 +00:21:40,801 --> 00:21:44,271 +又能执行 +Nearby Interaction GATT 服务 + +416 +00:21:44,271 --> 00:21:46,073 +接下来我会详细介绍 + +417 +00:21:46,073 --> 00:21:48,175 +最后 当您的 App 收到 + +418 +00:21:48,175 --> 00:21:51,078 +配件的配置数据时 + +419 +00:21:51,078 --> 00:21:55,682 +使用一个新的初始化器构造一个 +NINearbyAccessoryConfiguration 对象 + +420 +00:21:55,682 --> 00:21:59,453 +该初始化器 +同时提供 UWB 配置数据 + +421 +00:21:59,453 --> 00:22:02,155 +及它的蓝牙对等标识符 + +422 +00:22:02,155 --> 00:22:04,658 +使用这项配置运行您的 NISession + +423 +00:22:04,658 --> 00:22:07,294 +通过在 NISessionDelegate 中 + +424 +00:22:07,294 --> 00:22:11,164 +接收共享配置 来确保你完成了设置 + +425 +00:22:11,164 --> 00:22:15,502 +并将可共享的配置发送到配件 + +426 +00:22:15,502 --> 00:22:18,639 +为了让你的配件在它的蓝牙标识符 + +427 +00:22:18,639 --> 00:22:20,774 +和超宽带配置之间 + +428 +00:22:20,774 --> 00:22:23,277 +创建关系 + +429 +00:22:23,277 --> 00:22:27,781 +它必须实现新的 +Nearby Interaction GATT 服务 + +430 +00:22:27,781 --> 00:22:31,285 +Nearby Interaction 服务 +包含单个加密特性 + +431 +00:22:31,285 --> 00:22:35,289 +叫做配件配置数据 + +432 +00:22:35,289 --> 00:22:38,492 +它包含用于初始化 +NINearbyAccessoryConfiguration 对象 + +433 +00:22:38,492 --> 00:22:42,396 +相同 UWB 配置 + +434 +00:22:42,396 --> 00:22:43,697 +数据 + +435 +00:22:43,697 --> 00:22:48,869 +iOS 使用这个特性来验证 + +436 +00:22:48,869 --> 00:22:53,473 +在您的蓝牙对等标识符 +和您的 NISession 之间的关联 + +437 +00:22:53,473 --> 00:22:57,845 +您的应用无法直接读取此特征 + +438 +00:22:57,845 --> 00:23:00,113 +您可以在 +developer.apple.com/nearby-interaction 上 + +439 +00:23:00,113 --> 00:23:02,883 +找到更多关于 + +440 +00:23:02,883 --> 00:23:07,788 +Nearby Interaction GATT 服务的细节 + +441 +00:23:07,788 --> 00:23:11,592 +如果您的配件同时 +支持多个 NISession + +442 +00:23:11,592 --> 00:23:15,662 +创建配件配置数据的多个实例 + +443 +00:23:15,662 --> 00:23:20,167 +每个 NISession 的 +UWB 配置都不同 + +444 +00:23:20,167 --> 00:23:23,203 +这一点是配件所必需的 + +445 +00:23:23,203 --> 00:23:27,207 +让我们深入研究一些代码 +来讨论一下 + +446 +00:23:27,207 --> 00:23:30,277 +App 中需要实现什么 + +447 +00:23:30,277 --> 00:23:33,714 +配件后台会话要求配件 + +448 +00:23:33,714 --> 00:23:37,017 +与用户的 iPhone +进行 LE 配对 + +449 +00:23:37,017 --> 00:23:40,954 +您的应用负责触发这个过程 + +450 +00:23:40,954 --> 00:23:44,958 +要触发它 实施扫描配件的方法 + +451 +00:23:44,958 --> 00:23:50,364 +连接到配件并发现它的服务和特性 + +452 +00:23:50,364 --> 00:23:53,000 +然后 实施一个方法来读取 + +453 +00:23:53,000 --> 00:23:56,303 +配件的加密特征之一 + +454 +00:23:56,303 --> 00:23:59,273 +您只需执行一次 + +455 +00:23:59,273 --> 00:24:03,844 +它将向用户显示接受配对的提示 + +456 +00:24:03,844 --> 00:24:06,480 +辅助后台会话也需要 + +457 +00:24:06,480 --> 00:24:09,550 +与配件进行蓝牙连接 + +458 +00:24:09,550 --> 00:24:12,386 +即使您的应用在后台 也必须要 + +459 +00:24:12,386 --> 00:24:15,055 +能够形成这种连接 + +460 +00:24:15,055 --> 00:24:18,825 +那么就要实施一种方法来发起到 + +461 +00:24:18,825 --> 00:24:20,427 +配件的连接尝试 + +462 +00:24:20,427 --> 00:24:22,829 +即使配件不在蓝牙范围内 + +463 +00:24:22,829 --> 00:24:26,500 +您也应该这样做 + +464 +00:24:26,500 --> 00:24:29,636 +然后 当你的应用 +由 Core Bluetooth 重新启动后 + +465 +00:24:29,636 --> 00:24:35,175 +实施 CBManagerDelegate 方法 + +466 +00:24:35,175 --> 00:24:38,512 +并在建立连接时进行处理 + +467 +00:24:38,512 --> 00:24:42,850 +现在您就可以运行配件后台会话了 + +468 +00:24:42,850 --> 00:24:45,352 +通过提供配件的 UWB 配置数据 + +469 +00:24:45,352 --> 00:24:48,355 +和来自 +CBPeripheral 标识符的 + +470 +00:24:48,355 --> 00:24:53,060 +蓝牙对等标识符 + +471 +00:24:53,060 --> 00:24:55,896 +来创建 +NINearbyAccessoryConfiguration 对象 + +472 +00:24:55,896 --> 00:24:58,699 +使用该配置 +运行 NISession + +473 +00:24:58,699 --> 00:25:02,102 +它会在您的 App 在后台时运行 + +474 +00:25:02,102 --> 00:25:03,403 +内容就这么多了 + +475 +00:25:03,403 --> 00:25:05,873 +不过 Xcode 中还有一个设置 + +476 +00:25:05,873 --> 00:25:09,443 +需要更新 + +477 +00:25:09,443 --> 00:25:13,080 +这个后台模式需要 +Nearby Interaction 字符串 + +478 +00:25:13,080 --> 00:25:17,618 +位置在应用的 Info.plist 中 +UIBackgroundModes 数组里 + +479 +00:25:17,618 --> 00:25:20,721 +您还可以使用 +Xcode 功能编辑器 + +480 +00:25:20,721 --> 00:25:23,156 +添加这个后台模式 + +481 +00:25:23,156 --> 00:25:25,192 +您还需要保证 + +482 +00:25:25,192 --> 00:25:29,263 +启用了“使用低功耗蓝牙配件” +以确保您的 App + +483 +00:25:29,263 --> 00:25:33,734 +可以在后台连接配件 + +484 +00:25:33,734 --> 00:25:35,502 +关于这个新的配件后台会话 + +485 +00:25:35,502 --> 00:25:38,539 +有一个重要的注意事项 + +486 +00:25:38,539 --> 00:25:41,208 +当您的 App 在后台时 + +487 +00:25:41,208 --> 00:25:45,379 +NISession 将继续运行 +并且不会被暂停 + +488 +00:25:45,379 --> 00:25:49,616 +因此配件上可以获取超宽带测量值 + +489 +00:25:49,616 --> 00:25:53,253 +您必须在配件上的超宽带测量值上 + +490 +00:25:53,253 --> 00:25:54,988 +使用并进行操作 + +491 +00:25:54,988 --> 00:25:58,192 +您的 App 不会收到运行时间 + +492 +00:25:58,192 --> 00:26:00,928 +您也不会收到 +didUpdateNearbyObjectand + +493 +00:26:00,928 --> 00:26:02,262 +委托回调 + +494 +00:26:02,262 --> 00:26:06,066 +直到 App 返回到前台才会收到 + +495 +00:26:06,066 --> 00:26:08,202 +使用这种新的后台模式时 + +496 +00:26:08,202 --> 00:26:11,371 +我们来回顾一下以下的最优方法 + +497 +00:26:11,371 --> 00:26:13,974 +触发与您的配件的 LE 配对 + +498 +00:26:13,974 --> 00:26:17,344 +将提示用户接受配对 + +499 +00:26:17,344 --> 00:26:20,314 +这样做的时候 用户能直观地明白 + +500 +00:26:20,314 --> 00:26:23,283 +他们为什么要配对配件 + +501 +00:26:23,283 --> 00:26:26,153 +可能是在创建 +与配件关系的设置流中 + +502 +00:26:26,153 --> 00:26:29,156 +也可能是用户明确表示 + +503 +00:26:29,156 --> 00:26:32,759 +希望与配件交互时触发 + +504 +00:26:32,759 --> 00:26:34,928 +当您的 App 处于后台时 + +505 +00:26:34,928 --> 00:26:37,865 +您的 NISession +不会被暂停 + +506 +00:26:37,865 --> 00:26:40,467 +但它不会收到 +didUpdateNearbyObject + +507 +00:26:40,467 --> 00:26:42,369 +委托回调 + +508 +00:26:42,369 --> 00:26:45,539 +但是 您的配件将收到 + +509 +00:26:45,539 --> 00:26:47,541 +超宽带测量值 + +510 +00:26:47,541 --> 00:26:50,677 +直接在您的配件上处理这些测量值 + +511 +00:26:50,677 --> 00:26:54,515 +以确定用户应该采取什么操作 + +512 +00:26:54,515 --> 00:26:56,884 +最后 通过在重要的用户交互过程中 + +513 +00:26:56,884 --> 00:27:00,420 +仅从配件发送数据到 App + +514 +00:27:00,420 --> 00:27:02,823 +从而来管理电池使用 + +515 +00:27:02,823 --> 00:27:06,460 +例如 向用户显示通知 + +516 +00:27:06,460 --> 00:27:09,396 +以上就是您在后台会话中 +需要了解的全部内容 + +517 +00:27:09,396 --> 00:27:14,334 +接下来 最后一个主题是 +关于第三方硬件支持 + +518 +00:27:14,334 --> 00:27:17,838 +今天 我很高兴地向您宣布 + +519 +00:27:17,838 --> 00:27:20,908 +之前与 U1 兼容的 +Beta 版开发工具包 + +520 +00:27:20,908 --> 00:27:26,046 +现在已经结束 Beta 版测试 +可以更广泛地使用 + +521 +00:27:26,046 --> 00:27:29,616 +请访问 +developer.apple.com/nearby-interaction + +522 +00:27:29,616 --> 00:27:31,084 +了解更多关于 + +523 +00:27:31,084 --> 00:27:35,055 +兼容的超宽带开发套件 + +524 +00:27:35,055 --> 00:27:36,857 +我们还更新了 + +525 +00:27:36,857 --> 00:27:39,259 +配件制造商的规范 + +526 +00:27:39,259 --> 00:27:41,795 +以支持新的配件后台会话 + +527 +00:27:41,795 --> 00:27:44,698 +包括 Nearby Interaction GATT 服务 + +528 +00:27:44,698 --> 00:27:47,701 +内容也在刚才的网站中 + +529 +00:27:47,701 --> 00:27:52,639 +那么 让我们总结一下 +本次讲座中讨论的内容 + +530 +00:27:52,639 --> 00:27:56,877 +现在 Nearby Interaction 包含了 +新的相机辅助模式 + +531 +00:27:56,877 --> 00:28:00,380 +紧密地集成了 ARKit +和 Nearby Interaction + +532 +00:28:00,380 --> 00:28:02,549 +为您提供无缝体验 + +533 +00:28:02,549 --> 00:28:05,919 +以创造出空间感知体验 + +534 +00:28:05,919 --> 00:28:09,823 +引导用户到附近的对象 + +535 +00:28:09,823 --> 00:28:13,293 +配件后台会话使您能够发起会话 + +536 +00:28:13,293 --> 00:28:16,063 +并将会话扩展到后台 + +537 +00:28:16,063 --> 00:28:19,199 +让您为用户打造更加轻松 + +538 +00:28:19,199 --> 00:28:21,768 +无需手持的体验 + +539 +00:28:21,768 --> 00:28:23,737 +我们宣布了第三方兼容 + +540 +00:28:23,737 --> 00:28:28,509 +超宽带硬件支持的更新 令人振奋 + +541 +00:28:28,509 --> 00:28:31,845 +以上就是今年的 +Nearby Interaction 更新内容 + +542 +00:28:31,845 --> 00:28:33,447 +请下载演示视频 + +543 +00:28:33,447 --> 00:28:36,416 +请对更新的功能提供反馈 + +544 +00:28:36,416 --> 00:28:39,219 +请查看更新的第三方规范 + +545 +00:28:39,219 --> 00:28:43,190 +并去创造具有空间体验的 +神奇 App 吧 + +546 +00:28:43,190 --> 00:28:44,892 +谢谢 + +547 +00:28:44,892 --> 00:28:48,929 +♪ + diff --git "a/zho/2022 Session 10009 What\342\200\231s new in iPad app design.srt" "b/zho/2022 Session 10009 What\342\200\231s new in iPad app design.srt" new file mode 100644 index 0000000..6ead922 --- /dev/null +++ "b/zho/2022 Session 10009 What\342\200\231s new in iPad app design.srt" @@ -0,0 +1,1583 @@ +1 +00:00:00,000 --> 00:00:04,638 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:04,638 --> 00:00:08,775 +♪ + +3 +00:00:08,775 --> 00:00:11,845 +Bryant Jow:您好 欢迎来到 +“iPad App 设计”讲座 + +4 +00:00:11,845 --> 00:00:12,946 +我是 Bryant Jow + +5 +00:00:12,946 --> 00:00:14,147 +Grant Paul:我是 Grant Paul + +6 +00:00:14,147 --> 00:00:16,250 +我们来自 Apple 设计团队 + +7 +00:00:16,250 --> 00:00:18,318 +Bryant:今天 我们将 +向您介绍在 iPadOS 16 中 + +8 +00:00:18,318 --> 00:00:20,521 +有关 UIKit +和 SwiftUI 的更新内容 + +9 +00:00:20,521 --> 00:00:21,655 +以及如何通过一些简单的步骤 + +10 +00:00:21,655 --> 00:00:24,958 +将这些新内容融入您的 App 里 + +11 +00:00:24,958 --> 00:00:26,426 +在 iPadOS 16 中 + +12 +00:00:26,426 --> 00:00:28,862 +用户可以利用支持更大分辨率的优势 + +13 +00:00:28,862 --> 00:00:31,832 +使用扩展显示器和显示缩放功能 + +14 +00:00:31,832 --> 00:00:33,367 +以及使用 +舞台管理器 (Stage Manager) + +15 +00:00:33,367 --> 00:00:35,569 +在单独窗口中管理多个 App + +16 +00:00:35,569 --> 00:00:38,372 +这对 iPad App 意味着什么呢? + +17 +00:00:38,372 --> 00:00:40,674 +这意味着 +您要在设计 App 时充分考虑 + +18 +00:00:40,674 --> 00:00:42,075 +更大的屏幕和不同分辨率的情况 + +19 +00:00:42,075 --> 00:00:45,546 +以及支持 iPadOS 的不同输入方式 + +20 +00:00:45,546 --> 00:00:47,614 +现在 您的 iPad App 应该考虑 + +21 +00:00:47,614 --> 00:00:49,283 +如何像桌面应用那样 + +22 +00:00:49,283 --> 00:00:52,319 +在 iPad 上使用一些高级操作 + +23 +00:00:52,319 --> 00:00:54,788 +这就是我们为了 +让 App 变得更强大、更易用 + +24 +00:00:54,788 --> 00:00:58,358 +而作出的多种改进和更新的原因 + +25 +00:00:58,358 --> 00:01:01,528 +下面是我们的更新内容 + +26 +00:01:01,528 --> 00:01:04,064 +工具栏及其自定义能力 + +27 +00:01:04,064 --> 00:01:06,700 +文档菜单 + +28 +00:01:06,700 --> 00:01:08,635 +编辑菜单 + +29 +00:01:08,635 --> 00:01:10,604 +查找和替换功能 + +30 +00:01:10,604 --> 00:01:12,239 +导航 + +31 +00:01:12,239 --> 00:01:13,807 +搜索 + +32 +00:01:13,807 --> 00:01:15,542 +表格 + +33 +00:01:15,542 --> 00:01:17,878 +以及选择功能 + +34 +00:01:17,878 --> 00:01:19,446 +今天 我们将向您展示 + +35 +00:01:19,446 --> 00:01:21,281 +如何在下面两种功能设计中 + +36 +00:01:21,281 --> 00:01:24,251 +组合这些更新内容 + +37 +00:01:24,251 --> 00:01:28,055 +文档编辑和内容浏览 + +38 +00:01:28,055 --> 00:01:29,957 +我们将从文档编辑开始 + +39 +00:01:29,957 --> 00:01:31,725 +看看如何在您的 App 中 + +40 +00:01:31,725 --> 00:01:34,361 +帮助用户提升他们的使用效率 + +41 +00:01:34,361 --> 00:01:36,330 +我们来看工具栏 + +42 +00:01:36,330 --> 00:01:38,999 +工具栏是 App 设计中 +非常重要的组件 + +43 +00:01:38,999 --> 00:01:41,168 +因为它组合了 App 的功能 + +44 +00:01:41,168 --> 00:01:42,469 +工具栏的设计 + +45 +00:01:42,469 --> 00:01:45,038 +会影响人们工作的效率 + +46 +00:01:45,038 --> 00:01:49,309 +这是 iPadOS 15 中 +Pages App 中的工具栏 + +47 +00:01:49,309 --> 00:01:52,646 +在 iPadOS 16 中 +我们引入了新的工具栏布局 + +48 +00:01:52,646 --> 00:01:54,681 +将标题与左侧对齐 + +49 +00:01:54,681 --> 00:01:58,018 +并允许工具栏的中间位置 +容纳更多按钮 + +50 +00:01:58,018 --> 00:02:00,554 +让我们拉近一点 + +51 +00:02:00,554 --> 00:02:02,756 +这是工具栏的开头部分 + +52 +00:02:02,756 --> 00:02:05,292 +它应该包含 + +53 +00:02:05,292 --> 00:02:06,693 +帮助用户在文档内外进行导航的功能 + +54 +00:02:06,693 --> 00:02:08,962 +比如后退和侧边栏按钮 + +55 +00:02:08,962 --> 00:02:11,231 +它会显示新的文档标题和菜单 + +56 +00:02:11,231 --> 00:02:13,600 +我们稍后再来讨论 + +57 +00:02:13,600 --> 00:02:15,302 +在比以往更大的工具栏空间里 + +58 +00:02:15,302 --> 00:02:18,305 +App 可以将常用功能放到中间位置 + +59 +00:02:18,305 --> 00:02:19,673 +在 iPadOS 16 中 + +60 +00:02:19,673 --> 00:02:22,709 +Pages App 在这里 +提供了内容插入的功能 + +61 +00:02:22,709 --> 00:02:23,377 +您应该思考 + +62 +00:02:23,377 --> 00:02:25,412 +您的 App 中最常用的操作是什么 + +63 +00:02:25,412 --> 00:02:27,848 +让人们可以通过一键访问提高效率 + +64 +00:02:27,848 --> 00:02:30,117 +但请注意 不要在这里 + +65 +00:02:30,117 --> 00:02:31,919 +包含太多的功能项目 + +66 +00:02:31,919 --> 00:02:33,720 +让我们来看看当您的 App 中 + +67 +00:02:33,720 --> 00:02:36,223 +包含许多功能时应该怎么办 + +68 +00:02:36,223 --> 00:02:39,826 +在 iPadOS 16 中 +您可以启用自定义的工具栏 + +69 +00:02:39,826 --> 00:02:41,028 +这样人们就可以整理 + +70 +00:02:41,028 --> 00:02:43,230 +对他们来说最重要的操作功能 + +71 +00:02:43,230 --> 00:02:45,032 +如果您的 App 有很多工具栏项 + +72 +00:02:45,032 --> 00:02:47,534 +或并非所有人都需要的高级功能 + +73 +00:02:47,534 --> 00:02:50,103 +您应该考虑启用自定义工具栏 + +74 +00:02:50,103 --> 00:02:51,839 +注意中间位置的元素 + +75 +00:02:51,839 --> 00:02:55,342 +可以进行添加、删除或重新排列操作 + +76 +00:02:55,342 --> 00:02:57,945 +但这之外的工具栏项目不可自定义 + +77 +00:02:57,945 --> 00:03:00,147 +因为这些可能包括导航按钮 + +78 +00:03:00,147 --> 00:03:04,985 +或一些需要始终可访问的重要功能 + +79 +00:03:04,985 --> 00:03:08,188 +工具栏项目也可以分组或折叠 + +80 +00:03:08,188 --> 00:03:10,224 +使用分组将相关功能合并到 + +81 +00:03:10,224 --> 00:03:13,026 +工具栏或溢出菜单中 + +82 +00:03:13,026 --> 00:03:14,728 +在 Pages App 中 +类似的操作 + +83 +00:03:14,728 --> 00:03:18,599 +如插入表格、图表、形状和照片 + +84 +00:03:18,599 --> 00:03:20,734 +都被组合在一起 + +85 +00:03:20,734 --> 00:03:22,870 +当工具栏没有足够的空间时 + +86 +00:03:22,870 --> 00:03:25,239 +这些功能将折叠成一个加号按钮 + +87 +00:03:25,239 --> 00:03:26,707 +您还可以让宽工具栏项目 + +88 +00:03:26,707 --> 00:03:30,878 +在较小的窗口尺寸下 +折叠成紧凑的标识 + +89 +00:03:30,878 --> 00:03:35,816 +现在 让我们看一下工具栏的尾部 + +90 +00:03:35,816 --> 00:03:38,385 +这里可能包含多种项目 + +91 +00:03:38,385 --> 00:03:40,988 +任何可以调用检查器的按钮 + +92 +00:03:40,988 --> 00:03:43,991 +在任何窗口大小下 +都保持可见的重要选项 + +93 +00:03:43,991 --> 00:03:45,792 +和一个可供用户 + +94 +00:03:45,792 --> 00:03:47,528 +调用隐藏项目和自定义工具栏的 + +95 +00:03:47,528 --> 00:03:50,497 +可选溢出按钮 + +96 +00:03:50,497 --> 00:03:52,533 +当调整 App 窗口大小 +导致空间不足时 + +97 +00:03:52,533 --> 00:03:55,068 +中间的工具栏项目将自动隐藏 + +98 +00:03:55,068 --> 00:03:57,738 +同时显示溢出菜单按钮 + +99 +00:03:57,738 --> 00:03:59,840 +当窗口调整得更小时 + +100 +00:03:59,840 --> 00:04:03,076 +则只保留工具栏的头尾两部分 + +101 +00:04:03,076 --> 00:04:04,945 +因此为了确保在多数窗口大小下可见 + +102 +00:04:04,945 --> 00:04:07,314 +请确保您的重要功能 + +103 +00:04:07,314 --> 00:04:09,917 +放置在工具栏的尾部位置 + +104 +00:04:09,917 --> 00:04:12,119 +让我们来快速回顾一下刚才的内容 + +105 +00:04:12,119 --> 00:04:13,587 +考虑是否需要将常用功能 + +106 +00:04:13,587 --> 00:04:16,290 +放置在工具栏中 + +107 +00:04:16,290 --> 00:04:19,026 +将重要功能放在工具栏尾部 + +108 +00:04:19,026 --> 00:04:22,296 +以避免在较小的窗口中溢出 + +109 +00:04:22,296 --> 00:04:25,265 +如果您的 App +有许多工具栏项和高级功能 + +110 +00:04:25,265 --> 00:04:27,234 +请使用自定义功能 + +111 +00:04:27,234 --> 00:04:29,002 +并且只要有可能 + +112 +00:04:29,002 --> 00:04:32,773 +请尝试将类似的项目归为一组 + +113 +00:04:32,773 --> 00:04:34,641 +现在让我们看一下前面提到的 + +114 +00:04:34,641 --> 00:04:36,376 +新的文档菜单 + +115 +00:04:36,376 --> 00:04:39,279 +为了让人们更容易在不同 App 的相同位置 + +116 +00:04:39,279 --> 00:04:41,215 +找到与文档相关的操作 + +117 +00:04:41,215 --> 00:04:44,451 +我们在工具栏中 +引入了新的标题和菜单 + +118 +00:04:44,451 --> 00:04:47,554 +该布局的设计是为了像快速查看 + +119 +00:04:47,554 --> 00:04:50,324 +或 Keynote 讲演这样的 +文档编辑 App 而设计的 + +120 +00:04:50,324 --> 00:04:52,659 +请注意 这些 App +也可能有浏览器视图 + +121 +00:04:52,659 --> 00:04:54,061 +可以在文档标题的附近 + +122 +00:04:54,061 --> 00:04:55,963 +显示为后退按钮 + +123 +00:04:55,963 --> 00:04:57,331 +如果您的 App + +124 +00:04:57,331 --> 00:04:59,633 +主要用于编辑或查看文档 + +125 +00:04:59,633 --> 00:05:01,802 +您应该考虑使用这个新菜单 + +126 +00:05:01,802 --> 00:05:03,637 +让我们通过单击文档标题 + +127 +00:05:03,637 --> 00:05:05,372 +打开 Keynote 讲演的文档菜单 + +128 +00:05:05,372 --> 00:05:07,474 +在这里 您可以看到 +包含标准文档操作 + +129 +00:05:07,474 --> 00:05:11,845 +和该 App 特定操作的功能合集 + +130 +00:05:11,845 --> 00:05:13,947 +那么 这里应该放什么? + +131 +00:05:13,947 --> 00:05:15,749 +这个菜单应该包含 + +132 +00:05:15,749 --> 00:05:19,086 +影响整个文档的操作 + +133 +00:05:19,086 --> 00:05:21,255 +下面是一些应该放在菜单中的 + +134 +00:05:21,255 --> 00:05:23,490 +标准操作 + +135 +00:05:23,490 --> 00:05:28,529 +如复制、重命名、移动、导出和打印 + +136 +00:05:28,529 --> 00:05:31,565 +您还可以为您的 App +添加自定义操作 + +137 +00:05:31,565 --> 00:05:34,701 +但并非所有内容 +都应该放在文档菜单中 + +138 +00:05:34,701 --> 00:05:37,171 +比如 会将内容带至 App 以外的操作 + +139 +00:05:37,171 --> 00:05:38,972 +应该放在共享之下 + +140 +00:05:38,972 --> 00:05:42,509 +另外 直接影响文档内容的操作 + +141 +00:05:42,509 --> 00:05:44,444 +应该支持自定义工具栏 + +142 +00:05:44,444 --> 00:05:48,682 +并适时的出现在编辑菜单中 + +143 +00:05:48,682 --> 00:05:51,084 +接下来 我想谈谈几个功能特性 + +144 +00:05:51,084 --> 00:05:54,188 +可以帮助用户 +在 iPad App 中更有效地工作 + +145 +00:05:54,188 --> 00:05:56,723 +让我们看看编辑菜单 + +146 +00:05:56,723 --> 00:05:58,859 +这些菜单可能会出现在选定的文本上 + +147 +00:05:58,859 --> 00:06:01,862 +并包含编辑选项 例如复制和粘贴 + +148 +00:06:01,862 --> 00:06:05,132 +在 iPadOS 16 中 +编辑菜单焕然一新 + +149 +00:06:05,132 --> 00:06:08,302 +并针对触控和指针操作进行了优化 + +150 +00:06:08,302 --> 00:06:11,038 +使用触控时 菜单将水平显示 + +151 +00:06:11,038 --> 00:06:13,006 +而且用户现在可以 + +152 +00:06:13,006 --> 00:06:16,276 +在选项列表间来回滚动 + +153 +00:06:16,276 --> 00:06:18,178 +当使用指针时 + +154 +00:06:18,178 --> 00:06:20,147 +编辑菜单将通过垂直布局 + +155 +00:06:20,147 --> 00:06:22,182 +显示更全面的功能列表 + +156 +00:06:22,182 --> 00:06:23,684 +您的 App 应该同时支持 + +157 +00:06:23,684 --> 00:06:27,054 +指针和触控两种交互方式的显示风格 + +158 +00:06:27,054 --> 00:06:30,157 +当您将这些编辑菜单 +运用到您的 App 中时 + +159 +00:06:30,157 --> 00:06:33,327 +请您记住这几件事 + +160 +00:06:33,327 --> 00:06:35,128 +不要删除标准操作 + +161 +00:06:35,128 --> 00:06:37,097 +比如剪切、复制和粘贴 + +162 +00:06:37,097 --> 00:06:39,800 +这些编辑工具 +对许多工作流程都很重要 + +163 +00:06:39,800 --> 00:06:42,069 +并且应该始终可用 + +164 +00:06:42,069 --> 00:06:43,937 +您应该将您的自定义操作 + +165 +00:06:43,937 --> 00:06:46,406 +尽可能布局在相关的系统操作的附近 + +166 +00:06:46,406 --> 00:06:49,510 +例如在 iPadOS 16 中 +备忘录 App 将 + +167 +00:06:49,510 --> 00:06:53,547 +“格式”与“核对清单” +放在同一部分 + +168 +00:06:53,547 --> 00:06:56,383 +编辑菜单不仅限于文本字段 + +169 +00:06:56,383 --> 00:06:59,419 +它们还可以应用于文档画布上的对象 + +170 +00:06:59,419 --> 00:07:04,491 +这是在 Keynote 讲演中 +通过触控操作选择图层的菜单 + +171 +00:07:04,491 --> 00:07:07,628 +而这是通过指针操作时的菜单 + +172 +00:07:07,628 --> 00:07:10,631 +请尝试将这些菜单 +集成到任何可编辑的内容中 + +173 +00:07:10,631 --> 00:07:15,068 +以便用户在使用 +您的 App 时提高工作效率 + +174 +00:07:15,068 --> 00:07:16,603 +这就是编辑菜单 + +175 +00:07:16,603 --> 00:07:20,040 +现在 让我们 +深入了解查找和替换功能 + +176 +00:07:20,040 --> 00:07:22,743 +在 iPadOS 16 中 +我们引入了查找和替换功能 + +177 +00:07:22,743 --> 00:07:25,212 +使用系统键盘 我们可以快速搜索 + +178 +00:07:25,212 --> 00:07:30,217 +文档中的特定单词、短语等 + +179 +00:07:30,217 --> 00:07:32,085 +该功能也支持高级搜索 + +180 +00:07:32,085 --> 00:07:34,588 +比如匹配短语的特定部分 + +181 +00:07:34,588 --> 00:07:38,091 +或用不同的词替换所有匹配项 + +182 +00:07:38,091 --> 00:07:40,827 +当 iPad 连接到外部键盘时 + +183 +00:07:40,827 --> 00:07:43,096 +查找和替换界面会以紧凑形式 + +184 +00:07:43,096 --> 00:07:46,834 +出现在 App 上 + +185 +00:07:46,834 --> 00:07:49,069 +为了便于查找和替换 + +186 +00:07:49,069 --> 00:07:51,772 +请考虑在溢出菜单中添加相应按钮 + +187 +00:07:51,772 --> 00:07:55,142 +以及设置相应的快捷键 + +188 +00:07:55,142 --> 00:07:56,543 +这些是我们为文档编辑 + +189 +00:07:56,543 --> 00:07:58,879 +引入的一些新功能 + +190 +00:07:58,879 --> 00:08:00,514 +现在我要把话题 +交给 Grant Paul + +191 +00:08:00,514 --> 00:08:02,549 +他将为我们讨论更多的改进内容 + +192 +00:08:02,549 --> 00:08:05,185 +Grant:谢谢 Bryant + +193 +00:08:05,185 --> 00:08:07,554 +接下来我来说说内容浏览的改进 + +194 +00:08:07,554 --> 00:08:11,024 +您在许多 +不同的 iPad App 中工作 + +195 +00:08:11,024 --> 00:08:14,428 +而内容浏览器 +在 iPad 上无处不在 + +196 +00:08:14,428 --> 00:08:17,231 +无论您是 +在照片应用的照片库中进行管理 + +197 +00:08:17,231 --> 00:08:20,901 +或是浏览 Apple Music +在 Pages 文稿中选取文稿 + +198 +00:08:20,901 --> 00:08:23,637 +iPadOS 16 在内容浏览方面 + +199 +00:08:23,637 --> 00:08:26,607 +有一些很好的新功能和模式 + +200 +00:08:26,607 --> 00:08:28,976 +我将重点介绍三个部分 + +201 +00:08:28,976 --> 00:08:31,778 +它们对 App 非常重要 + +202 +00:08:31,778 --> 00:08:36,183 +首先是 App 导航的更新 + +203 +00:08:36,183 --> 00:08:39,820 +iPadOS 16 +拥有全新的导航风格 + +204 +00:08:39,820 --> 00:08:43,257 +我们称之为“浏览器风格”导航 + +205 +00:08:43,257 --> 00:08:47,528 +例如 文件 App 的 +后退和前进按钮 + +206 +00:08:47,528 --> 00:08:49,730 +可以让您轻松浏览文件夹 + +207 +00:08:49,730 --> 00:08:53,967 +这些功能 +可能位于侧边栏中的不同位置 + +208 +00:08:53,967 --> 00:08:56,170 +使用浏览器风格的导航 + +209 +00:08:56,170 --> 00:08:58,839 +可以由您的 App 选择 + +210 +00:08:58,839 --> 00:09:01,942 +在标题左侧的按钮 + +211 +00:09:01,942 --> 00:09:05,546 +您应该确保只保留那些导航按钮 + +212 +00:09:05,546 --> 00:09:09,883 +像后退和前进 或是侧边栏按钮 + +213 +00:09:09,883 --> 00:09:12,419 +浏览器风格的导航效果很好 + +214 +00:09:12,419 --> 00:09:15,622 +当您的 App 具有 +复杂的逻辑结构时 + +215 +00:09:15,622 --> 00:09:19,026 +人们会经常在不同功能之间切换 + +216 +00:09:19,026 --> 00:09:23,096 +比如文件浏览器或网络浏览器等等 + +217 +00:09:23,096 --> 00:09:27,534 +如果您的 App 架构 +较浅或扁平 比如照片 App + +218 +00:09:27,534 --> 00:09:30,370 +您可能不需要浏览器风格的导航功能 + +219 +00:09:30,370 --> 00:09:34,341 +因为 App 中的功能 +都集中在侧边栏 + +220 +00:09:34,341 --> 00:09:38,011 +只需点一下就可以了 + +221 +00:09:38,011 --> 00:09:41,181 +如果您确实需要浏览器风格的导航 + +222 +00:09:41,181 --> 00:09:45,285 +那么它会与 iPadOS 16 中的 +另一个新功能相得益彰 + +223 +00:09:45,285 --> 00:09:50,390 +将搜索栏放在导航栏的右上角 + +224 +00:09:50,390 --> 00:09:53,894 +当您的搜索栏用来 + +225 +00:09:53,894 --> 00:09:57,364 +过滤同一屏幕上看到的内容时 + +226 +00:09:57,364 --> 00:09:59,600 +搜索栏在右上角是很好的布局方式 + +227 +00:09:59,600 --> 00:10:02,236 +即使它放置在导航栏里 + +228 +00:10:02,236 --> 00:10:04,571 +也可支持搜索建议 + +229 +00:10:04,571 --> 00:10:09,643 +输入内容时 +搜索建议会立即显示出来 + +230 +00:10:09,643 --> 00:10:12,513 +您的 App +可以建议最近的搜索内容 + +231 +00:10:12,513 --> 00:10:14,648 +它还可以为搜索什么内容 + +232 +00:10:14,648 --> 00:10:16,517 +提出建议 + +233 +00:10:16,517 --> 00:10:21,355 +还可以建议过滤器缩小搜索范围 + +234 +00:10:21,355 --> 00:10:24,324 +再说一次 右上角的搜索是用于 + +235 +00:10:24,324 --> 00:10:27,394 +搜索程序内下方显示的内容 + +236 +00:10:27,394 --> 00:10:30,097 +如果您想在整个 App 内搜索 + +237 +00:10:30,097 --> 00:10:32,432 +最好将其保留放置在搜索 tab 中 + +238 +00:10:32,432 --> 00:10:34,401 +这样人们就可以 + +239 +00:10:34,401 --> 00:10:38,672 +在 App 的任何地方进行搜索 + +240 +00:10:38,672 --> 00:10:41,008 +这就是导航的新功能 + +241 +00:10:41,008 --> 00:10:45,078 +接下来 我想谈谈选择和菜单 + +242 +00:10:45,078 --> 00:10:48,682 +iPadOS 15 引入了团组选择 + +243 +00:10:48,682 --> 00:10:54,254 +使用指针一次快速选择多个项目 + +244 +00:10:54,254 --> 00:10:57,858 +但您仍必须用工具栏对选择进行操作 + +245 +00:10:57,858 --> 00:11:01,728 +并在操作完成后离开编辑模式 + +246 +00:11:01,728 --> 00:11:05,532 +iPadOS 16 让这一切变得更容易 + +247 +00:11:05,532 --> 00:11:07,234 +如果您使用团组选择 + +248 +00:11:07,234 --> 00:11:12,005 +iPadOS 将不再 +自动进入编辑模式 + +249 +00:11:12,005 --> 00:11:14,174 +您现在可以使用快捷键修饰符 + +250 +00:11:14,174 --> 00:11:18,011 +例如 Command 和 Shift 键 +进行选择和取消选择 + +251 +00:11:18,011 --> 00:11:21,181 +并无需进入编辑模式 + +252 +00:11:21,181 --> 00:11:23,684 +一旦您选择了笔记 + +253 +00:11:23,684 --> 00:11:29,957 +只需双指辅助点按就可以同时操作他们 + +254 +00:11:29,957 --> 00:11:33,894 +在触控时 您可以通过长按 + +255 +00:11:33,894 --> 00:11:36,663 +来获得相同的操作的菜单 + +256 +00:11:36,663 --> 00:11:42,135 +这些交互操作也同样适用于列表 + +257 +00:11:42,135 --> 00:11:45,372 +您可以按住 Command +选择多个笔记 + +258 +00:11:45,372 --> 00:11:48,175 +然后通过拖放将它们移动到文件夹中 + +259 +00:11:48,175 --> 00:11:49,843 +并调出操作菜单 + +260 +00:11:49,843 --> 00:11:53,247 +同时编辑多个笔记文件 + +261 +00:11:53,247 --> 00:11:56,149 +除了这些多项目菜单 + +262 +00:11:56,149 --> 00:12:01,288 +iPadOS 16 还支持 +空白区域的菜单 + +263 +00:12:01,288 --> 00:12:04,258 +您可以用它来创造新的内容 + +264 +00:12:04,258 --> 00:12:08,428 +例如 可以在文件中 +创建一个新文件夹 + +265 +00:12:08,428 --> 00:12:15,002 +或者 可以将 +复制的事件粘贴到日历中 + +266 +00:12:15,002 --> 00:12:18,805 +好的 我们了解了关于选择功能的 +一系列需要注意的事项 + +267 +00:12:18,805 --> 00:12:21,742 +让我们来回顾一下 + +268 +00:12:21,742 --> 00:12:24,244 +您的 App 应该支持键盘输入 + +269 +00:12:24,244 --> 00:12:28,949 +比如使用箭头键 +和 Tab 健进行导航 + +270 +00:12:28,949 --> 00:12:32,019 +支持团组选择以便快速选择 + +271 +00:12:32,019 --> 00:12:36,023 +通过使用指针选取网格中的多个项目 + +272 +00:12:36,023 --> 00:12:40,027 +使用指针或键盘时 + +273 +00:12:40,027 --> 00:12:43,397 +允许多选而不进入编辑模式 + +274 +00:12:43,397 --> 00:12:45,766 +添加可同时作用于 + +275 +00:12:45,766 --> 00:12:49,436 +多个选定的项目的菜单 + +276 +00:12:49,436 --> 00:12:51,071 +在空白区域使用上下文菜单 + +277 +00:12:51,071 --> 00:12:54,842 +创建新项目 + +278 +00:12:54,842 --> 00:12:58,679 +接下来我要谈的是子菜单 + +279 +00:12:58,679 --> 00:13:02,216 +在 iPhone 上 +子菜单是垂直展示的 + +280 +00:13:02,216 --> 00:13:05,485 +因为空间有限 +还需要多一个点击操作 + +281 +00:13:05,485 --> 00:13:07,721 +所以最好只在您真正需要的时候 + +282 +00:13:07,721 --> 00:13:11,024 +才在 iPhone 上使用子菜单 + +283 +00:13:11,024 --> 00:13:13,861 +但在 iPadOS 16 上 + +284 +00:13:13,861 --> 00:13:17,764 +子菜单可在空间充足时 +以水平方式打开 + +285 +00:13:17,764 --> 00:13:22,402 +这使得操作变得更快 +尤其在使用鼠标时 + +286 +00:13:22,402 --> 00:13:25,572 +例如 在日历中使用子菜单 + +287 +00:13:25,572 --> 00:13:30,210 +可以真正快速地 +将事件移动到不同日历中 + +288 +00:13:30,210 --> 00:13:34,214 +以及在提醒事项功能中使用子菜单 + +289 +00:13:34,214 --> 00:13:36,783 +快速更改到期日和优先级 + +290 +00:13:36,783 --> 00:13:38,986 +所以在 iPad 上 您应该考虑 + +291 +00:13:38,986 --> 00:13:42,556 +在 App 菜单中包含子菜单 + +292 +00:13:42,556 --> 00:13:46,693 +以便实现类似上面的快速更改功能 + +293 +00:13:46,693 --> 00:13:51,532 +除了子菜单 +iPadOS 16 还添加了新控件 + +294 +00:13:51,532 --> 00:13:54,434 +用于列表中的弹出按钮 + +295 +00:13:54,434 --> 00:13:57,070 +就像其他弹出按钮一样 + +296 +00:13:57,070 --> 00:14:00,040 +弹出一个包含各种选项的菜单 + +297 +00:14:00,040 --> 00:14:02,776 +让我们通过实际例子来了解一下 + +298 +00:14:02,776 --> 00:14:05,546 +在以前 +如果想编辑计划任务的优先级 + +299 +00:14:05,546 --> 00:14:07,981 +需要先进入细节视图 + +300 +00:14:07,981 --> 00:14:10,017 +然后再划回来 + +301 +00:14:10,017 --> 00:14:15,088 +这一连串复杂操作会让您脱离上下文 + +302 +00:14:15,088 --> 00:14:19,893 +在 iPadOS 16 中 +您可以就地更改优先级 + +303 +00:14:19,893 --> 00:14:23,864 +您只需在当前页面操作 这会快的多 + +304 +00:14:23,864 --> 00:14:25,232 +正如您在这里看到的 + +305 +00:14:25,232 --> 00:14:28,101 +列表中这些弹出按钮的主要用途 + +306 +00:14:28,101 --> 00:14:34,208 +取代弹出窗口 +和模态模块中的层级式导航 + +307 +00:14:34,208 --> 00:14:36,343 +当您使用弹出按钮时 + +308 +00:14:36,343 --> 00:14:37,477 +需要确保您有一组 + +309 +00:14:37,477 --> 00:14:40,881 +明确定义的选项可供选择 + +310 +00:14:40,881 --> 00:14:43,684 +同时也请确保只有在使用弹出按钮时 + +311 +00:14:43,684 --> 00:14:47,888 +您的菜单才能展现完美布局 + +312 +00:14:47,888 --> 00:14:51,391 +如果您的选项使用切换按钮更好 +那么请用切换按钮 + +313 +00:14:51,391 --> 00:14:53,794 +如果选项中真的需要更多控件 + +314 +00:14:53,794 --> 00:14:56,163 +也不要试图滥用弹出按钮 + +315 +00:14:56,163 --> 00:14:58,899 +但如果您只是有时才要用到一些功能 + +316 +00:14:58,899 --> 00:15:03,403 +那么在菜单栏中 +加入自定义选项是不错的选择 + +317 +00:15:03,403 --> 00:15:05,472 +当用户选择自定义选项时 + +318 +00:15:05,472 --> 00:15:07,941 +您的 App 应该能显示额外的控件 + +319 +00:15:07,941 --> 00:15:12,346 +而不妨碍其他选项 + +320 +00:15:12,346 --> 00:15:14,948 +如果您的选项需要描述 + +321 +00:15:14,948 --> 00:15:19,453 +您可以将文字 +放在列表中的弹出按钮的下方 + +322 +00:15:19,453 --> 00:15:22,689 +好的 这就是选择和菜单的新功能 + +323 +00:15:22,689 --> 00:15:25,626 +最后 我想谈谈表格 + +324 +00:15:25,626 --> 00:15:29,296 +表格是 iPadOS 16 中 +一个很棒的新组件 + +325 +00:15:29,296 --> 00:15:32,599 +它会使您的内容列表功能更强大 + +326 +00:15:32,599 --> 00:15:36,436 +在以前 您可能使用过 +称为列表的控件 + +327 +00:15:36,436 --> 00:15:38,071 +但这个控件的定义并不完全准确 + +328 +00:15:38,071 --> 00:15:42,075 +因为只有一列的表格不算真正的表格 + +329 +00:15:42,075 --> 00:15:45,379 +iPadOS 16 有一个真正的表格 + +330 +00:15:45,379 --> 00:15:49,683 +在 SwiftUI 中的表格控件 +可以显示多列信息 + +331 +00:15:49,683 --> 00:15:53,887 +您只需点击标题栏即可进行排序 + +332 +00:15:53,887 --> 00:15:57,157 +现在 由于 iPad 屏幕相对于桌面显示设备来说比较小 + +333 +00:15:57,157 --> 00:16:01,295 +您将只能显示最重要的列 + +334 +00:16:01,295 --> 00:16:03,163 +但是您可以定义显示哪些列 + +335 +00:16:03,163 --> 00:16:05,332 +比如用文件类型替换文件大小 + +336 +00:16:05,332 --> 00:16:09,136 +只需选择不同的排序选项 + +337 +00:16:09,136 --> 00:16:11,205 +并且对于那些 + +338 +00:16:11,205 --> 00:16:14,274 +强大的内容访问功能来说 + +339 +00:16:14,274 --> 00:16:17,578 +可排序表格还支持所有选择功能 + +340 +00:16:17,578 --> 00:16:21,348 +这个我前面讲过 + +341 +00:16:21,348 --> 00:16:24,551 +所以表格是一个非常强大的控件 + +342 +00:16:24,551 --> 00:16:27,387 +但如何正确使用它们很重要 + +343 +00:16:27,387 --> 00:16:30,924 +iOS 16 中 +内置的表格是为了显示 + +344 +00:16:30,924 --> 00:16:34,595 +有关内容列表的更多信息 + +345 +00:16:34,595 --> 00:16:37,231 +而不是像 Numbers 表格那样 +用来展示数据 + +346 +00:16:37,231 --> 00:16:39,499 +您可以将它们视为您的 App 中 + +347 +00:16:39,499 --> 00:16:43,504 +已有列表视图的扩展版本 + +348 +00:16:43,504 --> 00:16:47,641 +实际上 +当您将 App 窗口调整到很小时 + +349 +00:16:47,641 --> 00:16:52,846 +表格将切换回单列列表 + +350 +00:16:52,846 --> 00:16:55,115 +此时 我们建议 + +351 +00:16:55,115 --> 00:16:57,818 +获取表格中第二列数据 + +352 +00:16:57,818 --> 00:16:59,753 +并移动该信息 + +353 +00:16:59,753 --> 00:17:03,524 +到每个项目的第二行作为辅助信息 + +354 +00:17:03,524 --> 00:17:07,728 +以便所有信息仍然能显示出来 + +355 +00:17:07,728 --> 00:17:10,664 +对于排序 您可以使用工具栏按钮 + +356 +00:17:10,664 --> 00:17:13,700 +快速显示排序选项 + +357 +00:17:13,700 --> 00:17:17,871 +这就是 iPadOS 16 中的 +新组件和功能 + +358 +00:17:17,871 --> 00:17:19,173 +让我们把话题交给 Bryant + +359 +00:17:19,173 --> 00:17:22,376 +一起回顾我们今天讨论的所有内容 + +360 +00:17:22,376 --> 00:17:23,677 +Bryant:谢谢 Grant + +361 +00:17:23,677 --> 00:17:25,112 +我们今天介绍的很多功能 + +362 +00:17:25,112 --> 00:17:29,216 +旨在帮助用户 +提高使用 iPad 的工作效率 + +363 +00:17:29,216 --> 00:17:31,685 +当您考虑以上内容 +与您的 App 的关系时 + +364 +00:17:31,685 --> 00:17:34,188 +思考如何通过 +提供更多功能、更好的组织结构 + +365 +00:17:34,188 --> 00:17:37,024 +使您的 App 变的更强大 + +366 +00:17:37,024 --> 00:17:41,061 +并使常见的编辑和浏览任务更加高效 + +367 +00:17:41,061 --> 00:17:43,530 +在可调整大小的窗口和更大的屏幕中 + +368 +00:17:43,530 --> 00:17:45,432 +评估您的 App 的界面设计 + +369 +00:17:45,432 --> 00:17:47,234 +并确保您的 App + +370 +00:17:47,234 --> 00:17:49,469 +可在触控和鼠标之间无缝运行 + +371 +00:17:49,469 --> 00:17:51,271 +Grant:如果您想要了解 + +372 +00:17:51,271 --> 00:17:54,408 +如何设计一款 +出色的 iPad App + +373 +00:17:54,408 --> 00:17:57,110 +请看我们之前的视频 + +374 +00:17:57,110 --> 00:17:59,146 +“专为 iPad 设计” + +375 +00:17:59,146 --> 00:18:01,849 +Bryant:谢谢收看 + +376 +00:18:01,849 --> 00:18:07,354 +♪ + diff --git a/zho/2022 Session 10015 Design for Collaboration with Messages.srt b/zho/2022 Session 10015 Design for Collaboration with Messages.srt new file mode 100644 index 0000000..cfefd59 --- /dev/null +++ b/zho/2022 Session 10015 Design for Collaboration with Messages.srt @@ -0,0 +1,885 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,044 +Jaewoo Chang: 大家好 我是Jaewoo + +3 +00:00:11,078 --> 00:00:13,213 +是 Apple 设计 +团队的设计师 + +4 +00:00:13,247 --> 00:00:16,116 +人们每天有各种类型的协作 + +5 +00:00:16,149 --> 00:00:18,485 +包括与同事共同准备 +Keynote 讲演 + +6 +00:00:18,519 --> 00:00:22,289 +与朋友头脑风暴等 + +7 +00:00:22,322 --> 00:00:25,092 +为了打造一流的协作体验 + +8 +00:00:25,125 --> 00:00:29,530 +我们对 iOS 16 和 macOS Ventura +做了一些调整 + +9 +00:00:29,563 --> 00:00:32,266 +今天 我将解释下 +为何以信息 App + +10 +00:00:32,299 --> 00:00:35,235 +作为协作体验的重点 + +11 +00:00:35,269 --> 00:00:37,771 +并向您介绍端到端的协作流程 + +12 +00:00:37,804 --> 00:00:40,974 +展示我们所有新变化 + +13 +00:00:41,008 --> 00:00:43,443 +我还将分享一些 + +14 +00:00:43,477 --> 00:00:46,246 +使用信息 App +过程中的注意事项 + +15 +00:00:46,280 --> 00:00:48,048 +帮您设计超凡的协作体验 + +16 +00:00:48,081 --> 00:00:51,318 +话不多说 我们开始吧 + +17 +00:00:51,351 --> 00:00:55,556 +电子邮件是人们每天使用的 +重要沟通工具之一 + +18 +00:00:55,589 --> 00:01:00,294 +许多协作 App 将 +电子邮件作为主要的联系方式 + +19 +00:01:00,327 --> 00:01:05,566 +然而 通过电子邮件聊天协作 +反馈并不及时 + +20 +00:01:05,599 --> 00:01:10,037 +因为电子邮件的设计初衷 +是作为异步通信工具 + +21 +00:01:10,070 --> 00:01:14,274 +因此 我们将信息 App 加入协作方案 +作为电子邮件的补充 + +22 +00:01:14,308 --> 00:01:17,377 +用户可以在信息 App 的 +当前对话中 + +23 +00:01:17,411 --> 00:01:19,780 +发送协作邀请 + +24 +00:01:19,813 --> 00:01:23,016 +无需询问对方电子邮件地址 + +25 +00:01:23,050 --> 00:01:26,887 +有效沟通是成功协作的关键 + +26 +00:01:26,920 --> 00:01:31,491 +信息 App 在沟通有效性方面 +已具备许多强大的功能 + +27 +00:01:31,525 --> 00:01:36,363 +信息 App 对话也可轻松 +接入 FaceTime 通话中 + +28 +00:01:36,396 --> 00:01:40,267 +通过 FaceTime 通话 +和使用屏幕共享 + +29 +00:01:40,300 --> 00:01:42,002 +可大大提高协作效率 + +30 +00:01:42,035 --> 00:01:46,073 +我们来看看信息 App 和协作 App +是如何协同工作的 + +31 +00:01:46,106 --> 00:01:47,941 +我和朋友们都喜欢烘焙 + +32 +00:01:47,975 --> 00:01:51,278 +我们经常互相分享食谱 + +33 +00:01:51,311 --> 00:01:54,214 +我正在写一个 Pages 文稿 +里面有一些食谱 + +34 +00:01:54,248 --> 00:01:57,451 +想分享给朋友们 + +35 +00:01:57,484 --> 00:02:01,154 +我先点击 +工具栏中的“共享”按钮 + +36 +00:02:01,188 --> 00:02:04,324 +新系统的 +共享 popover 弹窗 + +37 +00:02:04,358 --> 00:02:06,927 +提供了两种文档共享方式 + +38 +00:02:06,960 --> 00:02:11,598 +我可以开启新的协作窗口 +也可以发送副本 + +39 +00:02:11,632 --> 00:02:15,636 +通过协作选项 +我可以使用信息 App + +40 +00:02:15,669 --> 00:02:18,939 +电子邮件或其它 +通信 App 发送邀请 + +41 +00:02:18,972 --> 00:02:23,010 +我和烘焙朋友们 +创建了 Cupcake Designers 群聊 + +42 +00:02:23,043 --> 00:02:26,914 +系统的共享 popover 弹窗 +知道我在这个群聊互动频繁 + +43 +00:02:26,947 --> 00:02:30,317 +将其作为对话建议显示在这里 + +44 +00:02:30,350 --> 00:02:33,487 +我选择这一群聊 开启新的协作 + +45 +00:02:33,520 --> 00:02:36,790 +现在 信息 App 输入区中 +出现了协作邀请 + +46 +00:02:36,823 --> 00:02:39,259 +并准备好发送 + +47 +00:02:39,293 --> 00:02:42,329 +点击发送按钮 即可马上启动协作 + +48 +00:02:42,362 --> 00:02:46,800 +工具栏中就能看到 +Cupcake Designers 的照片 + +49 +00:02:46,834 --> 00:02:50,771 +对话现已与此文档链接 + +50 +00:02:50,804 --> 00:02:54,107 +我的朋友 Lauren +和 Chris 刚加入 + +51 +00:02:55,342 --> 00:02:59,880 +点击群聊照片 +会出现 popover 弹窗 + +52 +00:02:59,913 --> 00:03:04,885 +添加此弹窗 +可便于访问通信工具 + +53 +00:03:04,918 --> 00:03:08,255 +也是一个快速协作的方案 + +54 +00:03:08,288 --> 00:03:11,592 +Pages 文稿可显示 +当前文档协作用户 + +55 +00:03:11,625 --> 00:03:14,261 +轻点弹窗中的信息 App 按钮 + +56 +00:03:14,294 --> 00:03:18,365 +可将信息 App 对话 +置于共享文档上层显示 + +57 +00:03:18,398 --> 00:03:21,034 +我可以很快回到群聊中 + +58 +00:03:21,068 --> 00:03:23,504 +讨论这份文件 + +59 +00:03:23,537 --> 00:03:26,306 +如果我需要 +进行 FaceTime 通话 + +60 +00:03:26,340 --> 00:03:30,043 +只需轻点弹窗中的音频或视频按钮 + +61 +00:03:31,211 --> 00:03:35,115 +现在 我可以和朋友们 +进行实时编辑 + +62 +00:03:35,148 --> 00:03:38,852 +与信息 App 的紧密整合 +可以解锁更多超级功能 + +63 +00:03:38,886 --> 00:03:42,589 +现在 信息 App 可以显示 +来自协作 App 的通知 + +64 +00:03:43,790 --> 00:03:47,461 +Chris 刚修改了 +烘焙食谱文档 + +65 +00:03:48,495 --> 00:03:53,300 +我可以通过信息 App 横幅 +直接打开文档 查看更新 + +66 +00:03:54,434 --> 00:03:57,337 +现在 协作 App 和信息 App +紧密联系 + +67 +00:03:57,371 --> 00:04:00,874 +进一步精简协作工作流程 + +68 +00:04:00,908 --> 00:04:05,078 +好 我们来看一个 +新的协作体验案例 + +69 +00:04:05,112 --> 00:04:07,915 +使用共享按钮 +和系统 popover 弹窗 + +70 +00:04:07,948 --> 00:04:10,517 +可轻松开启协作 + +71 +00:04:10,551 --> 00:04:14,655 +用户可轻松地在当前对话中 +发送邀请 + +72 +00:04:14,688 --> 00:04:17,691 +通过协作 popover 弹窗 +可轻松返回到 + +73 +00:04:17,724 --> 00:04:21,562 +信息 App 对话界面 +或开启 FaceTime 通话 + +74 +00:04:22,930 --> 00:04:26,967 +编辑协作 App 中的通知可以 +让用户了解更新信息 + +75 +00:04:28,435 --> 00:04:32,005 +现在 我们已经看了信息 App +和协作 App 是如何协同工作的 + +76 +00:04:32,039 --> 00:04:34,775 +我们换个话题 看看在 App 中 + +77 +00:04:34,808 --> 00:04:38,912 +设计协作的一些实用技巧 + +78 +00:04:38,946 --> 00:04:41,949 +从系统共享表开始 + +79 +00:04:41,982 --> 00:04:46,486 +经常使用 App 的人 +都熟悉系统共享表 + +80 +00:04:46,520 --> 00:04:51,458 +该共享表有多种用途 +包括共享网站 + +81 +00:04:51,491 --> 00:04:56,296 +歌曲和相簿 照片 +和其它类型的内容 + +82 +00:04:56,330 --> 00:04:58,966 +对话建议可帮助用户 + +83 +00:04:58,999 --> 00:05:02,769 +快速定位要分享的联系人 + +84 +00:05:02,803 --> 00:05:07,407 +通过系统共享表可轻松开启协作 + +85 +00:05:07,441 --> 00:05:12,346 +也让 App 中的协作 +更为一致且熟悉 + +86 +00:05:12,379 --> 00:05:15,716 +如果您决定使用系统共享表 + +87 +00:05:15,749 --> 00:05:19,887 +下一步就是在 App 中 +添加一个共享按钮 + +88 +00:05:19,920 --> 00:05:23,190 +将按钮置于方便操作的位置 + +89 +00:05:23,223 --> 00:05:26,326 +工具栏是个不错的选择 + +90 +00:05:26,360 --> 00:05:29,296 +现在 我们来仔细了解下 +如何根据需求 + +91 +00:05:29,329 --> 00:05:32,533 +自定义共享表 + +92 +00:05:32,566 --> 00:05:37,237 +用户可通过 header 中的弹出按钮 +选择如何共享文件 + +93 +00:05:37,271 --> 00:05:40,007 +如果您的 App +不支持发送副本 + +94 +00:05:40,040 --> 00:05:42,743 +弹出按钮将被隐藏 + +95 +00:05:42,776 --> 00:05:45,646 +弹出按钮下方的文本 +“允许所有人编辑” + +96 +00:05:45,679 --> 00:05:49,383 +是协作权限设置的入口 + +97 +00:05:49,416 --> 00:05:54,288 +您要提供 App 所支持 +默认设置的描述文本 + +98 +00:05:54,321 --> 00:05:58,926 +要尽可能简洁 以免文本截断 + +99 +00:05:58,959 --> 00:06:01,261 +轻点“允许所有人编辑”文本 + +100 +00:06:01,295 --> 00:06:04,464 +就会出现权限设置界面 + +101 +00:06:04,498 --> 00:06:08,368 +在自定义屏幕时 +选项结构要简单 + +102 +00:06:08,402 --> 00:06:13,106 +从而让用户可以轻松 +浏览选项 并快速做出决定 + +103 +00:06:13,140 --> 00:06:16,443 +macOS 的 popover 弹窗 +已重新设计 + +104 +00:06:16,476 --> 00:06:22,282 +从而对应 iOS 和 iPadOS 中 +包括对话建议的变化 + +105 +00:06:22,316 --> 00:06:27,054 +通过下拉菜单 +用户可选择共享文件的方式 + +106 +00:06:27,087 --> 00:06:30,357 +也可通过此 popover 弹窗 +设置权限 + +107 +00:06:30,390 --> 00:06:32,993 +同样 使用简洁的权限摘要字符串 + +108 +00:06:33,026 --> 00:06:35,429 +并保持简单的设置 + +109 +00:06:35,462 --> 00:06:38,932 +接下来 我们来谈谈如何优化 + +110 +00:06:38,966 --> 00:06:41,935 +在信息 App 中 +发起协作的体验 + +111 +00:06:41,969 --> 00:06:44,404 +用户不仅可以选择如何共享 + +112 +00:06:44,438 --> 00:06:48,675 +还可以从信息 App 输入区中 +自定义协作设置 + +113 +00:06:48,709 --> 00:06:53,247 +无需返回共享表更改选项 + +114 +00:06:53,280 --> 00:06:57,084 +另一种开启协作的便捷方式是 + +115 +00:06:57,117 --> 00:07:00,654 +使用拖放功能将文件 +添加到信息 App 对话中 + +116 +00:07:00,687 --> 00:07:04,658 +帮助用户轻松地 +从信息 App 输入区设置权限 + +117 +00:07:04,691 --> 00:07:07,895 +并通过发送按钮开启协作 + +118 +00:07:07,928 --> 00:07:11,164 +重要的是 需将协作按钮 + +119 +00:07:11,198 --> 00:07:13,467 +放在显眼的位置 + +120 +00:07:13,500 --> 00:07:15,569 +一旦开启协作 + +121 +00:07:15,602 --> 00:07:19,273 +协作按钮就会出现在 App 中 + +122 +00:07:19,306 --> 00:07:22,643 +此按钮是整个协作体验中 + +123 +00:07:22,676 --> 00:07:25,179 +最重要的 UI 元素之一 + +124 +00:07:25,212 --> 00:07:29,850 +要找到一个显眼的 +能吸引眼球的位置 + +125 +00:07:29,883 --> 00:07:33,987 +最好把协作按钮 +放在共享按钮旁边 + +126 +00:07:34,021 --> 00:07:36,857 +协作按钮的外观会根据用户 + +127 +00:07:36,890 --> 00:07:40,460 +开启协作的方式略有不同 + +128 +00:07:40,494 --> 00:07:43,931 +如果用户发送了1:1 +信息 App 对话的邀请 + +129 +00:07:43,964 --> 00:07:46,667 +则按钮为收件人头像 + +130 +00:07:46,700 --> 00:07:49,436 +如果是以群聊方式开启协作 + +131 +00:07:49,469 --> 00:07:51,338 +且该群聊有照片 + +132 +00:07:51,371 --> 00:07:53,874 +则系统会在 App 中显示该照片 + +133 +00:07:53,907 --> 00:07:56,577 +如果没有群聊照片 + +134 +00:07:56,610 --> 00:08:00,314 +将显示系统提供的符号 + +135 +00:08:00,347 --> 00:08:03,016 +一旦选定了协作按钮的位置 + +136 +00:08:03,050 --> 00:08:07,087 +就可以为 App 自定义 +协作 popover 弹窗了 + +137 +00:08:07,120 --> 00:08:11,291 +协作 popover 弹窗 +由三个独立部分组成 + +138 +00:08:11,325 --> 00:08:14,595 +顶部显示协作对象 + +139 +00:08:14,628 --> 00:08:18,799 +系统将从通讯录 App 中 +找到对应的个人资料图片 + +140 +00:08:18,832 --> 00:08:21,201 +在此处显示 + +141 +00:08:21,235 --> 00:08:23,904 +还有通信按钮 + +142 +00:08:23,937 --> 00:08:27,474 +如果没有与文档链接的 +信息 App 对话 + +143 +00:08:27,508 --> 00:08:30,344 +信息按钮将允许用户 +连接一个联系人 + +144 +00:08:30,377 --> 00:08:34,181 +中间部分可由用户自定义 + +145 +00:08:34,214 --> 00:08:37,417 +想想哪些信息或功能 +对使用 App 的人来说 + +146 +00:08:37,451 --> 00:08:39,620 +是必不可少的 + +147 +00:08:39,653 --> 00:08:43,590 +Pages 文稿显示带有展示设置的 +活跃参与者列表 + +148 +00:08:43,624 --> 00:08:47,828 +相反 备忘录 App +会显示最新的活动 + +149 +00:08:47,861 --> 00:08:49,730 +以及两个操作按钮 + +150 +00:08:49,763 --> 00:08:52,199 +尽量不要添加过多的信息或按钮 + +151 +00:08:52,232 --> 00:08:54,902 +导致协作弹窗过载 + +152 +00:08:54,935 --> 00:08:57,004 +保持界面简单明了 + +153 +00:08:57,037 --> 00:09:00,574 +还要确保此处添加的 +所有内容在视觉上 + +154 +00:09:00,607 --> 00:09:03,143 +与弹窗的其它元素一致 + +155 +00:09:03,177 --> 00:09:06,380 +如果 App 在弹窗中 +没有显示任何内容 + +156 +00:09:06,413 --> 00:09:08,715 +可将中间部分留空 + +157 +00:09:08,749 --> 00:09:11,852 +比如 提醒事项 和 文件 App + +158 +00:09:11,885 --> 00:09:16,223 +在弹窗底部 +有一个“管理共享文件”按钮 + +159 +00:09:16,256 --> 00:09:19,493 +如需要 可以自定义按钮标签 + +160 +00:09:19,526 --> 00:09:23,230 +此按钮可打开协作管理屏幕 + +161 +00:09:23,263 --> 00:09:25,332 +用户可在此屏幕上 +添加和移除参与者 + +162 +00:09:25,365 --> 00:09:28,268 +还可以更改其它设置 + +163 +00:09:28,302 --> 00:09:30,737 +如果 App 正在使用 +CloudKit 共享 + +164 +00:09:30,771 --> 00:09:34,074 +系统将提供管理屏幕 + +165 +00:09:34,107 --> 00:09:36,076 +如未使用 CloudKit 共享 + +166 +00:09:36,109 --> 00:09:39,213 +则用户可为 App +设置自己的管理屏幕 + +167 +00:09:40,781 --> 00:09:45,018 +macOS 上的协作弹窗 +与 iOS 的结构相同 + +168 +00:09:45,052 --> 00:09:48,255 +自定义中间部分时 + +169 +00:09:48,288 --> 00:09:51,158 +使用 MacOS UI 组件 +和设计模式 + +170 +00:09:51,191 --> 00:09:54,027 +最后 您需要特别考虑 + +171 +00:09:54,061 --> 00:09:57,397 +信息 App 中的横幅外观 + +172 +00:09:57,431 --> 00:10:01,134 +信息 App 中的横幅 +是发生重要变动时 + +173 +00:10:01,168 --> 00:10:03,437 +App 通知协作者的方式 + +174 +00:10:03,470 --> 00:10:07,508 +通过这些横幅 +用户无需打开文档 + +175 +00:10:07,541 --> 00:10:09,843 +即能了解对应的更新 + +176 +00:10:09,877 --> 00:10:14,081 +信息 App 中有多种横幅模板 +可供用户选择 + +177 +00:10:14,114 --> 00:10:18,218 +所做的编辑 添加的评论 +提及您的信息 + +178 +00:10:18,252 --> 00:10:21,121 +修改的文件 + +179 +00:10:21,154 --> 00:10:24,157 +提示信息 App 需要显示 +哪种类型的更新 + +180 +00:10:24,191 --> 00:10:28,095 +则对话中会显示相应的更新 + +181 +00:10:28,128 --> 00:10:30,697 +你可能会问 +如果多人在多个文档中 + +182 +00:10:30,731 --> 00:10:33,767 +进行多次编辑会怎样 + +183 +00:10:33,800 --> 00:10:36,870 +信息 App 将如何处理多个横幅 + +184 +00:10:36,904 --> 00:10:39,973 +为了避免过多的横幅干扰对话 + +185 +00:10:40,007 --> 00:10:43,544 +信息 App 会将 +这些横幅合而为一 + +186 +00:10:43,577 --> 00:10:46,980 +当用户点击此横幅中的查看按钮时 + +187 +00:10:47,014 --> 00:10:50,083 +信息 App 将在一个位置 +显示所有更新 + +188 +00:10:50,117 --> 00:10:53,153 +用户可选择要打开的更新 + +189 +00:10:53,187 --> 00:10:55,822 +好 我们已经了解了 +使用信息 App + +190 +00:10:55,856 --> 00:10:59,293 +设计最佳协作体验的所有细节 + +191 +00:10:59,326 --> 00:11:03,463 +采用新的系统共享表 +来更好地开启协作 + +192 +00:11:03,497 --> 00:11:05,732 +并自定义 +协作 popover 弹窗 + +193 +00:11:05,766 --> 00:11:10,204 +从而提供通信工具 +和良好的协作方案 + +194 +00:11:10,237 --> 00:11:13,340 +通过信息 App 整合 + +195 +00:11:13,373 --> 00:11:15,609 +用户可享受高效 成功的 +协作之旅 + +196 +00:11:15,642 --> 00:11:19,780 +希望这些更新能够帮助大家 +提升设计 App 的用户体验 + +197 +00:11:19,813 --> 00:11:21,515 +感谢观看 + diff --git a/zho/2022 Session 10016 Get more mileage out of your app with CarPlay.srt b/zho/2022 Session 10016 Get more mileage out of your app with CarPlay.srt new file mode 100644 index 0000000..ff6c709 --- /dev/null +++ b/zho/2022 Session 10016 Get more mileage out of your app with CarPlay.srt @@ -0,0 +1,1461 @@ +1 +00:00:00,434 --> 00:00:06,440 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:13,747 +大家好 欢迎来到 +“利用 CarPlay 车载让您的 App 一日千里” + +3 +00:00:13,780 --> 00:00:18,018 +我是André +今天的讲座将由我为大家介绍 + +4 +00:00:19,553 --> 00:00:24,525 +众所周知 CarPlay 车载是在车内使用 +iPhone 更智能 更安全的方式 + +5 +00:00:24,558 --> 00:00:30,163 +今天的讲座主要是关于您的 App +如何在 CarPlay 车载中使用 + +6 +00:00:30,197 --> 00:00:34,334 +首先 我们将快速回顾一下 +CarPlay 车载所支持的 App 类别 + +7 +00:00:34,368 --> 00:00:38,672 +然后 谈谈我们今年正在启用的 +新的 App 类别 + +8 +00:00:38,705 --> 00:00:42,242 +最后 介绍一个支持 + +9 +00:00:42,276 --> 00:00:45,245 +App开发的新工具 + +10 +00:00:45,279 --> 00:00:50,184 +并以导航 App 的重要新功能 +作为今天的收尾 + +11 +00:00:50,217 --> 00:00:53,220 +话不多说 我们开始吧 + +12 +00:00:55,155 --> 00:01:00,327 +为驾驶员而设计是 CarPlay 车载 +最基础的特性之一 + +13 +00:01:00,360 --> 00:01:04,932 +在开发您的 App 时 +应该首要考虑 + +14 +00:01:04,965 --> 00:01:06,867 +经常开车人群的需求 + +15 +00:01:06,900 --> 00:01:12,272 +因此 驾驶相关的使用场景 +是唯一需要考虑的 + +16 +00:01:12,306 --> 00:01:17,377 +与驾驶无关的使用场景 +都应忽略 + +17 +00:01:17,411 --> 00:01:20,881 +如一次性配置 登录 App + +18 +00:01:20,914 --> 00:01:24,952 +或阅读条款 +最好都在驾驶前后完成 + +19 +00:01:24,985 --> 00:01:29,289 +而不应出现在您 App 的 +CarPlayUI 界面中 + +20 +00:01:30,490 --> 00:01:34,828 +App 在 CarPlay 车载中显示 +需要获得相应的资质 + +21 +00:01:34,862 --> 00:01:38,699 +您可以在 Apple CarPlay 车载 +开发者网站上 + +22 +00:01:38,732 --> 00:01:42,402 +根据 App 的类别申请资质 + +23 +00:01:42,436 --> 00:01:47,541 +这是我们目前 CarPlay 车载中 +支持的 App 类别 + +24 +00:01:47,574 --> 00:01:52,112 +这些 App 涵盖了大多 +驾驶期间可能会执行的操作 + +25 +00:01:52,145 --> 00:01:55,482 +但很多用户反馈 + +26 +00:01:55,516 --> 00:01:59,219 +希望有更多驾驶相关的 App + +27 +00:01:59,253 --> 00:02:03,156 +我在此宣布 我们今年 +将增加两种新的 App 类别 + +28 +00:02:03,190 --> 00:02:06,326 +加油和驾驶任务 App + +29 +00:02:06,360 --> 00:02:09,630 +我们稍后会详细讨论这些内容 + +30 +00:02:09,663 --> 00:02:14,301 +但首先 我们先谈谈开发模板 + +31 +00:02:14,334 --> 00:02:18,005 +开发模板决定了 CarPlay 车载中 +App 的 UI 界面如何呈现 + +32 +00:02:18,038 --> 00:02:22,242 +您的 App 提供数据 +系统负责把 UI 绘制到 + +33 +00:02:22,276 --> 00:02:25,279 +车辆显示屏上 + +34 +00:02:25,312 --> 00:02:28,949 +这个模板的系统使用简便 + +35 +00:02:28,982 --> 00:02:32,519 +并且有很多好处 +包括帮助改善您的 App + +36 +00:02:32,553 --> 00:02:35,355 +使其更适用驾驶场景 + +37 +00:02:35,389 --> 00:02:38,392 +您不必担心字体大小等问题 + +38 +00:02:38,425 --> 00:02:42,462 +模板可帮助你们 +建立简单的 UI + +39 +00:02:42,496 --> 00:02:47,601 +及最后确保您 App 的 UI +与 CarPlay 车载中其它 App 一致 + +40 +00:02:47,634 --> 00:02:52,105 +使用户在需要时 操作更快捷 + +41 +00:02:52,139 --> 00:02:56,643 +这些模板可确保 App 的 UI +在所有支持 CarPlay 车载的 + +42 +00:02:56,677 --> 00:03:00,714 +车型上正常运行 +这也是同样重要的一点 + +43 +00:03:00,747 --> 00:03:04,651 +无论汽车搭载的输入设备 +是哪种屏幕类型 + +44 +00:03:04,685 --> 00:03:08,488 +您可能还想在不同的配置中 +测试自己的 App + +45 +00:03:08,522 --> 00:03:11,592 +我们稍后将会讨论更多 +关于测试的内容 + +46 +00:03:11,625 --> 00:03:16,663 +但可以说 开发模板 +已为您做了大部分的工作 + +47 +00:03:16,697 --> 00:03:19,499 +在构建 App 时 +有多个模板可供选择 + +48 +00:03:19,533 --> 00:03:23,036 +从数组按钮形式的网格模板 + +49 +00:03:23,070 --> 00:03:25,472 +到表格形式的列表模板 + +50 +00:03:25,506 --> 00:03:31,178 +开发人员和 iOS 用户 +应该都很熟悉了 + +51 +00:03:31,211 --> 00:03:34,882 +最重要的是 这些模板 +与整个 CarPlay 车载系统一致 + +52 +00:03:34,915 --> 00:03:38,986 +您的用户也了然于心 + +53 +00:03:39,019 --> 00:03:43,223 +之前我们谈到了 CarPlay 车载 +所支持 App 的类别 + +54 +00:03:43,257 --> 00:03:49,196 +有些模板与特定类别的 +相关性更高 + +55 +00:03:49,229 --> 00:03:53,667 +此图表可帮助您了解 +根据您 App 的类别 + +56 +00:03:53,700 --> 00:03:55,769 +可以选择哪些模板 + +57 +00:03:55,802 --> 00:04:01,708 +我知道这表格看起来 +像 DMV 视力表 不过不用担心 + +58 +00:04:01,742 --> 00:04:07,014 +您可以在我们的在线开发者文档中 +找到这个表格 + +59 +00:04:07,047 --> 00:04:11,118 +这里需要注意的是 +App 可以使用的模板 + +60 +00:04:11,151 --> 00:04:13,253 +取决于它的类别 + +61 +00:04:13,287 --> 00:04:16,490 +仅允许使用与 App 类别相关 + +62 +00:04:16,523 --> 00:04:19,793 +且适用的模板 + +63 +00:04:19,826 --> 00:04:23,330 +现在我们已经讨论了模板 +我们再来仔细看看 + +64 +00:04:23,363 --> 00:04:26,667 +iOS16 推出的新 App 类别 + +65 +00:04:26,700 --> 00:04:30,604 +首先看下新的加油 App + +66 +00:04:31,972 --> 00:04:37,211 +在 iOS14 中 我们推出了 +支持电动汽车充电的 App + +67 +00:04:37,244 --> 00:04:40,948 +这些 App 不仅可查找 +电动汽车充电站的位置 + +68 +00:04:40,981 --> 00:04:45,953 +它们的功能还不止于此 例如 +它们可帮助用户连接到 + +69 +00:04:45,986 --> 00:04:48,589 +正确的充电站并启动充电 + +70 +00:04:48,622 --> 00:04:52,025 +我们听许多开发人员说 +这种类型的功能将 + +71 +00:04:52,059 --> 00:04:56,196 +不仅适用于电动汽车 + +72 +00:04:56,230 --> 00:05:00,634 +无论是传统的汽油车 +还是替代燃料汽车 + +73 +00:05:00,667 --> 00:05:06,273 +这个新类别都可以让您的 +加油 App 支持 CarPlay 车载 + +74 +00:05:06,306 --> 00:05:09,443 +许多用户使用导航 App 来查找 + +75 +00:05:09,476 --> 00:05:12,546 +并驾驶到特定的位置 +因此您的加油 App 应在 + +76 +00:05:12,579 --> 00:05:17,351 +其 CarPlayUI 中启用更多功能 +而不仅仅是查找位置 + +77 +00:05:17,384 --> 00:05:19,887 +关于 App 可以启用的功能 +其中一个很好的例子 + +78 +00:05:19,920 --> 00:05:22,656 +就是启动加油 + +79 +00:05:22,689 --> 00:05:27,528 +现在 我们谈谈驾驶任务 App + +80 +00:05:27,561 --> 00:05:30,964 +驾驶任务是一款新型 +CarPlay 车载 App + +81 +00:05:30,998 --> 00:05:36,003 +旨在支持各种非常简单的App + +82 +00:05:36,036 --> 00:05:40,073 +请记住 这些 App 的主要目的 +必须是实现人们 + +83 +00:05:40,107 --> 00:05:44,511 +驾驶时需要完成的操作 +要对驾驶有实际帮助 + +84 +00:05:44,545 --> 00:05:47,814 +而不仅是一项任务 + +85 +00:05:49,349 --> 00:05:53,187 +这类 App 包括帮助 +控制汽车配件的应用 + +86 +00:05:53,220 --> 00:05:58,825 +提供驾驶或道路 +状态和信息的应用 + +87 +00:05:58,859 --> 00:06:05,165 +以及帮助完成驾驶前后 +操作的应用 + +88 +00:06:05,199 --> 00:06:08,202 +让我们看一些更具体的例子 + +89 +00:06:09,670 --> 00:06:13,707 +首先 我们有一个路况 App +可以通知用户 + +90 +00:06:13,740 --> 00:06:16,677 +重要的道路信息 + +91 +00:06:16,710 --> 00:06:21,181 +这个应用程序是使用 +CPPointOfInterestTemplate 搭建的 + +92 +00:06:21,215 --> 00:06:24,184 +请记住 +使用此 App 的用户正在驾驶 + +93 +00:06:24,218 --> 00:06:28,956 +因此这样的 App 应在 +用户位置附近提供 + +94 +00:06:28,989 --> 00:06:31,225 +非常简短的重要项目列表 + +95 +00:06:31,258 --> 00:06:34,828 +这并不是帮助用户在驾驶前 + +96 +00:06:34,862 --> 00:06:36,697 +做完整的路线规划 + +97 +00:06:38,465 --> 00:06:43,136 +在这个 App 中 这是用户 +在选择位置时看到的内容 + +98 +00:06:43,170 --> 00:06:47,341 +要注意控制文本长度 +从而信息可以一目了然 + +99 +00:06:47,374 --> 00:06:51,879 +因此 此处语言应尽量简洁 + +100 +00:06:54,181 --> 00:06:58,819 +接下来 我们看一个 +控制汽车配件的App + +101 +00:06:58,852 --> 00:07:01,855 +在这个案例中是 + +102 +00:07:01,889 --> 00:07:06,693 +该 App 使用 CPInformationTemplate +提供所连接配件的基本信息 + +103 +00:07:06,727 --> 00:07:12,900 +以及供用户操作的几个按钮 + +104 +00:07:12,933 --> 00:07:17,871 +注意 在本例中 这是 App 在 +CarPlay 车载中的整个UI + +105 +00:07:17,905 --> 00:07:20,073 +没有其它画面了 + +106 +00:07:20,107 --> 00:07:23,110 +当然 这款 App 还有 +很多其它功能 + +107 +00:07:23,143 --> 00:07:26,980 +比如管理配对的附件 + +108 +00:07:27,014 --> 00:07:30,884 +但任何驾驶无关的功能 + +109 +00:07:30,918 --> 00:07:34,755 +都不包括在该 App 的 +CarPlay UI 中 + +110 +00:07:34,788 --> 00:07:38,225 +用户下车时 +最好在 iPhone 上使用 + +111 +00:07:38,258 --> 00:07:42,362 +该 App 主 UI 进行 +非驾驶相关任务 + +112 +00:07:44,031 --> 00:07:49,870 +最后 让我们看几个 +使用 CPGridTemplate 的例子 + +113 +00:07:49,903 --> 00:07:53,974 +这是一个极其简单的 App +只有两个按钮 其它没了 + +114 +00:07:54,007 --> 00:07:56,543 +用户可以记录 + +115 +00:07:56,577 --> 00:07:59,546 +个人或商务里程 + +116 +00:07:59,580 --> 00:08:03,283 +这款 App 完全符合 +新的驾驶任务 App 类别 + +117 +00:08:03,317 --> 00:08:07,921 +因为它让用户可以在驾驶时 +执行所需的非常简单操作 + +118 +00:08:07,955 --> 00:08:11,658 +而无需启用任何其它 +非关键操作 + +119 +00:08:11,692 --> 00:08:14,695 +简单 切中要害 + +120 +00:08:14,728 --> 00:08:18,765 +通过该例可以看到 这种风格的 UI +可以服务于多种类别的 App + +121 +00:08:18,799 --> 00:08:23,170 +这里有另一个例子 +它的 UI 基本一样 + +122 +00:08:23,203 --> 00:08:28,108 +这是一个快速通道 +收费应答器 App + +123 +00:08:28,141 --> 00:08:32,479 +使用 CPGridTemplate +用户可选择车内有多少乘客 + +124 +00:08:32,513 --> 00:08:36,383 +它与前面案例的目标完全相同 + +125 +00:08:36,416 --> 00:08:39,019 +是另一个完美的驾驶任务 App + +126 +00:08:40,287 --> 00:08:42,990 +简而言之 +在设计驾驶任务 App 时 + +127 +00:08:43,023 --> 00:08:46,627 +一定要考虑制作单屏 App + +128 +00:08:46,660 --> 00:08:50,130 +可供用户进行驾驶期间 +最少的必要操作 + +129 +00:08:50,163 --> 00:08:54,801 +且在数秒内就能完成 + +130 +00:08:54,835 --> 00:08:59,072 +应该避免启用复杂 +或不常见的使用场景 + +131 +00:08:59,106 --> 00:09:04,044 +一个很好的例子就是 +首次设置或详细配置 + +132 +00:09:04,077 --> 00:09:07,080 +最后 您的 App 不应 +添加驾驶时不需要的功能 + +133 +00:09:07,114 --> 00:09:11,151 +即使是与汽车有关的 + +134 +00:09:11,185 --> 00:09:13,921 +这不是大杂烩 + +135 +00:09:13,954 --> 00:09:16,657 +以上就是驾驶任务 App + +136 +00:09:16,690 --> 00:09:21,795 +现在我们换一个话题 +谈谈如何测试 CarPlay 车载 App + +137 +00:09:21,828 --> 00:09:25,098 +我们将回顾当前的 +不同测试方式 + +138 +00:09:25,132 --> 00:09:29,102 +之后我会介绍一个新的工具 +CarPlay 车载模拟器 + +139 +00:09:29,136 --> 00:09:32,840 +开发人员可以使用 +不同的工具测试 + +140 +00:09:32,873 --> 00:09:36,276 +支持 CarPlay 车载的 App + +141 +00:09:36,310 --> 00:09:42,282 +首先 大家可以使用内置 CarPlay 车载 +窗口的 Xcode 模拟器 + +142 +00:09:42,316 --> 00:09:46,320 +如果您已经在使用 Xcode 模拟器 +来测试其它 App + +143 +00:09:46,353 --> 00:09:50,991 +这也是快速测试 CarPlay UI 的 +好方法 + +144 +00:09:51,024 --> 00:09:54,161 +其次 如果您想在实际的 iPhone 上 +测试自己的 App + +145 +00:09:54,194 --> 00:09:58,332 +当然可以把自己的手机连接到 +支持 CarPlay 车载的车辆 + +146 +00:09:58,365 --> 00:10:00,601 +或售后市场车载主机 + +147 +00:10:00,634 --> 00:10:04,204 +直到最近 这还是在 iPhone 上 +测试 CarPlay UI 中 + +148 +00:10:04,238 --> 00:10:08,675 +运行 App 的唯一方法 +但我很高兴地告诉您 + +149 +00:10:08,709 --> 00:10:13,013 +我们现在为提供了第三种选择 +可能会成为大家最倾向的选择 + +150 +00:10:13,046 --> 00:10:14,948 +CarPlay 车载模拟器 + +151 +00:10:14,982 --> 00:10:18,752 +我们详细了解下 + +152 +00:10:18,785 --> 00:10:20,821 +这是什么呢 + +153 +00:10:20,854 --> 00:10:24,491 +CarPlay 车载模拟器是一个 +独立的 Mac 应用程序 + +154 +00:10:24,525 --> 00:10:27,027 +可以复制一个 CarPlay 车载环境 + +155 +00:10:27,060 --> 00:10:30,597 +您只需在 Apple +开发者网站上下载 + +156 +00:10:30,631 --> 00:10:34,168 +“Additional Tools for Xcode”套件 +运行 App + +157 +00:10:34,201 --> 00:10:38,472 +然后用数据线连接您的 +iPhone 和 Mac + +158 +00:10:38,505 --> 00:10:41,375 +CarPlay 车载将在手机上 +启动并运行 + +159 +00:10:41,408 --> 00:10:44,811 +和连接到真正的汽车上一样 + +160 +00:10:44,845 --> 00:10:48,048 +这有什么特别的呢 +为什么要用这个模拟器呢 + +161 +00:10:48,081 --> 00:10:50,050 +有以下几个好处 + +162 +00:10:51,852 --> 00:10:54,888 +首先 使用 CarPlay +车载模拟器时 + +163 +00:10:54,922 --> 00:10:57,090 +CarPlay 车载在 +iPhone 上运行的方式 + +164 +00:10:57,124 --> 00:11:00,460 +和在汽车上一样 + +165 +00:11:00,494 --> 00:11:03,363 +这意味着您可以在手机上 +测试自己 App + +166 +00:11:03,397 --> 00:11:06,400 +而不需要经常往返于停车位 + +167 +00:11:06,433 --> 00:11:10,404 +或购买售后车载主机 + +168 +00:11:10,437 --> 00:11:14,641 +另一个好处是 +当使用 CarPlay 车载模拟器时 + +169 +00:11:14,675 --> 00:11:18,178 +您的手机与 Mac 连接 + +170 +00:11:18,212 --> 00:11:21,615 +您可以同时使用 Mac 上 +所有其它强大的开发人员工具 + +171 +00:11:21,648 --> 00:11:26,854 +无论是在 Xcode 中调试 +还是在 Instruments 中调整性能 + +172 +00:11:26,887 --> 00:11:30,224 +在 iOS 方面也是如此 +因为您的 App + +173 +00:11:30,257 --> 00:11:34,928 +是在真正的 iPhone 上运行的 +所以可以访问完整的 iPhone 功能 + +174 +00:11:34,962 --> 00:11:39,299 +如果没有真正的 CarPlay 车载系统 +或者现在的 CarPlay 车载模拟器 + +175 +00:11:39,333 --> 00:11:41,568 +有些场景是无法测试的 + +176 +00:11:43,470 --> 00:11:46,740 +一个很好的例子是测试 +导航 App 的语音指令 + +177 +00:11:46,773 --> 00:11:51,979 +是否与汽车的原生音频源正确融合 +如 FM 收音机 + +178 +00:11:52,012 --> 00:11:55,349 +现在 您可以在办公桌上 +方便地进行测试 + +179 +00:11:56,950 --> 00:11:59,686 +最后 您还可以使用 +CarPlay 车载模拟器 + +180 +00:11:59,720 --> 00:12:02,756 +来测试多种不同配置的汽车 + +181 +00:12:02,789 --> 00:12:06,593 +例如不同显示尺寸的汽车 + +182 +00:12:06,627 --> 00:12:10,197 +我们来看看 CarPlay 车载模拟器 +是怎么运行的 + +183 +00:12:10,230 --> 00:12:11,832 +好了 + +184 +00:12:11,865 --> 00:12:14,835 +如您所见 连接 iPhone 的 +CarPlay 车载显示屏 + +185 +00:12:14,868 --> 00:12:18,639 +与几个控制按钮一起 +出现在 App 中 + +186 +00:12:18,672 --> 00:12:22,643 +我们来看看有什么功能 + +187 +00:12:22,676 --> 00:12:25,312 +屏幕底部是模拟汽车中 + +188 +00:12:25,345 --> 00:12:28,916 +各种快捷键和控制旋钮 + +189 +00:12:31,018 --> 00:12:34,321 +您也可以在 CarPlay 车载视图中 +直接点击 + +190 +00:12:34,354 --> 00:12:36,123 +来模拟触摸屏车辆 + +191 +00:12:38,192 --> 00:12:41,295 +在窗口顶部有一些快捷控制 + +192 +00:12:41,328 --> 00:12:45,032 +仅有的几个 UI 按钮 +可以模拟汽车行驶过程中 + +193 +00:12:45,065 --> 00:12:48,535 +CarPlay 车载显示的限制 + +194 +00:12:48,569 --> 00:12:53,140 +例如 可以缩短音频 App 中的 +列表内容 + +195 +00:12:55,576 --> 00:12:59,079 +接下来的两个按钮分别用于 +模拟汽车何时请求 UI + +196 +00:12:59,112 --> 00:13:02,916 +和地图外观颜色的深浅 + +197 +00:13:04,952 --> 00:13:08,322 +最后一个按钮可以快速模拟 + +198 +00:13:08,355 --> 00:13:11,491 +手机与 CarPlay 车载的 +断开和重连 + +199 +00:13:11,525 --> 00:13:13,927 +因为当你们使用这个按钮时 +手机仍然与 Mac 保持连接 + +200 +00:13:13,961 --> 00:13:17,431 +您可以用它在 App 中 +使用Xcode + +201 +00:13:17,464 --> 00:13:20,567 +调试 CarPlay 车载重连的场景 + +202 +00:13:22,870 --> 00:13:25,572 +但我刚刚跳过的 +第一个按钮是什么呢 + +203 +00:13:25,606 --> 00:13:29,409 +您可能已经猜到了 +这将弹出一个 + +204 +00:13:29,443 --> 00:13:32,346 +高级功能的辅助窗口 + +205 +00:13:32,379 --> 00:13:34,815 +我们来看看有哪些高级功能 + +206 +00:13:36,817 --> 00:13:40,354 +在 General (常规) 选项卡中 +您可以选择 + +207 +00:13:40,387 --> 00:13:43,657 +CarPlay 车载的显示尺寸 + +208 +00:13:43,690 --> 00:13:47,027 +如果您的 App UI +仅由模板组成 + +209 +00:13:47,060 --> 00:13:51,064 +那可以尝试不同尺寸的 UI + +210 +00:13:51,098 --> 00:13:54,835 +查看该 UI 在不同的汽车中 +如何显示 + +211 +00:13:54,868 --> 00:13:58,305 +但正如我们之前谈到的 +系统将确保一切正常运行 + +212 +00:13:58,338 --> 00:14:00,674 +然而 如果您的 App 是用于导航的 + +213 +00:14:00,707 --> 00:14:04,178 +那么尝试不同的尺寸和纵横比 +以确保地图绘制代码 + +214 +00:14:04,211 --> 00:14:07,714 +正确运行是非常重要的 + +215 +00:14:07,748 --> 00:14:10,918 +这里有一些推荐的显示尺寸 +可以在 App 中进行测试 + +216 +00:14:10,951 --> 00:14:14,855 +我们看看 Cluster Display (群集信息) +选项卡 + +217 +00:14:14,888 --> 00:14:17,090 +可以看到 您可以通过 + +218 +00:14:17,124 --> 00:14:20,160 +仪表盘中的第二个显示器 +来模拟汽车 + +219 +00:14:20,194 --> 00:14:24,965 +只需勾选该选项 重新启动会话 + +220 +00:14:24,998 --> 00:14:27,434 +就会在主显示屏旁出现 + +221 +00:14:27,467 --> 00:14:30,470 +仪表盘的第二个窗口 + +222 +00:14:30,504 --> 00:14:34,775 +同样 这是与导航 App +最为相关的 + +223 +00:14:34,808 --> 00:14:39,112 +仪表盘显示器用于 +在汽车仪表盘可视角度中 + +224 +00:14:39,146 --> 00:14:43,750 +为驾驶员显示地图或转向卡 + +225 +00:14:43,784 --> 00:14:46,119 +我们稍后会详细了解 +关于仪表盘的内容 + +226 +00:14:46,153 --> 00:14:50,057 +这里可以快速浏览下 +新的 CarPlay 车载模拟器界面 + +227 +00:14:50,090 --> 00:14:53,460 +希望您也和我们一样 +认为这非常有用 + +228 +00:14:53,493 --> 00:14:58,498 +我们刚刚看到 CarPlay 车载 +如何在仪表盘中绘制实时地图 + +229 +00:14:58,532 --> 00:15:00,634 +但是您的导航 App 呢 + +230 +00:15:00,667 --> 00:15:05,038 +如何添加并测试仪表盘 +是否支持您的 App 呢 + +231 +00:15:05,072 --> 00:15:07,174 +我们一起来看看 + +232 +00:15:07,207 --> 00:15:10,844 +你可能还记得 在 iOS 13 中 +我们添加了 APIs + +233 +00:15:10,878 --> 00:15:14,982 +使导航 App 显示在 +CarPlay 车载仪表盘中 + +234 +00:15:15,015 --> 00:15:17,885 +要做到这一点 您需要编辑 +App 的 Info.plist 文件 + +235 +00:15:17,918 --> 00:15:22,489 +以声明对仪表盘的支持 +并进行所需的代理委托 + +236 +00:15:22,523 --> 00:15:27,261 +当它在仪表盘中出现和消失时 +代理会通知您的 App + +237 +00:15:27,294 --> 00:15:33,200 +并将 UIWindow 传到 App +以在其中绘制地图内容 + +238 +00:15:33,233 --> 00:15:34,968 +很简单 + +239 +00:15:35,002 --> 00:15:37,037 +如果你已经完成了 +那么有一个好消息 + +240 +00:15:37,070 --> 00:15:39,706 +添加仪表盘支持将是小菜一碟 + +241 +00:15:39,740 --> 00:15:42,709 +因为它遵循完全相同的模式 + +242 +00:15:42,743 --> 00:15:49,049 +看看我是如何在我的导航测试 App +Space Roads中实现此操作的 + +243 +00:15:49,082 --> 00:15:51,552 +我编辑了我的 Info.plist 文件 + +244 +00:15:51,585 --> 00:15:55,756 +声明对仪表盘导航场景的支持 + +245 +00:15:55,789 --> 00:15:59,493 +并添加了所需的 + +246 +00:15:59,526 --> 00:16:01,528 +然后进行了我的 + +247 +00:16:01,562 --> 00:16:05,365 +CPTemplateApplicationInstrumentCluster +场景委托 + +248 +00:16:05,399 --> 00:16:10,170 +以及我的 +CPInstrumentClusterControllerDelegate + +249 +00:16:10,204 --> 00:16:13,307 +这将提供一个窗口 +在其中绘制自己的内容 + +250 +00:16:13,340 --> 00:16:17,811 +并在仪表盘启动和结束时通知您 + +251 +00:16:17,845 --> 00:16:20,681 +使仪表盘视图可见 + +252 +00:16:20,714 --> 00:16:23,283 +这就是地图实时显示在 + +253 +00:16:23,317 --> 00:16:26,253 +汽车仪表盘中的全部内容 + +254 +00:16:26,286 --> 00:16:29,690 +虽然这与实现仪表盘支持非常相似 + +255 +00:16:29,723 --> 00:16:34,361 +但还有一些针对仪表盘的注意事项 + +256 +00:16:34,394 --> 00:16:40,734 +首先 仪表盘可允许用户 +放大或缩小地图 + +257 +00:16:40,767 --> 00:16:44,137 +您要负责用 + +258 +00:16:44,171 --> 00:16:48,075 +在自己的 App 中实现这一点 + +259 +00:16:48,108 --> 00:16:51,111 +类似地 如果您的 App +包含指南针或限速 + +260 +00:16:51,144 --> 00:16:53,680 +相应的代理将告知 +您的 App + +261 +00:16:53,714 --> 00:16:57,017 +何时适合绘制 + +262 +00:16:57,050 --> 00:17:01,722 +最后 注意您的仪表盘视图 + +263 +00:17:01,755 --> 00:17:05,092 +可能会被汽车仪表盘中的 +其它元素遮挡 + +264 +00:17:05,125 --> 00:17:10,063 +当然 iOS 已经有了一流的机制 +来处理这类情况 + +265 +00:17:10,097 --> 00:17:11,832 +安全区域 + +266 +00:17:11,865 --> 00:17:15,636 +您可以覆盖 +view controller 上的 + +267 +00:17:15,669 --> 00:17:19,006 +viewSafeAreaInsetsDidChange +以了解安全区域的变化 + +268 +00:17:19,039 --> 00:17:22,843 +并在仪表盘视图上使用 + +269 +00:17:22,876 --> 00:17:28,448 +来保证视图区域中的 +关键内容是可见的 + +270 +00:17:28,482 --> 00:17:31,385 +例如 如果有一条蓝色的路线 +显示用户的位置 + +271 +00:17:31,418 --> 00:17:34,121 +就要确保关键部分 + +272 +00:17:34,154 --> 00:17:36,957 +在安全区域内 + +273 +00:17:36,990 --> 00:17:41,795 +我们为搭建 CarPlay 车载 App 的 +开发者启用了一些新功能 + +274 +00:17:41,828 --> 00:17:44,865 +有一个测试 App 的新工具 + +275 +00:17:44,898 --> 00:17:47,367 +我们来看看它的实际应用 + +276 +00:17:47,401 --> 00:17:51,972 +首先 我将从我的 Mac 开始 +展示 CarPlay 车载模拟器 + +277 +00:17:52,005 --> 00:17:55,642 +App 已运行 +我只需连接我的手机 + +278 +00:18:02,716 --> 00:18:05,152 +看 它正在运行 CarPlay 车载 + +279 +00:18:05,185 --> 00:18:09,356 +我们看看 CarPlay 车载模拟器 +如何测试您的 App + +280 +00:18:09,389 --> 00:18:13,827 +即使你们的 App 主要是基于模板 +也可以使用它 + +281 +00:18:13,861 --> 00:18:18,899 +来确保 App 外观 +在深色和浅色背景中都适用 + +282 +00:18:18,932 --> 00:18:21,568 +我来运行 Express Lane App + +283 +00:18:24,137 --> 00:18:26,273 +我可以使用工具栏上的按钮 + +284 +00:18:26,306 --> 00:18:30,277 +在浅色和深色外观之间切换 + +285 +00:18:30,310 --> 00:18:35,048 +我的 App 为这两种风格 +提供了不同的视觉效果 + +286 +00:18:35,082 --> 00:18:38,552 +看起来不错 + +287 +00:18:38,585 --> 00:18:42,523 +现在我们切换到我编写的 +导航测试 App Space Roads + +288 +00:18:44,658 --> 00:18:47,895 +我将使用主配置面板 + +289 +00:18:47,928 --> 00:18:51,798 +尝试在不同的屏幕尺寸上 +绘制地图代码 + +290 +00:18:57,804 --> 00:19:01,074 +最后 我将启用仪表盘显示 + +291 +00:19:01,108 --> 00:19:03,844 +以测试仪表盘的支持 + +292 +00:19:08,081 --> 00:19:09,716 +显示出来了 效果很好 + +293 +00:19:10,617 --> 00:19:14,755 +早些时候 我在 CarPlay 车载模拟器中 +对我的 App 进行了全面测试 + +294 +00:19:14,788 --> 00:19:18,458 +所以现在 我有充分的信心 +App 在汽车上能完美运行 + +295 +00:19:18,492 --> 00:19:20,360 +我们来试下吧 + +296 +00:19:20,394 --> 00:19:23,297 +好了 现在在我的车里 +正如你所看到的 + +297 +00:19:23,330 --> 00:19:26,466 +我把手机连接到车上 +运行 CarPlay 车载 + +298 +00:19:27,868 --> 00:19:31,772 +首先 我们试着运行我 +连接的Trailer Controller App + +299 +00:19:31,805 --> 00:19:36,310 +这样可以向您展示 +模板如何使 App + +300 +00:19:36,343 --> 00:19:38,345 +在启用旋钮的车辆中正常运行 + +301 +00:19:40,247 --> 00:19:44,184 +这款车既有触摸屏 +也有旋钮控制器 + +302 +00:19:44,218 --> 00:19:47,621 +但许多用户喜欢在驾驶时 +使用旋钮控制器 + +303 +00:19:47,654 --> 00:19:51,758 +所以 App 用旋钮良好运行 +也非常重要 + +304 +00:19:51,792 --> 00:19:54,661 +如您所见 +我的 App 可以正常 + +305 +00:19:54,695 --> 00:19:57,998 +使用旋钮操作 最好的是 + +306 +00:19:58,031 --> 00:20:01,435 +我不需要其它特别的操作 +模板已全部涵盖了 + +307 +00:20:03,971 --> 00:20:07,975 +接下来 我们切换到 +我的导航 App Space Roads + +308 +00:20:08,008 --> 00:20:10,911 +我们启动 App + +309 +00:20:10,944 --> 00:20:14,781 +开始导航 + +310 +00:20:14,815 --> 00:20:16,750 +然后我点击 Go + +311 +00:20:16,783 --> 00:20:18,352 +好了 + +312 +00:20:18,385 --> 00:20:22,055 +我的 App 同时在 +中控台和仪表盘上 + +313 +00:20:22,089 --> 00:20:24,658 +都显示了实时地图视图 + +314 +00:20:24,691 --> 00:20:29,429 +实时地图正好在驾驶视线内 +真是太棒了 + +315 +00:20:29,463 --> 00:20:33,800 +我相信使用您导航 App 的司机 +也会喜欢的 + +316 +00:20:33,834 --> 00:20:35,802 +好了 这就是我今天的 +全部内容 + +317 +00:20:35,836 --> 00:20:40,407 +要了解更多信息 +请查看 CarPlay 开发者门户网站 + +318 +00:20:40,440 --> 00:20:44,011 +developer.apple.com/CarPlay + +319 +00:20:44,044 --> 00:20:47,114 +谢谢你们 祝大家旅途愉快 + diff --git a/zho/2022 Session 10017 Explore the machine learning development experience.srt b/zho/2022 Session 10017 Explore the machine learning development experience.srt new file mode 100644 index 0000000..e6a0cfc --- /dev/null +++ b/zho/2022 Session 10017 Explore the machine learning development experience.srt @@ -0,0 +1,1111 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,943 --> 00:00:12,246 +Geppy Parziale: +大家好 我是 Geppy Parziale + +3 +00:00:12,279 --> 00:00:15,148 +我是 Apple 的一名机器学习工程师 + +4 +00:00:15,182 --> 00:00:18,952 +今天 我想带大家来一趟 +构建 App 之旅 + +5 +00:00:18,986 --> 00:00:21,355 +运用机器学习来解决 + +6 +00:00:21,388 --> 00:00:25,893 +通常需要专家才能完成的工作 + +7 +00:00:27,394 --> 00:00:31,098 +这段旅程让我有机会向您展示 + +8 +00:00:31,131 --> 00:00:33,600 +如何将开源机器学习模型 +添加到您的 App 中 + +9 +00:00:33,634 --> 00:00:37,471 +并创造奇妙的新体验 + +10 +00:00:37,504 --> 00:00:39,640 +在这一过程中 我也会重点介绍 + +11 +00:00:39,673 --> 00:00:44,411 +Apple 开发生态中的一些工具 框架和 API + +12 +00:00:44,444 --> 00:00:48,749 +方便您用机器学习来构建 App + +13 +00:00:49,983 --> 00:00:53,654 +在构建 App 时 +您作为开发者会做一系列决定 + +14 +00:00:53,687 --> 00:00:57,824 +希望能为您的用户提供最佳体验 + +15 +00:00:57,858 --> 00:01:02,396 +在添加机器学习功能到 App 时 +也是如此 + +16 +00:01:04,031 --> 00:01:07,067 +在开发过程中 您或许会问 + +17 +00:01:07,100 --> 00:01:10,637 +我应该使用机器学习来 +构建这个功能吗 + +18 +00:01:10,671 --> 00:01:14,408 +如何获得机器学习模型 + +19 +00:01:14,441 --> 00:01:18,745 +我该如何让那个模型 +与 Apple 平台相兼容 + +20 +00:01:18,779 --> 00:01:22,716 +这个模型是否适合我的用户场景 + +21 +00:01:22,749 --> 00:01:26,320 +它可以在 +Apple 神经网络引擎上运行吗 + +22 +00:01:26,353 --> 00:01:29,590 +让我们一起踏上这段旅程吧 + +23 +00:01:29,623 --> 00:01:33,193 +我想构建一个 +给我家庭黑白照片 + +24 +00:01:33,227 --> 00:01:38,198 +添加逼真色彩的 App 这些照片 +是我在地下室的一个旧盒子里发现的 + +25 +00:01:39,666 --> 00:01:44,338 +当然 专业摄影师可能要通过 +辛苦的劳动 + +26 +00:01:44,371 --> 00:01:47,908 +花一些时间用照片编辑工具做到这一点 + +27 +00:01:47,941 --> 00:01:50,744 +但是 如果我想自动化这个过程 + +28 +00:01:50,777 --> 00:01:54,515 +那么如何在几秒钟内完成着色呢 + +29 +00:01:54,548 --> 00:01:57,584 +对于机器学习来说 +这似乎是一个完美的任务 + +30 +00:01:58,919 --> 00:02:02,155 +Apple 提供了数量巨大的框架和工具 + +31 +00:02:02,189 --> 00:02:06,026 +可以帮助您在 App 内 +构建和集成 ML 功能 + +32 +00:02:06,960 --> 00:02:09,296 +从数据处理到模型训练和推理 + +33 +00:02:09,329 --> 00:02:11,999 +都可以提供 + +34 +00:02:12,032 --> 00:02:15,669 +这一次 我会对其中一些进行使用 + +35 +00:02:15,702 --> 00:02:19,006 +但是要记住 根据您正在进行的 + +36 +00:02:19,039 --> 00:02:22,910 +具体的机器学习 您有很多种选择 + +37 +00:02:22,943 --> 00:02:25,712 +我在我的 App 中 +开发机器学习功能时 + +38 +00:02:25,746 --> 00:02:28,582 +经历了一系列阶段 + +39 +00:02:29,650 --> 00:02:32,753 +首先 我在技术论文 +或专门的网站 + +40 +00:02:32,786 --> 00:02:36,723 +找到正确的机器学习模型 + +41 +00:02:38,058 --> 00:02:40,360 +我搜索了照片着色 + +42 +00:02:40,394 --> 00:02:45,332 +并找到了一个名为 Colorizer 的模型 +可能适用于我的需求 + +43 +00:02:46,233 --> 00:02:50,337 +通过这个模型 +我可以获得这样的着色效果 + +44 +00:02:53,473 --> 00:02:55,175 +这是另一个 + +45 +00:02:56,643 --> 00:03:00,547 +这是另一个 非常好 + +46 +00:03:00,581 --> 00:03:03,083 +我来给您演示一下它是如何运行的 + +47 +00:03:03,116 --> 00:03:07,821 +着色器模型期望输入黑白图像 + +48 +00:03:07,855 --> 00:03:14,228 +我找到的 Python 源代码可以将任何 +RGB 图像转换为 LAB 颜色空间图像 + +49 +00:03:15,362 --> 00:03:18,031 +这个颜色空间有三个通道 + +50 +00:03:18,065 --> 00:03:22,102 +一个通道代表图像亮度或简称 L 通道 + +51 +00:03:22,135 --> 00:03:25,806 +而另外两个通道代表颜色组成 + +52 +00:03:25,839 --> 00:03:27,875 +把亮度作为着色器模型的输入 + +53 +00:03:27,908 --> 00:03:31,378 +丢弃两个颜色通道 + +54 +00:03:32,646 --> 00:03:35,516 +模型会预测出两个新的颜色通道 + +55 +00:03:35,549 --> 00:03:40,053 +与输入的 L 通道相结合 +形成最终的彩色图像 + +56 +00:03:41,154 --> 00:03:45,459 +让我们开始制作和我的 App +相兼容的模型 + +57 +00:03:45,492 --> 00:03:49,496 +为此 我可以将原始的 PyTorch 模型 + +58 +00:03:49,530 --> 00:03:53,300 +通过 coremltools 转换成 +Core ML 格式 + +59 +00:03:53,333 --> 00:03:58,071 +这是我使用的将 PyTorch 模型 +转换为 Core ML 的简单 Python 脚本 + +60 +00:03:59,439 --> 00:04:02,910 +首先 我导入 PyTorch 模型结构和权重 + +61 +00:04:04,378 --> 00:04:07,114 +然后跟踪导入的模型 + +62 +00:04:07,147 --> 00:04:11,285 +最终将 PyTorch 模型 +转换成 Core ML 并保存 + +63 +00:04:12,953 --> 00:04:15,389 +一旦模型采用 Core ML 格式 + +64 +00:04:15,422 --> 00:04:18,992 +我就需要验证一下 +转换工作是否成功 + +65 +00:04:19,026 --> 00:04:23,130 +我可以直接用 Python +在 coremltools 中验证 + +66 +00:04:23,163 --> 00:04:25,499 +这很简单 + +67 +00:04:25,532 --> 00:04:28,702 +我在 RGB 颜色空间中导入图像 + +68 +00:04:28,735 --> 00:04:31,238 +并将其转换为 Lab 颜色空间 + +69 +00:04:32,940 --> 00:04:37,144 +单独取出亮度通道 +把颜色通道丢弃 + +70 +00:04:38,745 --> 00:04:41,515 +使用 Core ML 模型进行预测 + +71 +00:04:42,616 --> 00:04:44,918 +最后用预测的颜色通道 +和输入的亮度通道 + +72 +00:04:44,952 --> 00:04:48,355 +组合成 LAB 图像再转换为 RGB + +73 +00:04:49,723 --> 00:04:53,794 +这让我可以验证 +转换后的模型功能 + +74 +00:04:53,827 --> 00:04:57,464 +与原始 PyTorch 模型的功能是否匹配 + +75 +00:04:57,497 --> 00:05:01,301 +我将此阶段称为模型验证 + +76 +00:05:01,335 --> 00:05:05,305 +不过 还有一个重要的检验需要完成 + +77 +00:05:05,339 --> 00:05:10,644 +我需要了解这个模型 +在我的目标设备上运行得是否足够快 + +78 +00:05:10,677 --> 00:05:13,747 +所以我需要在设备上评估模型 + +79 +00:05:13,780 --> 00:05:17,851 +确保它可以提供 +最好的用户体验 + +80 +00:05:17,885 --> 00:05:22,322 +在 Xcode 14 中支持 +新的 Core ML 性能报告 + +81 +00:05:22,356 --> 00:05:26,393 +针对 Core ML 模型 +执行一个基于时间的分析 + +82 +00:05:26,426 --> 00:05:29,630 +只需要将模型拖放到 Xcode 中 + +83 +00:05:29,663 --> 00:05:32,699 +在几秒之内就能创建一个性能报告 + +84 +00:05:33,834 --> 00:05:37,871 +使用这个工具 +可以看到预估的预测时间 + +85 +00:05:37,905 --> 00:05:43,577 +在 M1 和运行 iPadOS 16 的 iPad Pro 上 +差不多是 90 毫秒 + +86 +00:05:44,578 --> 00:05:48,215 +对我的照片着色 App 很完美 + +87 +00:05:48,248 --> 00:05:51,718 +如果您想了解更多关于 +性能报告的信息 + +88 +00:05:51,752 --> 00:05:56,957 +建议您观看今年的课程 +“优化您的 Core ML 使用” + +89 +00:05:56,990 --> 00:06:01,128 +性能报告可以帮助您 +对模型进行评估 + +90 +00:06:01,161 --> 00:06:04,798 +并确保它提供 +最佳的设备端用户体验 + +91 +00:06:05,966 --> 00:06:09,937 +确定模型功能和性能后 + +92 +00:06:09,970 --> 00:06:11,872 +下面让我将它集成到 App 内 + +93 +00:06:13,507 --> 00:06:18,178 +集成过程与之前在 Python 中 +所做的是相同的 + +94 +00:06:18,212 --> 00:06:20,848 +但这一次 使用 Xcode +和所有您熟悉的其他工具 + +95 +00:06:20,881 --> 00:06:24,151 +在 Swift 中无缝完成 + +96 +00:06:26,286 --> 00:06:29,289 +记住 这个模型现在是 Core ML 格式 + +97 +00:06:29,323 --> 00:06:33,227 +需要一个代表亮度的单通道图像 + +98 +00:06:34,695 --> 00:06:37,798 +所以类似于我 +之前在 Python 中所做的 + +99 +00:06:37,831 --> 00:06:43,203 +我需要将输入的 RGB 图像 +转换到 Lab 颜色空间图像 + +100 +00:06:45,839 --> 00:06:48,408 +我可以以多种方式实现这个转换 + +101 +00:06:48,442 --> 00:06:52,212 +直接在 Swift 中 +使用 vImage 或 Metal + +102 +00:06:53,514 --> 00:06:57,784 +深入探索文档 +我发现 Core Image 框架 + +103 +00:06:57,818 --> 00:07:00,554 +可以提供一些有帮助的东西 + +104 +00:07:02,656 --> 00:07:06,360 +所以 让我告诉您如何实现 +RGB 到 LAB 的转换 + +105 +00:07:06,393 --> 00:07:08,929 +并使用 Core ML 模型进行预测 + +106 +00:07:10,864 --> 00:07:13,667 +这是 Swift 代码用来从 RGB 图像中 + +107 +00:07:13,700 --> 00:07:17,538 +提取亮度并将其传递给 Core ML 模型 + +108 +00:07:17,571 --> 00:07:22,509 +首先 我将 RGB 图像转换成 LAB +并提取亮度 + +109 +00:07:23,944 --> 00:07:27,014 +然后 我将亮度转换成 CGImage + +110 +00:07:27,047 --> 00:07:30,050 +并为 Core ML 模型准备输入 + +111 +00:07:31,585 --> 00:07:33,921 +最后 进行预测 + +112 +00:07:33,954 --> 00:07:37,658 +要从输入的 RGB 图像得到 L 通道 + +113 +00:07:37,691 --> 00:07:41,094 +首先使用新的 +CIFilter convertRGBtoLab + +114 +00:07:41,128 --> 00:07:45,365 +将 RGB 图像转换成 LAB 图像 + +115 +00:07:45,399 --> 00:07:49,570 +亮度值被设定在 0 到 100 之间 + +116 +00:07:51,038 --> 00:07:54,708 +然后 我用颜色矩阵和 Lab 图像相乘 + +117 +00:07:54,741 --> 00:07:59,613 +来去掉颜色通道 +将亮度返回给调用者 + +118 +00:07:59,646 --> 00:08:02,983 +现在我们分析一下 +在模型输出时发生了什么 + +119 +00:08:04,751 --> 00:08:07,921 +Core ML 模型返回了 + +120 +00:08:07,955 --> 00:08:10,624 +两个 MLShapedArray +其中包含预测的颜色通道 + +121 +00:08:12,326 --> 00:08:18,031 +在预测之后 我将两个 MLShapedArray +转换成 CIImage + +122 +00:08:19,533 --> 00:08:23,937 +最后 将它们 +与输入的亮度结合起来 + +123 +00:08:23,971 --> 00:08:28,075 +这会生成一个新的 LAB 图像 +将它转换为 RGB 并返回 + +124 +00:08:30,344 --> 00:08:34,715 +要将两个 MLShapedArray +转换成 CIImage + +125 +00:08:34,748 --> 00:08:38,752 +我首先从每个成型阵列中提取值 + +126 +00:08:38,785 --> 00:08:42,356 +然后创建两个 CIImage +代表两个颜色通道 + +127 +00:08:42,389 --> 00:08:44,958 +并返回它们 + +128 +00:08:44,992 --> 00:08:47,961 +要将亮度通道与预测的颜色通道结合起来 + +129 +00:08:47,995 --> 00:08:51,498 +我使用了一个自定义的 CIKernel + +130 +00:08:51,532 --> 00:08:55,068 +它以三个通道作为输入 +并返回一个 CIImage + +131 +00:08:56,503 --> 00:09:00,107 +然后 我使用新的 CIFilter +convertLabToRGB + +132 +00:09:00,140 --> 00:09:04,978 +将 LAB 图像转换为 RGB +并将其返回给调用者 + +133 +00:09:05,012 --> 00:09:08,015 +这是自定义 CIKernel 的源码 + +134 +00:09:08,048 --> 00:09:12,052 +用于把亮度通道和预测的两个颜色通道 + +135 +00:09:12,085 --> 00:09:13,754 +结合到一个 CIImage 内 + +136 +00:09:14,888 --> 00:09:19,359 +关于 RGB 图像和 LAB 图像互相转换 +的新的 CIFilter + +137 +00:09:19,393 --> 00:09:23,664 +更多信息请参阅课程 + +138 +00:09:23,697 --> 00:09:27,734 +“使用 Core Image Metal +和SwiftUI 显示 EDR 内容” + +139 +00:09:29,002 --> 00:09:32,472 +现在我已经在我的 App 中 +完成了这个 ML 功能的整合 + +140 +00:09:32,506 --> 00:09:34,541 +让我们看看它的实际效果 + +141 +00:09:34,575 --> 00:09:36,443 +但是 等一下 + +142 +00:09:36,476 --> 00:09:41,014 +在 App 中如何实时 +为我的旧家庭照片着色 + +143 +00:09:41,048 --> 00:09:45,519 +我可以花一些时间将它们一一数字化 +并将它们导入我的 App + +144 +00:09:46,653 --> 00:09:48,956 +但我有一个更好的主意 + +145 +00:09:48,989 --> 00:09:51,925 +可以使用 iPad 相机扫描这些照片 + +146 +00:09:51,959 --> 00:09:54,061 +并实时给它们着色 + +147 +00:09:54,094 --> 00:09:58,465 +我想这会很有趣 +而且我有实现这个的所有条件 + +148 +00:09:58,498 --> 00:10:01,535 +但首先 我必须解决一个问题 + +149 +00:10:02,970 --> 00:10:06,607 +我的模型处理图像需要 90 毫秒 + +150 +00:10:06,640 --> 00:10:09,877 +如果我想处理视频 就需要更快一些 + +151 +00:10:11,111 --> 00:10:13,013 +为了获得流畅的用户体验 + +152 +00:10:13,046 --> 00:10:16,850 +我想让设备的摄像头 +运行速度至少在每秒 30 帧 + +153 +00:10:17,885 --> 00:10:22,256 +这意味着相机 +大约每 30 毫秒就要产生一帧 + +154 +00:10:24,191 --> 00:10:28,529 +但是由于模型为单个视频帧着色 +需要大约 90 毫秒 + +155 +00:10:28,562 --> 00:10:32,566 +所以每次着色都会错过 2 到 3 帧 + +156 +00:10:35,269 --> 00:10:39,406 +模型的总预测时间依赖于模型架构 + +157 +00:10:39,439 --> 00:10:44,111 +以及使用的计算单元运算 + +158 +00:10:44,144 --> 00:10:48,515 +再来看性能报告 +我注意到我的模型 + +159 +00:10:48,549 --> 00:10:54,188 +共有61个运算 +结合使用了神经网络引擎和 CPU + +160 +00:10:55,622 --> 00:10:59,726 +如果我想要更快的预测时间 +我需要改变模型 + +161 +00:11:00,694 --> 00:11:03,530 +我决定尝试修改模型架构 + +162 +00:11:03,564 --> 00:11:06,967 +探索一些可能更快的替代方案 + +163 +00:11:07,000 --> 00:11:11,972 +然而 修改架构 +意味着需要重新训练网络 + +164 +00:11:13,941 --> 00:11:15,609 +Apple 提供了不同的解决方案 + +165 +00:11:15,642 --> 00:11:19,112 +让我可以在 Mac 上 +直接训练机器学习模型 + +166 +00:11:20,514 --> 00:11:25,018 +就我而言 由于原始模型 +是用 PyTorch 开发的 + +167 +00:11:25,052 --> 00:11:27,888 +我决定使用 Metal 上新的 PyTorch + +168 +00:11:27,921 --> 00:11:31,625 +这样我就可以利用到 +由 Apple 芯片提供的 + +169 +00:11:31,658 --> 00:11:33,660 +众多硬件加速能力 + +170 +00:11:35,696 --> 00:11:40,167 +如果您有兴趣了解 +使用 Metal 加速 PyTorch + +171 +00:11:40,200 --> 00:11:43,937 +请查看课程 +“使用 Metal 加速机器学习” + +172 +00:11:46,173 --> 00:11:49,810 +修改之后 +我们需要回退一步 + +173 +00:11:50,878 --> 00:11:53,914 +重新训练之后 +我需要将模型重新转成 Core ML 格式 + +174 +00:11:53,947 --> 00:11:57,317 +并再次进行验证 + +175 +00:11:59,052 --> 00:12:01,455 +这一次 模型集成 + +176 +00:12:01,488 --> 00:12:04,725 +只要简单地把旧模型更换成新模型 + +177 +00:12:04,758 --> 00:12:08,195 +重新训练了一些候选的替代模型后 + +178 +00:12:08,228 --> 00:12:11,932 +经过验证 +其中一个可以满足我的需求 + +179 +00:12:11,965 --> 00:12:16,537 +这是对应的性能报告 + +180 +00:12:16,570 --> 00:12:18,672 +它完全在神经网络引擎上运行 + +181 +00:12:18,705 --> 00:12:22,843 +现在的预测时间大约是 16 毫秒 + +182 +00:12:22,876 --> 00:12:24,545 +适用于视频 + +183 +00:12:27,347 --> 00:12:32,186 +但性能报告 +只展示了 App 性能的一方面 + +184 +00:12:33,353 --> 00:12:36,723 +在运行 App 后 +我立即注意到 + +185 +00:12:36,757 --> 00:12:40,294 +着色并不如预期流畅 + +186 +00:12:40,327 --> 00:12:43,697 +App 在运行时究竟发生了什么 + +187 +00:12:45,132 --> 00:12:50,103 +为了理解这一点 我可以使用 +Instruments 中新的 Core ML 模板 + +188 +00:12:52,706 --> 00:12:55,576 +分析 Core ML 踪迹的初始部分 + +189 +00:12:55,609 --> 00:13:00,514 +加载模型后 我注意到 +App 会累积预测 + +190 +00:13:00,547 --> 00:13:02,549 +这是出乎意料的 + +191 +00:13:02,583 --> 00:13:06,587 +我希望每次只针对一帧做一次预测 + +192 +00:13:08,121 --> 00:13:12,826 +放大踪迹 并检查最初的几次预测 + +193 +00:13:12,860 --> 00:13:16,296 +我发现在第一个预测完成前 + +194 +00:13:16,330 --> 00:13:18,565 +App 请求了第二个 Core ML 预测 + +195 +00:13:19,800 --> 00:13:23,904 +在这里 当第二个请求提交给 Core ML 时 + +196 +00:13:23,937 --> 00:13:26,440 +神经网络引擎仍在处理第一个请求 + +197 +00:13:27,574 --> 00:13:30,310 +同样 第三个预测开始时 + +198 +00:13:30,344 --> 00:13:33,413 +同时仍在处理第二个 + +199 +00:13:33,447 --> 00:13:35,549 +甚至经过四次预测之后 + +200 +00:13:35,582 --> 00:13:39,052 +请求和执行之间的延迟 + +201 +00:13:39,086 --> 00:13:42,055 +已经有大约 20 毫秒 + +202 +00:13:42,089 --> 00:13:45,759 +不应如此 +我需要确保只有完成之前的预测后 + +203 +00:13:45,792 --> 00:13:50,330 +才会开始新的预测 +以避免这些串联 + +204 +00:13:51,798 --> 00:13:55,936 +在解决这个问题的同时 +我也发现我不小心将 + +205 +00:13:55,969 --> 00:14:01,175 +相机帧速率设置为 60fps +而不是所需的 30fps + +206 +00:14:03,377 --> 00:14:06,513 +确保 App 在上一个预测完成后 + +207 +00:14:06,547 --> 00:14:08,849 +才开始预测新的视频帧 + +208 +00:14:08,882 --> 00:14:12,219 +并将相机帧率设置为每秒 30 帧 + +209 +00:14:12,252 --> 00:14:15,923 +我可以看到 +Core ML正确地分派了单个预测 + +210 +00:14:15,956 --> 00:14:20,160 +给到 Apple 神经网络引擎 +现在 App 运行顺利 + +211 +00:14:22,362 --> 00:14:24,731 +所以我们的旅程也到达了终点 + +212 +00:14:26,066 --> 00:14:28,869 +我们用我的旧家庭照片 +来测试一下 App + +213 +00:14:34,508 --> 00:14:38,512 +这是我在我的地下室发现的黑白照片 + +214 +00:14:38,545 --> 00:14:42,583 +这些照片上是我很久以前 +在意大利到访过的一些地方 + +215 +00:14:49,389 --> 00:14:52,426 +这是在罗马斗兽场拍的一张 +很棒的照片 + +216 +00:14:53,760 --> 00:14:56,730 +墙壁和天空的颜色是如此逼真 + +217 +00:14:59,266 --> 00:15:01,034 +我们来看看这张 + +218 +00:15:03,370 --> 00:15:06,240 +这是意大利南部的蒙特堡 + +219 +00:15:06,273 --> 00:15:07,741 +非常好 + +220 +00:15:09,643 --> 00:15:12,513 +这是我的家乡 格罗塔利 + +221 +00:15:12,546 --> 00:15:15,949 +为这些图像添加颜色 +触发了很多回忆 + +222 +00:15:17,184 --> 00:15:20,554 +请注意我只在照片上进行着色 + +223 +00:15:20,587 --> 00:15:23,390 +相机流中的其他场景保持黑白 + +224 +00:15:26,326 --> 00:15:29,796 +在这里 我利用的是 Vision 框架中的 + +225 +00:15:29,830 --> 00:15:32,432 +矩形检测算法 + +226 +00:15:32,466 --> 00:15:37,204 +使用 VNDetectRectangleRequest +我可以分离出场景中的照片 + +227 +00:15:37,237 --> 00:15:39,806 +把它作为着色模型的输入 + +228 +00:15:41,041 --> 00:15:43,277 +现在让我回顾一下 + +229 +00:15:44,645 --> 00:15:48,982 +在这次旅程中 我探索了大量 +Apple 提供的框架、API 和工具 + +230 +00:15:49,016 --> 00:15:52,819 +让您的 App + +231 +00:15:52,853 --> 00:15:56,423 +可以准备、集成和评估机器学习功能 + +232 +00:15:56,456 --> 00:15:59,660 +开始这段旅程时 +我定义了一个问题 + +233 +00:15:59,693 --> 00:16:02,863 +这个问题 +需要一个开源的机器学习模型解决 + +234 +00:16:03,964 --> 00:16:06,800 +我找到了一个符合功能条件的模型 + +235 +00:16:06,834 --> 00:16:10,304 +并使其与 Apple 平台相兼容 + +236 +00:16:10,337 --> 00:16:13,440 +我使用新的性能报告 + +237 +00:16:13,473 --> 00:16:16,276 +直接在设备上评估了模型性能 + +238 +00:16:16,310 --> 00:16:19,379 +通过您熟悉的工具和框架 + +239 +00:16:19,413 --> 00:16:21,548 +我在 App 内集成了模型 + +240 +00:16:22,983 --> 00:16:27,154 +我使用 Instruments 中 +新的 Core ML 模板优化了模型 + +241 +00:16:27,187 --> 00:16:30,524 +借助 Apple 的工具和框架 +我可以直接在 Apple 设备和平台上 + +242 +00:16:30,557 --> 00:16:34,828 +处理开发的各个阶段 + +243 +00:16:34,862 --> 00:16:38,866 +从数据准备 训练 到集成和优化 + +244 +00:16:40,901 --> 00:16:44,938 +今天我们只讲了一小部分 +您作为开发者 + +245 +00:16:44,972 --> 00:16:49,042 +可以通过 Apple +提供的框架和工具实现强大功能 + +246 +00:16:49,076 --> 00:16:52,446 +请参考与此相关的其他课程 + +247 +00:16:52,479 --> 00:16:56,950 +为您的 App 引入机器学习 +带来更多灵感 + +248 +00:16:56,984 --> 00:16:59,786 +探索和尝试框架和工具 + +249 +00:16:59,820 --> 00:17:03,724 +利用软件和硬件之间 +强大的协同能力 + +250 +00:17:03,757 --> 00:17:06,026 +来加速您的机器学习功能 + +251 +00:17:06,059 --> 00:17:09,196 +并丰富您 App 的用户体验 + +252 +00:17:09,229 --> 00:17:12,332 +祝您有一个愉快的 WWDC 再见 + diff --git a/zho/2022 Session 10018 Bring Continuity Camera to your macOS app.srt b/zho/2022 Session 10018 Bring Continuity Camera to your macOS app.srt new file mode 100644 index 0000000..3e91b96 --- /dev/null +++ b/zho/2022 Session 10018 Bring Continuity Camera to your macOS app.srt @@ -0,0 +1,1493 @@ +1 +00:00:00,000 --> 00:00:03,837 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,837 --> 00:00:09,409 +♪ + +3 +00:00:09,409 --> 00:00:11,879 +Karen Xing: +嗨 我是 Karen Xing + +4 +00:00:11,879 --> 00:00:14,414 +我是相机软件团队的工程师 + +5 +00:00:14,414 --> 00:00:16,750 +欢迎来到 “集成连续互通 + +6 +00:00:16,750 --> 00:00:19,186 +至您的 macOS App 中“ 的讲座 + +7 +00:00:19,186 --> 00:00:21,688 +首先 我将谈一谈 + +8 +00:00:21,688 --> 00:00:24,124 +什么是“连续互通”相机? + +9 +00:00:24,124 --> 00:00:26,760 +接下来 我将探讨您的 App 如何 + +10 +00:00:26,760 --> 00:00:29,530 +借助“连续互通”相机 + +11 +00:00:29,530 --> 00:00:32,165 +实现相机的自动选择 + +12 +00:00:32,165 --> 00:00:34,935 +最后 我将介绍 +macOS 13 中用于 + +13 +00:00:34,935 --> 00:00:40,474 +“连续互通”相机的全新 API + +14 +00:00:40,474 --> 00:00:42,109 +有了“连续互通”相机 + +15 +00:00:42,109 --> 00:00:45,279 +您就可以将 iPhone +用作网络摄像头 + +16 +00:00:45,279 --> 00:00:46,680 +无缝切换的设置 + +17 +00:00:46,680 --> 00:00:49,116 +让您只需将 iPhone +移至 Mac 附近 + +18 +00:00:49,116 --> 00:00:54,621 +它就能通过无线方式连接 +使您快速加入通话 + +19 +00:00:54,621 --> 00:00:57,191 +满足以下几项条件 + +20 +00:00:57,191 --> 00:00:59,927 +您的 iPhone 即可成为 + +21 +00:00:59,927 --> 00:01:01,962 +您 Mac 上的外接摄像头和麦克风 + +22 +00:01:01,962 --> 00:01:07,334 +首先 您必须使用 +macOS 13 和 iOS 16 + +23 +00:01:07,334 --> 00:01:10,971 +Mac 和 iPhone +必须登录同一 + +24 +00:01:10,971 --> 00:01:13,941 +通过双重认证的 Apple ID + +25 +00:01:13,941 --> 00:01:15,642 +如果使用有线方式连接 + +26 +00:01:15,642 --> 00:01:20,113 +手机需通过 USB 连接到 Mac + +27 +00:01:20,113 --> 00:01:22,382 +如果使用无线方式连接 + +28 +00:01:22,382 --> 00:01:24,952 +两台设备需位于彼此附近 + +29 +00:01:24,952 --> 00:01:28,622 +并同时开启蓝牙和 Wi-Fi + +30 +00:01:28,622 --> 00:01:31,625 +与其进行口头介绍 +不如由我立刻演示 + +31 +00:01:31,625 --> 00:01:35,596 +“连续互通”相机 +在设备上的神奇表现 + +32 +00:01:35,596 --> 00:01:38,765 +我身边有一台 MacBook Pro +和一台 iPhone 13 Pro + +33 +00:01:38,765 --> 00:01:42,569 +两台设备 +都登录了同一 Apple ID + +34 +00:01:47,107 --> 00:01:50,444 +手机放置在 +与我的 MacBook 相连的支架上 + +35 +00:01:50,444 --> 00:01:52,679 +我将加入与同事 Eric 的 + +36 +00:01:52,679 --> 00:01:54,381 +视频会议通话 + +37 +00:01:54,381 --> 00:01:58,919 +并向您展示如何在 Zoom 中 +使用“连续互通”相机 + +38 +00:02:04,258 --> 00:02:07,094 +这个 App +首先使用内置摄像头启动 + +39 +00:02:07,094 --> 00:02:09,830 +随后 一个流程指引对话框出现 + +40 +00:02:09,830 --> 00:02:12,866 +介绍您可以使用新相机实现的功能 + +41 +00:02:12,866 --> 00:02:14,835 +当您将 Mac +升级到 macOS 13 之后 + +42 +00:02:14,835 --> 00:02:18,105 +首次打开“相机” App + +43 +00:02:18,105 --> 00:02:20,841 +以及有一台可以使用 +“连续互通”相机的 iPhone 时 + +44 +00:02:20,841 --> 00:02:25,879 +此对话框将出现一次 + +45 +00:02:27,881 --> 00:02:30,284 +嗨 Eric! + +46 +00:02:30,284 --> 00:02:35,155 +Eric:哦 Karen!嗨! + +47 +00:02:35,155 --> 00:02:38,258 +在系统显示流程指引对话框后 + +48 +00:02:38,258 --> 00:02:40,928 +“连续互通”相机和麦克风设备 + +49 +00:02:40,928 --> 00:02:45,532 +将在所有 App 中可用 + +50 +00:02:51,872 --> 00:02:55,542 +让我们切换到这个相机 +看看它的使用效果 + +51 +00:03:01,114 --> 00:03:05,319 +“连续互通”相机使用 +iPhone 的后置摄像头系统 + +52 +00:03:05,319 --> 00:03:07,354 +让您获得期望中 iPhone 所能实现的 + +53 +00:03:07,354 --> 00:03:09,122 +出色的视频质量 + +54 +00:03:09,122 --> 00:03:13,060 +并适用于手机的所有四个朝向 + +55 +00:03:16,897 --> 00:03:19,733 +竖排模式为您提供 + +56 +00:03:19,733 --> 00:03:23,637 +与横排模式相比更放大的画面 + +57 +00:03:27,307 --> 00:03:30,477 +“连续互通”相机还能实现 + +58 +00:03:30,477 --> 00:03:33,647 +网络摄像头从前无法实现的功能 + +59 +00:03:33,647 --> 00:03:37,184 +其中包括数个新的视频效果 + +60 +00:03:37,184 --> 00:03:38,986 +您可能已经很熟悉 + +61 +00:03:38,986 --> 00:03:41,355 +iOS 14.5 +和 macOS 12.3 中引入的 + +62 +00:03:41,355 --> 00:03:45,993 +“人物居中”和人像模式 + +63 +00:03:45,993 --> 00:03:48,462 +如果还不熟悉 我强烈建议您观看 + +64 +00:03:48,462 --> 00:03:53,333 +WWDC 2021 中的 +“新的相机拍摄功能”讲座 + +65 +00:03:53,333 --> 00:03:55,636 +了解更多关于系统视频效果 + +66 +00:03:55,636 --> 00:04:00,307 +以及如何在 App 中 +与其交互的信息 + +67 +00:04:00,307 --> 00:04:03,710 +让我们前往“控制中心” +并为“连续互通”相机 + +68 +00:04:03,710 --> 00:04:06,380 +启用系统视频效果 + +69 +00:04:09,550 --> 00:04:15,255 +当您四处移动时 “人物居中” 效果 +确保您处在画面之中 + +70 +00:04:17,491 --> 00:04:19,359 +人像模式将背景模糊 + +71 +00:04:19,359 --> 00:04:22,196 +自然而然地把焦点放在您身上 + +72 +00:04:22,196 --> 00:04:25,365 +人像模式仅支持在搭载 +Apple 芯片的 Mac 上使用 + +73 +00:04:25,365 --> 00:04:27,100 +但有了“连续互通”相机后 + +74 +00:04:27,100 --> 00:04:32,072 +它现在可用于所有搭载 +Intel 和 Apple 芯片的 Mac + +75 +00:04:35,909 --> 00:04:38,378 +“摄影室灯光”是一种 +新的系统视频效果 + +76 +00:04:38,378 --> 00:04:40,547 +在 macOS 13 上可用 + +77 +00:04:40,547 --> 00:04:42,783 +可在 iPhone 12 或更新机型上 + +78 +00:04:42,783 --> 00:04:45,219 +使用此效果 + +79 +00:04:45,219 --> 00:04:48,589 +想以最佳状态出现在屏幕上 +就启用这个功能吧 + +80 +00:04:48,589 --> 00:04:50,958 +它令人惊叹的照明效果 + +81 +00:04:50,958 --> 00:04:54,795 +能使背景变暗 照亮您的脸 + +82 +00:04:54,795 --> 00:04:58,131 +“摄影室灯光”非常适合 +光照条件不佳的环境 + +83 +00:04:58,131 --> 00:05:00,968 +例如您正身处窗前 + +84 +00:05:00,968 --> 00:05:03,971 +为了进行清晰比较 + +85 +00:05:03,971 --> 00:05:08,475 +我将分别展示每个视频效果 +同时使用效果也不错 + +86 +00:05:13,480 --> 00:05:15,516 +这些效果可以任意组合 + +87 +00:05:15,516 --> 00:05:19,119 +同时使用 + +88 +00:05:25,125 --> 00:05:28,328 +我非常想为您展示 + +89 +00:05:28,328 --> 00:05:30,631 +“连续互通”相机 +另一个很棒的功能 + +90 +00:05:30,631 --> 00:05:34,034 +当您需要协同工作 +并分享办公桌上的物件时 + +91 +00:05:34,034 --> 00:05:36,103 +可以使用“桌面视图” + +92 +00:05:36,103 --> 00:05:38,972 +macOS 13 配备了 +“桌面视图” App + +93 +00:05:38,972 --> 00:05:42,776 +可以进入“控制中心”启动 + +94 +00:05:48,448 --> 00:05:51,051 +它的工作原理跟悬吊俯拍相机类似 + +95 +00:05:51,051 --> 00:05:54,054 +但不需要任何复杂的设备 + +96 +00:05:54,054 --> 00:05:57,257 +iPhone 会将 +超广角摄像头源分成两部分 + +97 +00:05:57,257 --> 00:06:00,561 +同时呈现桌面和人脸 + +98 +00:06:00,561 --> 00:06:02,963 +让您可以协作完成学校项目 + +99 +00:06:02,963 --> 00:06:05,399 +或教朋友编织针法 + +100 +00:06:05,399 --> 00:06:08,135 +它利用超广角摄像头 + +101 +00:06:08,135 --> 00:06:10,737 +扩展的垂直视野 + +102 +00:06:10,737 --> 00:06:14,374 +将透视失真校正 +应用于裁剪出来的画面 + +103 +00:06:14,374 --> 00:06:18,011 +随后旋转这些画面创建桌面视图 + +104 +00:06:18,011 --> 00:06:21,014 +您可以使用大多数视频会议 App + +105 +00:06:21,014 --> 00:06:24,852 +均提供的共享窗口功能 + +106 +00:06:24,852 --> 00:06:29,256 +同时分享“桌面视图”与主摄像头源 + +107 +00:06:52,279 --> 00:06:54,281 +“桌面视图”也可以单独使用 + +108 +00:06:54,281 --> 00:06:57,017 +无需与主摄像头视频流并行 + +109 +00:06:57,017 --> 00:06:58,285 +但是 当您确实需要同时 + +110 +00:06:58,285 --> 00:07:00,454 +使用“桌面视图”和主摄像头视频流 + +111 +00:07:00,454 --> 00:07:04,057 +我们建议在主摄像头中 +启用“人物居中” + +112 +00:07:04,057 --> 00:07:07,561 +以获得拍摄人物面部 +和身体更好的取景效果 + +113 +00:07:07,561 --> 00:07:09,696 +手机放置的横排和竖排模式 + +114 +00:07:09,696 --> 00:07:12,733 +均支持这项功能 + +115 +00:07:12,733 --> 00:07:16,069 +竖排模式的用途最为广泛 + +116 +00:07:16,069 --> 00:07:19,173 +因为垂直视野的范围更大 + +117 +00:07:19,173 --> 00:07:22,009 +“桌面视图”相机 API 也可以 + +118 +00:07:22,009 --> 00:07:24,278 +为您的 App 提供 + +119 +00:07:24,278 --> 00:07:26,413 +适配的定制集成方案 + +120 +00:07:26,413 --> 00:07:29,883 +稍后我将谈到 API + +121 +00:07:29,883 --> 00:07:32,219 +在 Mac 上进行视频会议通话期间 + +122 +00:07:32,219 --> 00:07:34,454 +我们既希望您专注于会议本身 + +123 +00:07:34,454 --> 00:07:35,923 +也想确保 + +124 +00:07:35,923 --> 00:07:38,358 +您不会错过任何重要事项 + +125 +00:07:38,358 --> 00:07:40,761 +使用“连续互通”相机时 + +126 +00:07:40,761 --> 00:07:43,764 +您手机上的所有通知都将静音 + +127 +00:07:43,764 --> 00:07:49,169 +重要的来电通知 +将转发至您的 Mac 上 + +128 +00:07:49,169 --> 00:07:50,671 +再见 Eric! + +129 +00:07:50,671 --> 00:07:53,273 +Eric:再见 Karen! + +130 +00:07:58,846 --> 00:08:00,247 +Karen:我们刚刚谈到了 + +131 +00:08:00,247 --> 00:08:03,417 +无需在 App 中 +编写任何一行新代码 + +132 +00:08:03,417 --> 00:08:07,154 +就可以让用户获得的出色体验 + +133 +00:08:07,154 --> 00:08:09,923 +随着一些新 API 的运用 + +134 +00:08:09,923 --> 00:08:12,559 +“连续互通”相机体验可以 + +135 +00:08:12,559 --> 00:08:16,597 +在您的 App 中变得更为精妙绝伦 + +136 +00:08:16,597 --> 00:08:18,165 +现在大多数用户都至少 + +137 +00:08:18,165 --> 00:08:20,834 +在 Mac 上拥有两种相机设备 + +138 +00:08:20,834 --> 00:08:24,404 +我们进一步思考了 +应当如何管理相机 + +139 +00:08:24,404 --> 00:08:28,475 +在 macOS 13 之前 +当设备被拔出 + +140 +00:08:28,475 --> 00:08:31,845 +或者系统中有 +更好的相机可供使用时 + +141 +00:08:31,845 --> 00:08:33,213 +通常需要在 App 中 + +142 +00:08:33,213 --> 00:08:36,383 +手动进行选择 + +143 +00:08:36,383 --> 00:08:39,953 +我们希望通过在 App 中 +实现相机的自动切换 + +144 +00:08:39,953 --> 00:08:43,423 +为客户提供绝妙体验 + +145 +00:08:43,423 --> 00:08:46,960 +我们在 AVFoundation 框架中 +添加了两个新的 API + +146 +00:08:46,960 --> 00:08:49,963 +帮助您在 App 中构建此功能: + +147 +00:08:49,963 --> 00:08:52,833 +AVCaptureDevice 上的 +类属性 userPreferredCamera + +148 +00:08:52,833 --> 00:08:56,970 +以及 systemPreferredCamera + +149 +00:08:56,970 --> 00:09:00,407 +userPreferredCamera +是一个读/写属性 + +150 +00:09:00,407 --> 00:09:02,009 +每当用户在 App 中选择相机时 + +151 +00:09:02,009 --> 00:09:05,646 +都需要设定此属性 + +152 +00:09:05,646 --> 00:09:08,081 +这就让 AVCaptureDevice 类 + +153 +00:09:08,081 --> 00:09:11,118 +能够学习用户的偏好 +为每个 App + +154 +00:09:11,118 --> 00:09:15,022 +存储一份跨启动和重启的相机列表 + +155 +00:09:15,022 --> 00:09:18,625 +并使用该信息推荐相机 + +156 +00:09:18,625 --> 00:09:21,061 +它还考虑到是否有任何相机 + +157 +00:09:21,061 --> 00:09:25,199 +连接或断开的情况 + +158 +00:09:25,199 --> 00:09:28,035 +该属性可键值观察 + +159 +00:09:28,035 --> 00:09:31,104 +并可以基于用户偏好 + +160 +00:09:31,104 --> 00:09:33,273 +智能地返回最佳选择 + +161 +00:09:33,273 --> 00:09:36,910 +当最近的首选设备断开连接时 + +162 +00:09:36,910 --> 00:09:38,812 +它会自发地更换 + +163 +00:09:38,812 --> 00:09:41,815 +列表中下一个可用相机 + +164 +00:09:41,815 --> 00:09:44,384 +即使没有用户选择历史 + +165 +00:09:44,384 --> 00:09:47,487 +或未连接任何首选设备 + +166 +00:09:47,487 --> 00:09:49,756 +该属性也将始终尝试返回 + +167 +00:09:49,756 --> 00:09:52,125 +可即时使用的相机设备 + +168 +00:09:52,125 --> 00:09:56,463 +并优先考虑之前 +已进行过视频流传输的相机 + +169 +00:09:56,463 --> 00:09:59,666 +只有在系统中没有可用相机时 + +170 +00:09:59,666 --> 00:10:03,103 +才返回 nil + +171 +00:10:03,103 --> 00:10:06,807 +systemPreferredCamera +是一个只读属性 + +172 +00:10:06,807 --> 00:10:08,842 +它将 userPreferredCamera + +173 +00:10:08,842 --> 00:10:11,278 +与其他因素结合 + +174 +00:10:11,278 --> 00:10:15,516 +对系统中相机的最佳选择进行建议 + +175 +00:10:15,516 --> 00:10:19,152 +例如 当“连续互通”相机出现 + +176 +00:10:19,152 --> 00:10:22,756 +并示意应当自动选择它时 +该属性会返回 + +177 +00:10:22,756 --> 00:10:26,527 +与 userPreferredCamera 不同的值 + +178 +00:10:26,527 --> 00:10:29,963 +该属性还对设备挂起进行内部追踪 + +179 +00:10:29,963 --> 00:10:34,801 +因此它会将未挂起的设备 +优先于挂起的设备 + +180 +00:10:34,801 --> 00:10:37,938 +这有助于构建自动切换行为 + +181 +00:10:37,938 --> 00:10:40,641 +便于在内置摄像头 +因 MacBook 合盖而挂起时 + +182 +00:10:40,641 --> 00:10:44,545 +更换为另一个摄像头 + +183 +00:10:44,545 --> 00:10:48,682 +出现以下情况时 “连续互通”相机 +将示意自动选择它: + +184 +00:10:48,682 --> 00:10:51,585 +手机放在固定支架上 + +185 +00:10:51,585 --> 00:10:54,788 +处于横排模式 屏幕关闭 + +186 +00:10:54,788 --> 00:10:57,758 +并通过 USB 连接到 Mac + +187 +00:10:57,758 --> 00:11:00,994 +或与 Mac 距离接近 + +188 +00:11:00,994 --> 00:11:04,364 +在这种情况下 用户的意图很明确 + +189 +00:11:04,364 --> 00:11:08,035 +即应当将该备 +作为“连续互通”相机使用 + +190 +00:11:10,704 --> 00:11:13,607 +采用 systemPreferredCamera API 时 + +191 +00:11:13,607 --> 00:11:16,410 +您应当不断通过键值观察该属性 + +192 +00:11:16,410 --> 00:11:18,545 +并更新相应的 AVCaptureSession + +193 +00:11:18,545 --> 00:11:20,981 +视频输入设备 + +194 +00:11:20,981 --> 00:11:25,118 +提供绝佳的相机选择体验 + +195 +00:11:25,118 --> 00:11:27,821 +userPreferredCamera +和 systemPreferredCamera + +196 +00:11:27,821 --> 00:11:31,592 +已被不少第一方 App 采用 + +197 +00:11:31,592 --> 00:11:35,295 +随着越来越多的 App +采用这些 API + +198 +00:11:35,295 --> 00:11:37,564 +我们将能够为客户提供 + +199 +00:11:37,564 --> 00:11:41,168 +一种适用于 Apple 设备的 + +200 +00:11:41,168 --> 00:11:43,871 +通用且稳定的相机选择方法 + +201 +00:11:43,871 --> 00:11:46,039 +让我来为您演示说明 + +202 +00:11:46,039 --> 00:11:48,909 +“连续互通”相机自动切换 + +203 +00:11:48,909 --> 00:11:51,245 +在 FaceTime 通话中的应用 + +204 +00:11:56,416 --> 00:11:57,684 +在 FaceTime 通话中 + +205 +00:11:57,684 --> 00:12:00,754 +我正处于自动相机选择模式 + +206 +00:12:00,754 --> 00:12:02,689 +如果想要在 App 中同时提供 + +207 +00:12:02,689 --> 00:12:06,994 +手动和自动行为选项 +我们建议添加新的 UI + +208 +00:12:06,994 --> 00:12:10,397 +用于启用和禁用自动模式 + +209 +00:12:13,267 --> 00:12:16,937 +FaceTime 通话目前正通过 +内置摄像头进行视频流传输 + +210 +00:12:16,937 --> 00:12:19,173 +当我将手机从办公桌上拿起来 + +211 +00:12:19,173 --> 00:12:23,210 +并将其放在 +MacBook 后面的支架上时… + +212 +00:12:26,180 --> 00:12:30,184 +FaceTime 通话无缝切换 +为使用“连续互通”相机 + +213 +00:12:30,184 --> 00:12:32,119 +进行视频流传输 + +214 +00:12:32,119 --> 00:12:33,921 +新的类属性 + +215 +00:12:33,921 --> 00:12:36,123 +systemPreferredCamera +将在此情况下发挥作用 + +216 +00:12:36,123 --> 00:12:39,126 +当手机处于随时 +可以传输视频流的状态时 + +217 +00:12:39,126 --> 00:12:43,630 +属性值更改为“连续互通”相机 + +218 +00:12:43,630 --> 00:12:47,234 +您或许希望用类似的方式构建 App + +219 +00:12:47,234 --> 00:12:49,870 +以下是我实施自动相机选择 + +220 +00:12:49,870 --> 00:12:55,042 +和手动选择模式的秘诀 + +221 +00:12:55,042 --> 00:12:57,911 +当自动相机选择启用时 + +222 +00:12:57,911 --> 00:13:02,716 +开始对 systemPreferredCamera +属性进行键值观察 + +223 +00:13:02,716 --> 00:13:05,652 +通过更新您会话的输入设备 + +224 +00:13:05,652 --> 00:13:09,022 +随时跟进 +systemPreferredCamera 的变化 + +225 +00:13:09,022 --> 00:13:11,191 +在自动模式下 我们强烈推荐 + +226 +00:13:11,191 --> 00:13:12,392 +仍然为用户提供 + +227 +00:13:12,392 --> 00:13:15,963 +自主挑选相机的选项 + +228 +00:13:15,963 --> 00:13:17,831 +当用户选中不同的相机时 + +229 +00:13:17,831 --> 00:13:20,501 +为该设备设定 userPreferredCamera + +230 +00:13:20,501 --> 00:13:22,169 +随后反映在 + +231 +00:13:22,169 --> 00:13:26,573 +systemPreferredCamera 属性值中 + +232 +00:13:26,573 --> 00:13:29,209 +当自动相机选择关闭时 + +233 +00:13:29,209 --> 00:13:33,814 +停止对 systemPreferredCamera +属性的键值观察 + +234 +00:13:33,814 --> 00:13:36,416 +在手动模式下 +无需追踪 systemPreferredCamera + +235 +00:13:36,416 --> 00:13:39,253 +您需要将用户选择的相机 + +236 +00:13:39,253 --> 00:13:42,489 +更新至会话的输入设备 + +237 +00:13:42,489 --> 00:13:44,725 +但与自动模式相同 您仍然需要 + +238 +00:13:44,725 --> 00:13:46,560 +在每次用户选择不同的相机时 + +239 +00:13:46,560 --> 00:13:49,563 +设定 userPreferredCamera 属性 + +240 +00:13:49,563 --> 00:13:53,033 +保存用户偏好相机的历史纪录 + +241 +00:13:53,033 --> 00:13:55,202 +并在回到“自动相机选择”模式时 + +242 +00:13:55,202 --> 00:13:59,072 +推荐合适的相机 + +243 +00:13:59,072 --> 00:14:03,277 +如需了解整合 +userPreferredCamera 和 + +244 +00:14:03,277 --> 00:14:06,280 +systemPreferredCamera API 的 +最佳实践 请查看 + +245 +00:14:06,280 --> 00:14:10,851 +全新示例 App +“‘连续互通’相机示例” + +246 +00:14:10,851 --> 00:14:14,188 +不仅为 Mac +带来绝妙的网络摄像头体验 + +247 +00:14:14,188 --> 00:14:17,991 +“连续互通”相机 +还为您提供了新的机会 + +248 +00:14:17,991 --> 00:14:21,795 +在Mac App 中 +充分利用 iPhone 特有的 + +249 +00:14:21,795 --> 00:14:23,630 +强大相机功能 + +250 +00:14:23,630 --> 00:14:27,935 +我们在 macOS 13 上 +添加了一些 AVCapture API + +251 +00:14:27,935 --> 00:14:30,103 +帮助 App 更好地利用 + +252 +00:14:30,103 --> 00:14:33,207 +“连续互通”相机设备 + +253 +00:14:33,207 --> 00:14:36,476 +由于“连续互通”相机的存在 +我们在 macOS 上实现了令人惊叹的 + +254 +00:14:36,476 --> 00:14:39,913 +iPhone 级照片拍摄质量 + +255 +00:14:39,913 --> 00:14:44,051 +首先 高分辨率照片的 +拍摄将得到支持 + +256 +00:14:44,051 --> 00:14:47,654 +从前 macOS 仅支持与视频分辨率 + +257 +00:14:47,654 --> 00:14:49,389 +同等的照片拍摄 + +258 +00:14:49,389 --> 00:14:52,426 +从 macOS 13 开始 您将能够 + +259 +00:14:52,426 --> 00:14:56,797 +使用“连续互通”相机拍摄 +分辨率高达 1,200 万像素的照片 + +260 +00:14:56,797 --> 00:14:59,333 +想要启用这项功能 +在拍摄会话开始前 + +261 +00:14:59,333 --> 00:15:01,902 +首先要在 +AVCapturePhotoOutput 对象上 + +262 +00:15:01,902 --> 00:15:05,038 +将 highResolutionCaptureEnabled +设置为 true + +263 +00:15:05,038 --> 00:15:08,008 +然后在每次拍摄的 + +264 +00:15:08,008 --> 00:15:10,911 +photoSettings 对象上 + +265 +00:15:10,911 --> 00:15:16,350 +将 highResolutionPhotoEnabled +属性设置为 true + +266 +00:15:16,350 --> 00:15:19,319 +除了拍摄高分辨率照片 + +267 +00:15:19,319 --> 00:15:23,123 +“连续互通”相机还支持 + +268 +00:15:23,123 --> 00:15:25,592 +控制照片质量优先于拍摄速度 + +269 +00:15:25,592 --> 00:15:30,030 +实现方式是首先 +在 photoOutput 对象上 + +270 +00:15:30,030 --> 00:15:32,165 +设置 +maxPhotoQualityPrioritization + +271 +00:15:32,165 --> 00:15:36,603 +随后在 +AVCapturePhotoSettings 对象上 + +272 +00:15:36,603 --> 00:15:39,006 +为每次拍摄设置 + +273 +00:15:39,006 --> 00:15:44,111 +photoQualityPrioritization 属性 + +274 +00:15:44,111 --> 00:15:47,281 +如需了解 +如何为 App 选择正确优先级 + +275 +00:15:47,281 --> 00:15:49,516 +请您查看 + +276 +00:15:49,516 --> 00:15:52,252 +WWDC 2021 + +277 +00:15:52,252 --> 00:15:58,158 +“使用视频格式拍摄高质量照片” + +278 +00:15:58,158 --> 00:16:01,695 +另一个与照片相关的功能 +是闪光灯拍摄 + +279 +00:16:01,695 --> 00:16:04,932 +您可以通过在 photoSettings +对象上设置 flashMode + +280 +00:16:04,932 --> 00:16:08,068 +来控制闪光灯是应该打开、关闭 + +281 +00:16:08,068 --> 00:16:09,870 +还是自动选择 + +282 +00:16:09,870 --> 00:16:14,842 +基于场景和光照条件 + +283 +00:16:14,842 --> 00:16:17,411 +我们也让 AVCaptureMetadataOutput +适用于 macOS + +284 +00:16:17,411 --> 00:16:22,049 +允许对拍摄会话产生的时序元数据 + +285 +00:16:22,049 --> 00:16:25,185 +进行处理 + +286 +00:16:25,185 --> 00:16:27,654 +您现在可以对来自 iPhone 的 +面部元数据对象 + +287 +00:16:27,654 --> 00:16:32,092 +和人体元数据对象进行流传输 + +288 +00:16:32,092 --> 00:16:34,161 +让我们看看如何设置会话 + +289 +00:16:34,161 --> 00:16:37,531 +来接收人脸元数据对象 + +290 +00:16:37,531 --> 00:16:39,066 +在具备适当的视频输入和输出的 + +291 +00:16:39,066 --> 00:16:41,468 +会话设置完成后 + +292 +00:16:41,468 --> 00:16:44,972 +您需要创建 +AVCaptureMetadataOutput + +293 +00:16:44,972 --> 00:16:48,842 +并调用 addOutput +将其添加到会话中 + +294 +00:16:48,842 --> 00:16:51,712 +要特定接收人脸元数据 + +295 +00:16:51,712 --> 00:16:54,414 +必须在输出处设置对象类型数组 + +296 +00:16:54,414 --> 00:16:57,784 +包含人脸对象类型 + +297 +00:16:57,784 --> 00:17:01,221 +通过检查 +availableMetadataObjectTypes 属性 + +298 +00:17:01,221 --> 00:17:02,155 +确保能够支持 + +299 +00:17:02,155 --> 00:17:06,026 +请求的元数据类型 + +300 +00:17:06,026 --> 00:17:10,731 +接下来设置委托 接收元数据回调 + +301 +00:17:10,731 --> 00:17:12,566 +会话开始运行后 + +302 +00:17:12,566 --> 00:17:13,867 +您将得到回调 + +303 +00:17:13,867 --> 00:17:18,572 +以及实时生成的人脸元数据对象 + +304 +00:17:18,572 --> 00:17:22,609 +除了我们刚刚谈到的照片拍摄输出 + +305 +00:17:22,609 --> 00:17:24,044 +和拍摄元数据输出 + +306 +00:17:24,044 --> 00:17:27,714 +“连续互通”相机 +还支持视频数据输出 + +307 +00:17:27,714 --> 00:17:33,320 +电影文件输出和视频预览层功能 + +308 +00:17:33,320 --> 00:17:37,057 +以下是“连续互通”相机支持的 +视频格式列表 + +309 +00:17:37,057 --> 00:17:38,692 +了解这些信息 + +310 +00:17:38,692 --> 00:17:42,129 +有助于将此相机 +集成到您的 App 中 + +311 +00:17:42,129 --> 00:17:45,165 +它支持三种 16x9 画幅格式 + +312 +00:17:45,165 --> 00:17:48,936 +从 640x480 到 1080p + +313 +00:17:48,936 --> 00:17:53,640 +和一种 4x3 画幅格式:1920x1440 + +314 +00:17:53,640 --> 00:17:54,942 +您可以选择 + +315 +00:17:54,942 --> 00:17:57,711 +支持最高每秒 30 帧 + +316 +00:17:57,711 --> 00:18:01,181 +或最高每秒 60 帧的格式 +视需要而定 + +317 +00:18:01,181 --> 00:18:05,285 +另一项主要新增功能 +是“桌面视图”设备 API + +318 +00:18:05,285 --> 00:18:10,090 +“桌面视图”相机作为 +单独的 AVCaptureDevice 公开 + +319 +00:18:10,090 --> 00:18:12,793 +有两种方法可以找到这个设备 + +320 +00:18:12,793 --> 00:18:14,461 +第一种方法是 +通过在设备发现会话中 + +321 +00:18:14,461 --> 00:18:17,130 +查询 +AVCaptureDeviceTypeDeskViewCamera + +322 +00:18:17,130 --> 00:18:20,968 +来进行查找 + +323 +00:18:20,968 --> 00:18:23,136 +另一种方法是 如果您已经知道 + +324 +00:18:23,136 --> 00:18:26,540 +主摄像头的 AVCaptureDevice 对象 + +325 +00:18:26,540 --> 00:18:28,909 +就可以使用该设备上的 +companionDeskViewCamera 属性 + +326 +00:18:28,909 --> 00:18:33,013 +来访问“桌面视图”设备 + +327 +00:18:33,013 --> 00:18:35,916 +此 API 将有助于在周围存在 + +328 +00:18:35,916 --> 00:18:37,618 +多个“连续互通”相机的情况下 + +329 +00:18:37,618 --> 00:18:42,055 +对主摄像头和 +“桌面视图”设备进行配对 + +330 +00:18:42,055 --> 00:18:44,458 +一旦有了所需的“桌面视图”相机的 + +331 +00:18:44,458 --> 00:18:46,894 +AVCaptureDevice 对象 + +332 +00:18:46,894 --> 00:18:50,898 +您可以将它与拍摄视频数据输出、 + +333 +00:18:50,898 --> 00:18:52,566 +电影文件输出、 + +334 +00:18:52,566 --> 00:18:55,869 +或拍摄会话中的 +视频预览层一起使用 + +335 +00:18:55,869 --> 00:19:00,674 +就像使用其他相机设备一样 + +336 +00:19:00,674 --> 00:19:03,544 +“桌面视图”设备 +目前支持一种流格式 + +337 +00:19:03,544 --> 00:19:06,180 +即 420v 像素格式 + +338 +00:19:06,180 --> 00:19:10,350 +该格式的分辨率为 1920x1440 + +339 +00:19:10,350 --> 00:19:14,154 +支持的最高帧率为每秒 30 帧 + +340 +00:19:14,154 --> 00:19:16,423 +讲座就到这里结束了 + +341 +00:19:16,423 --> 00:19:18,492 +您已经了解了“连续互通”相机 + +342 +00:19:18,492 --> 00:19:22,162 +如何在 macOS 上 +实现奇妙的相机选择 + +343 +00:19:22,162 --> 00:19:25,699 +以及几个 +在 Mac App 中用于集成 + +344 +00:19:25,699 --> 00:19:27,968 +“连续互通”相机的新 API + +345 +00:19:27,968 --> 00:19:31,271 +我很期待看到您运用这些 API + +346 +00:19:31,271 --> 00:19:34,208 +希望您之后 +在 WWDC 上一切顺利 + +347 +00:19:34,208 --> 00:19:38,645 +♪ + diff --git a/zho/2022 Session 10019 Get to know Create ML Components.srt b/zho/2022 Session 10019 Get to know Create ML Components.srt new file mode 100644 index 0000000..08975fd --- /dev/null +++ b/zho/2022 Session 10019 Get to know Create ML Components.srt @@ -0,0 +1,2164 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,276 +♪ + +3 +00:00:09,276 --> 00:00:11,011 +您好 我是 Alejandro + +4 +00:00:11,011 --> 00:00:13,247 +我是 +CreateML 团队的工程师 + +5 +00:00:13,247 --> 00:00:15,582 +今天我要介绍一个 + +6 +00:00:15,582 --> 00:00:19,453 +基于组件构建 +机器学习模型的全新 API + +7 +00:00:19,453 --> 00:00:21,655 +Create ML 提供一种 +简单的 API + +8 +00:00:21,655 --> 00:00:23,957 +来训练机器学习的模型 + +9 +00:00:23,957 --> 00:00:25,826 +它基于一组支持的任务 + +10 +00:00:25,826 --> 00:00:31,198 +比如图像分类 声音分类等等 + +11 +00:00:31,198 --> 00:00:33,567 +在 WWDC 2021 + +12 +00:00:33,567 --> 00:00:36,937 +我们就 Create ML 框架 +进行了两场精彩的演讲 + +13 +00:00:36,937 --> 00:00:39,873 +如果您还没看过 +请务必查看这些内容 + +14 +00:00:39,873 --> 00:00:42,943 +但现在我想谈谈 +如何超越预定义任务 + +15 +00:00:42,943 --> 00:00:44,611 +如果您想自定义 + +16 +00:00:44,611 --> 00:00:48,115 +Create ML 解决方案 +以外的任务 该怎么办? + +17 +00:00:48,115 --> 00:00:51,752 +又或者 如果您想构建 +其他类型的任务 该怎么办? + +18 +00:00:51,752 --> 00:00:54,254 +使用组件 您就可以 +用新的创造性方式 + +19 +00:00:54,254 --> 00:00:56,056 +进行任务编写 + +20 +00:00:56,056 --> 00:00:58,325 +让我们进一步探讨 + +21 +00:00:58,325 --> 00:01:00,427 +我将从分解机器学习任务 + +22 +00:01:00,427 --> 00:01:03,397 +并解释每个组件的作用开始 + +23 +00:01:03,397 --> 00:01:07,234 +然后讨论应该如何将组件拼合起来 + +24 +00:01:07,234 --> 00:01:10,404 +接下来是自定义图像任务的示例 + +25 +00:01:10,404 --> 00:01:13,507 +之后 我将讨论表列任务 + +26 +00:01:13,507 --> 00:01:16,610 +最后以部署策略结束今天的讲座 + +27 +00:01:16,610 --> 00:01:18,378 +就让我从探讨一项机器学习任务的 + +28 +00:01:18,378 --> 00:01:20,781 +内部细节入手 以便让您了解 + +29 +00:01:20,781 --> 00:01:23,217 +它的内容和工作原理 + +30 +00:01:23,217 --> 00:01:25,652 +这样一来 +当我们开始构建自定义任务时 + +31 +00:01:25,652 --> 00:01:27,421 +您就会更容易理解我在说什么 + +32 +00:01:27,421 --> 00:01:31,158 +我将以图像分类器为例 + +33 +00:01:31,158 --> 00:01:34,094 +图像分类器使用标记图像列表 + +34 +00:01:34,094 --> 00:01:36,096 +对模型进行训练 + +35 +00:01:36,096 --> 00:01:38,799 +在这个例子当中 +我有一系列猫和狗的图像 + +36 +00:01:38,799 --> 00:01:41,235 +各自带有标签 + +37 +00:01:41,235 --> 00:01:45,339 +但让我们先来研究一下 +图像在每一步是如何转换的 + +38 +00:01:45,339 --> 00:01:48,208 +为此 我将展开图像分类任务 + +39 +00:01:48,208 --> 00:01:50,711 +看看里面有些什么 + +40 +00:01:50,711 --> 00:01:53,280 +从概念上看 图像分类器非常简单 + +41 +00:01:53,280 --> 00:01:56,650 +它由特征提取器和分类器组成 + +42 +00:01:56,650 --> 00:01:59,987 +重要的一点 +是 Create ML 组件 + +43 +00:01:59,987 --> 00:02:02,890 +让您可以独立访问这些组件 + +44 +00:02:02,890 --> 00:02:07,761 +您可以通过添加 移除 +或切换组件来编写新任务 + +45 +00:02:07,761 --> 00:02:10,664 +我将用方框来代表组件 + +46 +00:02:10,664 --> 00:02:12,900 +用箭头代表数据流 + +47 +00:02:12,900 --> 00:02:15,669 +让我们关注图像分类器的第一步 + +48 +00:02:15,669 --> 00:02:18,272 +特征提取 + +49 +00:02:18,272 --> 00:02:21,308 +通常 特征提取器 +会对输入进行降维处理 + +50 +00:02:21,308 --> 00:02:24,278 +只保留有趣的关键部分 + +51 +00:02:24,278 --> 00:02:25,646 +即“特征” + +52 +00:02:25,646 --> 00:02:26,980 +处理图像时 + +53 +00:02:26,980 --> 00:02:31,018 +特征提取器从图像中寻找模式 + +54 +00:02:31,018 --> 00:02:33,687 +Create ML 使用 +Vision Feature Print + +55 +00:02:33,687 --> 00:02:36,223 +它是由 Vision 框架提供的 + +56 +00:02:36,223 --> 00:02:39,459 +出色的图像特征提取器 + +57 +00:02:39,459 --> 00:02:41,528 +现在 让我们再来谈谈第二部分 + +58 +00:02:41,528 --> 00:02:42,930 +分类器 + +59 +00:02:42,930 --> 00:02:45,199 +分类器使用一组示例 + +60 +00:02:45,199 --> 00:02:47,668 +来学习分类 + +61 +00:02:47,668 --> 00:02:50,771 +常见的实现方式包括逻辑回归算法 + +62 +00:02:50,771 --> 00:02:54,241 +提升树算法和神经网络算法 + +63 +00:02:54,241 --> 00:02:57,711 +也就是说 图像分类器的训练 +从带注释的图像开始 + +64 +00:02:57,711 --> 00:03:02,249 +接下来是带注释的特征 +并以分类器结束 + +65 +00:03:02,249 --> 00:03:05,118 +那我们为什么要对它进行拆解呢? + +66 +00:03:05,118 --> 00:03:08,689 +因为我们想扩展可能性 + +67 +00:03:08,689 --> 00:03:10,657 +也许您想通过增加对比度 + +68 +00:03:10,657 --> 00:03:12,860 +对图像做一些预处理 + +69 +00:03:12,860 --> 00:03:15,062 +也许您想对所有图像进行归一化处理 + +70 +00:03:15,062 --> 00:03:19,533 +以确保提取特征前 +它们具有统一的亮度 + +71 +00:03:19,533 --> 00:03:22,803 +也许您想尝试不同的特征提取器 + +72 +00:03:22,803 --> 00:03:25,639 +也许您想尝试不同的分类器 + +73 +00:03:25,639 --> 00:03:27,975 +可能性永无止境 + +74 +00:03:27,975 --> 00:03:30,644 +这些只是其中的几个选项 + +75 +00:03:30,644 --> 00:03:33,113 +因此我们在 macOS iOS +iPadOS 和 tvOS 中 + +76 +00:03:33,113 --> 00:03:37,718 +添加了对 ML 组件的支持 + +77 +00:03:37,718 --> 00:03:40,053 +我们希望您能创建出新的模型 + +78 +00:03:40,053 --> 00:03:41,722 +使用我们提供的部分组件 + +79 +00:03:41,722 --> 00:03:43,457 +与您自己的组件配合 + +80 +00:03:43,457 --> 00:03:46,226 +甚至是和社群中其他人 +创建的组件一同使用 + +81 +00:03:46,226 --> 00:03:49,730 +您可以在我们所有的平台上使用它 + +82 +00:03:49,730 --> 00:03:54,835 +以下是 Create ML Components 中 +内置的一些组件 + +83 +00:03:54,835 --> 00:03:58,238 +但让我先回过头来介绍一些概念 + +84 +00:03:58,238 --> 00:03:59,706 +组件分为两种类型 + +85 +00:03:59,706 --> 00:04:02,176 +转换器和估算器 + +86 +00:04:02,176 --> 00:04:04,011 +转换器仅仅是一种 + +87 +00:04:04,011 --> 00:04:07,014 +能够执行部分转换的类型 + +88 +00:04:07,014 --> 00:04:10,350 +它定义输入类型和输出类型 + +89 +00:04:10,350 --> 00:04:14,221 +例如 图像特征提取器获取输入图像 + +90 +00:04:14,221 --> 00:04:17,691 +并产出特征整形数组 + +91 +00:04:17,691 --> 00:04:21,628 +而估算器则需要从数据中学习 + +92 +00:04:21,628 --> 00:04:25,098 +它获取输入示例 进行一些处理后 + +93 +00:04:25,098 --> 00:04:27,267 +生成转换器 + +94 +00:04:27,267 --> 00:04:30,370 +我们称这个过程为“拟合” + +95 +00:04:30,370 --> 00:04:33,140 +很好 解决了这些概念 + +96 +00:04:33,140 --> 00:04:35,609 +接下来我会说明 +Create ML 组件 + +97 +00:04:35,609 --> 00:04:37,711 +如何通过合成各个组件 + +98 +00:04:37,711 --> 00:04:41,181 +创建处图像分类器 + +99 +00:04:41,181 --> 00:04:44,084 +这是一个使用组件的图像分类器 + +100 +00:04:44,084 --> 00:04:46,954 +它将 ImageFeaturePrint +作为特征提取器 + +101 +00:04:46,954 --> 00:04:50,290 +将 LogisticRegressionClassifier +作为分类器 + +102 +00:04:50,290 --> 00:04:52,159 +无论一个组件 + +103 +00:04:52,159 --> 00:04:54,428 +是转换器还是估算器 + +104 +00:04:54,428 --> 00:04:58,999 +都可以用 +appending 方法进行组合 + +105 +00:04:58,999 --> 00:05:02,503 +这就是为什么说 +组件可以带来无限的可能性 + +106 +00:05:02,503 --> 00:05:05,272 +您可以使用全连接神经网络 +作为分类器 + +107 +00:05:05,272 --> 00:05:09,443 +而不是简单更改逻辑回归算法 + +108 +00:05:09,443 --> 00:05:13,413 +您也可以在 CoreML 模型中 +使用自定义特征提取器 + +109 +00:05:13,413 --> 00:05:16,450 +例如 可以在模型库中找到的 + +110 +00:05:16,450 --> 00:05:19,786 +无头 ResNet-50 模型 + +111 +00:05:19,786 --> 00:05:21,688 +合成两个组件时 + +112 +00:05:21,688 --> 00:05:23,390 +第一个组件的输出类型 + +113 +00:05:23,390 --> 00:05:25,759 +必须和第二个组件的输入类型匹配 + +114 +00:05:25,759 --> 00:05:27,995 +就我们的图像分类器来说 + +115 +00:05:27,995 --> 00:05:30,831 +特征提取器的输出是一个 +来自 CoreML 框架的 + +116 +00:05:30,831 --> 00:05:32,666 +Shaped 数组 + +117 +00:05:32,666 --> 00:05:36,503 +这也是逻辑回归分类器的输入 + +118 +00:05:36,503 --> 00:05:39,740 +如果在使用附加法时 +遇到编译器错误 + +119 +00:05:39,740 --> 00:05:41,909 +首先要检查这里 + +120 +00:05:41,909 --> 00:05:44,444 +确保类型匹配 + +121 +00:05:44,444 --> 00:05:48,415 +但我要澄清一个 +跟拟合有关的重要观点 + +122 +00:05:48,415 --> 00:05:50,551 +我之前说过 拟合是 + +123 +00:05:50,551 --> 00:05:53,487 +从估算器到转换器的过程 + +124 +00:05:53,487 --> 00:05:55,088 +让我们从组合估算器的角度 + +125 +00:05:55,088 --> 00:05:57,524 +来看一看 + +126 +00:05:57,524 --> 00:05:58,825 +当组合估算器中 + +127 +00:05:58,825 --> 00:06:01,061 +既有转换器又有估算器时 + +128 +00:06:01,061 --> 00:06:03,330 +例如在图像分类器的案例中 + +129 +00:06:03,330 --> 00:06:05,933 +仅对估算器的部分进行拟合 + +130 +00:06:05,933 --> 00:06:09,002 +但转换器是该过程的重要组成部分 + +131 +00:06:09,002 --> 00:06:11,271 +因为它们被用于向估算器的拟合方法 + +132 +00:06:11,271 --> 00:06:14,308 +馈送正确的特征 + +133 +00:06:14,308 --> 00:06:15,509 +这是代码 + +134 +00:06:15,509 --> 00:06:16,877 +图像分类器 + +135 +00:06:16,877 --> 00:06:19,446 +需要一个带注释的特征集合 + +136 +00:06:19,446 --> 00:06:24,251 +其中特征是图像 注释是字符串 + +137 +00:06:24,251 --> 00:06:25,886 +我们将在进入演示时 + +138 +00:06:25,886 --> 00:06:28,956 +讨论特征的加载 + +139 +00:06:28,956 --> 00:06:32,326 +一旦有了数据 就可以调用拟合法 + +140 +00:06:32,326 --> 00:06:37,264 +它将返回经过训练的模型 +即一个转换器 + +141 +00:06:37,264 --> 00:06:39,933 +要重点注意的是 拟合时使用的类型 + +142 +00:06:39,933 --> 00:06:42,269 +与生成转换器的类型 + +143 +00:06:42,269 --> 00:06:44,972 +相互关联 但并不相同 + +144 +00:06:44,972 --> 00:06:47,774 +尤其是拟合法中使用的类型 + +145 +00:06:47,774 --> 00:06:49,643 +始终是集合 + +146 +00:06:49,643 --> 00:06:52,045 +在使用监督估算器的情况下 + +147 +00:06:52,045 --> 00:06:55,415 +特征必须包括注释 + +148 +00:06:55,415 --> 00:06:58,485 +Create ML Components +使用 AnnotatedFeature 类型 + +149 +00:06:58,485 --> 00:07:03,056 +来表述特征及其注释 + +150 +00:07:03,056 --> 00:07:06,226 +一旦有了模型 就可以进行预测 + +151 +00:07:06,226 --> 00:07:08,462 +无论是用我刚刚拟合的模型 + +152 +00:07:08,462 --> 00:07:11,765 +还是从硬盘加载的参数 + +153 +00:07:11,765 --> 00:07:15,702 +两者采用的 API 都是相同的 + +154 +00:07:15,702 --> 00:07:17,571 +由于我训练的是分类器 + +155 +00:07:17,571 --> 00:07:20,874 +结果就是分类分布 + +156 +00:07:20,874 --> 00:07:25,312 +该分布包含了每个标签的概率 + +157 +00:07:25,312 --> 00:07:27,681 +在这种情况下 我只为图像打印 + +158 +00:07:27,681 --> 00:07:30,817 +可能性最高的标签 + +159 +00:07:30,817 --> 00:07:33,320 +拟合法还提供了一种机制 + +160 +00:07:33,320 --> 00:07:37,457 +用于观察训练事件 包括验证指标 + +161 +00:07:37,457 --> 00:07:39,826 +在这个例子中 我传送验证数据 + +162 +00:07:39,826 --> 00:07:43,096 +并打印验证准确性 + +163 +00:07:43,096 --> 00:07:44,798 +请注意 只有监督估算器 + +164 +00:07:44,798 --> 00:07:48,402 +才提供验证指标 + +165 +00:07:48,402 --> 00:07:50,003 +一旦完成了模型的训练 + +166 +00:07:50,003 --> 00:07:52,372 +您可以保存学习的参数 + +167 +00:07:52,372 --> 00:07:56,009 +既可以在将来重新使用 +也可以部署到 App 中 + +168 +00:07:56,009 --> 00:07:58,545 +您可以使用 write 方法 +进行这项操作 + +169 +00:07:58,545 --> 00:08:02,249 +之后可以通过 read 方法 +进行数据读取 + +170 +00:08:02,249 --> 00:08:04,184 +这就是合成 + +171 +00:08:04,184 --> 00:08:06,653 +从这里开始就变得有趣了 + +172 +00:08:06,653 --> 00:08:08,755 +先来谈谈新任务的编写吧 + +173 +00:08:08,755 --> 00:08:11,758 +这是 Create ML +刚刚开始支持的功能 + +174 +00:08:13,727 --> 00:08:17,598 +假使您想训练模型 +对图像进行评分该怎么做? + +175 +00:08:17,598 --> 00:08:19,633 +假设您有一些水果的照片 + +176 +00:08:19,633 --> 00:08:21,602 +但不是要对水果进行分类 + +177 +00:08:21,602 --> 00:08:23,670 +而是要评价它 + +178 +00:08:23,670 --> 00:08:26,607 +根据它的成熟程度进行评分 + +179 +00:08:26,607 --> 00:08:28,809 +为此 您需要使用回归 + +180 +00:08:28,809 --> 00:08:30,944 +而不是分类 + +181 +00:08:30,944 --> 00:08:33,046 +所以我来写一个图像回归器 + +182 +00:08:33,046 --> 00:08:37,551 +根据成熟度为香蕉图像打分 + +183 +00:08:37,551 --> 00:08:43,090 +我会给每张图片一个 +介于 1 到 10 之间的成熟度值 + +184 +00:08:43,090 --> 00:08:47,594 +图像回归器与图像分类器很相似 + +185 +00:08:47,594 --> 00:08:49,696 +唯一的区别是估算器 + +186 +00:08:49,696 --> 00:08:54,168 +将成为回归器而不是分类器 + +187 +00:08:54,168 --> 00:08:55,869 +您可能已经猜到了 + +188 +00:08:55,869 --> 00:08:58,238 +这将会很容易 + +189 +00:08:58,238 --> 00:09:01,875 +帮您回忆一下 +这是我们的图像分类器 + +190 +00:09:01,875 --> 00:09:04,411 +而这是一个图像回归器 + +191 +00:09:04,411 --> 00:09:07,181 +我用线性回归器替换了 + +192 +00:09:07,181 --> 00:09:09,583 +逻辑回归分类器 + +193 +00:09:09,583 --> 00:09:12,786 +这一简单的改变也使拟合法的 + +194 +00:09:12,786 --> 00:09:15,122 +预期输入发生了变化 + +195 +00:09:15,122 --> 00:09:17,791 +之前 它预期的是图像和标签 + +196 +00:09:17,791 --> 00:09:20,961 +现在 它预期的是图像和分数 + +197 +00:09:20,961 --> 00:09:22,429 +概念说到这里就足够了 + +198 +00:09:22,429 --> 00:09:25,899 +让我用实际的代码来演示一下 + +199 +00:09:28,502 --> 00:09:31,538 +让我向您展示如何 +编写自定义图像回归器 + +200 +00:09:31,538 --> 00:09:33,640 +我将从定义 +ImageRegressor 结构 + +201 +00:09:33,640 --> 00:09:36,443 +以封装代码开始 + +202 +00:09:38,445 --> 00:09:40,547 +我有一个包含不同成熟度的 + +203 +00:09:40,547 --> 00:09:42,716 +香蕉图像的文件夹 + +204 +00:09:42,716 --> 00:09:46,119 +我将首先定义这个 URL + +205 +00:09:48,121 --> 00:09:51,124 +下一步是添加 train 方法 + +206 +00:09:51,124 --> 00:09:52,292 +在这里您可以使用 + +207 +00:09:52,292 --> 00:09:56,230 +训练数据来生成模型 + +208 +00:09:56,230 --> 00:09:59,266 +我将在返回类型上 +使用“some”关键字 + +209 +00:09:59,266 --> 00:10:00,968 +这样一来 当我在组合估算器中 + +210 +00:10:00,968 --> 00:10:05,138 +添加或修改步骤时 +返回类型就不会改变 + +211 +00:10:05,138 --> 00:10:07,341 +现在 我要定义估算器 + +212 +00:10:07,341 --> 00:10:09,042 +它只是简单地在特征提取器上 + +213 +00:10:09,042 --> 00:10:14,047 +附加了线性回归器 + +214 +00:10:14,047 --> 00:10:16,316 +现在 我需要加载训练用的图像 + +215 +00:10:16,316 --> 00:10:17,584 +以及它们的分数 + +216 +00:10:17,584 --> 00:10:19,820 +我可以使用 AnnotatedFiles +它是一个 + +217 +00:10:19,820 --> 00:10:24,157 +包含 URL 和字符串标签的 +AnnotatedFeatures 集合 + +218 +00:10:24,157 --> 00:10:29,730 +它提供了一个满足我需求的 +方便的初始设定式 + +219 +00:10:29,730 --> 00:10:32,599 +我的文件都有一个名称 +后面跟一个破折号 + +220 +00:10:32,599 --> 00:10:34,201 +后面跟着成熟度值 + +221 +00:10:34,201 --> 00:10:37,604 +所以我要指定分隔符为破折号 + +222 +00:10:37,604 --> 00:10:39,306 +并且指定注释位于 + +223 +00:10:39,306 --> 00:10:41,308 +文件名组件的 index: 1 + +224 +00:10:41,308 --> 00:10:42,543 +我还准备通过 + +225 +00:10:42,543 --> 00:10:46,146 +使用类型参数 仅请求图像文件 + +226 +00:10:46,146 --> 00:10:49,683 +现在有了 URL +我就需要加载图像 + +227 +00:10:49,683 --> 00:10:51,385 +这可以通过 +mapFeatures 方法 + +228 +00:10:51,385 --> 00:10:56,690 +和 ImageReader +来实现 + +229 +00:10:56,690 --> 00:10:58,725 +我还需要将分数 + +230 +00:10:58,725 --> 00:11:01,662 +从字符串转换为浮点值 + +231 +00:11:01,662 --> 00:11:05,599 +这可以通过 +mapAnnotations 方法来实现 + +232 +00:11:08,936 --> 00:11:12,005 +这样一来 我就获得了训练数据 + +233 +00:11:12,005 --> 00:11:15,175 +但我想把其中一些拿出来用于验证 + +234 +00:11:15,175 --> 00:11:17,911 +这可以使用 +randomSplit 方法来实现 + +235 +00:11:17,911 --> 00:11:19,446 +我将保留 80% 的数据用于训练 + +236 +00:11:19,446 --> 00:11:25,219 +并使用剩余的进行验证 + +237 +00:11:25,219 --> 00:11:27,221 +现在 我准备好进行拟合了 + +238 +00:11:29,957 --> 00:11:32,025 +我还要保存训练好的参数 + +239 +00:11:32,025 --> 00:11:33,827 +以便部署到我的 App 中 + +240 +00:11:33,827 --> 00:11:36,129 +我要选择一个保存的位置 + +241 +00:11:40,033 --> 00:11:42,236 +我将调用 write 方法 + +242 +00:11:44,671 --> 00:11:46,940 +最后 我将返回转换器 + +243 +00:11:50,944 --> 00:11:53,514 +这是使用组件定义和训练模型的 + +244 +00:11:53,514 --> 00:11:55,249 +本质所在 + +245 +00:11:55,249 --> 00:11:57,651 +我定义了组合估算器 + +246 +00:11:57,651 --> 00:12:00,921 +加载了训练数据 调用了拟合方法 + +247 +00:12:00,921 --> 00:12:03,257 +用 write 方法来保存参数 + +248 +00:12:03,257 --> 00:12:05,592 +但还有些地方是可以改进的 + +249 +00:12:05,592 --> 00:12:08,562 +首先 我正在传递验证数据集 + +250 +00:12:08,562 --> 00:12:11,231 +但并没有观察验证错误 + +251 +00:12:11,231 --> 00:12:12,933 +所以我会这样做 + +252 +00:12:12,933 --> 00:12:15,135 +拟合法需要一个事件处理程序 + +253 +00:12:15,135 --> 00:12:17,237 +可以用于收集指标 + +254 +00:12:21,375 --> 00:12:23,777 +现在 我将只打印训练 + +255 +00:12:23,777 --> 00:12:26,914 +和验证的最大误差值 + +256 +00:12:26,914 --> 00:12:30,751 +我还想要最终模型的平均绝对误差 + +257 +00:12:33,987 --> 00:12:36,356 +我的计算方法是将拟合转换器 + +258 +00:12:36,356 --> 00:12:37,991 +用于验证特征 + +259 +00:12:37,991 --> 00:12:40,594 +然后将它与实际分数一起传递给 + +260 +00:12:40,594 --> 00:12:44,565 +meanAbsoluteError 函数 + +261 +00:12:44,565 --> 00:12:46,800 +运行之后 我并没有 +获得一个出色的模型 + +262 +00:12:46,800 --> 00:12:49,136 +错误率很高 + +263 +00:12:49,136 --> 00:12:52,206 +这是因为我没有足够多的香蕉图像 + +264 +00:12:52,206 --> 00:12:54,808 +我应该去获取更多图像 +但在这样做之前 + +265 +00:12:54,808 --> 00:12:57,244 +我可以尝试增强数据集 + +266 +00:12:57,244 --> 00:13:00,514 +我可以对图像进行旋转和缩放 +以获得更多示例 + +267 +00:13:00,514 --> 00:13:02,482 +为此 我将编写一个新方法 + +268 +00:13:02,482 --> 00:13:05,586 +使用带注释的图像并对其进行增强 + +269 +00:13:05,586 --> 00:13:08,155 +它会返回一个带注释的图像数组 + +270 +00:13:13,827 --> 00:13:17,664 +我要实现的第一种增强是旋转 + +271 +00:13:20,801 --> 00:13:23,704 +我会在 -pi 和 pi 之间 +随机选取一个角度 + +272 +00:13:23,704 --> 00:13:26,073 +并以这个角度旋转图像 + +273 +00:13:26,073 --> 00:13:28,542 +我还设置了随机缩放 + +274 +00:13:31,144 --> 00:13:32,713 +之后会返回三个图像 + +275 +00:13:32,713 --> 00:13:36,083 +原始的 旋转的和缩放的 + +276 +00:13:39,119 --> 00:13:40,687 +现在有了增强函数 + +277 +00:13:40,687 --> 00:13:44,691 +我将使用它来借助 +flatMap 增强我的训练图像 + +278 +00:13:49,429 --> 00:13:53,367 +我的数据集中 +每个元素都将转换为一个数组 + +279 +00:13:53,367 --> 00:13:56,937 +FlatMap 将该数组集合 +平铺为单个数组 + +280 +00:13:56,937 --> 00:13:59,606 +这是拟合法所需要的 + +281 +00:13:59,606 --> 00:14:02,409 +请注意 增强仅适用于拟合 + +282 +00:14:02,409 --> 00:14:04,945 +而不适用于预测 + +283 +00:14:04,945 --> 00:14:07,481 +好的 这样我的准确性就提高了 + +284 +00:14:07,481 --> 00:14:09,383 +让我来谈谈另一项 + +285 +00:14:09,383 --> 00:14:12,219 +可以进一步改善我的模型的措施 + +286 +00:14:12,219 --> 00:14:13,620 +我想使用 Vision 框架 + +287 +00:14:13,620 --> 00:14:16,924 +将图像裁剪到只剩突出对象 + +288 +00:14:16,924 --> 00:14:19,326 +这是我的训练数据中的一张图片 + +289 +00:14:19,326 --> 00:14:23,096 +一个人拿着香蕉 背景中有其他水果 + +290 +00:14:23,096 --> 00:14:27,301 +模型可能会混淆照片中的其他物体 + +291 +00:14:27,301 --> 00:14:29,269 +使用 Vision 框架 API + +292 +00:14:29,269 --> 00:14:31,004 +可以实现自动裁剪图像 + +293 +00:14:31,004 --> 00:14:33,574 +仅突出最显著的对象 + +294 +00:14:33,574 --> 00:14:38,745 +查看 WWDC 2019 上 +关于 Vision 的演讲以了解 + +295 +00:14:38,745 --> 00:14:41,949 +如果写一个自定义转换器 + +296 +00:14:41,949 --> 00:14:44,184 +就可以轻松地将 +这种转换应用于所有图像 + +297 +00:14:44,184 --> 00:14:46,420 +在拟合和预测时均可使用 + +298 +00:14:46,420 --> 00:14:47,988 +让我告诉您该怎么做 + +299 +00:14:47,988 --> 00:14:49,423 +为了符合转换器协议 + +300 +00:14:49,423 --> 00:14:51,425 +我唯一需要做的 + +301 +00:14:51,425 --> 00:14:53,660 +就是实现应用的方法 + +302 +00:14:53,660 --> 00:14:55,896 +在这个案例里 +我想要它获取一张图片 + +303 +00:14:55,896 --> 00:14:57,698 +并返回一张图片 + +304 +00:14:57,698 --> 00:14:59,266 +我就不详细解释这段代码了 + +305 +00:14:59,266 --> 00:15:02,236 +但还是提一句 +如果得不到显著的对象 + +306 +00:15:02,236 --> 00:15:06,306 +只需要返回原始图像 + +307 +00:15:06,306 --> 00:15:08,141 +现在有了自定义转换器 + +308 +00:15:08,141 --> 00:15:10,077 +我要将它添加到我的图像回归器中 + +309 +00:15:16,416 --> 00:15:18,218 +我只需要在特征提取之前 + +310 +00:15:18,218 --> 00:15:19,987 +使用自定义转换器即可 + +311 +00:15:28,695 --> 00:15:31,431 +现在显著性成了 +我任务定义的一部分 + +312 +00:15:31,431 --> 00:15:34,134 +它将用于裁剪每个训练图像 + +313 +00:15:34,134 --> 00:15:37,070 +进行推理时也会用到它 + +314 +00:15:37,070 --> 00:15:39,706 +这是将任务定义 +同时分配给训练和推理的 + +315 +00:15:39,706 --> 00:15:42,142 +优势之一 + +316 +00:15:42,142 --> 00:15:44,378 +在继续下一个任务之前 + +317 +00:15:44,378 --> 00:15:46,813 +我要强调几个重点事项 + +318 +00:15:46,813 --> 00:15:50,651 +使用组件 我可以创建自定义任务 + +319 +00:15:50,651 --> 00:15:53,453 +我通过使用 appending 方法 +来实现这一点 + +320 +00:15:53,453 --> 00:15:55,956 +我使用 AnnotatedFiles 来加载 + +321 +00:15:55,956 --> 00:15:58,125 +带有注释名称的文件 + +322 +00:15:58,125 --> 00:16:01,428 +也可以加载由目录注释的文件 + +323 +00:16:01,428 --> 00:16:04,665 +我使用 ImageReader +将 URL 映射到图像 + +324 +00:16:04,665 --> 00:16:08,602 +并将注释从字符串映射到值 + +325 +00:16:08,602 --> 00:16:12,239 +我使用 randomSplit +留出一个验证数据集 + +326 +00:16:12,239 --> 00:16:15,409 +还保存了训练好的参数供以后使用 + +327 +00:16:15,409 --> 00:16:18,278 +然后我添加了增强功能 +并定义了一个自定义转换器 + +328 +00:16:18,278 --> 00:16:20,314 +来改进我的模型 + +329 +00:16:20,314 --> 00:16:23,250 +但这不仅仅适用于图像 + +330 +00:16:23,250 --> 00:16:26,320 +我要换个方向 +谈谈另一种类型的任务 + +331 +00:16:26,320 --> 00:16:28,188 +表列任务 + +332 +00:16:28,188 --> 00:16:30,958 +它们是使用表列数据的任务 + +333 +00:16:30,958 --> 00:16:33,493 +表列数据的特点是拥有 + +334 +00:16:33,493 --> 00:16:35,295 +不同类型的多种特征 + +335 +00:16:35,295 --> 00:16:37,130 +它既包含了数值数据 + +336 +00:16:37,130 --> 00:16:39,333 +也包含了分类数据 + +337 +00:16:39,333 --> 00:16:42,402 +房价数据就是一个受欢迎的例子 + +338 +00:16:42,402 --> 00:16:44,905 +既涉及面积和房龄之类的数据 + +339 +00:16:44,905 --> 00:16:46,507 +也包含了街区位置 + +340 +00:16:46,507 --> 00:16:48,742 +建筑类型等信息 + +341 +00:16:48,742 --> 00:16:51,111 +现在您想学习预测一个值 + +342 +00:16:51,111 --> 00:16:53,780 +比如说 销售价格 + +343 +00:16:53,780 --> 00:16:58,352 +2021 年 我们引入了 +TabularData 框架 + +344 +00:16:58,352 --> 00:17:00,153 +现在您可以使用 +TabularData 框架 + +345 +00:17:00,153 --> 00:17:02,356 +配合 Create ML 组件 + +346 +00:17:02,356 --> 00:17:06,927 +来创建和训练表列分类器和回归器 + +347 +00:17:06,927 --> 00:17:09,696 +我还推荐您查看 +关于 TabularData 的 Tech Talk + +348 +00:17:09,696 --> 00:17:12,232 +它对数据探索进行了精彩的介绍 + +349 +00:17:12,232 --> 00:17:15,269 +您在构建表列任务时可能会需要 + +350 +00:17:15,269 --> 00:17:17,971 +让我们了解一下吧 + +351 +00:17:17,971 --> 00:17:21,408 +在处理表列数据时 表列的每一列 + +352 +00:17:21,408 --> 00:17:23,877 +都包含不同类型的特征 + +353 +00:17:23,877 --> 00:17:26,413 +您可能希望基于每一列 + +354 +00:17:26,413 --> 00:17:28,448 +包含的信息类型 + +355 +00:17:28,448 --> 00:17:30,150 +比如分布 数值范围 + +356 +00:17:30,150 --> 00:17:32,352 +和其他因素分别进行处理 + +357 +00:17:32,352 --> 00:17:36,323 +Create ML Components 提供了 +ColumnSelector 来执行此操作 + +358 +00:17:36,323 --> 00:17:38,492 +来看看这个例子 + +359 +00:17:38,492 --> 00:17:42,029 +我刚才提到了房价 但房价太离谱了 + +360 +00:17:42,029 --> 00:17:44,765 +我将改用鳄梨价格来举例 + +361 +00:17:44,765 --> 00:17:47,267 +这里有一张鳄梨价格表 + +362 +00:17:47,267 --> 00:17:49,236 +我想创建一个表列回归器 + +363 +00:17:49,236 --> 00:17:52,105 +基于表列数据预测鳄梨价格 + +364 +00:17:52,105 --> 00:17:54,241 +表列里既有包含数值数据的列 + +365 +00:17:54,241 --> 00:17:56,643 +例如袋数 年份和总量 + +366 +00:17:56,643 --> 00:18:01,715 +也有包含类型和 +区域等分类数据的列 + +367 +00:18:01,715 --> 00:18:03,450 +有些回归器受益于 + +368 +00:18:03,450 --> 00:18:06,620 +对这些值更好的表述 + +369 +00:18:06,620 --> 00:18:08,088 +比如说 + +370 +00:18:08,088 --> 00:18:11,658 +这是数据集中总量值的分布 + +371 +00:18:11,658 --> 00:18:14,094 +它接近正态分布 + +372 +00:18:14,094 --> 00:18:17,698 +但较大的值大多 +在 15,000 附近 + +373 +00:18:17,698 --> 00:18:20,234 +我认为这是数据集可以 + +374 +00:18:20,234 --> 00:18:23,036 +受益于归一化的绝佳范例 + +375 +00:18:23,036 --> 00:18:27,274 +所以我要做的第一件事 +就是将这些值归一化 + +376 +00:18:27,274 --> 00:18:30,978 +为此 我可以将希望归一化的列名 + +377 +00:18:30,978 --> 00:18:35,082 +传递给 ColumnSelector +然后使用标准缩放器 + +378 +00:18:35,082 --> 00:18:37,084 +这是代码 + +379 +00:18:37,084 --> 00:18:39,520 +首先 我创建一个列选取器 + +380 +00:18:39,520 --> 00:18:42,789 +然后传递我想要缩放的列名 + +381 +00:18:42,789 --> 00:18:45,492 +所有列必须包含相同类型的元素 + +382 +00:18:45,492 --> 00:18:47,761 +在个例子中是 Double + +383 +00:18:47,761 --> 00:18:50,130 +然后我解析可选类型 + +384 +00:18:50,130 --> 00:18:53,133 +之所以这样做 +是因为我知道没有缺失值 + +385 +00:18:53,133 --> 00:18:56,904 +但也可以使用 imputer +来替换缺失值 + +386 +00:18:56,904 --> 00:18:58,805 +然后 我在解析代码上 + +387 +00:18:58,805 --> 00:19:01,308 +附加 StandardScaler + +388 +00:19:01,308 --> 00:19:02,676 +所以 一开始的这张表列中 + +389 +00:19:02,676 --> 00:19:05,612 +袋数达到好几万 + +390 +00:19:05,612 --> 00:19:08,415 +总量达到几十万 + +391 +00:19:08,415 --> 00:19:10,083 +在对这几列进行缩放后 + +392 +00:19:10,083 --> 00:19:13,187 +最终得到的值规模接近于 1 + +393 +00:19:13,187 --> 00:19:16,723 +这可以提升模型的性能 + +394 +00:19:16,723 --> 00:19:20,427 +更具体来说 +这些值现在的平均数为 0 + +395 +00:19:20,427 --> 00:19:24,064 +标准差为 1 + +396 +00:19:24,064 --> 00:19:27,067 +这是一个类似的例子 +但在这个例子中 + +397 +00:19:27,067 --> 00:19:29,603 +我选择了类型和区域列 + +398 +00:19:29,603 --> 00:19:34,074 +它们是字符串类型并执行独热编码 + +399 +00:19:34,074 --> 00:19:37,377 +独热编码是指对分类数据进行编码 + +400 +00:19:37,377 --> 00:19:42,149 +使用数组来指示类别 + +401 +00:19:42,149 --> 00:19:44,451 +这个例子中有三个类别 + +402 +00:19:44,451 --> 00:19:47,588 +铜 银和金 + +403 +00:19:47,588 --> 00:19:50,157 +每个类别在数组中 +都拥有唯一的位置 + +404 +00:19:50,157 --> 00:19:54,194 +由处于该位置的 1 表示 + +405 +00:19:54,194 --> 00:19:57,331 +另一种方法是使用序数编码器 + +406 +00:19:57,331 --> 00:20:01,034 +为每个类别分配一个连续的数字 + +407 +00:20:01,034 --> 00:20:04,204 +仅有几个类别时 +更适合使用独热编码器 + +408 +00:20:04,204 --> 00:20:07,941 +类别较多时 则应当使用序数编码器 + +409 +00:20:07,941 --> 00:20:13,447 +现在让我把这些结合起来 +创建一个表列回归器 + +410 +00:20:17,217 --> 00:20:19,453 +和之前一样 我将以创建结构开始 + +411 +00:20:19,453 --> 00:20:23,957 +并定义数据 URL +和参数 URL + +412 +00:20:25,792 --> 00:20:27,761 +我还想定义一个列 ID + +413 +00:20:27,761 --> 00:20:30,364 +用于我要预测的列 即价格 + +414 +00:20:32,966 --> 00:20:35,702 +我将单独定义我的任务 以便 + +415 +00:20:35,702 --> 00:20:38,539 +对它应用 train +和 predict 两种方法 + +416 +00:20:41,208 --> 00:20:44,011 +就像之前提到的那样 +我要把总量归一化 + +417 +00:20:46,780 --> 00:20:49,049 +然后 我将使用增强树回归器 + +418 +00:20:49,049 --> 00:20:53,153 +来预测价格 + +419 +00:20:53,153 --> 00:20:55,189 +它先获取注释列的名称 + +420 +00:20:55,189 --> 00:20:58,025 +这也就是结果预测列 + +421 +00:20:58,025 --> 00:21:01,762 +然后获取所有三个特征列的名称 + +422 +00:21:01,762 --> 00:21:03,931 +我就从这三列开始 + +423 +00:21:03,931 --> 00:21:07,367 +然后我会使用 +appending 方法组合这些段落 + +424 +00:21:07,367 --> 00:21:08,836 +并返回任务 + +425 +00:21:13,540 --> 00:21:15,475 +现在有了任务定义 + +426 +00:21:15,475 --> 00:21:17,644 +我就像之前一样 +添加 train 方法 + +427 +00:21:20,547 --> 00:21:23,083 +和之前一样 我想确保返回类型 + +428 +00:21:23,083 --> 00:21:26,453 +不取决于我模型的细节 + +429 +00:21:26,453 --> 00:21:32,392 +第一步是将 CSV 文件 +加载到dataFrame中 + +430 +00:21:32,392 --> 00:21:35,028 +我使用 TabularData +框架来执行此操作 + +431 +00:21:35,028 --> 00:21:37,364 +和之前一样 我想拆分一些数据 + +432 +00:21:37,364 --> 00:21:39,399 +用于验证 + +433 +00:21:43,704 --> 00:21:46,039 +我将训练和验证数据集传递给 + +434 +00:21:46,039 --> 00:21:47,608 +拟合法 + +435 +00:21:50,511 --> 00:21:53,514 +我也会像之前一样报告验证错误 + +436 +00:21:53,514 --> 00:21:55,883 +并保存训练好的参数供以后使用 + +437 +00:21:59,553 --> 00:22:01,755 +最后 我会返回转换器 + +438 +00:22:04,892 --> 00:22:06,627 +有了训练好的转换器 + +439 +00:22:06,627 --> 00:22:09,763 +就可以用它来基于 +dataFrame进行价格预测 + +440 +00:22:09,763 --> 00:22:13,967 +我需要写一个 +predict 方法来实现预测 + +441 +00:22:17,404 --> 00:22:19,740 +首先 我将从任务定义中加载模型 + +442 +00:22:19,740 --> 00:22:22,109 +和参数 URL + +443 +00:22:24,978 --> 00:22:27,581 +我需要确保用于预测的dataFrame + +444 +00:22:27,581 --> 00:22:30,884 +包含我用作特征的列 + +445 +00:22:30,884 --> 00:22:35,155 +类型 区域和总量 + +446 +00:22:35,155 --> 00:22:38,325 +预测值将出现在价格列中 + +447 +00:22:38,325 --> 00:22:40,661 +我将使用我在顶部定义的列 ID + +448 +00:22:44,565 --> 00:22:46,700 +我的表列回归器这样就完成了 + +449 +00:22:46,700 --> 00:22:48,936 +我写了一个 train 方法 +只需要调用一次 + +450 +00:22:48,936 --> 00:22:50,370 +就可以生成训练好的参数 + +451 +00:22:50,370 --> 00:22:52,606 +还有一个 predict 方法 + +452 +00:22:52,606 --> 00:22:54,575 +可以基于类型 地区以及 + +453 +00:22:54,575 --> 00:22:56,977 +鳄梨的总量 返回鳄梨价格的预测 + +454 +00:22:56,977 --> 00:22:59,346 +这就是我需要在 +App 中使用的全部内容 + +455 +00:22:59,346 --> 00:23:01,014 +在处理表列任务时 + +456 +00:23:01,014 --> 00:23:03,350 +还有几点需要牢记 + +457 +00:23:03,350 --> 00:23:04,985 +您可以使用 ColumnSelector 操作 + +458 +00:23:04,985 --> 00:23:07,287 +来处理特定的列 + +459 +00:23:07,287 --> 00:23:10,257 +值得注意的是 树形分类器和回归器 + +460 +00:23:10,257 --> 00:23:13,961 +都是表列类的 但您也可以 +使用非表列估算器 + +461 +00:23:13,961 --> 00:23:15,529 +例如线性回归器 + +462 +00:23:15,529 --> 00:23:19,366 +来处理使用 +AnnotatedFeatureProvider 的表列任务 + +463 +00:23:19,366 --> 00:23:22,169 +请参阅相关文档 + +464 +00:23:22,169 --> 00:23:23,470 +在进行预测时 + +465 +00:23:23,470 --> 00:23:26,039 +请创建一个包含所需列的dataFrame + +466 +00:23:26,039 --> 00:23:29,142 +确保使用的类型正确 + +467 +00:23:29,142 --> 00:23:31,745 +现在您已经知道应该 +如何创建自定义任务了 + +468 +00:23:31,745 --> 00:23:34,781 +那就让我们来谈谈部署 + +469 +00:23:34,781 --> 00:23:38,785 +到目前为止 我都在使用相同的 +API 进行训练和推理 + +470 +00:23:38,785 --> 00:23:41,655 +我想指出的是 +在使用 Create ML Components 时 + +471 +00:23:41,655 --> 00:23:43,657 +您的模型就是代码 + +472 +00:23:43,657 --> 00:23:45,058 +您需要任务定义 + +473 +00:23:45,058 --> 00:23:48,962 +即使只是从文件加载训练好的参数 + +474 +00:23:48,962 --> 00:23:50,998 +这在部分情况下很有用 + +475 +00:23:50,998 --> 00:23:55,169 +但有时您也许希望 +使用 Core ML 进行部署 + +476 +00:23:55,169 --> 00:23:58,105 +使用 Core ML 时 +就必须将代码抛在脑后 + +477 +00:23:58,105 --> 00:24:01,508 +模型完全由模型文件表述 + +478 +00:24:01,508 --> 00:24:03,210 +如果您已经 +准备好使用 Core ML + +479 +00:24:03,210 --> 00:24:05,045 +那么这一工作流可能会很顺畅 + +480 +00:24:05,045 --> 00:24:08,749 +还具备优化张量操作的优势 + +481 +00:24:08,749 --> 00:24:10,050 +但还有一些注意事项 + +482 +00:24:10,050 --> 00:24:12,252 +您应该记住 + +483 +00:24:12,252 --> 00:24:15,055 +Core ML 并不支持所有操作 + +484 +00:24:15,055 --> 00:24:17,558 +具体来说 它不支持自定义转换器 + +485 +00:24:17,558 --> 00:24:19,293 +和估算器 + +486 +00:24:19,293 --> 00:24:21,261 +而且 Core ML +只支持几种类型 + +487 +00:24:21,261 --> 00:24:24,131 +比如图像和整形数组 + +488 +00:24:24,131 --> 00:24:25,866 +如果您使用自定义类型 + +489 +00:24:25,866 --> 00:24:27,835 +您可能需要 +在使用 Core ML 模型时 + +490 +00:24:27,835 --> 00:24:30,103 +在 App 中进行转换 + +491 +00:24:30,103 --> 00:24:33,640 +这就是将转换器导出为 +Core ML 模型的方法 + +492 +00:24:33,640 --> 00:24:36,376 +如果转换器中包含不受支持的操作 + +493 +00:24:36,376 --> 00:24:39,079 +将会引发错误 + +494 +00:24:39,079 --> 00:24:41,748 +如果您更希望将任务定义 + +495 +00:24:41,748 --> 00:24:43,584 +连同训练参数一同进行部署 + +496 +00:24:43,584 --> 00:24:46,887 +应当考虑将它们 +捆绑在一个 Swift 软件包中 + +497 +00:24:46,887 --> 00:24:49,556 +这样一来 您就可以提供 +简单的方法来加载参数 + +498 +00:24:49,556 --> 00:24:51,458 +和执行预测 + +499 +00:24:51,458 --> 00:24:53,927 +有关 Swift 软件包资源的 +更多信息 + +500 +00:24:53,927 --> 00:24:58,198 +请查看 WWDC 2020 +关于 Swift 软件包的演讲 + +501 +00:24:58,198 --> 00:24:59,833 +我想说的就这么多 + +502 +00:24:59,833 --> 00:25:01,235 +要记住的重点是 + +503 +00:25:01,235 --> 00:25:04,638 +您现在可以通过合成 +创建自定义任务 + +504 +00:25:04,638 --> 00:25:06,673 +可能性永无止境 + +505 +00:25:06,673 --> 00:25:08,775 +我期待看到您的创造 + +506 +00:25:08,775 --> 00:25:09,943 +如想了解更高阶的技巧 + +507 +00:25:09,943 --> 00:25:12,579 +包括音频和视频任务 请查看 + +508 +00:25:12,579 --> 00:25:15,516 +“使用 Create ML Components +创建高阶模型”讲座 + +509 +00:25:15,516 --> 00:25:17,251 +我的同事 David 将展示 + +510 +00:25:17,251 --> 00:25:20,287 +更高阶的自定义任务 + +511 +00:25:20,287 --> 00:25:24,291 +谢谢 希望您享受 +WWDC 2022 的其他内容 + +512 +00:25:24,291 --> 00:25:29,062 +♪ + diff --git a/zho/2022 Session 10020 Compose advanced models with Create ML Components.srt b/zho/2022 Session 10020 Compose advanced models with Create ML Components.srt new file mode 100644 index 0000000..922e390 --- /dev/null +++ b/zho/2022 Session 10020 Compose advanced models with Create ML Components.srt @@ -0,0 +1,1223 @@ +1 +00:00:00,200 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,676 +♪ + +3 +00:00:09,676 --> 00:00:11,612 +嗨 我的名字叫 David Findlay + +4 +00:00:11,612 --> 00:00:14,014 +我是 Create ML 团队的工程师 + +5 +00:00:14,014 --> 00:00:16,583 +本讲座的主题 +是 Create ML 组件 + +6 +00:00:16,583 --> 00:00:20,487 +这是一种强大的新方法 +用于构建您自己的机器学习任务 + +7 +00:00:20,487 --> 00:00:23,023 +我的同事 Alejandro + +8 +00:00:23,023 --> 00:00:25,092 +在“了解 Create ML 组件” +讲座中做了介绍 + +9 +00:00:25,092 --> 00:00:27,394 +他探讨了 +如何将 Create ML 任务 + +10 +00:00:27,394 --> 00:00:29,863 +解构为组件 并揭示了 + +11 +00:00:29,863 --> 00:00:31,865 +构建自定义模型是多么简单 + +12 +00:00:31,865 --> 00:00:35,002 +转换器和估算器是主要的构件 + +13 +00:00:35,002 --> 00:00:37,938 +您可以将它们组合在一起 + +14 +00:00:37,938 --> 00:00:40,140 +构建自定义模型 如图像回归 + +15 +00:00:40,140 --> 00:00:43,377 +本讲座的内容远不止基础知识 + +16 +00:00:43,377 --> 00:00:46,613 +我想演示 Create ML 组件 +会带来哪些可能性 + +17 +00:00:46,613 --> 00:00:49,917 +我们看一下本讲座的内容 +有很多东西要讲 + +18 +00:00:49,917 --> 00:00:53,187 +我先讲视频数据 再详细介绍 + +19 +00:00:53,187 --> 00:00:57,090 +处理时序数据的新组件 + +20 +00:00:57,090 --> 00:00:58,792 +然后我会把这些概念付诸实践 + +21 +00:00:58,792 --> 00:01:01,061 +只使用转换器构建一个 + +22 +00:01:01,061 --> 00:01:03,430 +人体动作重复次数计数器 + +23 +00:01:03,430 --> 00:01:05,232 +最后 我会训练 + +24 +00:01:05,232 --> 00:01:07,201 +自定义声音分类器模型 + +25 +00:01:07,201 --> 00:01:09,469 +我将讨论增量拟合 它允许您 + +26 +00:01:09,469 --> 00:01:11,271 +批量更新模型 提前停止训练 + +27 +00:01:11,271 --> 00:01:13,941 +并为模型设置检查点 + +28 +00:01:13,941 --> 00:01:17,144 +这种级别的灵活性带来了很多机会 + +29 +00:01:17,144 --> 00:01:19,012 +我等不及了 + +30 +00:01:19,012 --> 00:01:21,081 +让我们开始吧 + +31 +00:01:21,081 --> 00:01:24,551 +在 2020 年 +全球开发者大会 (WWDC) 上 + +32 +00:01:24,551 --> 00:01:26,153 +我们介绍了 +Create ML 中的动作分类 + +33 +00:01:26,153 --> 00:01:28,989 +它允许您对视频中的动作进行分类 + +34 +00:01:28,989 --> 00:01:31,625 +我们还演示了如何创建健身分类器 + +35 +00:01:31,625 --> 00:01:34,127 +来识别一个人的锻炼项目 + +36 +00:01:34,127 --> 00:01:37,998 +如开合跳 弓步和深蹲 + +37 +00:01:37,998 --> 00:01:40,501 +例如 您可以使用动作分类器 + +38 +00:01:40,501 --> 00:01:44,037 +将此视频中的动作识别为开合跳 + +39 +00:01:44,037 --> 00:01:47,441 +但如果您想数一下您的开合跳次数 +该怎么办? + +40 +00:01:47,441 --> 00:01:49,109 +您需要考虑的第一件事是 + +41 +00:01:49,109 --> 00:01:52,079 +开合跳跨越连续多帧 + +42 +00:01:52,079 --> 00:01:55,182 +您需要一种处理时序数据的方法 + +43 +00:01:55,182 --> 00:01:57,050 +感谢 Swift AsyncSequence + +44 +00:01:57,050 --> 00:01:59,386 +让这变得很容易 + +45 +00:01:59,386 --> 00:02:01,889 +如果您不熟悉 AsyncSequence + +46 +00:02:01,889 --> 00:02:06,260 +请查看 +“认识 AsyncSequence”讲座 + +47 +00:02:06,260 --> 00:02:09,062 +通过 Create ML 组件 +您可以 + +48 +00:02:09,062 --> 00:02:13,133 +使用视频阅读器 +将视频作为异步序列帧读取 + +49 +00:02:13,133 --> 00:02:16,170 +AsyncSequence 提供了一种 +循环访问序列帧的方式 + +50 +00:02:16,170 --> 00:02:19,840 +和从视频中接收的顺序一样 + +51 +00:02:19,840 --> 00:02:22,576 +例如 我可以使用 map 方法 + +52 +00:02:22,576 --> 00:02:26,146 +轻松地异步转换每个视频帧 + +53 +00:02:26,146 --> 00:02:30,551 +当您想一次处理一帧时 这很有用 + +54 +00:02:30,551 --> 00:02:32,085 +但如果您想一次处理多帧 + +55 +00:02:32,085 --> 00:02:34,254 +该怎么办? + +56 +00:02:34,254 --> 00:02:36,857 +这就是时序转换器的用武之地 + +57 +00:02:36,857 --> 00:02:39,626 +例如 您可能想要对视频帧进行下采样 + +58 +00:02:39,626 --> 00:02:42,095 +以加快视频中的动作 + +59 +00:02:42,095 --> 00:02:44,064 +您可以为此使用下采样器 + +60 +00:02:44,064 --> 00:02:45,766 +下采样器需要传入一个异步序列 + +61 +00:02:45,766 --> 00:02:48,802 +并返回一个经过下采样的异步序列 + +62 +00:02:48,802 --> 00:02:51,505 +或者您可能想要将帧分组到窗口中 + +63 +00:02:51,505 --> 00:02:54,708 +这对于计算动作重复次数很重要 + +64 +00:02:54,708 --> 00:02:58,111 +这就是滑动窗口转换器的用武之地 + +65 +00:02:58,111 --> 00:03:00,881 +您可以指定窗口长度 +也就是分组到窗口中的帧数 + +66 +00:03:00,881 --> 00:03:03,450 +并指定步幅 + +67 +00:03:03,450 --> 00:03:06,587 +也就是控制滑动间隔的方式 + +68 +00:03:06,587 --> 00:03:09,957 +同样 输入是一个异步序列 + +69 +00:03:09,957 --> 00:03:15,662 +在这种情况下 +输出是一个窗口化的异步序列 + +70 +00:03:15,662 --> 00:03:17,965 +一般来说 时序转换器 + +71 +00:03:17,965 --> 00:03:20,601 +提供了一种将异步序列处理为 + +72 +00:03:20,601 --> 00:03:22,903 +新的异步序列的方法 + +73 +00:03:22,903 --> 00:03:25,772 +那么让我们把这些概念付诸实践 + +74 +00:03:25,772 --> 00:03:27,941 +我不知道您的情况 但是当我锻炼时 + +75 +00:03:27,941 --> 00:03:30,143 +我总是数不清我的动作重复次数 + +76 +00:03:30,143 --> 00:03:32,112 +所以我决定稍微改变一下 + +77 +00:03:32,112 --> 00:03:34,214 +用 Create ML 组件 +构建一个 + +78 +00:03:34,214 --> 00:03:36,383 +动作重复次数计数器 + +79 +00:03:36,383 --> 00:03:39,920 +在这个例子中 我将介绍如何 + +80 +00:03:39,920 --> 00:03:42,256 +将转换器和时序转换器组合在一起 + +81 +00:03:42,256 --> 00:03:45,526 +让我们从姿态提取开始 + +82 +00:03:45,526 --> 00:03:49,296 +我可以使用人体姿态提取器 +来提取姿态 + +83 +00:03:49,296 --> 00:03:50,831 +输入是一个图像 + +84 +00:03:50,831 --> 00:03:54,401 +输出是一个人体姿态数组 + +85 +00:03:54,401 --> 00:03:56,837 +在底层 +我们利用 Vision 框架 + +86 +00:03:56,837 --> 00:03:59,573 +来提取姿态 + +87 +00:03:59,573 --> 00:04:02,376 +请注意 图像可以包含多个人 + +88 +00:04:02,376 --> 00:04:05,012 +这在集体锻炼中很常见 + +89 +00:04:05,012 --> 00:04:08,415 +这就是输出是人体姿态数组的原因 + +90 +00:04:08,415 --> 00:04:11,185 +但我只对一次计算一个人的 + +91 +00:04:11,185 --> 00:04:13,520 +动作重复次数感兴趣 + +92 +00:04:13,520 --> 00:04:16,356 +所以我将姿态提取器 + +93 +00:04:16,356 --> 00:04:19,660 +和姿态选择器组合 + +94 +00:04:19,660 --> 00:04:22,129 +姿态选择器接受传入姿态数组 + +95 +00:04:22,129 --> 00:04:26,834 +以及选择策略 +然后返回一个单独的姿态 + +96 +00:04:26,834 --> 00:04:29,236 +有几个选择策略可供选择 + +97 +00:04:29,236 --> 00:04:30,604 +对于这个例子 + +98 +00:04:30,604 --> 00:04:33,507 +我将使用 +rightMostJointLocation 策略 + +99 +00:04:33,507 --> 00:04:38,312 +下一步是将姿态分组到窗口中 + +100 +00:04:38,312 --> 00:04:42,015 +我将为此添加一个滑动窗口转换器 + +101 +00:04:42,015 --> 00:04:44,852 +我将使用 90 的窗口长度和步幅 + +102 +00:04:44,852 --> 00:04:47,120 +这将生成不重叠窗口 + +103 +00:04:47,120 --> 00:04:49,823 +每个窗口 90 个姿态 + +104 +00:04:49,823 --> 00:04:52,826 +回想一下 滑动窗口转换器 +是时序的 + +105 +00:04:52,826 --> 00:04:55,729 +这使整个任务都是时序的 + +106 +00:04:55,729 --> 00:05:00,367 +预期输入是一个异步序列帧 + +107 +00:05:00,367 --> 00:05:05,639 +最后 我将添加一个 +人体动作计数器 + +108 +00:05:05,639 --> 00:05:06,740 +这个时序转换器 + +109 +00:05:06,740 --> 00:05:10,043 +需要传入窗口化的异步序列帧 + +110 +00:05:10,043 --> 00:05:13,013 +并返回截止到当时的 + +111 +00:05:13,013 --> 00:05:14,515 +累积动作重复次数 + +112 +00:05:14,515 --> 00:05:15,749 +到目前为止 您可能已经注意到 + +113 +00:05:15,749 --> 00:05:18,285 +这个次数是一个浮点数 + +114 +00:05:18,285 --> 00:05:21,822 +这是因为此任务也计算 +部分动作的次数 + +115 +00:05:21,822 --> 00:05:23,323 +就这么简单 + +116 +00:05:23,323 --> 00:05:25,626 +现在我可以在我的锻炼视频中 +计算我的重复次数了 + +117 +00:05:25,626 --> 00:05:27,961 +并确保我没有作弊 + +118 +00:05:27,961 --> 00:05:31,265 +但更好的方法是 +在 App 中实时计算重复次数 + +119 +00:05:31,265 --> 00:05:35,169 +这样就可以跟踪当前的锻炼情况 + +120 +00:05:35,169 --> 00:05:38,071 +让我告诉您如何做到这一点 + +121 +00:05:38,071 --> 00:05:40,607 +首先 我将使用 +readCamera 方法 + +122 +00:05:40,607 --> 00:05:42,409 +该方法需要传入相机配置 + +123 +00:05:42,409 --> 00:05:45,879 +会返回一个异步的相机序列帧 + +124 +00:05:45,879 --> 00:05:49,149 +接下来 我将步幅参数 +调整为 15 帧 + +125 +00:05:49,149 --> 00:05:52,286 +这样我就可以更频繁地获得 +更新的计数 + +126 +00:05:52,286 --> 00:05:55,422 +如果我的相机 +以每秒 30 帧的速度捕获帧 + +127 +00:05:55,422 --> 00:05:58,859 +那么我每半秒计数一次 + +128 +00:05:58,859 --> 00:06:03,397 +现在我可以锻炼了 +而无需担心漏记某个重复动作 + +129 +00:06:03,397 --> 00:06:06,133 +到目前为止 我已经探讨了 + +130 +00:06:06,133 --> 00:06:08,669 +用于转换异步序列的时序组件 + +131 +00:06:08,669 --> 00:06:11,238 +接下来 我想专注于训练 + +132 +00:06:11,238 --> 00:06:14,641 +依赖时序数据的自定义模型 + +133 +00:06:14,641 --> 00:06:18,445 +2019 年 我们演示了 +如何在 Create ML 中 + +134 +00:06:18,445 --> 00:06:19,947 +训练声音分类器 + +135 +00:06:19,947 --> 00:06:22,716 +然后在 2021 年 我们推出了 + +136 +00:06:22,716 --> 00:06:24,952 +声音分类的增强功能 + +137 +00:06:24,952 --> 00:06:26,420 +我想更进一步 + +138 +00:06:26,420 --> 00:06:30,657 +增量训练自定义声音分类器 + +139 +00:06:30,657 --> 00:06:33,393 +Create ML 框架中的 +MLSoundClassifier + +140 +00:06:33,393 --> 00:06:34,695 +仍是训练自定义声音分类器模型的 + +141 +00:06:34,695 --> 00:06:36,897 +最简单方法 + +142 +00:06:36,897 --> 00:06:39,933 +但是当您需要更多的 +可定制性和控制性时 + +143 +00:06:39,933 --> 00:06:42,169 +您可以使用其底层的组件 + +144 +00:06:42,169 --> 00:06:46,406 +最简单的形式下 +声音分类器有两个组件: + +145 +00:06:46,406 --> 00:06:49,076 +Audio Feature Print +是一个特征提取器 + +146 +00:06:49,076 --> 00:06:51,745 +以及您选择的一个分类器 + +147 +00:06:51,745 --> 00:06:54,248 +AudioFeaturePrint 是一个 + +148 +00:06:54,248 --> 00:06:56,850 +从音频缓冲区的异步序列中 + +149 +00:06:56,850 --> 00:06:59,253 +提取音频特征的时序转换器 + +150 +00:06:59,253 --> 00:07:01,755 +与滑动窗口转换器相似 + +151 +00:07:01,755 --> 00:07:04,358 +AudioFeaturePrint +将异步序列窗口化 + +152 +00:07:04,358 --> 00:07:07,327 +然后提取特征 + +153 +00:07:07,327 --> 00:07:09,530 +有几个分类器可供选择 + +154 +00:07:09,530 --> 00:07:14,034 +但对于这个例子 +我将使用逻辑回归分类器 + +155 +00:07:14,034 --> 00:07:16,837 +然后将其与特征提取器组合在一起 + +156 +00:07:16,837 --> 00:07:20,574 +以构建自定义声音分类器 + +157 +00:07:20,574 --> 00:07:23,644 +下一步是将自定义声音分类器 + +158 +00:07:23,644 --> 00:07:25,379 +与标记过的训练数据相拟合 + +159 +00:07:25,379 --> 00:07:27,881 +如要了解有关收集训练数据的 +更多信息 + +160 +00:07:27,881 --> 00:07:30,150 +“了解 Create ML 组件”讲座 + +161 +00:07:30,150 --> 00:07:32,085 +是一个很好的起点 + +162 +00:07:32,085 --> 00:07:34,688 +到目前为止 一切进展顺利 + +163 +00:07:34,688 --> 00:07:36,623 +但是构建机器学习模型 + +164 +00:07:36,623 --> 00:07:39,660 +可能是一个迭代过程 + +165 +00:07:39,660 --> 00:07:43,030 +例如 您可能会随着时间的推移 +发现和收集新的训练数据 + +166 +00:07:43,030 --> 00:07:46,333 +并希望更新您的模型 + +167 +00:07:46,333 --> 00:07:49,503 +您可以提高模型质量 + +168 +00:07:49,503 --> 00:07:53,340 +但是从头开始重新训练模型 +非常耗时 + +169 +00:07:53,340 --> 00:07:55,943 +这是因为您需要对以前的所有数据 + +170 +00:07:55,943 --> 00:07:58,045 +重新进行特征提取 + +171 +00:07:58,045 --> 00:08:00,714 +让我举个例子说明 + +172 +00:08:00,714 --> 00:08:04,184 +在使用新发现的数据 +对模型进行训练时如何节省时间 + +173 +00:08:04,184 --> 00:08:06,687 +关键是对训练数据进行预处理 + +174 +00:08:06,687 --> 00:08:09,456 +并将此过程与模型拟合分开 + +175 +00:08:09,456 --> 00:08:12,793 +在这个例子中 我可以 +将提取音频特征 + +176 +00:08:12,793 --> 00:08:15,429 +与分类器拟合分开进行 + +177 +00:08:15,429 --> 00:08:17,531 +这通常是有效的 + +178 +00:08:17,531 --> 00:08:19,967 +在一系列转换器 + +179 +00:08:19,967 --> 00:08:21,635 +后接一个估算器时 + +180 +00:08:21,635 --> 00:08:24,638 +您可以对 +经过转换器进入估算器的输入 + +181 +00:08:24,638 --> 00:08:26,507 +进行预处理 + +182 +00:08:26,507 --> 00:08:30,143 +您需要做的就是调用预处理方法 + +183 +00:08:30,143 --> 00:08:33,514 +然后将模型与经过预处理的特征 +相拟合 + +184 +00:08:33,514 --> 00:08:35,849 +我觉得这很方便 因为我不需要 + +185 +00:08:35,849 --> 00:08:38,785 +改变声音分类器的组成 + +186 +00:08:38,785 --> 00:08:41,088 +现在可以单独提取特征 + +187 +00:08:41,088 --> 00:08:44,057 +我可以灵活地只对新数据提取 + +188 +00:08:44,057 --> 00:08:46,760 +音频特征 + +189 +00:08:46,760 --> 00:08:49,129 +当您发现模型的新训练数据时 + +190 +00:08:49,129 --> 00:08:51,999 +您可以轻松地对这些数据 +进行单独的预处理 + +191 +00:08:51,999 --> 00:08:54,001 +然后将新增的特征添加到 + +192 +00:08:54,001 --> 00:08:56,770 +之前提取的特征上 + +193 +00:08:56,770 --> 00:08:58,605 +这只是预处理可以节省时间的 + +194 +00:08:58,605 --> 00:09:01,742 +第一个例子 + +195 +00:09:01,742 --> 00:09:04,645 +让我们回到模型构建周期 + +196 +00:09:04,645 --> 00:09:06,813 +您可能需要调整估算器参数 + +197 +00:09:06,813 --> 00:09:09,483 +直到您对模型的质量感到满意为止 + +198 +00:09:09,483 --> 00:09:12,386 +通过将特征提取与拟合分开 + +199 +00:09:12,386 --> 00:09:14,821 +您可以只提取一次特征 + +200 +00:09:14,821 --> 00:09:18,325 +然后将模型与不同的估算器参数 +相拟合 + +201 +00:09:18,325 --> 00:09:19,593 +我们来看一个 + +202 +00:09:19,593 --> 00:09:21,261 +在不重新进行特征提取的情况下 + +203 +00:09:21,261 --> 00:09:24,531 +更改分类器参数的例子 + +204 +00:09:24,531 --> 00:09:26,934 +假设我已经提取了特征 + +205 +00:09:26,934 --> 00:09:30,771 +我将修改分类器的 L2 惩罚参数 + +206 +00:09:30,771 --> 00:09:33,006 +然后我需要将新的分类器 + +207 +00:09:33,006 --> 00:09:35,375 +添加到旧的特征提取器上 + +208 +00:09:35,375 --> 00:09:37,945 +在调整估算器时 + +209 +00:09:37,945 --> 00:09:40,747 +不更改特征提取器很重要 + +210 +00:09:40,747 --> 00:09:43,050 +因为这会使之前提取的特征无效 + +211 +00:09:43,050 --> 00:09:47,421 +我们看一下如何以增量方式 +使用批量数据拟合模型 + +212 +00:09:47,421 --> 00:09:49,323 +机器学习模型 + +213 +00:09:49,323 --> 00:09:51,725 +通常受益于大量的训练数据 + +214 +00:09:51,725 --> 00:09:55,095 +但是 您的 App 可能 +受到有限内存的限制 + +215 +00:09:55,095 --> 00:09:56,730 +那么您该怎么办? + +216 +00:09:56,730 --> 00:09:59,266 +您可以使用 Create ML 组件 +来训练模型 + +217 +00:09:59,266 --> 00:10:02,569 +每次只将一批数据加载到内存中 + +218 +00:10:02,569 --> 00:10:05,606 +我需要做的第一件事是将现有分类器 + +219 +00:10:05,606 --> 00:10:07,708 +更换为可更新的分类器 + +220 +00:10:07,708 --> 00:10:10,077 +为了使用批量数据训练自定义模型 + +221 +00:10:10,077 --> 00:10:12,679 +分类器需要可更新 + +222 +00:10:12,679 --> 00:10:16,383 +例如 可以轻松使用的 + +223 +00:10:16,383 --> 00:10:17,684 +全连接神经网络分类器 + +224 +00:10:17,684 --> 00:10:20,220 +而不是不可更新的 + +225 +00:10:20,220 --> 00:10:22,022 +逻辑回归分类器 + +226 +00:10:25,292 --> 00:10:28,795 +好 现在我将编写一个训练循环 + +227 +00:10:28,795 --> 00:10:32,032 +我首先将创建一个默认的 +初始化模型 + +228 +00:10:32,032 --> 00:10:34,034 +还不能用来进行预测 + +229 +00:10:34,034 --> 00:10:37,838 +因为这只是训练的起点 + +230 +00:10:37,838 --> 00:10:39,873 +然后我会在训练开始前 + +231 +00:10:39,873 --> 00:10:41,909 +提取音频特征 + +232 +00:10:41,909 --> 00:10:43,110 +这是一个重要的步骤 + +233 +00:10:43,110 --> 00:10:46,914 +因为我不想每次迭代都提取特征 + +234 +00:10:46,914 --> 00:10:49,750 +下一步是定义训练循环 + +235 +00:10:49,750 --> 00:10:51,385 +并指定您想要训练的 + +236 +00:10:51,385 --> 00:10:53,854 +迭代次数 + +237 +00:10:53,854 --> 00:10:57,891 +在继续之前 我将导入 +Swift Algorithms 开源软件包 + +238 +00:10:57,891 --> 00:11:01,328 +我将用它来创建批量训练数据 + +239 +00:11:01,328 --> 00:11:02,796 +请务必查看 WWDC 2021 的 + +240 +00:11:02,796 --> 00:11:05,332 +“认识 Swift 算法 +和集合包”讲座 + +241 +00:11:05,332 --> 00:11:08,702 +以了解更多信息 + +242 +00:11:10,404 --> 00:11:13,507 +分批次发生在训练循环内 + +243 +00:11:13,507 --> 00:11:15,709 +我将使用 chunks 方法 +将特征分组为批次 + +244 +00:11:15,709 --> 00:11:18,345 +以便进行训练 + +245 +00:11:18,345 --> 00:11:20,347 +块大小是一次性加载到内存中的 + +246 +00:11:20,347 --> 00:11:23,116 +特征数量 + +247 +00:11:23,116 --> 00:11:26,520 +然后 我通过迭代批次 + +248 +00:11:26,520 --> 00:11:28,655 +调用 update 方法来更新模型 + +249 +00:11:31,491 --> 00:11:33,293 +当您增量训练模型时 + +250 +00:11:33,293 --> 00:11:35,495 +您可以解锁更多的训练技巧 + +251 +00:11:35,495 --> 00:11:36,597 +例如 + +252 +00:11:36,597 --> 00:11:39,066 +在这个训练图中 +经过大约 10 次迭代 + +253 +00:11:39,066 --> 00:11:42,669 +模型精度就会稳定在 95% + +254 +00:11:42,669 --> 00:11:45,005 +此时模型已经收敛 + +255 +00:11:45,005 --> 00:11:46,640 +您可以提前停止 + +256 +00:11:46,640 --> 00:11:50,511 +让我们在训练循环中实施提前停止 + +257 +00:11:50,511 --> 00:11:52,779 +我需要做的第一件事是 + +258 +00:11:52,779 --> 00:11:54,581 +对我的验证集进行预测 + +259 +00:11:54,581 --> 00:11:56,350 +我在这里使用了 +mapFeatures 方法 + +260 +00:11:56,350 --> 00:11:58,819 +因为我需要将验证集预测结果 +与其标注数据 + +261 +00:11:58,819 --> 00:12:01,722 +进行配对 + +262 +00:12:01,722 --> 00:12:04,691 +下一步是衡量模型的质量 + +263 +00:12:04,691 --> 00:12:06,760 +我现在将使用内置衡量标准 + +264 +00:12:06,760 --> 00:12:08,128 +但没有什么能阻止您 + +265 +00:12:08,128 --> 00:12:10,664 +实施自定义标准 + +266 +00:12:10,664 --> 00:12:12,499 +最后 我将 + +267 +00:12:12,499 --> 00:12:16,270 +在模型达到 +95% 的精度时 停止训练 + +268 +00:12:16,270 --> 00:12:19,506 +在训练循环之外 +我会将模型写入磁盘 + +269 +00:12:19,506 --> 00:12:22,843 +以便以后使用它进行预测 + +270 +00:12:22,843 --> 00:12:24,378 +除了提前停止 + +271 +00:12:24,378 --> 00:12:26,780 +我还想谈谈模型检查点 + +272 +00:12:28,549 --> 00:12:30,984 +您可以在训练期间保存模型的进度 + +273 +00:12:30,984 --> 00:12:33,153 +而不是等到最后 + +274 +00:12:33,153 --> 00:12:34,788 +您甚至可以使用检查点来恢复训练 + +275 +00:12:34,788 --> 00:12:37,424 +这很方便 + +276 +00:12:37,424 --> 00:12:41,328 +尤其是在模型需要很长时间 +来训练时 + +277 +00:12:41,328 --> 00:12:45,032 +您需要做的就是在训练循环中 +保存您的模型 + +278 +00:12:45,032 --> 00:12:47,501 +我们建议通过定义检查点间隔 + +279 +00:12:47,501 --> 00:12:49,469 +每隔几次迭代就这样做一次 + +280 +00:12:49,469 --> 00:12:51,605 +就这么简单 + +281 +00:12:51,605 --> 00:12:54,675 +在本讲座中 我介绍了时序组件 + +282 +00:12:54,675 --> 00:12:56,643 +这是一种通过时序数据 +比如音频和视频 + +283 +00:12:56,643 --> 00:13:00,247 +构建机器学习任务的新方法 + +284 +00:13:00,247 --> 00:13:02,916 +我将时序组件组合在一起 + +285 +00:13:02,916 --> 00:13:05,752 +以制作人体动作重复次数计数器 + +286 +00:13:05,752 --> 00:13:08,922 +最后 我谈到了增量拟合 + +287 +00:13:08,922 --> 00:13:10,724 +这将为您开启新的可能性 + +288 +00:13:10,724 --> 00:13:13,427 +以便将机器学习构建到 +您的 App 中 + +289 +00:13:13,427 --> 00:13:16,763 +感谢您的光临 +请畅享 WWDC 的其余部分 + +290 +00:13:16,763 --> 00:13:21,301 +♪ + diff --git a/zho/2022 Session 10022 Create camera extensions with Core Media IO.srt b/zho/2022 Session 10022 Create camera extensions with Core Media IO.srt new file mode 100644 index 0000000..dba6c7f --- /dev/null +++ b/zho/2022 Session 10022 Create camera extensions with Core Media IO.srt @@ -0,0 +1,2127 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,676 --> 00:00:11,211 +Brad Ford: 欢迎大家 + +3 +00:00:11,245 --> 00:00:15,382 +我是来自 Camera Software Engineering +团队的 Brad Ford + +4 +00:00:15,415 --> 00:00:18,452 +在这一讲座中 我将向您介绍 + +5 +00:00:18,485 --> 00:00:22,022 +CoreMedia IO 的相机扩展 +这是一种用于 macOS 的 + +6 +00:00:22,055 --> 00:00:25,626 +现代相机驱动程序架构 +是 DAL plug-ins 的替代品 + +7 +00:00:27,094 --> 00:00:30,731 +DAL plug-ins 这一技术 +允许你为插入 Mac 的硬件 + +8 +00:00:30,764 --> 00:00:35,335 +创建相机驱动程序 +或者虚拟相机 + +9 +00:00:35,369 --> 00:00:39,540 +从 MacOS 10.7 开始问世 +已有很长一段时间了 + +10 +00:00:40,707 --> 00:00:45,712 +DAL plug-ins 提供了将 macOS +扩展为富媒体平台的能力 + +11 +00:00:45,746 --> 00:00:50,284 +为专业人士和消费者 +提供第三方相机产品的支持 + +12 +00:00:51,518 --> 00:00:54,254 +这也是 Mac 出类拔萃的 +原因之一 + +13 +00:00:56,123 --> 00:00:58,859 +但 DAL plug-ins +还存在一些问题 + +14 +00:00:58,892 --> 00:01:02,196 +它们会将不受信任的代码 +直接加载到 App 的进程中 + +15 +00:01:02,229 --> 00:01:05,933 +导致 App 会容易因插件漏洞而崩溃 + +16 +00:01:05,966 --> 00:01:08,869 +或者受到恶意软件的攻击 + +17 +00:01:08,902 --> 00:01:11,872 +因此 它们不能与 +FaceTime 通话 + +18 +00:01:11,905 --> 00:01:16,176 +QuickTime 播放器和 PhotoBoth 等 +Apple App 一起使用 + +19 +00:01:16,210 --> 00:01:19,213 +也不能与许多第三方 +相机 App 一起使用 + +20 +00:01:19,246 --> 00:01:23,283 +除非这些 App 有意 +禁用资料库验证 + +21 +00:01:23,317 --> 00:01:26,787 +或者用户关闭系统完整性保护 + +22 +00:01:26,820 --> 00:01:29,022 +而这两种做法都不推荐 + +23 +00:01:29,056 --> 00:01:33,360 +因为会降低系统的安全性和稳定性 + +24 +00:01:33,393 --> 00:01:35,562 +同时这种插件也很难开发 + +25 +00:01:35,596 --> 00:01:38,732 +它们带一个 +大约 2011 年的 C API + +26 +00:01:38,765 --> 00:01:43,537 +和一套繁多的 +C++ 辅助类 SDK 需要您学习 + +27 +00:01:43,570 --> 00:01:46,607 +最重要的是 它们的文档很少 + +28 +00:01:47,875 --> 00:01:50,043 +是升级换代的时候了 + +29 +00:01:50,077 --> 00:01:54,147 +macOS 12.3 推出了完全现代化 +的 DAL plug-ins 替代品 + +30 +00:01:54,181 --> 00:01:57,851 +称为 Camera Extensions (相机扩展) + +31 +00:01:59,553 --> 00:02:03,524 +一个将用户安全性放在首位的架构 + +32 +00:02:03,557 --> 00:02:05,492 +我们来了解一下它是如何工作的 + +33 +00:02:05,526 --> 00:02:09,096 +首先 我将提供一段技术概述 + +34 +00:02:09,129 --> 00:02:13,734 +接下来 我将向您展示 +如何从头开始构建相机扩展 + +35 +00:02:13,767 --> 00:02:18,739 +然后 介绍 API 的 +主要类型和函数 + +36 +00:02:18,772 --> 00:02:23,977 +解释如何将 CoreMedia IO 扩展 +当作输出设备使用 + +37 +00:02:24,011 --> 00:02:28,882 +最后 介绍我们的 +DAL plug-in 弃用计划 + +38 +00:02:28,916 --> 00:02:31,652 +我们开始吧 + +39 +00:02:31,685 --> 00:02:35,856 +相机扩展 +也称为 CoreMedia IO 扩展 + +40 +00:02:35,889 --> 00:02:40,060 +是一种将相机驱动程序打包 +并交付给 Mac app 的新方法 + +41 +00:02:41,061 --> 00:02:42,462 +它们很安全 + +42 +00:02:42,496 --> 00:02:46,300 +您的扩展代码 +被隔离到自己的守护进程中 + +43 +00:02:46,333 --> 00:02:50,037 +该进程被沙盒化 +并以用户角色运行 + +44 +00:02:50,070 --> 00:02:53,240 +您的扩展提供的所有缓冲区 + +45 +00:02:53,273 --> 00:02:56,443 +在交付给 App 之前都会经过验证 + +46 +00:02:56,476 --> 00:02:57,911 +它们速度快 + +47 +00:02:57,945 --> 00:02:59,947 +该框架处理扩展进程 + +48 +00:02:59,980 --> 00:03:02,749 +和 App 之间的 IPC 层 + +49 +00:03:02,783 --> 00:03:05,552 +以性能为重点 + +50 +00:03:05,586 --> 00:03:08,155 +该框架还负责将缓冲区 + +51 +00:03:08,188 --> 00:03:11,525 +同时传递给多个客户端 + +52 +00:03:11,558 --> 00:03:12,960 +它们很现代 + +53 +00:03:12,993 --> 00:03:17,064 +该扩展可以用 Swift +或 Objective-C 书写 + +54 +00:03:18,532 --> 00:03:19,900 +它们很简单 + +55 +00:03:19,933 --> 00:03:22,002 +只要学习几个类别 + +56 +00:03:22,035 --> 00:03:25,305 +实现几个协议就可以启动和运行 + +57 +00:03:25,339 --> 00:03:27,774 +该框架会处理样板代码 + +58 +00:03:29,476 --> 00:03:31,278 +它们很容易部署 + +59 +00:03:31,311 --> 00:03:34,014 +您可以将它们作为 App +在 App Store 商店中发布 + +60 +00:03:36,149 --> 00:03:40,320 +相机扩展 100% 向后兼容 + +61 +00:03:40,354 --> 00:03:43,390 +现有的 AVFoundation +拍摄 API + +62 +00:03:45,492 --> 00:03:50,364 +相机扩展如内置相机一样 +支持所有相机 App + +63 +00:03:50,397 --> 00:03:52,733 +包括 Apple 的 App + +64 +00:03:52,766 --> 00:03:55,903 +下面是如何在 FaceTime 通话的 +摄像头选择器中 + +65 +00:03:55,936 --> 00:03:58,205 +显示相机扩展的示例 + +66 +00:03:58,238 --> 00:04:02,342 +相机扩展可以提供怎样的体验 + +67 +00:04:02,376 --> 00:04:05,812 +我们先来研究三种常见的用法 + +68 +00:04:05,846 --> 00:04:08,615 +最简单的用途是纯软件相机 + +69 +00:04:08,649 --> 00:04:12,452 +例如显示色彩条纹的相机 + +70 +00:04:12,486 --> 00:04:15,923 +显示特定的测试图案的相机 + +71 +00:04:15,956 --> 00:04:22,062 +以不同的帧率或分辨率 +程序化生成图像的相机 + +72 +00:04:22,095 --> 00:04:25,232 +或用于流式传输 +预渲染内容的相机 + +73 +00:04:25,265 --> 00:04:29,236 +如电影中的帧 +以测试声画同步 + +74 +00:04:30,871 --> 00:04:34,808 +第二个用例是为实际插入 Mac + +75 +00:04:34,842 --> 00:04:39,379 +或以无线方式发现的 +相机提供驱动 + +76 +00:04:39,413 --> 00:04:44,017 +相机扩展完全支持热插拔 + +77 +00:04:44,051 --> 00:04:47,421 +处理硬件有几种选择 + +78 +00:04:47,454 --> 00:04:52,259 +首选方法是使用完全 +在用户空间运行的 + +79 +00:04:52,292 --> 00:04:55,863 +DriverKit 扩展或 DEXT + +80 +00:04:55,896 --> 00:04:58,932 +如硬件必须在内核级进行寻址 + +81 +00:04:58,966 --> 00:05:03,136 +则可以使用传统的 +IOVideoFamily kext 方式 + +82 +00:05:03,170 --> 00:05:05,806 +不鼓励再开发新的 kext 代码 + +83 +00:05:05,839 --> 00:05:11,278 +因为 kext 本质上不太安全 +且会导致系统不稳定 + +84 +00:05:14,047 --> 00:05:16,783 +Apple 为 USB 视频类 +或 UVC 摄像头 + +85 +00:05:16,817 --> 00:05:21,588 +提供了一个类兼容的扩展 + +86 +00:05:21,622 --> 00:05:25,058 +它非常适合符合 UVC 规范的相机 + +87 +00:05:26,193 --> 00:05:29,263 +然而 如果您需要支持 + +88 +00:05:29,296 --> 00:05:31,765 +使用非标准协议的 +USB 摄像头 + +89 +00:05:31,798 --> 00:05:35,035 +具有 UVC 规范之外的 +附加功能 + +90 +00:05:35,068 --> 00:05:40,107 +可以创建一个覆盖 Apple +UVC 扩展的相机扩展 + +91 +00:05:40,140 --> 00:05:44,678 +允许您声明特定的产品 +和供应商 ID + +92 +00:05:44,711 --> 00:05:48,382 +如果您有兴趣了解更多 +这方面的信息 + +93 +00:05:48,415 --> 00:05:51,585 +请参考 developer.apple.com 上 + +94 +00:05:51,618 --> 00:05:55,489 +标题为 “Overriding the default USB +video class extension” 的文章 + +95 +00:05:55,522 --> 00:05:58,926 +这篇文章解释了 +如何创建最小的 DEXT bundle + +96 +00:05:58,959 --> 00:06:04,398 +以及需要在 Info.plist 中 +覆盖哪些 IOKitPersonalities 键 + +97 +00:06:05,432 --> 00:06:08,535 +第三种常见用途是创意相机 + +98 +00:06:08,569 --> 00:06:11,471 +一种软件和硬件的混合体 + +99 +00:06:12,673 --> 00:06:16,376 +您的扩展从连接在 Mac 上的 +另一个物理相机 + +100 +00:06:16,410 --> 00:06:18,178 +访问视频流 + +101 +00:06:18,212 --> 00:06:20,547 +对这些缓冲区添加效果 + +102 +00:06:20,581 --> 00:06:24,318 +并将它们作为一个新的相机流 +发送给客户端 + +103 +00:06:26,353 --> 00:06:31,592 +或者一个创意相机 +从几个相机获取视频流 + +104 +00:06:31,625 --> 00:06:35,128 +合成这些视频流 +并发送到 App + +105 +00:06:37,164 --> 00:06:40,534 +像这样的创意相机 +可能会使用配置 App + +106 +00:06:40,567 --> 00:06:44,438 +来控制合成或参数化滤镜 + +107 +00:06:44,471 --> 00:06:48,075 +创意相机的可能性可谓无穷无尽 + +108 +00:06:49,243 --> 00:06:51,879 +现在我们已经了解了 +主要使用案例 + +109 +00:06:51,912 --> 00:06:56,183 +我们来分析一下 +CoreMedia IO 扩展 + +110 +00:06:56,216 --> 00:06:59,119 +首先是 CoreMedia IO 部分 + +111 +00:07:00,721 --> 00:07:03,824 +CoreMedia IO 是用于 + +112 +00:07:03,857 --> 00:07:07,794 +发布或发现摄像头驱动程序的 +底层框架 + +113 +00:07:07,828 --> 00:07:11,431 +您已经知道 +它包含了旧版 DAL API + +114 +00:07:11,465 --> 00:07:15,736 +和替代它的新相机扩展 API + +115 +00:07:15,769 --> 00:07:19,673 +但也包含了一组 +强大的底层 C API + +116 +00:07:19,706 --> 00:07:24,244 +供 App 开发人员查找和检查 +系统上的摄像头 + +117 +00:07:25,612 --> 00:07:28,282 +那关于扩展部分是怎样的呢 + +118 +00:07:29,783 --> 00:07:35,088 +CoreMedia IO 扩展建立在 +macOS Catalina 首次引入的 + +119 +00:07:35,122 --> 00:07:38,525 +SystemExtensions 框架之上 + +120 +00:07:38,559 --> 00:07:41,728 +避免了一次性安装程序的需要 + +121 +00:07:41,762 --> 00:07:45,799 +相反 您可以在 App 中 +发布您的扩展 + +122 +00:07:45,832 --> 00:07:49,803 +扩展可执行文件 +位于 App bundle 中 + +123 +00:07:49,837 --> 00:07:52,973 +通过调用 +SystemExtensions 框架 + +124 +00:07:53,006 --> 00:07:58,078 +您的 App 可以为 +系统上的所有用户 + +125 +00:07:58,111 --> 00:08:01,048 +安装 升级或降级您的扩展 + +126 +00:08:01,081 --> 00:08:03,717 +卸载非常简单 + +127 +00:08:03,750 --> 00:08:06,553 +删除该 App +SystemExtensions 框架 + +128 +00:08:06,587 --> 00:08:10,357 +就会对所有用户卸载您的相机扩展 + +129 +00:08:10,390 --> 00:08:13,627 +这种分发机制允许 +在 App Store 商店中使用 + +130 +00:08:13,660 --> 00:08:18,098 +让您的相机扩展可轻松部署到 +更广泛的受众中 + +131 +00:08:19,900 --> 00:08:22,636 +要了解更多关于系统扩展框架的信息 + +132 +00:08:22,669 --> 00:08:26,840 +请参阅 developer.apple.com/ + +133 +00:08:26,874 --> 00:08:29,877 +documentation/systemextensions 网站 + +134 +00:08:31,745 --> 00:08:36,817 +请务必查看 WWDC 2019 中标题为 + +135 +00:08:36,850 --> 00:08:39,520 +“System Extensions and DriverKit” +的视频 + +136 +00:08:40,654 --> 00:08:44,224 +这是我们对相机扩展的技术概述 + +137 +00:08:44,258 --> 00:08:46,527 +现在 我们来实际构建一个扩展 + +138 +00:08:46,560 --> 00:08:50,397 +下面是如何在几分钟内启动 + +139 +00:08:50,430 --> 00:08:52,099 +并运行相机扩展的快速演示 + +140 +00:08:53,634 --> 00:08:58,906 +我已经用 Xcode 创建了一个名为 +ExampleCam 的单窗口 MacOS app + +141 +00:08:58,939 --> 00:09:02,042 +至此 我只添加了几行代码 + +142 +00:09:03,844 --> 00:09:07,247 +App Delegate 保持不变 + +143 +00:09:07,281 --> 00:09:11,518 +在主 storyboard 中 +我添加了两个按钮 + +144 +00:09:11,552 --> 00:09:15,055 +一个用于安装 一个用于卸载扩展 + +145 +00:09:15,088 --> 00:09:17,991 +还有一个用于显示状态的文本字段 + +146 +00:09:19,293 --> 00:09:23,130 +在 ViewController 类中 +我添加了 IBActions + +147 +00:09:23,163 --> 00:09:27,100 +来连接安装和卸载按钮 + +148 +00:09:28,635 --> 00:09:31,939 +这些函数 +创建 OSSystemExtensionRequest + +149 +00:09:31,972 --> 00:09:34,975 +来激活 + +150 +00:09:35,008 --> 00:09:39,980 +或停用 App bundle 中的扩展 + +151 +00:09:40,013 --> 00:09:43,650 +在底部 我添加了记录状态的 + +152 +00:09:43,684 --> 00:09:48,956 +OSSystemExtensionRequestDelegate +函数的基础实现 + +153 +00:09:50,591 --> 00:09:56,063 +App 的 entitlement 文件包括 +App Sandbox = YES + +154 +00:09:56,096 --> 00:09:58,699 +定义了一个 AppGroup + +155 +00:10:00,734 --> 00:10:05,038 +我在这里只添加了一个新的键 +即 “System Extension” + +156 +00:10:05,072 --> 00:10:09,176 +只要您的 App 要安装系统扩展 +就需要该键值 + +157 +00:10:09,209 --> 00:10:13,714 +此时 如果我运行此 App + +158 +00:10:13,747 --> 00:10:17,417 +并点击安装扩展按钮 + +159 +00:10:17,451 --> 00:10:20,287 +会出现一个致命错误 +因为 App 正在查找 + +160 +00:10:20,320 --> 00:10:23,724 +bundle 包中 +尚不存在的扩展 + +161 +00:10:27,394 --> 00:10:33,567 +为了创建和嵌入系统扩展 +我点击 File (文件) + +162 +00:10:33,600 --> 00:10:37,571 +New (新建) Target (目标) + +163 +00:10:37,604 --> 00:10:41,074 +然后在 macOS 下 +一直滚动到底部 + +164 +00:10:41,108 --> 00:10:44,211 +System Extension (系统扩展) 处 + +165 +00:10:44,244 --> 00:10:48,982 +然后选择 “Camera Extension (相机扩展)” +点击下一步 + +166 +00:10:49,016 --> 00:10:53,987 +命名 我选择 “Extension” + +167 +00:10:54,021 --> 00:10:58,559 +确保 “Embedded in Application” +已设置 + +168 +00:10:58,592 --> 00:11:01,528 +然后点击 “Finish” + +169 +00:11:01,562 --> 00:11:06,366 +在新的扩展文件夹中 +我得到了四个新文件 + +170 +00:11:06,400 --> 00:11:10,737 +Info.plist 通过定义 +它的 MachServiceName + +171 +00:11:10,771 --> 00:11:13,640 +将其标识为 CMIOExtension + +172 +00:11:15,008 --> 00:11:17,177 +这条信息很关键 + +173 +00:11:17,211 --> 00:11:22,549 +只有它存在 CoreMedia IO +注册助手才会启动您的扩展 + +174 +00:11:25,285 --> 00:11:29,590 +到了这一步 我们给系统扩展提供一个 + +175 +00:11:29,623 --> 00:11:32,292 +使用说明 + +176 +00:11:32,326 --> 00:11:36,997 +entitlement 文件显示 +它是沙盒化 App + +177 +00:11:37,030 --> 00:11:41,635 +我需要确保扩展的 App group + +178 +00:11:41,668 --> 00:11:45,739 +以 MachServiceName 为前缀 +以便通过验证 + +179 +00:11:47,140 --> 00:11:51,478 +因此 我将其从 App 扩展 + +180 +00:11:51,512 --> 00:11:56,283 +复制并粘贴到扩展 entitlement 文件 + +181 +00:11:56,316 --> 00:11:57,651 +就是这样 + +182 +00:11:59,152 --> 00:12:03,590 +Main.swift 文件作为扩展的入口点 + +183 +00:12:03,624 --> 00:12:05,893 +并启动服务 + +184 +00:12:05,926 --> 00:12:09,563 +ExtensionProvider.swift 文件 + +185 +00:12:09,596 --> 00:12:12,032 +为我们提供了一个功能齐全的相机 + +186 +00:12:12,065 --> 00:12:15,936 +它包含一个 DeviceSource + +187 +00:12:15,969 --> 00:12:19,806 +一个 StreamSource +和一个 ProviderSource + +188 +00:12:19,840 --> 00:12:22,943 +所有这些都是 +创建纯软件相机所需的 + +189 +00:12:22,976 --> 00:12:25,012 +不错的小模板 + +190 +00:12:26,280 --> 00:12:29,683 +在这个文件中 我搜索 + +191 +00:12:29,716 --> 00:12:32,953 +“SampleCapture” + +192 +00:12:32,986 --> 00:12:38,392 +并将其替换为 “ExampleCam” + +193 +00:12:38,425 --> 00:12:42,229 +这样我的相机名称 型号 + +194 +00:12:42,262 --> 00:12:45,566 +和制造商都有了合适的名称 + +195 +00:12:48,535 --> 00:12:51,538 +好了 我们可以编译并运行了 + +196 +00:12:57,211 --> 00:13:00,881 +当我按下 Install (安装) 按钮时 + +197 +00:13:00,914 --> 00:13:04,051 +啊哦 失败了 + +198 +00:13:04,084 --> 00:13:07,387 +这是因为系统扩展只能由 +驻留在 /Applications 中的 + +199 +00:13:07,421 --> 00:13:09,923 +App 安装 + +200 +00:13:09,957 --> 00:13:12,159 +我们移动后再试一次 + +201 +00:13:26,507 --> 00:13:30,410 +这次成功了 + +202 +00:13:30,444 --> 00:13:33,847 +系统提示我通过在 +“System Settings (系统设置)” 中 + +203 +00:13:33,881 --> 00:13:38,385 +进行身份验证 +来安装被阻止的扩展 + +204 +00:13:38,418 --> 00:13:41,788 +在 “System Settings (系统设置)” 中 +我找到了 “Privacy & Security (隐私与安全)” + +205 +00:13:41,822 --> 00:13:43,757 +然后单击 “Allow (允许)” 按钮 + +206 +00:13:45,459 --> 00:13:48,462 +使用密码进行身份验证 + +207 +00:13:48,495 --> 00:13:53,033 +然后看到我的结果已更改为0 +表示“no error (无错误)” + +208 +00:13:53,066 --> 00:13:58,539 +如果我使用 +systemextensionsctl list 工具 + +209 +00:13:58,572 --> 00:14:03,544 +就确认成功了 现在我的系统上 + +210 +00:14:03,577 --> 00:14:05,379 +就激活了一个的扩展 + +211 +00:14:05,412 --> 00:14:09,249 +现在我可以打开任何相机 App +找到并欣赏我的作品 + +212 +00:14:10,918 --> 00:14:13,654 +我们来启动 FaceTime 通话 + +213 +00:14:13,687 --> 00:14:16,924 +ExampleCam 出现在 +相机选择器中 + +214 +00:14:16,957 --> 00:14:20,127 +这有点像 70 年代的 +老式乒乓游戏 + +215 +00:14:20,160 --> 00:14:23,664 +画一条水平白线 +以每秒 60 帧的速度 + +216 +00:14:23,697 --> 00:14:25,265 +上下移动 + +217 +00:14:28,836 --> 00:14:32,840 +要移除相机 我只需要删除 App + +218 +00:14:37,244 --> 00:14:41,648 +系统会提示我确认 +是否连同 App + +219 +00:14:41,682 --> 00:14:43,517 +一起卸载该扩展程序 + +220 +00:14:49,122 --> 00:14:54,228 +ExampleCam 演示展示了从头开始 +制作软件相机是多么容易 + +221 +00:14:54,261 --> 00:14:58,298 +现在我们提升一个档次 +把软件相机 + +222 +00:14:58,332 --> 00:15:00,133 +变成一个创意相机 + +223 +00:15:02,736 --> 00:15:06,139 +我把第二个例子 +称为 CIFilterCam + +224 +00:15:06,173 --> 00:15:09,243 +CI 代表 CoreImage + +225 +00:15:09,276 --> 00:15:11,778 +这是一个带有各种滤镜效果的框架 + +226 +00:15:11,812 --> 00:15:14,414 +您可以将其应用于静态图片或视频 + +227 +00:15:15,549 --> 00:15:19,553 +为了创建 CIFilterCam +我从 ExampleCam 壳程序开始 + +228 +00:15:19,586 --> 00:15:22,456 +但决定将该 App 作为配置 App + +229 +00:15:22,489 --> 00:15:24,925 +和安装程序 + +230 +00:15:24,958 --> 00:15:30,097 +我添加了一个相机选择器按钮 +一个滤镜选择器按钮 + +231 +00:15:30,130 --> 00:15:32,866 +和一个忽略效果的按钮 + +232 +00:15:32,900 --> 00:15:36,570 +我还添加了一个实时视频预览视图 + +233 +00:15:36,603 --> 00:15:40,274 +这是一个 +由 AVCaptureVideoPreviewLayer + +234 +00:15:40,307 --> 00:15:43,610 +支持的标准视图 +可以显示滤镜相机当前工作 + +235 +00:15:43,644 --> 00:15:46,847 +通过取消选中 bypass 按钮 + +236 +00:15:46,880 --> 00:15:50,951 +可以看到应用在视频上的各种滤镜 + +237 +00:15:50,984 --> 00:15:56,123 +从色彩效果 + +238 +00:15:56,156 --> 00:15:58,325 +到变形滤镜 + +239 +00:16:02,563 --> 00:16:05,165 +我比较喜欢凹凸变形的效果 + +240 +00:16:06,533 --> 00:16:09,703 +我可以将这些应用于内置 +FaceTime 通话相机 + +241 +00:16:09,736 --> 00:16:13,273 +或连接到 Mac 的 +任何物理相机 + +242 +00:16:15,309 --> 00:16:19,446 +我把附近的 iPhone +设置为连续互通相机 + +243 +00:16:22,950 --> 00:16:24,618 +我们用用看 + +244 +00:16:29,223 --> 00:16:32,726 +CIFilterCam App 本身并 +没有什么特别之处 + +245 +00:16:32,759 --> 00:16:34,761 +只是一个特效相机 App + +246 +00:16:34,795 --> 00:16:38,065 +真正有趣的地方是 +这款 App 是一个 + +247 +00:16:38,098 --> 00:16:43,403 +所有 App 都可以使用的 +虚拟滤镜相机的前端 + +248 +00:16:43,437 --> 00:16:46,406 +我启动 FaceTime 通话 +和 PhotoBooth + +249 +00:16:46,440 --> 00:16:50,811 +确保它们都对应 CIFilterCam + +250 +00:16:50,844 --> 00:16:55,048 +现在 当在我的配置 App 中 +更改滤镜时 + +251 +00:16:55,082 --> 00:16:58,685 +每个使用 CIFilterCam 的 App +都会随之更改 + +252 +00:16:59,887 --> 00:17:04,758 +如果我选择了不同来源的相机 +每个相机 App 都会接受更改 + +253 +00:17:06,059 --> 00:17:09,997 +App 中的每一个按钮 +都会转化为一个简单的属性调用 + +254 +00:17:10,030 --> 00:17:15,602 +通知滤镜相机扩展 +告诉它 “嗨 扩展 用这个相机” + +255 +00:17:15,636 --> 00:17:18,872 +或者 “嗨 扩展 使用其它的滤镜” + +256 +00:17:20,307 --> 00:17:22,342 +或者这个滤镜 + +257 +00:17:25,779 --> 00:17:27,281 +或者这个滤镜 + +258 +00:17:31,118 --> 00:17:34,321 +支持在扩展内运行硬件相机 + +259 +00:17:34,354 --> 00:17:37,357 +需要 MacOS Ventura + +260 +00:17:37,391 --> 00:17:42,863 +您还需要将 +com.apple.security.device.camera 键值 + +261 +00:17:42,896 --> 00:17:45,132 +添加到扩展的 entitlement 文件中 + +262 +00:17:45,165 --> 00:17:49,203 +以表明您将使用另一台相机 + +263 +00:17:49,236 --> 00:17:52,639 +由于您要使用相机 + +264 +00:17:52,673 --> 00:17:56,343 +系统会提示用户授予扩展的权限 + +265 +00:17:56,376 --> 00:18:00,380 +因此您必须在 Info.plist 中 +提供 NSCameraUsageDescription + +266 +00:18:01,715 --> 00:18:05,118 +这就完成了构建相机扩展的基础 + +267 +00:18:05,152 --> 00:18:07,855 +现在我们继续讨论 API + +268 +00:18:10,157 --> 00:18:13,493 +技术栈的底部是守护程序进程 + +269 +00:18:13,527 --> 00:18:17,264 +每个守护程序进程对应 +一个第一方或第三方相机扩展 + +270 +00:18:18,498 --> 00:18:22,870 +在相机 App 进程中 +有几个层在起作用 + +271 +00:18:22,903 --> 00:18:25,372 +首先是私有框架代码 + +272 +00:18:25,405 --> 00:18:29,343 +通过 IPC +与您的相机扩展对话 + +273 +00:18:29,376 --> 00:18:31,845 +再上一层是另一个私有层 + +274 +00:18:31,879 --> 00:18:35,082 +它将 CoreMedia IO 扩展 +调用转换为 + +275 +00:18:35,115 --> 00:18:37,518 +传统 DAL plug-in 调用 + +276 +00:18:38,819 --> 00:18:40,187 +再往上 + +277 +00:18:40,220 --> 00:18:45,692 +我们可以找到发布 DAL plug-ins 的 +公共 CoreMedia IO API + +278 +00:18:45,726 --> 00:18:48,462 +对于此接口的客户端来说 + +279 +00:18:48,495 --> 00:18:52,299 +CoreMedia IO 扩展 +和 DAL plug-ins 之间没有区别 + +280 +00:18:52,332 --> 00:18:55,435 +所有东西看起来 +都像是 DAL plug-in + +281 +00:18:55,469 --> 00:18:58,972 +最后 位于顶部的 +是 AVFoundation + +282 +00:18:59,006 --> 00:19:01,675 +它是 CoreMedia IO 的客户端 + +283 +00:19:01,708 --> 00:19:05,779 +它将 DAL plug-ins +重新发布为 AVCaptureDevices + +284 +00:19:07,848 --> 00:19:12,219 +与传统的 DAL plug-in 架构 +相比 + +285 +00:19:12,252 --> 00:19:16,290 +DAL plug-ins 可能包括 +也可能不包括守护进程 + +286 +00:19:16,323 --> 00:19:20,093 +但它们都直接在 +App 进程中运行 + +287 +00:19:20,127 --> 00:19:22,596 +由 CoreMedia IO 框架加载的代码 + +288 +00:19:22,629 --> 00:19:25,732 +这使得该 App 易受到 +恶意软件的攻击 + +289 +00:19:25,766 --> 00:19:30,838 +相机扩展完全消除了这种攻击媒介 + +290 +00:19:30,871 --> 00:19:35,843 +您的扩展必须经过沙盒 App 保护 +否则不允许运行 + +291 +00:19:36,877 --> 00:19:40,147 +Apple 的 RegisterAssistantService +通过它的 + +292 +00:19:40,180 --> 00:19:44,017 +CMIOExtensionMachServiceName +来识别 + +293 +00:19:44,051 --> 00:19:49,156 +并将其作为一个名为 _cmiodalassistors 的 +用户角色帐户启动 + +294 +00:19:50,057 --> 00:19:54,728 +Sandboxd 将自定义沙盒配置文件 +应用于您的进程中 + +295 +00:19:54,761 --> 00:19:57,431 +它是为相机使用量身定制的 + +296 +00:19:59,266 --> 00:20:02,669 +自定义沙盒配置文件允许您通过 + +297 +00:20:02,703 --> 00:20:06,006 +预期的通用硬件界面进行通信 + +298 +00:20:06,039 --> 00:20:10,744 +USB 蓝牙 WiFi + +299 +00:20:10,777 --> 00:20:15,148 +作为客户端而不是开放端口的服务器 + +300 +00:20:15,182 --> 00:20:17,518 +甚至 Firewire + +301 +00:20:17,551 --> 00:20:23,056 +它还允许您的扩展从自己的 +容器和 tmp 中读取和写入 + +302 +00:20:24,424 --> 00:20:29,563 +相机扩展沙盒配置文件 +比一般的 App 更加封闭 + +303 +00:20:29,596 --> 00:20:33,367 +例如 派生 执行或 POSIX 派生子进程 + +304 +00:20:33,400 --> 00:20:38,505 +访问 Windows 服务器 + +305 +00:20:38,539 --> 00:20:41,308 +连接到前台用户帐户 +或在全局命名空间中 + +306 +00:20:41,341 --> 00:20:44,811 +注册您自己的 MACH 服务 + +307 +00:20:44,845 --> 00:20:49,349 +这些事情都不被允许 + +308 +00:20:51,118 --> 00:20:54,955 +如果在开发扩展的过程中 +发现沙盒 + +309 +00:20:54,988 --> 00:20:57,491 +对于合法的拍摄案例来说限制太多 + +310 +00:20:57,524 --> 00:21:00,727 +请通过反馈助理向我们提供反馈 + +311 +00:21:00,761 --> 00:21:04,064 +我们会认真考虑放宽限制 + +312 +00:21:04,097 --> 00:21:06,333 +早期的架构图 + +313 +00:21:06,366 --> 00:21:08,836 +显示了相机扩展的守护进程 + +314 +00:21:08,869 --> 00:21:12,239 +它将缓冲区直接传递到应用层 + +315 +00:21:12,272 --> 00:21:15,175 +实际上还有一层安全措施 + +316 +00:21:17,044 --> 00:21:20,681 +在守护程序和 App 之间有一个 + +317 +00:21:20,714 --> 00:21:23,851 +名为 RegisterAsistantService 的 +代理服务 + +318 +00:21:23,884 --> 00:21:29,022 +其将强制执行透明 同意和控制策略 + +319 +00:21:29,056 --> 00:21:32,192 +当一款 App +第一次尝试使用相机时 + +320 +00:21:32,226 --> 00:21:35,062 +系统会询问用户是否可以使用 + +321 +00:21:35,095 --> 00:21:37,865 +所有的相机都要获得这种许可 + +322 +00:21:37,898 --> 00:21:40,000 +而不仅仅是内置相机 + +323 +00:21:40,033 --> 00:21:43,537 +代理服务代表您处理同意操作 + +324 +00:21:43,570 --> 00:21:46,039 +如果用户拒绝相机访问 + +325 +00:21:46,073 --> 00:21:50,043 +代理将停止将缓冲区传入该 App + +326 +00:21:50,077 --> 00:21:53,747 +它还将处理归因 让系统知道 + +327 +00:21:53,780 --> 00:21:57,551 +特定的 App 正在使用特定的相机 + +328 +00:21:57,584 --> 00:22:00,153 +因此守护进程消耗的电量 + +329 +00:22:00,187 --> 00:22:03,190 +可以归因于使用相机的 App + +330 +00:22:04,691 --> 00:22:08,495 +CoreMedia IO 扩展 +有四个主要类别 + +331 +00:22:08,529 --> 00:22:12,499 +提供商 设备和流 + +332 +00:22:13,534 --> 00:22:16,970 +提供商有设备 设备有流 + +333 +00:22:17,004 --> 00:22:20,374 +这三个设备都可以有属性 + +334 +00:22:22,843 --> 00:22:25,345 +您可以通过提供源来创建这三个主类 + +335 +00:22:25,379 --> 00:22:27,881 +它们分别是 + +336 +00:22:27,915 --> 00:22:33,187 +ProviderSource +DeviceSource 和 StreamSource + +337 +00:22:35,155 --> 00:22:39,026 +ExtensionProvider 是 +最低级别的对象 + +338 +00:22:39,059 --> 00:22:44,097 +允许您根据需要添加和删除设备 +例如热插拔事件 + +339 +00:22:45,599 --> 00:22:49,403 +当客户端进程尝试连接时 +它会得到通知 + +340 +00:22:49,436 --> 00:22:53,006 +从而使您有机会将设备发布限制到 + +341 +00:22:53,040 --> 00:22:54,875 +某些 App 上 + +342 +00:22:54,908 --> 00:22:59,580 +它还会向您的提供程序源对象 +查询属性实现 + +343 +00:23:01,882 --> 00:23:05,853 +下面是扩展的主要入口点 + +344 +00:23:05,886 --> 00:23:08,822 +您可以创建 +自己的 ExtensionProviderSource + +345 +00:23:08,856 --> 00:23:13,193 +符合 +CMIOExtensionProviderSource 协议 + +346 +00:23:13,227 --> 00:23:16,230 +并创建一个 ExtensionProvider + +347 +00:23:16,263 --> 00:23:19,499 +您需要调用提供者类方法以启动服务 + +348 +00:23:19,533 --> 00:23:23,003 +startService +并传递您的提供者实例 + +349 +00:23:25,038 --> 00:23:29,209 +ExtensionProvider 实现了 +两个只读属性 + +350 +00:23:29,243 --> 00:23:32,379 +这两个属性在扩展的生命周期内 +不会更改 + +351 +00:23:32,412 --> 00:23:36,283 +制造商和供应商名称 + +352 +00:23:36,316 --> 00:23:38,185 +这两个都是字符串 + +353 +00:23:40,087 --> 00:23:44,191 +接下来 +是 CMIOExtensionDevice + +354 +00:23:44,224 --> 00:23:48,762 +它可以管理数据流 +根据需要添加或删除它们 + +355 +00:23:48,795 --> 00:23:51,331 +您的设备可以呈现多个流 + +356 +00:23:51,365 --> 00:23:56,003 +但注意 AVFoundation 会忽略 +除第一个输入流之外的所有流 + +357 +00:23:57,237 --> 00:24:01,875 +创建设备时 您需要提供设备源 + +358 +00:24:01,909 --> 00:24:07,681 +本地化名称 UUID 形式的设备 ID + +359 +00:24:07,714 --> 00:24:11,518 +以及可选的 legacyID 字符串 + +360 +00:24:11,552 --> 00:24:14,988 +这些属性一直 +渗透到 AVFoundation + +361 +00:24:16,723 --> 00:24:19,726 +您的设备的 +LocalizedName 将成为 + +362 +00:24:19,760 --> 00:24:23,730 +AVCaptureDevice 的 +localizedName + +363 +00:24:23,764 --> 00:24:29,169 +除非您还 +提供了 legacyDeviceID + +364 +00:24:29,203 --> 00:24:34,608 +否则您指定的 deviceID 将成为 +AVCaptureDevice 的唯一标识符 + +365 +00:24:34,641 --> 00:24:38,278 +如果您正在更新 DAL plug-in + +366 +00:24:38,312 --> 00:24:40,647 +并且需要保持与以前发布的 +uniqueIdentifier 向后兼容性时 + +367 +00:24:40,681 --> 00:24:43,717 +才需要提供此功能 + +368 +00:24:44,751 --> 00:24:47,287 +如果您提供了 LegacyDeviceID + +369 +00:24:47,321 --> 00:24:50,891 +则 AVCaptureDevice +会将其用作唯一标识 + +370 +00:24:52,659 --> 00:24:59,066 +您可用 CMIOExtensionDeviceSource +创建 CMIOExtensionDevice + +371 +00:24:59,099 --> 00:25:01,969 +该 CMIOExtensionDeviceSource +可以选择性地实现其它属性 + +372 +00:25:02,002 --> 00:25:04,471 +如 deviceModel + +373 +00:25:04,505 --> 00:25:08,775 +这些属性对于同一型号的所有相机 +应该是相同的 + +374 +00:25:08,809 --> 00:25:12,379 +如果您的设备可以进入挂起状态 + +375 +00:25:12,412 --> 00:25:16,950 +例如如果有隐私虹膜 +则应实现 isSuspended + +376 +00:25:16,984 --> 00:25:20,621 +当翻盖合上时 +Apple 笔记本电脑上的内置相机 + +377 +00:25:20,654 --> 00:25:24,157 +进入暂停状态 + +378 +00:25:24,191 --> 00:25:27,961 +设备的传输类型显示其连接方式 + +379 +00:25:27,995 --> 00:25:32,332 +例如通过 USB 蓝牙或 Firewire + +380 +00:25:33,967 --> 00:25:37,838 +最后 如果您的相机 +与麦克风物理配对 + +381 +00:25:37,871 --> 00:25:40,908 +则可以将其作为链接设备公开 + +382 +00:25:40,941 --> 00:25:44,278 +所有这些属性都是只读的 + +383 +00:25:44,311 --> 00:25:48,715 +接下来是非常 +重要的 MIOExtensionStream + +384 +00:25:48,749 --> 00:25:52,819 +它在 CMIOExtension 中 +执行繁重的工作 + +385 +00:25:52,853 --> 00:25:58,058 +可以发布视频格式 +定义有效的帧率 + +386 +00:25:58,091 --> 00:26:01,461 +并配置激活的格式 + +387 +00:26:01,495 --> 00:26:04,965 +使用标准时钟 如主机时钟 + +388 +00:26:04,998 --> 00:26:07,534 +或提供自己的定制时钟 + +389 +00:26:07,568 --> 00:26:11,438 +来驱动其产生的每个缓冲区的计时 + +390 +00:26:11,471 --> 00:26:16,043 +最重要的是 +它可以向客户端发送缓冲区采样 + +391 +00:26:18,445 --> 00:26:21,381 +扩展流源 + +392 +00:26:21,415 --> 00:26:24,051 +发布 +CMIOExtensionStreamFormats + +393 +00:26:24,084 --> 00:26:28,488 +这些成为 +AVCaptureDeviceFormats + +394 +00:26:28,522 --> 00:26:31,758 +客户端可以读写活动格式索引 + +395 +00:26:31,792 --> 00:26:33,827 +以更改活动格式 + +396 +00:26:35,329 --> 00:26:39,633 +帧持续时间 相当于最大帧率 + +397 +00:26:39,666 --> 00:26:44,338 +最大帧持续时间 与最小帧率相同 + +398 +00:26:46,273 --> 00:26:51,912 +DAL plug-in 方式提供了 +名为 DAL 控制的第四个接口 + +399 +00:26:51,945 --> 00:26:55,949 +Plug-in 开发人员使用这些 +来展示诸如自动曝光 + +400 +00:26:55,983 --> 00:27:00,687 +亮度 清晰度 平移和缩放等功能 + +401 +00:27:00,721 --> 00:27:04,591 +虽然功能强大 +但它们的实现并不一致 + +402 +00:27:04,625 --> 00:27:08,195 +因此 App 开发人员很难使用它们 + +403 +00:27:08,228 --> 00:27:13,233 +在 CMIOExtension 架构中 +我们不提供 DAL 控制替代品 + +404 +00:27:13,267 --> 00:27:15,936 +相反 所有东西都是属性 + +405 +00:27:17,471 --> 00:27:21,074 +您已经了解了提供程序 + +406 +00:27:21,108 --> 00:27:23,577 +设备和流级别的许多标准属性 + +407 +00:27:23,610 --> 00:27:25,746 +您还可以创建自定义属性 + +408 +00:27:25,779 --> 00:27:30,784 +并将其传播到 App 层 就像我在 +CIFilterCam 演示中所做的那样 + +409 +00:27:32,019 --> 00:27:36,423 +CoreMedia IO 的 C 属性接口 +使用 C 结构 + +410 +00:27:36,456 --> 00:27:41,595 +来标识属性的选择符 作用域和元素 + +411 +00:27:41,628 --> 00:27:43,630 +这些都被视为其地址 + +412 +00:27:45,132 --> 00:27:49,169 +选择符是由四个字符组成的 +代码形式的属性名称 + +413 +00:27:49,203 --> 00:27:53,040 +例如 CUST 表示自定义 + +414 +00:27:53,073 --> 00:27:56,944 +作用域可以是全局的 +输入的或输出的 + +415 +00:27:56,977 --> 00:28:00,047 +元素可以是您想要的任何数字 + +416 +00:28:00,080 --> 00:28:03,383 +主元素始终为零 + +417 +00:28:03,417 --> 00:28:07,621 +CMIOExtensions 通过将属性地址元素 +编码到一个自定义属性名中 + +418 +00:28:07,654 --> 00:28:12,559 +将属性连接到旧世界 + +419 +00:28:12,593 --> 00:28:17,397 +首先 字符 4cc_ + +420 +00:28:17,431 --> 00:28:20,234 +然后是选择符 作用域和元素 + +421 +00:28:20,267 --> 00:28:24,037 +由下划线分隔的四字符代码 + +422 +00:28:24,071 --> 00:28:29,576 +使用此方法 您可以将任何字符串 +或数据值传递给 App 层 + +423 +00:28:30,644 --> 00:28:33,547 +AVFoundation 不能使用 +自定义属性 + +424 +00:28:33,580 --> 00:28:37,684 +因此如果您的配置 App 需要 +使用自定义属性 + +425 +00:28:37,718 --> 00:28:41,722 +则必须坚持 +使用 CoreMedia IO C API + +426 +00:28:41,755 --> 00:28:44,691 +这是我们对 API 的高级描述 + +427 +00:28:44,725 --> 00:28:47,761 +现在我们来谈谈输出设备 + +428 +00:28:49,329 --> 00:28:53,267 +DAL plug-ins 一个鲜为人知的功能 +是它们能够呈现相机的 + +429 +00:28:53,300 --> 00:28:56,737 +对立面 一种输出设备 + +430 +00:28:56,770 --> 00:29:01,675 +消费 App 实时产生的视频 +而不是提供视频 + +431 +00:29:01,708 --> 00:29:04,611 +这是 CoreMedia IO 中 +“O” 的部分 + +432 +00:29:04,645 --> 00:29:07,648 +输入和输出 + +433 +00:29:07,681 --> 00:29:11,451 +输出设备在专业视频领域很常见 + +434 +00:29:11,485 --> 00:29:16,023 +一些常见的用途是输出录影带 +将视频信号发送到 + +435 +00:29:16,056 --> 00:29:20,427 +外部录像机 或实时预览监控 + +436 +00:29:20,460 --> 00:29:23,730 +例如在带有 SDI 输入的 +专业面板上 + +437 +00:29:25,232 --> 00:29:28,502 +需要注意的一点是 + +438 +00:29:28,535 --> 00:29:31,672 +输出设备没有对应的 +AVFoundation API + +439 +00:29:31,705 --> 00:29:33,674 +要将帧发送到输出设备 + +440 +00:29:33,707 --> 00:29:38,011 +必须直接 +使用 CoreMedia IO C API + +441 +00:29:39,313 --> 00:29:43,283 +CMIOExtension 流 +是以源 + +442 +00:29:43,317 --> 00:29:47,254 +或接收器方向创建的 + +443 +00:29:47,287 --> 00:29:50,624 +Sink 流使用 +来自 App 的数据 + +444 +00:29:50,657 --> 00:29:56,296 +客户端通过将样本缓冲区 +插入到一个简单的队列产生 sink 流 + +445 +00:29:56,330 --> 00:30:01,235 +这将在您的扩展中转换成 +consumeSampleBuffer 调用 + +446 +00:30:01,268 --> 00:30:04,404 +一旦您使用了该缓冲区 就可 + +447 +00:30:04,438 --> 00:30:07,741 +通过 notifyScheduledOutputChanged +通知它们 + +448 +00:30:09,576 --> 00:30:13,847 +有一些专门针对输出设备的流属性 + +449 +00:30:13,881 --> 00:30:18,952 +它们主要处理队列大小 +启动前缓冲多少帧 + +450 +00:30:18,986 --> 00:30:22,055 +以及当所有数据都被消耗时 +发出信号 + +451 +00:30:23,557 --> 00:30:27,261 +现在进入我们今天的第五个 +也是最后一个话题 + +452 +00:30:28,929 --> 00:30:31,932 +在前面的演示中 我展示了 + +453 +00:30:31,965 --> 00:30:33,867 +DAL plug-in 架构的图表 + +454 +00:30:33,901 --> 00:30:36,937 +并强调了它的许多安全问题 + +455 +00:30:36,970 --> 00:30:40,140 +我们已经用相机扩展功能 +解决了这些缺点 + +456 +00:30:40,174 --> 00:30:43,243 +并完全致力于其持续发展 + +457 +00:30:43,277 --> 00:30:46,280 +它们是今后的路径 + +458 +00:30:46,313 --> 00:30:49,316 +那么这对 DAL plug-ins +意味着什么呢 + +459 +00:30:49,349 --> 00:30:51,552 +这意味着即将结束 + +460 +00:30:53,253 --> 00:30:58,358 +从 macOS 12.3 开始 +DAL 插件已经被弃用 + +461 +00:30:58,392 --> 00:31:01,395 +所以在构建时会收到编译警告 + +462 +00:31:01,428 --> 00:31:04,498 +这是个好的开始 但还不够 + +463 +00:31:04,531 --> 00:31:07,367 +只要允许加载传统的 DAL plug-ins + +464 +00:31:07,401 --> 00:31:09,937 +相机 App +仍然处于风险之中 + +465 +00:31:11,872 --> 00:31:15,175 +为了全面解决安全漏洞 + +466 +00:31:15,209 --> 00:31:20,581 +并使所有用户的系统更加强大 +我们计划在 macOS Ventura 之后的 + +467 +00:31:20,614 --> 00:31:24,117 +下一个主要版本中完全禁用 + +468 +00:31:26,320 --> 00:31:28,388 +这对您意味着什么 + +469 +00:31:28,422 --> 00:31:30,824 +我们希望这信息足够清晰了 + +470 +00:31:30,858 --> 00:31:33,060 +如果您目前维护的 +是 DAL plug-in + +471 +00:31:33,093 --> 00:31:37,297 +那么是时候将您的代码 +移植到相机扩展了 + +472 +00:31:38,398 --> 00:31:41,602 +另外 请告诉我们您遇到的问题 + +473 +00:31:41,635 --> 00:31:45,939 +我们希望能解决这些问题 +并提供丰富功能 + +474 +00:31:45,973 --> 00:31:48,509 +非常期待与您的合作 + +475 +00:31:48,542 --> 00:31:53,013 +今天关于 macOS +相机扩展的介绍就到这里 + +476 +00:31:53,046 --> 00:31:56,617 +我们迫不及待地想知道 +您会给 Mac 带来 + +477 +00:31:56,650 --> 00:31:58,085 +哪些新鲜而有创意的相机体验 + +478 +00:31:58,118 --> 00:32:00,954 +并希望您能享受这个过程 + diff --git a/zho/2022 Session 10023 What's new in the Photos picker.srt b/zho/2022 Session 10023 What's new in the Photos picker.srt new file mode 100644 index 0000000..d5d092d --- /dev/null +++ b/zho/2022 Session 10023 What's new in the Photos picker.srt @@ -0,0 +1,1122 @@ +1 +00:00:00,067 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,610 +♪ + +3 +00:00:09,610 --> 00:00:11,245 +大家好 我是 Justin + +4 +00:00:11,245 --> 00:00:13,280 +照片团队的工程师 + +5 +00:00:13,280 --> 00:00:15,983 +今天 我想介绍一些针对 + +6 +00:00:15,983 --> 00:00:18,619 +系统照片选择器做出的改进 + +7 +00:00:18,619 --> 00:00:21,388 +系统照片选择器 +是大多数 App 访问 + +8 +00:00:21,388 --> 00:00:24,224 +iOS 中照片和视频的最佳方式 + +9 +00:00:24,224 --> 00:00:26,960 +选择器在进程外独立运行 这样您的 App + +10 +00:00:26,960 --> 00:00:29,796 +无需请求任何 +库访问权限便可使用选择器 + +11 +00:00:29,796 --> 00:00:33,734 +它具有直观的 UI +和易于使用的 API + +12 +00:00:33,734 --> 00:00:36,670 +如果您不熟悉 PHPicker API + +13 +00:00:36,670 --> 00:00:39,840 +您可以观看我们 +往年的 WWDC 会议 + +14 +00:00:39,840 --> 00:00:43,343 +我们有详细的介绍 + +15 +00:00:43,343 --> 00:00:46,413 +今天 我将从在选择器中 + +16 +00:00:46,413 --> 00:00:50,083 +添加新功能的概览开始 + +17 +00:00:50,083 --> 00:00:53,353 +然后 我将介绍当前一些其他的 + +18 +00:00:53,353 --> 00:00:56,857 +选择器所支持的平台和框架 + +19 +00:00:56,857 --> 00:00:59,927 +那么 我们一起深入探讨吧 + +20 +00:00:59,927 --> 00:01:02,863 +一经推出 选择器便支持 + +21 +00:01:02,863 --> 00:01:06,333 +过滤图像、视频、和实况照片 + +22 +00:01:06,333 --> 00:01:08,669 +但是 我们了解到您的某些 App + +23 +00:01:08,669 --> 00:01:11,138 +可能有其他需求 + +24 +00:01:11,138 --> 00:01:13,974 +例如 一个屏幕截图拼接 App + +25 +00:01:13,974 --> 00:01:17,211 +只需要显示选择器中的屏幕截图 + +26 +00:01:17,211 --> 00:01:20,214 +当前可以使用今年新增的 + +27 +00:01:20,214 --> 00:01:23,584 +屏幕截图过滤器 + +28 +00:01:23,584 --> 00:01:27,588 +除了屏幕截图 +我们还添加了其他资产类型 + +29 +00:01:27,588 --> 00:01:31,725 +比如录屏和慢动作视频 + +30 +00:01:31,725 --> 00:01:34,027 +您还可以使用 +PHAsset.PlaybackStyle + +31 +00:01:34,027 --> 00:01:38,532 +创建新的过滤器 + +32 +00:01:38,532 --> 00:01:42,970 +除了电影视频、 +深度效果照片和连拍 + +33 +00:01:42,970 --> 00:01:45,706 +所有新过滤器都已向后移植 + +34 +00:01:45,706 --> 00:01:48,408 +如果您的 App +面向的是 iOS 15 + +35 +00:01:48,408 --> 00:01:50,878 +只要您使用 +iOS 16 SDK 进行编译 + +36 +00:01:50,878 --> 00:01:53,847 +该功能仍可继续使用 + +37 +00:01:53,847 --> 00:01:58,218 +对于复合过滤器来说 +除了现有的“any” + +38 +00:01:58,218 --> 00:02:00,954 +现在您也可以使用“all”和“not” + +39 +00:02:00,954 --> 00:02:04,358 +而且也已向后移植到 iOS 15 + +40 +00:02:04,358 --> 00:02:06,994 +我们一起看一些代码示例 + +41 +00:02:06,994 --> 00:02:12,299 +要显示视频和实况照片 +您可以将其与“any”结合 + +42 +00:02:12,299 --> 00:02:17,404 +或者您可能只想显示屏幕截图 + +43 +00:02:17,404 --> 00:02:20,140 +要显示除屏幕截图以外的所有图像 + +44 +00:02:20,140 --> 00:02:22,442 +您可以使用“all”和“not” + +45 +00:02:22,442 --> 00:02:25,612 +来结合图像和屏幕截图过滤器 + +46 +00:02:25,612 --> 00:02:29,149 +最后 如果您面向的是 iOS 16 + +47 +00:02:29,149 --> 00:02:32,286 +您可以使用 +.cinematicVideos 过滤器 + +48 +00:02:32,286 --> 00:02:35,122 +接下来 我将介绍与半高选择器 + +49 +00:02:35,122 --> 00:02:37,624 +有关的改进 + +50 +00:02:37,624 --> 00:02:41,995 +在 iOS 15 中 UIKit 具有新的 +UISheetPresentationController API + +51 +00:02:41,995 --> 00:02:47,301 +可用于以半高模式呈现选择器 + +52 +00:02:47,301 --> 00:02:50,637 +其在大多数情况下可良好运作 + +53 +00:02:50,637 --> 00:02:53,807 +但是有些人可能想要实现自定义 UI + +54 +00:02:53,807 --> 00:02:56,543 +以调整选定的资产并将这些更改 + +55 +00:02:56,543 --> 00:03:00,447 +反映回选择器中 + +56 +00:03:00,447 --> 00:03:03,650 +在 iOS 16 中 +您可以使用其资产标识符 + +57 +00:03:03,650 --> 00:03:07,321 +来取消选择资产 + +58 +00:03:07,321 --> 00:03:10,858 +如此处所示 +调用 deselectAssets 后 + +59 +00:03:10,858 --> 00:03:16,697 +选择器已取消第二张照片的选择 + +60 +00:03:16,697 --> 00:03:21,568 +您还可以调用 moveAsset 方法 +对资产进行重新排序 + +61 +00:03:21,568 --> 00:03:24,705 +现在我们熟悉了 +所有新的选择器功能 + +62 +00:03:24,705 --> 00:03:27,574 +我将介绍平台支持 + +63 +00:03:27,574 --> 00:03:30,577 +目前 系统照片选择器只能 + +64 +00:03:30,577 --> 00:03:33,814 +由 iOS 和 iPadOS App 使用 + +65 +00:03:33,814 --> 00:03:35,983 +今年 我们把照片选择器 + +66 +00:03:35,983 --> 00:03:41,154 +引入到了其他两个平台 +分别是 macOS 和 watchOS + +67 +00:03:41,154 --> 00:03:44,157 +iPadOS 选择器也更新了设计 + +68 +00:03:44,157 --> 00:03:46,493 +但这一新的设计仅适用于 iPad + +69 +00:03:46,493 --> 00:03:49,696 +我们先来看看新的 iPad UI + +70 +00:03:49,696 --> 00:03:51,398 +选择器现在显示了侧边栏 + +71 +00:03:51,398 --> 00:03:55,202 +以利用更大的 iPad 显示屏 + +72 +00:03:55,202 --> 00:03:57,070 +侧边栏使不同收藏夹之间的 + +73 +00:03:57,070 --> 00:03:59,239 +导航更加快捷 + +74 +00:03:59,239 --> 00:04:01,275 +但是如果没有足够的空间 + +75 +00:04:01,275 --> 00:04:03,677 +就像在分屏模式下一样 + +76 +00:04:03,677 --> 00:04:08,215 +我们将回退到 +现有的紧凑型选择器 UI + +77 +00:04:08,215 --> 00:04:11,718 +接下来是 macOS + +78 +00:04:11,718 --> 00:04:16,056 +macOS 选择器还具有 +Mac 风格控件的侧边栏 + +79 +00:04:16,056 --> 00:04:20,527 +和 iOS 选择器一样 支持多选 + +80 +00:04:20,527 --> 00:04:23,931 +网格中的流体缩放 +并具有强大的搜索功能 + +81 +00:04:23,931 --> 00:04:27,434 +允许您搜索诸如人物、地点、 + +82 +00:04:27,434 --> 00:04:30,070 +等等分类 + +83 +00:04:30,070 --> 00:04:34,408 +新的选择器 UI +也应用到了 NSOpenPanel 中 + +84 +00:04:34,408 --> 00:04:38,278 +您可以用其选择系统照片库中的资产 + +85 +00:04:38,278 --> 00:04:39,847 +并且首次支持 + +86 +00:04:39,847 --> 00:04:43,617 +选择存储在 +iCloud Photos 中的资产 + +87 +00:04:43,617 --> 00:04:46,086 +您的 App 将免费获得新的 UI + +88 +00:04:46,086 --> 00:04:49,857 +而无需采取任何适配操作 + +89 +00:04:49,857 --> 00:04:54,228 +NSOpenPanel 选择器支持拖放 + +90 +00:04:54,228 --> 00:04:57,164 +iOS、iPadOS 和 macOS +上的标准选择器 + +91 +00:04:57,164 --> 00:05:00,734 +也支持该操作 + +92 +00:05:00,734 --> 00:05:04,838 +如果您的 App 只需要 +选择几张图片或几个视频 + +93 +00:05:04,838 --> 00:05:08,742 +NSOpenPanel API +将满足您的需求 + +94 +00:05:08,742 --> 00:05:11,245 +但请记住 照片库中所选的文件 + +95 +00:05:11,245 --> 00:05:15,115 +可能随时被系统删除 + +96 +00:05:15,115 --> 00:05:18,118 +如果您需要确保其长期可用性 + +97 +00:05:18,118 --> 00:05:23,557 +您应该将其复制到 +由您的 App 管理的位置 + +98 +00:05:23,557 --> 00:05:28,095 +对于以媒体为中心的 macOS App +我们建议您默认为 + +99 +00:05:28,095 --> 00:05:32,699 +新的照片选择器 +以获得最佳用户体验 + +100 +00:05:32,699 --> 00:05:37,237 +但是 您的 App 仍应 +提供一种可替代方式 + +101 +00:05:37,237 --> 00:05:39,573 +来使用 NSOpenPanel API + +102 +00:05:39,573 --> 00:05:42,843 +从文件系统中选择资产 + +103 +00:05:42,843 --> 00:05:46,480 +有时您的用户可能仍想在照片库外 + +104 +00:05:46,480 --> 00:05:50,984 +选择资产 + +105 +00:05:50,984 --> 00:05:55,522 +最后 我将介绍 watchOS + +106 +00:05:55,522 --> 00:05:58,192 +首次 您能够访问存储于 + +107 +00:05:58,192 --> 00:06:01,562 +使用全新 API 手表里的图像 + +108 +00:06:01,562 --> 00:06:04,264 +watchOS 选择器也会用完进程 + +109 +00:06:04,264 --> 00:06:06,934 +和 iOS 和 macOS 选择器一样 + +110 +00:06:06,934 --> 00:06:10,771 +因此您无需请求任何 +库访问权限即可使用 + +111 +00:06:10,771 --> 00:06:13,373 +其 UI 类似于 iOS 选择器 + +112 +00:06:13,373 --> 00:06:17,177 +但针对较小的屏幕进行了优化 + +113 +00:06:17,177 --> 00:06:21,682 +您可以在网格中或 +按收藏夹浏览您的照片 + +114 +00:06:21,682 --> 00:06:24,785 +您可以配置选择器以显示选择顺序 + +115 +00:06:24,785 --> 00:06:29,356 +以及指定选择限制 + +116 +00:06:29,356 --> 00:06:32,626 +但是 与 iOS +和 macOS 不同的是 + +117 +00:06:32,626 --> 00:06:36,697 +只有图像会显示 +在 watchOS 选择器中 + +118 +00:06:36,697 --> 00:06:39,733 +如果设备存储的照片超过 500 张 + +119 +00:06:39,733 --> 00:06:43,370 +将只显示最近的 500 帐图像 + +120 +00:06:43,370 --> 00:06:45,005 +您可能想知道 + +121 +00:06:45,005 --> 00:06:48,041 +“PHPickerViewController +是基于 UIKit 的 + +122 +00:06:48,041 --> 00:06:52,546 +那么如何将其用于我的 +macOS 或 watchOS App 中?” + +123 +00:06:52,546 --> 00:06:54,548 +您可能已经猜到了 + +124 +00:06:54,548 --> 00:07:00,687 +AppKit 和 SwiftUI +目前提供了新的选择器 API + +125 +00:07:00,687 --> 00:07:03,690 +我们先来看看 AppKit API + +126 +00:07:03,690 --> 00:07:07,961 +实际上 +其与 UIKit API 十分相似 + +127 +00:07:07,961 --> 00:07:11,265 +您有权限访问相同的 +PHPickerConfiguration 类型 + +128 +00:07:11,265 --> 00:07:13,767 +及其属性 + +129 +00:07:13,767 --> 00:07:16,336 +只有一个很小的区别: + +130 +00:07:16,336 --> 00:07:19,706 +PHPickerViewController +是一个适用于 AppKit App 的 + +131 +00:07:19,706 --> 00:07:23,710 +NSViewController 子类 + +132 +00:07:23,710 --> 00:07:27,481 +随着基于 +AppKit 的 PHPicker 的引入 + +133 +00:07:27,481 --> 00:07:31,785 +是时候舍弃传统的媒体库浏览器了 + +134 +00:07:31,785 --> 00:07:35,122 +PHPicker 要强大得多 + +135 +00:07:35,122 --> 00:07:38,158 +如果您正同时打造 +UIKit 和 AppKit App + +136 +00:07:38,158 --> 00:07:43,730 +PHPicker 也更加容易维护 + +137 +00:07:43,730 --> 00:07:47,734 +最后 我将介绍 SwiftUI API + +138 +00:07:49,970 --> 00:07:53,540 +还记得您在本视频开始时 +看到的 iOS 选择器吗? + +139 +00:07:53,540 --> 00:07:58,045 +只需几行 SwiftUI 代码 +即可将其呈现 + +140 +00:07:58,045 --> 00:08:00,514 +更重要的是 您有权访问 + +141 +00:08:00,514 --> 00:08:03,016 +所有支持选择器的平台上的 + +142 +00:08:03,016 --> 00:08:06,220 +SwiftUI PhotosPicker API + +143 +00:08:06,220 --> 00:08:10,958 +iOS、iPadOS +macOS 和 watchOS + +144 +00:08:10,958 --> 00:08:13,694 +选择器将根据平台 + +145 +00:08:13,694 --> 00:08:17,297 +您 App 的配置 +和可用的屏幕空间 + +146 +00:08:17,297 --> 00:08:20,133 +自动选择最佳布局 + +147 +00:08:20,133 --> 00:08:23,070 +您无需为选择器 UI 绞尽脑汁 + +148 +00:08:23,070 --> 00:08:26,640 +这样您可以更加专注于 +将您的 App 打造得更加完善 + +149 +00:08:29,409 --> 00:08:32,980 +在我们通过演示 +详细了解新 API 之前 + +150 +00:08:32,980 --> 00:08:34,481 +我将先介绍如何加载 + +151 +00:08:34,481 --> 00:08:38,318 +已选择的照片和视频 + +152 +00:08:38,318 --> 00:08:42,055 +您通过 SwiftUI 绑定收到的选择 + +153 +00:08:42,055 --> 00:08:45,459 +只包含占位符对象 + +154 +00:08:45,459 --> 00:08:50,030 +您仍然需要按需加载实际资产数据 + +155 +00:08:50,030 --> 00:08:51,932 +请记住 某些资产数据 + +156 +00:08:51,932 --> 00:08:54,635 +不会立即加载 + +157 +00:08:54,635 --> 00:08:56,837 +如果遇到错误 + +158 +00:08:56,837 --> 00:08:58,939 +加载操作也可能失败 + +159 +00:08:58,939 --> 00:09:02,075 +例如 选择器 +尝试从 iCloud Photos + +160 +00:09:02,075 --> 00:09:05,512 +下载数据 但设备未连接 + +161 +00:09:05,512 --> 00:09:08,015 +到互联网 + +162 +00:09:08,015 --> 00:09:12,486 +一些像视频这样的大文件 +可能需要很长时间才能下载 + +163 +00:09:12,486 --> 00:09:16,456 +所以我们建议您显示 +每个项目的内联加载 UI + +164 +00:09:16,456 --> 00:09:21,061 +而替换掉阻塞加载指示器 + +165 +00:09:21,061 --> 00:09:23,564 +PhotosPicker +使用 Transferable + +166 +00:09:23,564 --> 00:09:26,767 +这是一种用于 +在 App 和扩展程序之间 + +167 +00:09:26,767 --> 00:09:29,903 +传输数据的新 SwiftUI 协议 + +168 +00:09:29,903 --> 00:09:33,507 +您可以直接通过 +Transferable 加载 SwiftUI Image + +169 +00:09:33,507 --> 00:09:35,809 +但对于高级用例 + +170 +00:09:35,809 --> 00:09:37,845 +您应该定义符合 +Transferable 协议的 + +171 +00:09:37,845 --> 00:09:40,280 +自己的模型对象 + +172 +00:09:40,280 --> 00:09:44,918 +以完全控制要加载的数据类型 + +173 +00:09:44,918 --> 00:09:47,688 +有关 Transferable 的更多信息 + +174 +00:09:47,688 --> 00:09:50,891 +您可以查看 +“Meet Transferable”一期 + +175 +00:09:50,891 --> 00:09:54,862 +如果您的 App 需要 +同时处理很多项目 + +176 +00:09:54,862 --> 00:09:57,531 +或类似视频等大型资产 + +177 +00:09:57,531 --> 00:10:00,634 +将所有内容同时加载到内存中 + +178 +00:10:00,634 --> 00:10:03,170 +或许不可行 + +179 +00:10:03,170 --> 00:10:08,008 +为了减少内存使用 您可以使用 +FileTransferRepresentation + +180 +00:10:08,008 --> 00:10:11,712 +将选定的资产加载为文件 + +181 +00:10:11,712 --> 00:10:13,647 +当将资产作为文件加载时 + +182 +00:10:13,647 --> 00:10:16,216 +请记住 您的 App 将负责 + +183 +00:10:16,216 --> 00:10:19,219 +管理这些资产的生命周期 + +184 +00:10:19,219 --> 00:10:21,822 +文件在收到时应始终 + +185 +00:10:21,822 --> 00:10:27,227 +复制到您的 App 目录 +并在不需要时将其删除 + +186 +00:10:27,227 --> 00:10:30,163 +现在我要开始演示了! + +187 +00:10:30,163 --> 00:10:31,932 +我已经将此演示 App + +188 +00:10:31,932 --> 00:10:34,635 +设置为显示帐户个人资料页面 + +189 +00:10:34,635 --> 00:10:39,206 +现在 个人资料图像 +只是一个占位符图标 + +190 +00:10:39,206 --> 00:10:42,676 +我们想使用 +PhotosPicker API 添加一个编辑按钮 + +191 +00:10:42,676 --> 00:10:45,012 +来更改个人资料图像 + +192 +00:10:45,012 --> 00:10:47,014 +个人资料图像视图已经可以响应 + +193 +00:10:47,014 --> 00:10:50,384 +我们视图模型中定义的图像状态 + +194 +00:10:50,384 --> 00:10:52,719 +所以我们只需在收到选择器选择时 + +195 +00:10:52,719 --> 00:10:56,190 +更新图像状态 + +196 +00:10:56,190 --> 00:10:58,592 +首先 我们进入我们的视图模型 + +197 +00:10:58,592 --> 00:11:01,495 +并添加一个新的 +imageSelection 属性 + +198 +00:11:01,495 --> 00:11:04,031 +其将作为选择绑定 + +199 +00:11:04,031 --> 00:11:07,301 +传递给 PhotosPicker API + +200 +00:11:07,301 --> 00:11:10,938 +现在我们可以回到 +我们的个人资料图像视图 + +201 +00:11:10,938 --> 00:11:14,341 +并添加一个启动选择器的覆盖按钮 + +202 +00:11:19,213 --> 00:11:22,683 +好了 我们暂停一下 并查看一下 + +203 +00:11:22,683 --> 00:11:24,384 +我们刚刚添加的代码 + +204 +00:11:24,384 --> 00:11:26,086 +我们添加了一个 +PhotosPicker 视图 + +205 +00:11:26,086 --> 00:11:29,289 +向其传递了我们 +刚刚定义的选择绑定 + +206 +00:11:29,289 --> 00:11:33,060 +并将其配置为仅显示图像 + +207 +00:11:33,060 --> 00:11:34,294 +PhotosPicker 的标签 + +208 +00:11:34,294 --> 00:11:39,099 +是一个带有圆形背景的 +铅笔标志符号 + +209 +00:11:39,099 --> 00:11:42,336 +我们可以生成并运行 +以查看我们目前所有的操作 + +210 +00:11:42,336 --> 00:11:46,006 +可以点击编辑按钮来启动选择器 + +211 +00:11:46,006 --> 00:11:49,910 +点击图像会自动关闭选择器 + +212 +00:11:49,910 --> 00:11:52,513 +但不会更新个人资料图像 + +213 +00:11:52,513 --> 00:11:53,714 +为什么? + +214 +00:11:53,714 --> 00:11:55,816 +我们还需要连接图片选择 + +215 +00:11:55,816 --> 00:11:57,351 +和图像状态 + +216 +00:11:57,351 --> 00:11:59,453 +所以 我们开始连接吧 + +217 +00:11:59,453 --> 00:12:01,054 +我们可以回到视图模型 + +218 +00:12:01,054 --> 00:12:04,625 +并响应已设置的图像选择 + +219 +00:12:04,625 --> 00:12:08,695 +如果图像选择数为零 +我们将图像状态设置为 empty + +220 +00:12:08,695 --> 00:12:12,533 +否则 开始加载图像 + +221 +00:12:12,533 --> 00:12:15,536 +可以看到发生了一个编译器错误 +因为我们还没有实现 + +222 +00:12:15,536 --> 00:12:17,871 +loadTransferable 方法 + +223 +00:12:17,871 --> 00:12:19,473 +接下来 将其修复 + +224 +00:12:23,043 --> 00:12:25,646 +实现过程非常简单 + +225 +00:12:25,646 --> 00:12:28,248 +我们只需要响应完成处理程序 + +226 +00:12:28,248 --> 00:12:29,917 +并更新图像状态 + +227 +00:12:29,917 --> 00:12:34,221 +前提是请求仍是最新请求 + +228 +00:12:34,221 --> 00:12:37,791 +我们生成并运行 +以查看它的运行情况 + +229 +00:12:37,791 --> 00:12:43,230 +我可以点击 +编辑按钮并选择一个图像 + +230 +00:12:43,230 --> 00:12:46,900 +非常好!运行符合预期 + +231 +00:12:46,900 --> 00:12:52,339 +实际上 该项目也已设置为 +可在 macOS 上运行 + +232 +00:12:52,339 --> 00:12:56,210 +我刚刚添加的代码 +会自动在 macOS 上运行吗? + +233 +00:12:56,210 --> 00:12:59,446 +我们生成并运行以找出答案 + +234 +00:12:59,446 --> 00:13:01,014 +可以编译! + +235 +00:13:01,014 --> 00:13:04,151 +我可以打开选择器 选择一张图像 + +236 +00:13:04,151 --> 00:13:07,955 +图像可以显示在 App 中 + +237 +00:13:07,955 --> 00:13:09,990 +这就是所有的演示了 + +238 +00:13:09,990 --> 00:13:13,227 +您刚刚看到了在 +iOS 和 macOS 上的演示 + +239 +00:13:13,227 --> 00:13:17,030 +其实相同的代码 +也可以在 watchOS 上运行 + +240 +00:13:17,030 --> 00:13:20,434 +但是 有几件事要记住 + +241 +00:13:23,270 --> 00:13:25,806 +watchOS 选择器 +专为简单的流程 + +242 +00:13:25,806 --> 00:13:28,275 +和短暂的互动而设计 + +243 +00:13:28,275 --> 00:13:31,778 +图像根据设备尺寸进行缩放 + +244 +00:13:31,778 --> 00:13:36,617 +通常 图像将与 +已配对的 iPhone 同步 + +245 +00:13:36,617 --> 00:13:39,987 +但是 家庭设置可以让没有 + +246 +00:13:39,987 --> 00:13:41,488 +iPhone 的家庭成员 + +247 +00:13:41,488 --> 00:13:46,093 +享受 Apple Watch 的 +功能和优势 + +248 +00:13:46,093 --> 00:13:49,229 +如果设备处于家庭设置模式 + +249 +00:13:49,229 --> 00:13:52,900 +可以使用选择器 +选择 iCloud 照片中 + +250 +00:13:52,900 --> 00:13:55,302 +最近的 1000 张图像 + +251 +00:13:55,302 --> 00:13:59,439 +选择器可能需要 +从互联网中下载一些图像 + +252 +00:13:59,439 --> 00:14:01,208 +如果这样的话 + +253 +00:14:01,208 --> 00:14:04,878 +关闭之前 选择器中将显示加载 UI + +254 +00:14:06,747 --> 00:14:08,715 +本期结束之前 我想对您说 + +255 +00:14:08,715 --> 00:14:11,351 +我们致力于使系统照片选择器 + +256 +00:14:11,351 --> 00:14:15,489 +成为大多数 App 访问 +照片和视频的最佳方式 + +257 +00:14:15,489 --> 00:14:17,591 +如果您仍在使用自定义选择器 + +258 +00:14:17,591 --> 00:14:20,327 +我们真的鼓励您 +换用系统照片选择器 + +259 +00:14:20,327 --> 00:14:23,397 +谢谢 祝您在 WWDC 愉快! + +260 +00:14:23,397 --> 00:14:27,534 +♪ + diff --git a/zho/2022 Session 10024 What's new in Vision.srt b/zho/2022 Session 10024 What's new in Vision.srt new file mode 100644 index 0000000..72287ee --- /dev/null +++ b/zho/2022 Session 10024 What's new in Vision.srt @@ -0,0 +1,1546 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,676 --> 00:00:11,645 +Brett Keating: +大家好 我叫 Brett Keating + +3 +00:00:11,678 --> 00:00:15,549 +很高兴为您介绍 +Vision 框架中的新内容 + +4 +00:00:15,582 --> 00:00:17,551 +您可能刚接触 Vision + +5 +00:00:17,584 --> 00:00:21,388 +也许这是您首次参加 +有关 Vision 框架的讲座 + +6 +00:00:21,421 --> 00:00:23,991 +如果是这样的话 诚挚欢迎 + +7 +00:00:24,024 --> 00:00:28,862 +我们先简要回顾下 +Vision 框架的亮点 + +8 +00:00:28,896 --> 00:00:31,665 +以下是关于 +Vision 框架的一些信息 + +9 +00:00:31,698 --> 00:00:34,434 +Vision 于 2017 年首次推出 + +10 +00:00:34,468 --> 00:00:37,871 +从那时起 人们就使用 +Vision 提供的技术 + +11 +00:00:37,905 --> 00:00:40,841 +开发出了无数好用的 App + +12 +00:00:40,874 --> 00:00:43,510 +Vision 是 +计算机视界算法的集合 + +13 +00:00:43,544 --> 00:00:45,646 +可随着时间的推移持续增长 + +14 +00:00:45,679 --> 00:00:47,781 +包括人脸检测 图像分类 + +15 +00:00:47,814 --> 00:00:52,019 +和轮廓定位 诸如此类 + +16 +00:00:52,052 --> 00:00:56,490 +所以这些算法中都可以 +通过简便 统一的 API 来实现 + +17 +00:00:56,523 --> 00:00:58,926 +如果您知道如何在 Vision 框架中 +运行一种算法 + +18 +00:00:58,959 --> 00:01:01,061 +就知道如何运行全部算法 + +19 +00:01:01,094 --> 00:01:04,698 +Vision 在它支持的所有平台上 + +20 +00:01:04,731 --> 00:01:06,934 +充分利用 Apple 芯片的优势 + +21 +00:01:06,967 --> 00:01:10,771 +在 Vision 的许多核心算法中 +加强了机器学习能力 + +22 +00:01:10,804 --> 00:01:13,473 +Vision 适用于 tvOS + +23 +00:01:13,507 --> 00:01:15,709 +iOS 和 macOS + +24 +00:01:15,742 --> 00:01:19,179 +并将在 Mac 上充分利用 +Apple 芯片的优势 + +25 +00:01:20,113 --> 00:01:23,884 +这里将展示关于 Vision 框架的 +一些最新补充 + +26 +00:01:23,917 --> 00:01:25,252 +包括 Person Segmentation + +27 +00:01:27,287 --> 00:01:31,358 +还有手势估计也会有相关的演示 + +28 +00:01:34,761 --> 00:01:37,631 +这是我们的 Action +和 Vision 示范 App + +29 +00:01:37,664 --> 00:01:41,134 +它使用的是人体姿势估计 +和轨迹分析 + +30 +00:01:42,069 --> 00:01:46,306 +我们先以一些新的修订 +来开始今天的议程 + +31 +00:01:46,340 --> 00:01:49,176 +即对现有请求的更新 + +32 +00:01:49,209 --> 00:01:54,081 +可能会提供更多的功能 +提高性能或提高准确性 + +33 +00:01:57,150 --> 00:02:00,454 +首先 我们有一个新的修订版 +用于文本识别 + +34 +00:02:00,487 --> 00:02:06,527 +这是 VNRecognizeTextRequestRevision3 +提供的第三次修订版 + +35 +00:02:06,560 --> 00:02:10,464 +这是文本识别器 +有强大的实时文本功能 + +36 +00:02:10,497 --> 00:02:13,333 +文本识别器支持多种语言 + +37 +00:02:13,367 --> 00:02:15,969 +您可以 +使用 supportedRecognitionLanguages + +38 +00:02:16,003 --> 00:02:19,173 +查看目前支持的语种 + +39 +00:02:19,206 --> 00:02:23,443 +我们现在添加了一些新的语种 +可以看下以下的例子 + +40 +00:02:23,477 --> 00:02:27,247 +现在 Vision 中支持韩语 + +41 +00:02:27,281 --> 00:02:31,618 +这是用 Vison 提取 +韩语收据的例子 + +42 +00:02:31,652 --> 00:02:35,255 +这是一个对应的日语示例 + +43 +00:02:35,289 --> 00:02:38,058 +在当前支持语种中 + +44 +00:02:38,091 --> 00:02:40,961 +也显示了 Vision 的 +文本识别结果 + +45 +00:02:40,994 --> 00:02:46,767 +文本识别方面 我们有 +一种全新的自动语言识别功能 + +46 +00:02:46,800 --> 00:02:50,170 +您仍然可以使用 +recognitionLanguages 属性 + +47 +00:02:50,204 --> 00:02:53,740 +指定要使用的识别语言 + +48 +00:02:53,774 --> 00:02:56,577 +但是要假设您之前并不知道 + +49 +00:02:56,610 --> 00:02:59,913 +您的 App 用户可能会 +尝试识别哪种语言 + +50 +00:02:59,947 --> 00:03:03,417 +现在 仅对于准确的识别模式 + +51 +00:03:03,450 --> 00:03:07,955 +您可能会通过将 automaticallyDetectsLanguage的 +值设为 true + +52 +00:03:07,988 --> 00:03:11,091 +让文本识别器自动检测语言 + +53 +00:03:12,759 --> 00:03:15,562 +在您不知道识别哪种语言的情况下 + +54 +00:03:15,596 --> 00:03:18,398 +最好使用这种方法 + +55 +00:03:18,432 --> 00:03:21,702 +因为语言检测偶尔会出错 + +56 +00:03:21,735 --> 00:03:25,038 +如果您已经提前知道了识别哪种语言 + +57 +00:03:25,072 --> 00:03:27,975 +最好还是向 Vision +指定这些语言 + +58 +00:03:28,008 --> 00:03:31,612 +并关闭 +automaticallyDetectsLanguage + +59 +00:03:34,681 --> 00:03:39,119 +接下来 我们来看下用于 +条码检测的第三次修订 + +60 +00:03:39,152 --> 00:03:43,123 +名为 +VNDetectBarcodesRequestRevision3 + +61 +00:03:43,156 --> 00:03:46,360 +本次修订利用了 +现代机器的后台学习能力 + +62 +00:03:46,393 --> 00:03:49,162 +这与之前的修订不同 + +63 +00:03:49,196 --> 00:03:51,431 +条码有多种符号 + +64 +00:03:51,465 --> 00:03:55,769 +包括商店产品上常见的条形码 +二维码 + +65 +00:03:55,802 --> 00:03:59,239 +用于医疗保健的专业代码 + +66 +00:03:59,273 --> 00:04:01,775 +为了了解 Vision 支持哪些符号 + +67 +00:04:01,808 --> 00:04:03,977 +您可以 +调用 supportedSymbologies + +68 +00:04:06,113 --> 00:04:08,582 +接下来 我们谈谈性能 + +69 +00:04:08,615 --> 00:04:10,617 +一部分是因为我们使用的是 +机器学习 + +70 +00:04:10,651 --> 00:04:15,222 +可一次检测多个代码时 +而不是一次一个 + +71 +00:04:15,255 --> 00:04:20,160 +所以图像包含多个代码的 +请求会更快一些 + +72 +00:04:20,194 --> 00:04:25,465 +此外 由于提高了准确性 + +73 +00:04:25,499 --> 00:04:27,167 +且极少重复检测 + +74 +00:04:27,201 --> 00:04:31,538 +在包含许多代码的给定图像中 +可以检测更多代码 + +75 +00:04:31,572 --> 00:04:34,441 +针对一些代码 边界框做了改进 + +76 +00:04:34,474 --> 00:04:39,780 +特别是线性代码 例如 ean13 +之前是返回了一行 + +77 +00:04:39,813 --> 00:04:42,850 +现在 边界框包围了 +整个可见代码 + +78 +00:04:45,018 --> 00:04:49,022 +最后 机器学习模型可以忽略弧面 + +79 +00:04:49,056 --> 00:04:53,393 +反射以及其它曾经 +影响检测准确性的东西 + +80 +00:04:56,797 --> 00:04:59,733 +这两个新修订版可用于文本识别 + +81 +00:04:59,766 --> 00:05:03,504 +条形码检测 +为插入式 UI 元素的 + +82 +00:05:03,537 --> 00:05:08,075 +VisionKit 数据扫描器 API +搭建技术基础 + +83 +00:05:08,108 --> 00:05:11,879 +可以设置相机流 +扫描并返回条形码和文本 + +84 +00:05:11,912 --> 00:05:14,948 +这对我们的 SDK 来说 +是一个神级补充 + +85 +00:05:14,982 --> 00:05:19,119 +我强烈建议您查看 +有关的讲座以了解更多信息 + +86 +00:05:19,152 --> 00:05:22,956 +今天我要告诉您的 +最后的一个全新修订版 + +87 +00:05:22,990 --> 00:05:25,626 +是一个光流请求的新版本 + +88 +00:05:25,659 --> 00:05:29,363 +名为 +VNGenerateOpticalFlowRequestRevision2 + +89 +00:05:29,396 --> 00:05:32,900 +和条码检测器一样 +这个新版本也利用了 + +90 +00:05:32,933 --> 00:05:35,102 +现代机器的后台学习能力 + +91 +00:05:37,471 --> 00:05:41,508 +虽然光流法是一个 +研究时间最长的计算机视觉问题 + +92 +00:05:41,542 --> 00:05:44,444 +与构成我们日常生活一部分的 +文字和条形码检测相比 + +93 +00:05:44,478 --> 00:05:47,981 +您可能对它的作用不太了解 + +94 +00:05:48,849 --> 00:05:52,452 +光流分析两个连续的图像 + +95 +00:05:52,486 --> 00:05:54,621 +通常来自视频的帧 + +96 +00:05:54,655 --> 00:05:56,590 +根据您的使用场景 可能会看到 + +97 +00:05:56,623 --> 00:06:00,027 +两个相邻的帧之间的动作 +或在其间跳过几帧 + +98 +00:06:00,060 --> 00:06:02,996 +但无论如何 这两个图像 +应该按时间顺序排列 + +99 +00:06:04,831 --> 00:06:09,303 +该分析提供了一个 +运动的方向和幅度的估计 + +100 +00:06:09,336 --> 00:06:13,774 +或第一张图像有多少部分需要 +“move (移动)” + +101 +00:06:13,807 --> 00:06:17,544 +才能在第二张图像中正确定位 + +102 +00:06:17,578 --> 00:06:20,480 +结果是 VNPixelBufferObservation + +103 +00:06:20,514 --> 00:06:23,684 +这代表这个动作 +在图像中的所有位置 + +104 +00:06:23,717 --> 00:06:25,485 +这是一个双通道图像 + +105 +00:06:25,519 --> 00:06:28,021 +一个通道包含 X 幅度 + +106 +00:06:28,055 --> 00:06:30,791 +另一个包含 Y 幅度 + +107 +00:06:30,824 --> 00:06:34,094 +这些合起来在每个像素上 +形成二维向量 + +108 +00:06:34,127 --> 00:06:37,064 +排列在这个 2D 图像中 +以便他们的位置 + +109 +00:06:37,097 --> 00:06:41,134 +映射到图像中的相应位置 +作为输入 + +110 +00:06:41,168 --> 00:06:43,470 +我们从这个视角看一下 + +111 +00:06:43,504 --> 00:06:47,541 +假设有一个传入的视频 +并且有几帧画面传进来 + +112 +00:06:47,574 --> 00:06:50,210 +我们特别关注一下这两个图像 + +113 +00:06:50,244 --> 00:06:52,479 +在这里 有一只狗在沙滩上奔跑 + +114 +00:06:52,513 --> 00:06:54,248 +从左图到右图 + +115 +00:06:54,281 --> 00:06:57,017 +似乎这只狗已经向左移动了一点 + +116 +00:06:57,050 --> 00:06:59,419 +您会如何估算并表现这个移动 + +117 +00:07:01,255 --> 00:07:03,323 +对 您会运行光流法 + +118 +00:07:03,357 --> 00:07:05,926 +然后得到类似于下图的图像 + +119 +00:07:05,959 --> 00:07:08,562 +较暗的区域是发现移动的地方 + +120 +00:07:08,595 --> 00:07:12,566 +它确实看起来像狗的外形 + +121 +00:07:12,599 --> 00:07:16,170 +这是因为这个场景中 +只有狗真正有所移动 + +122 +00:07:16,203 --> 00:07:19,907 +在这张图中我们使用 +“false color”展示了运动矢量 + +123 +00:07:19,940 --> 00:07:23,777 +从向量到调色板映射 x y + +124 +00:07:23,810 --> 00:07:27,681 +在这种 false color 的表现中 +红色色调恰好表明 + +125 +00:07:27,714 --> 00:07:30,150 +向左移动 + +126 +00:07:30,184 --> 00:07:33,253 +现在您已经看到了一帧的例子 + +127 +00:07:33,287 --> 00:07:35,989 +接下来我们看看在 +整个视频剪辑中是怎么样的 + +128 +00:07:36,023 --> 00:07:39,660 +这是小狗在沙滩接水瓶的短片 + +129 +00:07:39,693 --> 00:07:42,196 +我们对其进行了光流计算 + +130 +00:07:42,229 --> 00:07:45,065 +左边是修订版 1 的结果 + +131 +00:07:45,098 --> 00:07:49,002 +右边是我们基于机器语言的 +修订版 2 的结果 + +132 +00:07:49,036 --> 00:07:52,639 +希望可以清楚看到 +修订版 2 的一些改进 + +133 +00:07:52,673 --> 00:07:55,142 +一方面 也是最明显的 + +134 +00:07:55,175 --> 00:07:58,712 +水瓶的动作捕捉更准确 + +135 +00:07:58,745 --> 00:08:03,083 +您可能还会看到 +狗的预估动作有所改进 + +136 +00:08:03,116 --> 00:08:05,953 +到尾部的变化最为清楚 + +137 +00:08:05,986 --> 00:08:10,023 +但是在新的版本中 +也能看到它的耳朵在动 + +138 +00:08:10,057 --> 00:08:13,293 +第一个修订版还包含 +一些背景声音的变化 + +139 +00:08:13,327 --> 00:08:17,664 +而第二次修订更加连贯 +表示背景没有移动 + +140 +00:08:17,698 --> 00:08:21,668 +希望这个例子能让您对这项技术的 +作用有更全面的了解 + +141 +00:08:21,702 --> 00:08:25,272 +现在我们深入了解一下 +如何在您的 App 中使用这一技术 + +142 +00:08:25,305 --> 00:08:29,910 +很明显 最主要的使用案例 +是发现视频中的局部运动 + +143 +00:08:29,943 --> 00:08:32,980 +这可直接应用到安防视频使用场景 + +144 +00:08:33,013 --> 00:08:35,682 +在这类视频中 识别和定位 + +145 +00:08:35,716 --> 00:08:37,784 +偏离背景的局部动作是最重要的 + +146 +00:08:37,818 --> 00:08:40,053 +应该说 对于固定相机来说 + +147 +00:08:40,087 --> 00:08:44,391 +光流确实效果最好 +例如大多数安全摄像头 + +148 +00:08:44,424 --> 00:08:46,393 +您可能想要使用 +Vision 的目标跟踪器 + +149 +00:08:46,426 --> 00:08:48,795 +跟踪视频中移动的对象 + +150 +00:08:48,829 --> 00:08:51,265 +但需要知道在哪里初始化跟踪器 + +151 +00:08:51,298 --> 00:08:54,501 +光流也可以提供帮助 + +152 +00:08:54,535 --> 00:08:58,338 +如果您懂得计算机视觉 +或图像处理 + +153 +00:08:58,372 --> 00:09:00,407 +您可能会利用我们的光流结果 + +154 +00:09:00,440 --> 00:09:03,076 +以启用进一步的视频处理 + +155 +00:09:03,110 --> 00:09:06,747 +视频插值或视频动作分析 + +156 +00:09:06,780 --> 00:09:10,851 +可以从信息光流中大大受益 + +157 +00:09:10,884 --> 00:09:13,854 +现在 我们深入研究下 +修订版 1 和修订版 2 之间 + +158 +00:09:13,887 --> 00:09:16,023 +重要的附加差异 + +159 +00:09:16,857 --> 00:09:19,459 +修订版 1 总能返回光流场 + +160 +00:09:19,493 --> 00:09:22,029 +作为输入 具有相同的分辨率 + +161 +00:09:22,062 --> 00:09:25,032 +默认情况下 修订版 2 +也将执行此默认设定值 + +162 +00:09:25,065 --> 00:09:28,135 +不过 这里也有一个小问题 +一部分是因为 + +163 +00:09:28,168 --> 00:09:32,039 +修订版 2 是基于机器语言 +基础模型的输出 + +164 +00:09:32,072 --> 00:09:36,710 +与大多数输入图像分辨率相比 +分辨率相对较低 + +165 +00:09:36,743 --> 00:09:40,414 +因此 要匹配修订版 1 的 +默认行为 + +166 +00:09:40,447 --> 00:09:42,382 +必须进行一些上采样 + +167 +00:09:42,416 --> 00:09:45,853 +我们使用双线性上采样来实现 + +168 +00:09:45,886 --> 00:09:48,856 +这是解释上采样作用的视觉示例 + +169 +00:09:48,889 --> 00:09:52,659 +左边 我们有一个网络输出的 +放大部分 + +170 +00:09:52,693 --> 00:09:55,863 +这是低分辨率 因此出现像素化 + +171 +00:09:55,896 --> 00:10:00,000 +整体流场可能宽高比为 7:5 + +172 +00:10:00,033 --> 00:10:03,504 +右边 我们有一个取自同一场的 +相同的区域 + +173 +00:10:03,537 --> 00:10:06,507 +上采样到原始图像分辨率 + +174 +00:10:06,540 --> 00:10:11,645 +也许那个图像也有 +不同的纵横比 如 16:9 + +175 +00:10:11,678 --> 00:10:14,948 +您会注意到流场的边缘 +通过双线性上采样 + +176 +00:10:14,982 --> 00:10:18,018 +变得平滑 + +177 +00:10:18,051 --> 00:10:20,854 +由于潜在不同的纵横比 + +178 +00:10:20,888 --> 00:10:23,524 +记住 作为上采样过程的一部分 + +179 +00:10:23,557 --> 00:10:25,893 +流动图像会被拉伸 + +180 +00:10:25,926 --> 00:10:28,061 +为的是流场 + +181 +00:10:28,095 --> 00:10:30,230 +与图像中发生的变化相对应 + +182 +00:10:30,264 --> 00:10:32,266 +当直接进行网络输出时 + +183 +00:10:32,299 --> 00:10:36,136 +您应该考虑这与映射流结果 +到原始图像时 + +184 +00:10:36,170 --> 00:10:39,006 +分辨率和纵横比的方式是类似的 + +185 +00:10:41,575 --> 00:10:43,777 +您可以通过请求 +打开 keepNetworkOutput + +186 +00:10:43,810 --> 00:10:47,581 +选择跳过上采样 + +187 +00:10:47,614 --> 00:10:49,983 +这将为您提供原始模型输出 + +188 +00:10:50,017 --> 00:10:54,154 +为了选择可用的输出分辨率 + +189 +00:10:54,188 --> 00:10:57,357 +有四种计算精度 +可以应用于请求的设置 + +190 +00:10:57,391 --> 00:11:00,694 +您可以看到分辨率 +在此表中的每个精度设置 + +191 +00:11:00,727 --> 00:11:03,297 +但一定要经常检查观察到的 + +192 +00:11:03,330 --> 00:11:05,265 +像素缓冲区的宽度和高度 + +193 +00:11:06,066 --> 00:11:07,634 +什么时候应该使用网络输出 + +194 +00:11:07,668 --> 00:11:10,404 +什么时候应该允许 +Vision 上采样 + +195 +00:11:10,437 --> 00:11:14,408 +如果您已经在使用光流 +并想要这种行为向后兼容 + +196 +00:11:14,441 --> 00:11:17,678 +默认行为无疑是最好的 + +197 +00:11:17,711 --> 00:11:20,280 +如果您想要上采样输出 +也是一个不错的选择 + +198 +00:11:20,314 --> 00:11:24,885 +双线性对您来说是可以接受的 +值得额外的内存和延迟 + +199 +00:11:24,918 --> 00:11:28,355 +如果您不需要全分辨率 +网络输出是最好的 + +200 +00:11:28,388 --> 00:11:33,227 +它可以即时形成对应关系 +或者初始化一个跟踪器 + +201 +00:11:33,260 --> 00:11:35,262 +如果您确实需要完整的分辨率流 + +202 +00:11:35,295 --> 00:11:37,364 +但更愿意使用 +您自己的上采样方法 + +203 +00:11:37,397 --> 00:11:40,567 +网络输出也可能是 +正确的选择 + +204 +00:11:40,601 --> 00:11:44,705 +这涵盖了本次讲座中 +新的算法修订 + +205 +00:11:44,738 --> 00:11:47,140 +接下来我们讨论一下 +在 Vision 框架中 + +206 +00:11:47,174 --> 00:11:50,511 +所讲到的所有内容 +以及对您有何影响 + +207 +00:11:50,544 --> 00:11:53,780 +五年前 +当 Vision 最初发布时 + +208 +00:11:53,814 --> 00:11:56,316 +我们首次介绍了人脸检测和 +人脸关键点标记 + +209 +00:11:56,350 --> 00:11:59,419 +这是每个算法的修订版 1 + +210 +00:11:59,453 --> 00:12:03,123 +从那之后 +我们发布了两个更新的版本 + +211 +00:12:03,156 --> 00:12:06,593 +使用效率更高 技术更准确 + +212 +00:12:06,627 --> 00:12:10,330 +所以 我们现在正在 +不断从 Vision 框架 + +213 +00:12:10,364 --> 00:12:15,035 +移除这些算法的第一次修订 +并保留第二次和第三次修订 + +214 +00:12:15,068 --> 00:12:18,138 +不过 如果您使用的是修订版 1 +那也没关系 + +215 +00:12:18,172 --> 00:12:21,708 +我们将继续支持 +指定修订版 1 的代码 + +216 +00:12:21,742 --> 00:12:26,947 +或已编译的代码 +仅包含修订版 1 的 SDK + +217 +00:12:26,980 --> 00:12:28,749 +您可能会问 这怎么可能呢 + +218 +00:12:28,782 --> 00:12:32,252 +修订版 1 在后台执行算法 + +219 +00:12:32,286 --> 00:12:36,256 +在此图中 我称之为 +“修订版 1 检测器” + +220 +00:12:36,290 --> 00:12:40,527 +同样 修订版 2 使用 +修订版 2 检测器 + +221 +00:12:40,561 --> 00:12:42,796 +我们为此版本所做的 + +222 +00:12:42,829 --> 00:12:45,065 +是为了使用修订版 2 检测器的输出 + +223 +00:12:45,098 --> 00:12:48,101 +满足修订 1 的请求 + +224 +00:12:48,135 --> 00:12:52,506 +此外 修订 1 请求 +将被标记为已弃用 + +225 +00:12:52,539 --> 00:12:56,376 +这允许我们完全删除 +旧的版本 1 的检测器 + +226 +00:12:56,410 --> 00:12:59,613 +允许 Vision 框架保持精简 + +227 +00:12:59,646 --> 00:13:01,448 +这有多个好处 + +228 +00:13:01,481 --> 00:13:04,318 +不只是为了节省磁盘空间 + +229 +00:13:04,351 --> 00:13:09,256 +降低操作系统版本和 SDK 的 +下载和安装成本 + +230 +00:13:09,289 --> 00:13:13,760 +所有的 Vision 专家都可能有 +对自己说 “但是 等一下” + +231 +00:13:13,794 --> 00:13:18,298 +“修订版 2 会返回倒置 +而修订版 1 不会” + +232 +00:13:18,332 --> 00:13:21,435 +“难道这种行为差异不会 +影响某些 App 吗” + +233 +00:13:21,468 --> 00:13:24,605 +答案是肯定的 除非我们采取 + +234 +00:13:24,638 --> 00:13:27,541 +保留修订版 1 行为的 +预防性措施 + +235 +00:13:27,574 --> 00:13:32,312 +我们不会从修订版 2 检测器 +返回倒置 + +236 +00:13:32,346 --> 00:13:35,616 +类似的 +修订版 2 标记检测器 + +237 +00:13:35,649 --> 00:13:40,053 +将返回与修订版 1 标记 +相匹配的结果 + +238 +00:13:40,087 --> 00:13:42,389 +执行时间相当 + +239 +00:13:42,422 --> 00:13:45,726 +您应该体验准确性的提升 + +240 +00:13:45,759 --> 00:13:48,262 +任何情况下 +此改变不需要任何 App + +241 +00:13:48,295 --> 00:13:52,332 +对其代码进行任何修改 +将继续有效 + +242 +00:13:54,134 --> 00:13:57,237 +不过 我们仍鼓励您采取行动 + +243 +00:13:57,271 --> 00:13:59,573 +当有更好的选择时 + +244 +00:13:59,606 --> 00:14:02,509 +不应该满足于使用修订版 1 + +245 +00:14:02,543 --> 00:14:04,645 +我们一直推荐使用最新版本 + +246 +00:14:04,678 --> 00:14:07,548 +应这些请求 则应该是修订版 3 + +247 +00:14:08,749 --> 00:14:11,251 +当然 这个建议的主要原因 + +248 +00:14:11,285 --> 00:14:14,588 +是使用最新的技术 +它提供了最高级别的 + +249 +00:14:14,621 --> 00:14:18,725 +准确性和性能 谁又会拒绝呢 + +250 +00:14:18,759 --> 00:14:22,129 +此外 我们经过了数次建立和沟通 + +251 +00:14:22,162 --> 00:14:24,565 +我们在此再次重申 + +252 +00:14:24,598 --> 00:14:28,368 +最佳的实践是明确指定 +您的修订版本 + +253 +00:14:28,402 --> 00:14:31,371 +而不是依靠默认行为 + +254 +00:14:31,405 --> 00:14:34,408 +这就是我们在 +Spring 清扫中所做的 + +255 +00:14:34,441 --> 00:14:36,944 +现在来谈一谈我们是如何 +使用 Vision 框架 + +256 +00:14:36,977 --> 00:14:38,812 +简化调试 App 流程的 + +257 +00:14:38,846 --> 00:14:41,949 +我们为 Vision +添加了快速查看预览支持 + +258 +00:14:41,982 --> 00:14:44,685 +这对 Vision 来说意味着什么 + +259 +00:14:44,718 --> 00:14:48,255 +好了 现在您可以将鼠标悬停在 +调试器中的 VNObservations + +260 +00:14:48,288 --> 00:14:52,860 +只需单击一下 输入图像上的结果 +就得以可视化 + +261 +00:14:52,893 --> 00:14:55,863 +Xcode Playgrounds 也同样适用 + +262 +00:14:55,896 --> 00:14:59,099 +要了解这对您的调试有何帮助 +唯一方法 + +263 +00:14:59,132 --> 00:15:00,334 +就是演示一遍 + +264 +00:15:00,367 --> 00:15:02,603 +我们来看一个 Xcode 演示 + +265 +00:15:04,471 --> 00:15:08,208 +这里有一个简单的例程 +用来检测面部标记 + +266 +00:15:08,242 --> 00:15:11,345 +并返回人脸观察结果 + +267 +00:15:11,378 --> 00:15:15,849 +首先 我们设置了人脸标记请求 + +268 +00:15:15,883 --> 00:15:20,921 +然后 如果准备好了一个 +课堂上用的图像 就展示出来 + +269 +00:15:20,954 --> 00:15:24,458 +然后 公布一个数列来保存结果 + +270 +00:15:26,126 --> 00:15:27,995 +在自动释放池内 + +271 +00:15:28,028 --> 00:15:31,098 +我们用那个图像 +实例化一个请求处理程序 + +272 +00:15:31,131 --> 00:15:34,034 +然后执行我们的请求 + +273 +00:15:34,067 --> 00:15:38,338 +假设一切顺利 我们可以检索 +请求的结果 + +274 +00:15:39,206 --> 00:15:44,011 +在我们检索结果之后 +我运行它并到达断点 + +275 +00:15:44,044 --> 00:15:45,812 +现在我在调试程序 + +276 +00:15:45,846 --> 00:15:47,581 +当我将鼠标悬停在结果上时 + +277 +00:15:47,614 --> 00:15:50,284 +覆盖图显示我检测到三张脸 + +278 +00:15:50,317 --> 00:15:53,754 +不错 我的输入图像中 +确实有三张图 + +279 +00:15:53,787 --> 00:15:56,557 +但我怎么知道观察到的是哪张脸呢 + +280 +00:15:56,590 --> 00:15:59,927 +这就是 +Quick Look Preview 的工作 + +281 +00:15:59,960 --> 00:16:04,898 +当我提出这个要求时 +为了可视化结果 + +282 +00:16:04,932 --> 00:16:07,501 +可以点击每个“eye (眼睛)”图标 + +283 +00:16:07,534 --> 00:16:12,206 +标记的地方和人脸边界框 + +284 +00:16:12,239 --> 00:16:14,408 +出现了绘制的叠加层 + +285 +00:16:15,676 --> 00:16:18,612 +现在您就知道 +第一个观察到的是哪个图像 + +286 +00:16:19,780 --> 00:16:23,250 +我可以点击下一个 +画出第二次观察的叠加 + +287 +00:16:23,283 --> 00:16:25,619 +以及第三次观察 + +288 +00:16:27,521 --> 00:16:30,924 +继续下一个断点 +我们运行一些 + +289 +00:16:30,958 --> 00:16:34,561 +打印面部观察结果代码 +到调试控制台 + +290 +00:16:34,595 --> 00:16:37,497 +可以想象 在打印面部信息的 + +291 +00:16:37,531 --> 00:16:40,534 +调试控制台中 + +292 +00:16:40,567 --> 00:16:43,570 +您的脑海里很难马上想象 +每张脸是属于谁的 + +293 +00:16:43,604 --> 00:16:46,907 +或者从这些打印的标记来判断 +结果是否正确 + +294 +00:16:48,976 --> 00:16:51,245 +这里还要指出一点 + +295 +00:16:51,278 --> 00:16:54,515 +我通过引入 autoreleasepool + +296 +00:16:54,548 --> 00:16:57,918 +人为地强制请求超出范围的 +处理程序 + +297 +00:16:57,951 --> 00:17:00,420 +既然请求处理程序超出范围 + +298 +00:17:00,454 --> 00:17:03,924 +我们再次使用 Quick Look Preview +支持这个结果 + +299 +00:17:03,957 --> 00:17:06,693 +好的 您知道覆盖仍然被绘制 + +300 +00:17:06,727 --> 00:17:08,395 +但图像是不可用的 + +301 +00:17:09,496 --> 00:17:12,966 +需要牢记的是 +使用的图像请求处理程序 + +302 +00:17:13,000 --> 00:17:16,737 +生成观察结果 +必须仍在某个范围内 + +303 +00:17:16,770 --> 00:17:21,108 +从而让 Quick Look Preview +可显示原始图像 + +304 +00:17:21,141 --> 00:17:25,212 +那是因为图像请求处理程序 +是您的输入图像所在的位置 + +305 +00:17:25,245 --> 00:17:28,348 +操作将继续 但图像不可用 + +306 +00:17:28,382 --> 00:17:31,952 +这种快速查看预览支持 +在 Xcode Playgrounds 会话中 + +307 +00:17:31,985 --> 00:17:34,054 +做快速实验时 查看运作时 + +308 +00:17:34,087 --> 00:17:37,691 +非常有用 + +309 +00:17:37,724 --> 00:17:40,160 +现在我们来看看 + +310 +00:17:40,194 --> 00:17:44,865 +在这里 我们设置了一个简单的场地 +分析图像的条形码 + +311 +00:17:44,898 --> 00:17:47,935 +而不是查看这段代码 +我们做一些修改 + +312 +00:17:47,968 --> 00:17:50,537 +并检查它对结果的影响 + +313 +00:17:50,571 --> 00:17:52,773 +我们首先在两个条形码的图像上 + +314 +00:17:52,806 --> 00:17:56,743 +使用修订版 2 + +315 +00:17:56,777 --> 00:18:00,113 +如果我们要求所有的结果 +所有结果就会一次性显示出来 + +316 +00:18:00,147 --> 00:18:03,150 +第一个结果也在最后显示出来 + +317 +00:18:04,718 --> 00:18:07,287 +修订版 2 有几个问题 + +318 +00:18:07,321 --> 00:18:10,257 +首先 它错过了第一个条形码 + +319 +00:18:10,290 --> 00:18:13,427 +此外 它检测到第二个条形码两次 + +320 +00:18:13,460 --> 00:18:15,329 +它通过条形码 +给您提供了一条线 + +321 +00:18:15,362 --> 00:18:17,564 +而不是一个完整的边界框 + +322 +00:18:19,566 --> 00:18:23,637 +如果我们现在改为修订版 3 而非 2 +会发生什么呢 + +323 +00:18:26,106 --> 00:18:28,609 +首先 我们检测两个条形码 + +324 +00:18:28,642 --> 00:18:32,346 +得到的不是一条线 +而是完整的边界框 + +325 +00:18:33,313 --> 00:18:35,949 +Quick Look Preview 支持 +最了不起的就是 + +326 +00:18:35,983 --> 00:18:39,553 +无需您的帮助 也能以可视化结果 + +327 +00:18:39,586 --> 00:18:41,522 +编写各种实用函数 + +328 +00:18:41,555 --> 00:18:44,625 +它们可以直接叠加 +在调试器中的图像上 + +329 +00:18:44,658 --> 00:18:46,560 +或 Xcode Playground 中 + +330 +00:18:49,796 --> 00:18:54,101 +这就是 Vision 中的 +Quick Look Preview 支持 + +331 +00:18:54,134 --> 00:18:58,071 +现在您可以更轻松地了解 +观察到的是哪一个 + +332 +00:18:58,105 --> 00:19:00,407 +为了将它与您的输入图像 +一起使用 + +333 +00:19:00,440 --> 00:19:02,976 +只要确保保持范围内的 +图像请求处理程序 + +334 +00:19:03,010 --> 00:19:06,113 +希望 Xcode Playground 的支持 +帮助您更容易实现 + +335 +00:19:06,146 --> 00:19:08,482 +Vision 框架代码 Live Tuning + +336 +00:19:08,515 --> 00:19:11,418 +我们今天讲了 Vision 中 +一些重要的更新 + +337 +00:19:11,451 --> 00:19:14,588 +出于快速查看的目的 +我们为文本识别 + +338 +00:19:14,621 --> 00:19:19,493 +条形码检测和光流添加了重大修订 + +339 +00:19:21,295 --> 00:19:25,999 +随着修订的持续进行 +我们也将删除旧的版本 + +340 +00:19:26,033 --> 00:19:27,768 +所以要保持更新 + +341 +00:19:27,801 --> 00:19:30,771 +使用最新 最好的技术 + +342 +00:19:30,804 --> 00:19:34,241 +我们也让 Vision 的应用 +在 Quick Look Preview 支持下的调试 + +343 +00:19:34,274 --> 00:19:36,643 +更加容易 + +344 +00:19:36,677 --> 00:19:41,048 +希望您喜欢本次讲座 +并享受精彩纷呈的 WWDC + diff --git a/zho/2022 Session 10025 Capture machine-readable codes and text with VisionKit.srt b/zho/2022 Session 10025 Capture machine-readable codes and text with VisionKit.srt new file mode 100644 index 0000000..10f344c --- /dev/null +++ b/zho/2022 Session 10025 Capture machine-readable codes and text with VisionKit.srt @@ -0,0 +1,1020 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:13,313 +Ron Santos: 嗨 大家好 我是 Ron Santos +一名输入工程师 + +3 +00:00:13,347 --> 00:00:16,550 +今天我和大家一起聊下 +如何捕捉机读编码 + +4 +00:00:16,583 --> 00:00:18,285 +以及从视频流中解析文本 + +5 +00:00:18,318 --> 00:00:21,722 +或者 如我们常说的 数据扫描 + +6 +00:00:21,755 --> 00:00:24,124 +什么是数据扫描呢 + +7 +00:00:24,157 --> 00:00:28,662 +其实就是使用某种感应器 +比如说相机,来读取数据的方法 + +8 +00:00:29,763 --> 00:00:32,199 +通常是文本形式的数据 + +9 +00:00:32,232 --> 00:00:35,035 +例如 收据的一些有趣资讯 + +10 +00:00:35,068 --> 00:00:38,338 +如电话号码 日期和价格 + +11 +00:00:39,706 --> 00:00:42,709 +或者是机器可读的编码数据 + +12 +00:00:42,743 --> 00:00:45,612 +如常见的二维码 + +13 +00:00:45,646 --> 00:00:48,282 +您之前可能使用过数据扫描 + +14 +00:00:48,315 --> 00:00:51,218 +如在相机 App 中 +或 iOS 15 中推出的 + +15 +00:00:51,251 --> 00:00:53,720 +实况文本功能 + +16 +00:00:53,754 --> 00:00:56,323 +我相信您在日常生活中 + +17 +00:00:56,356 --> 00:00:59,760 +也用过 App 自带的扫描功能 + +18 +00:00:59,793 --> 00:01:02,596 +但如果要搭建自己的 +数据扫描器呢 + +19 +00:01:02,629 --> 00:01:04,198 +应该怎么做呢 + +20 +00:01:04,231 --> 00:01:07,034 +iOS SDK 视您的需要 + +21 +00:01:07,067 --> 00:01:08,602 +提供了多种场景 + +22 +00:01:09,303 --> 00:01:12,472 +选项之一就是 +使用 AVFoundation 框架 + +23 +00:01:12,506 --> 00:01:14,241 +建立拍摄图形 + +24 +00:01:14,274 --> 00:01:17,945 +将输入和输出连接到 +同一个 session 进行配置 + +25 +00:01:17,978 --> 00:01:22,549 +生成如机器可读 +代码的 AVMetadataObjects + +26 +00:01:22,583 --> 00:01:25,752 +如果您还想捕获文本 +还有另一个选项 + +27 +00:01:25,786 --> 00:01:29,990 +就是将 AVFoundation +与 Vision 框架相结合 + +28 +00:01:30,023 --> 00:01:32,693 +在这个图表中 +您创建的是视频数据的输出 + +29 +00:01:32,726 --> 00:01:35,662 +而非元数据输出 + +30 +00:01:35,696 --> 00:01:40,200 +视频数据输出 +带来了 sample buffers + +31 +00:01:40,234 --> 00:01:43,170 +可以与文本一起输入到 Vision 框架 + +32 +00:01:43,203 --> 00:01:47,774 +也可以和条码识别请求共同使用 +进行 Vision的物体观察功能 + +33 +00:01:47,808 --> 00:01:49,843 +关于使用 Vision +进行数据扫描的更多内容 + +34 +00:01:49,877 --> 00:01:54,581 +可以查看 WWDC21 中“Extract +document data using Vision”的内容 + +35 +00:01:54,615 --> 00:01:58,519 +好 以上是使用AVFoundation +和 Vision 进行数据扫描的内容 + +36 +00:01:58,552 --> 00:02:03,724 +在 iOS 16中 我们有一个新的选项 +将这些工作都浓缩到了一起 + +37 +00:02:03,757 --> 00:02:07,494 +VisionKit 框架中的 +DataScannerViewController 正式推出 + +38 +00:02:07,528 --> 00:02:10,964 +结合了 AVFoundation +和 Vision 的功能 + +39 +00:02:10,998 --> 00:02:13,934 +专门用于数据扫描目的 + +40 +00:02:13,967 --> 00:02:17,671 +DataScannerViewController 用户 +可使用如 + +41 +00:02:17,704 --> 00:02:22,176 +实时摄影机预览 实用的指引标签 + +42 +00:02:22,209 --> 00:02:24,411 +物品高光显示功能 + +43 +00:02:24,444 --> 00:02:29,049 +tap-to-focus (轻点对焦) +也是可选功能之一 + +44 +00:02:29,082 --> 00:02:32,920 +最后 还可通过 pinch-to-zoom (手势缩放) +功能来放大图像 + +45 +00:02:34,221 --> 00:02:37,090 +我们再来聊聊其他的 +对开发者来说实用的功能 + +46 +00:02:37,124 --> 00:02:40,561 +DataScannerViewController 是 +UIViewController 的子类 + +47 +00:02:40,594 --> 00:02:42,896 +您可以选择自己喜欢的展示方式 + +48 +00:02:42,930 --> 00:02:46,466 +所识别物体的坐标 +总是显示在观察坐标系中 + +49 +00:02:46,500 --> 00:02:48,702 +您无需费时将图像空间 + +50 +00:02:48,735 --> 00:02:51,572 +转换到 Vision 坐标 +再到观察坐标 + +51 +00:02:51,605 --> 00:02:54,241 +您也可以通过指定 +观察坐标系中的感兴趣区域 + +52 +00:02:54,274 --> 00:02:58,979 +限制观察的活动区间 + +53 +00:02:59,012 --> 00:03:01,815 +文本识别方面 您可以指定内容类型 + +54 +00:03:01,849 --> 00:03:04,918 +限制所查找的文本类型 + +55 +00:03:04,952 --> 00:03:06,486 +在机器可读代码方面 + +56 +00:03:06,520 --> 00:03:10,290 +您可以指定具体查找哪种符号 + +57 +00:03:10,324 --> 00:03:12,359 +我明白 使用您的 App + +58 +00:03:12,392 --> 00:03:15,929 +我知道数据扫描只是 +其众多功能之一 + +59 +00:03:15,963 --> 00:03:18,365 +但是需要很多代码 + +60 +00:03:18,398 --> 00:03:20,067 +通过 DataScannerViewController + +61 +00:03:20,100 --> 00:03:22,369 +我们的目标是为您完成常规工作 + +62 +00:03:22,402 --> 00:03:24,638 +从而您可以将时间 +聚焦在其它功能上 + +63 +00:03:24,671 --> 00:03:28,008 +接下来 我给您介绍下 +如何将其添加到 App 中 + +64 +00:03:28,041 --> 00:03:31,011 +首先是隐私使用说明 + +65 +00:03:31,044 --> 00:03:34,448 +App 尝试捕捉视频时 +iOS 会询问用户 + +66 +00:03:34,481 --> 00:03:38,085 +提供访问相机的明确权限 + +67 +00:03:38,118 --> 00:03:42,256 +您要提供一段描述性信息 +用于说明需求 + +68 +00:03:42,289 --> 00:03:45,759 +那就需要在 App 的 +Info.plist 文件中 + +69 +00:03:45,792 --> 00:03:48,095 +添加 +“privacy - camera usage description” + +70 +00:03:48,128 --> 00:03:52,966 +记得要尽可能详尽 +这样用户知道他们提供权限的内容 + +71 +00:03:53,000 --> 00:03:55,102 +接下来是代码实现 + +72 +00:03:55,135 --> 00:03:57,504 +不管您要在哪里显示 +数据扫描器 + +73 +00:03:57,538 --> 00:03:59,773 +首先要导入 VisionKit + +74 +00:04:01,008 --> 00:04:05,012 +接下来 由于并不是所有型号的 +设备都支持数据扫描 + +75 +00:04:05,045 --> 00:04:08,549 +使用 isSupported 类属性 +隐藏实现功能的 + +76 +00:04:08,582 --> 00:04:10,217 +按钮或菜单 + +77 +00:04:10,250 --> 00:04:13,620 +这样使用不到这一功能的用户 +就不需要看到这个界面了 + +78 +00:04:14,888 --> 00:04:19,259 +如果您想知道的话 可以告诉您 +任何搭载 Apple Neural Engine 的 + +79 +00:04:19,293 --> 00:04:22,396 +2018 及以上版本的 iPhone 和 iPad 设备 +都支持数据扫描 + +80 +00:04:22,429 --> 00:04:24,932 +您还要检查下可用性 + +81 +00:04:24,965 --> 00:04:27,801 +还记得隐私使用说明吗 + +82 +00:04:27,835 --> 00:04:31,572 +如果用户允许了相机权限 +以及设备没有其它限制条件 + +83 +00:04:31,605 --> 00:04:34,374 +则扫描功能可用 + +84 +00:04:34,408 --> 00:04:37,110 +如 Screen Time 的 +内容和隐私限制中 + +85 +00:04:37,144 --> 00:04:41,081 +限制了 相机 App 的 +访问权限 + +86 +00:04:41,114 --> 00:04:43,584 +现在 您可以配置实例了 + +87 +00:04:43,617 --> 00:04:47,254 +首先 指定您感兴趣的数据类别 + +88 +00:04:47,287 --> 00:04:51,458 +例如 您可以扫描二维码和文本 + +89 +00:04:52,559 --> 00:04:55,829 +您可以视需要发送 +语言列表到文本识别器 + +90 +00:04:55,863 --> 00:04:59,099 +作为不同处理方面的提示 + +91 +00:04:59,132 --> 00:05:01,201 +如拼写纠错 + +92 +00:05:01,235 --> 00:05:04,805 +如果您知道要查找什么语言 +列出来 + +93 +00:05:04,838 --> 00:05:08,308 +在两种语言脚本外观相似的情况下 +这是很有用的 + +94 +00:05:08,342 --> 00:05:10,244 +如果不提供指定语言 + +95 +00:05:10,277 --> 00:05:13,947 +则默认为用户的语言偏好 + +96 +00:05:13,981 --> 00:05:17,050 +您也可以请求具体的文本内容类型 + +97 +00:05:17,084 --> 00:05:20,554 +在这一例子中 +我想让扫描装置查找 URLs + +98 +00:05:20,587 --> 00:05:23,056 +既然您已经指明了 +要识别的数据类型 + +99 +00:05:23,090 --> 00:05:26,193 +就可以创建 DataScanner 实例了 + +100 +00:05:26,226 --> 00:05:29,630 +在前面的案例中 +我解释了条形码符号 + +101 +00:05:29,663 --> 00:05:33,267 +识别语言和文本内容类型 + +102 +00:05:33,300 --> 00:05:37,471 +容我花几分钟解释下 +它们的其它可选选项 + +103 +00:05:37,504 --> 00:05:41,108 +条形码符号方面 +我们和 Vision 条码检测器 + +104 +00:05:41,141 --> 00:05:43,877 +支持的符号一样 + +105 +00:05:43,911 --> 00:05:46,980 +在语言方面 +作为实况文本功能的一部分 + +106 +00:05:47,014 --> 00:05:50,150 +DataScannerViewController 支持 +同样的语言 + +107 +00:05:50,184 --> 00:05:55,455 +我很高兴地说 在 iOS 16 中 +我们新增支持日语和韩语 + +108 +00:05:55,489 --> 00:05:58,325 +当然 未来这也可能有 +进一步的变动 + +109 +00:05:58,358 --> 00:06:00,694 +所以使用 +supportedTextRecognitionLanguages + +110 +00:06:00,727 --> 00:06:04,498 +这一类属性获得更多最新列表 + +111 +00:06:04,531 --> 00:06:07,868 +最后 当扫描有具体语义的文本时 + +112 +00:06:07,901 --> 00:06:10,971 +DataScannerViewController 可以 +查找这其中类型 + +113 +00:06:11,905 --> 00:06:14,908 +我们的数据扫描器已准备好 +展示给用户了 + +114 +00:06:14,942 --> 00:06:18,846 +和其它 view controller 的 +展示一样 全屏 + +115 +00:06:18,879 --> 00:06:22,883 +使用表格 或将其添加到 +另一个视图层级中 + +116 +00:06:22,916 --> 00:06:24,184 +您可以自行决定 + +117 +00:06:24,218 --> 00:06:26,520 +随后 展示完成后 + +118 +00:06:26,553 --> 00:06:29,890 +调出 startScanning() +开始查找数据 + +119 +00:06:29,923 --> 00:06:32,626 +所以现在 我想要倒退一步 +用一点时间 + +120 +00:06:32,659 --> 00:06:35,729 +再看下数据扫描器的初始化参数 + +121 +00:06:35,762 --> 00:06:38,365 +我在这 +用了 recognizedDataTypes + +122 +00:06:38,398 --> 00:06:42,169 +但还有其它可以多样化 +您的体验 + +123 +00:06:43,136 --> 00:06:44,805 +我们逐一看下 + +124 +00:06:44,838 --> 00:06:49,243 +recognizedDataTypes 可以让您 +指定需要识别的数据类型 + +125 +00:06:49,276 --> 00:06:52,946 +文本 机器可读代码 +以及各是什么类型 + +126 +00:06:52,980 --> 00:06:56,183 +qualityLevel 可以设置为 +平衡 快或准确 + +127 +00:06:56,216 --> 00:06:59,353 +设置为快这一质量级别 则会在 +识别大尺寸 清晰度高的物体时 + +128 +00:06:59,386 --> 00:07:02,222 +为确保速度牺牲分辨率 + +129 +00:07:02,256 --> 00:07:04,024 +如标志上的文本 + +130 +00:07:04,057 --> 00:07:05,959 +准确这一质量级别可以 +带来高精确性 + +131 +00:07:05,993 --> 00:07:10,998 +即使是扫描微型二维码或 +微小序列号 + +132 +00:07:11,031 --> 00:07:15,636 +我推荐最开始使用平衡这一级别 +这在大部分场景都适用 + +133 +00:07:15,669 --> 00:07:18,572 +recognizesMultipleItems 可供您 + +134 +00:07:18,605 --> 00:07:20,774 +在一个框架内识别一个或多个物体 + +135 +00:07:20,807 --> 00:07:23,877 +比如如果您想一次识别多个条码 + +136 +00:07:23,911 --> 00:07:26,580 +当出现错误时 +用户没有点击别处的情况下 + +137 +00:07:26,613 --> 00:07:29,950 +默认识别最中心的物体 + +138 +00:07:29,983 --> 00:07:33,153 +绘制高光时开启高帧率跟踪 + +139 +00:07:33,187 --> 00:07:36,190 +在相机移动或场景改变时 + +140 +00:07:36,223 --> 00:07:39,927 +高光可尽可能跟随物体 + +141 +00:07:39,960 --> 00:07:43,130 +开启或禁用 +pinch-to-zoom (手势缩放) + +142 +00:07:43,163 --> 00:07:47,434 +我们还有一些方法 +让您可以自行调整缩放范围 + +143 +00:07:47,467 --> 00:07:49,870 +开启指引时 屏幕顶部 +会显示对应的标签 + +144 +00:07:49,903 --> 00:07:52,806 +帮助引导用户 + +145 +00:07:52,840 --> 00:07:56,877 +最后 如果需要的话 +您可以启用系统高光 + +146 +00:07:56,910 --> 00:07:59,546 +或者也可以禁用 +自行绘制高光 + +147 +00:08:00,447 --> 00:08:02,349 +现在您知道如何展示 +数据扫描器了 + +148 +00:08:02,382 --> 00:08:04,985 +我们来聊聊如何摄取识别物体 + +149 +00:08:05,018 --> 00:08:07,888 +以及如何绘制自定义高光 + +150 +00:08:08,922 --> 00:08:12,326 +首先 为数据扫描器提供一个代理 + +151 +00:08:12,359 --> 00:08:13,994 +有了代理后 + +152 +00:08:14,027 --> 00:08:17,097 +可以执行 +dataScanner didTapOn 方法 + +153 +00:08:17,130 --> 00:08:20,133 +用户点击一个物体时 +可调用此功能 + +154 +00:08:20,167 --> 00:08:24,538 +通过这一方法 您可以看到这种 +全新 RecognizeItem 的实例 + +155 +00:08:24,571 --> 00:08:29,776 +RecognizedItem 是将文本或条形码 +作为关联值的枚举类型 + +156 +00:08:29,810 --> 00:08:33,647 +在文本方面 转录属性 +保留识别字符串 + +157 +00:08:33,680 --> 00:08:36,383 +在条形码方面 如果负载包含字符串 + +158 +00:08:36,416 --> 00:08:39,720 +您可以使用 +payloadStringValue 来获取 + +159 +00:08:39,753 --> 00:08:42,556 +关于 RecognizedItem +还有两点需要知道的 + +160 +00:08:42,589 --> 00:08:46,560 +首先 每个识别物体都有一个 +独特的标识符 + +161 +00:08:46,593 --> 00:08:48,896 +在它整个生命周期中 +都可用其进行追踪 + +162 +00:08:48,929 --> 00:08:51,498 +这一生命周期始于 +物体首次识别之时 + +163 +00:08:51,532 --> 00:08:54,001 +离开视野后则周期结束 + +164 +00:08:54,034 --> 00:08:57,204 +第二 每个 RecognizedItem +都有一个性能界限 + +165 +00:08:57,237 --> 00:08:59,907 +这一界限不是矩形 +但包含有四个点 + +166 +00:08:59,940 --> 00:09:01,441 +每个角落各一个点 + +167 +00:09:01,475 --> 00:09:04,645 +接下来 我们来聊聊 +场景改变时 识别物体需调用的 + +168 +00:09:04,678 --> 00:09:07,548 +三种相关代理方法 + +169 +00:09:07,581 --> 00:09:09,516 +第一种是 didAdd + +170 +00:09:09,550 --> 00:09:12,753 +在场景中识别新物体时调用 + +171 +00:09:12,786 --> 00:09:15,255 +如果要自行绘制高光 + +172 +00:09:15,289 --> 00:09:18,292 +可以在这里为每个新物体绘制一个 + +173 +00:09:18,325 --> 00:09:23,030 +您可以根据关联值的 ID +跟踪高光 + +174 +00:09:23,063 --> 00:09:25,866 +在新的视图中加入视图层级时 + +175 +00:09:25,899 --> 00:09:28,836 +添加到 DataScanner 的 +overlayContainerView 中 + +176 +00:09:28,869 --> 00:09:33,941 +这样它们可以出现在相机预览的 +上层 但在其它补充浏览器下层 + +177 +00:09:35,142 --> 00:09:37,477 +下一个代理方法是 didUpdate + +178 +00:09:37,511 --> 00:09:40,614 +在物体移动或相机移动时调用 + +179 +00:09:40,647 --> 00:09:44,551 +也可以在识别文本改变 +需要转录时调用 + +180 +00:09:44,585 --> 00:09:47,554 +扫描器扫描文本时间越久 + +181 +00:09:47,588 --> 00:09:50,791 +转录越精准 因此会发生变化 + +182 +00:09:50,824 --> 00:09:54,027 +使用更新物体的 ID +从您刚创建的词典中 + +183 +00:09:54,061 --> 00:09:56,530 +获取高光 + +184 +00:09:56,563 --> 00:10:00,767 +然后将视图绘制成更新的界限 + +185 +00:10:00,801 --> 00:10:03,437 +最后是 didRemove 代理方法 + +186 +00:10:03,470 --> 00:10:07,040 +在物体从场景中消失时调用 + +187 +00:10:07,074 --> 00:10:09,977 +在这个方法中 +您可以忽略所有高光视图 + +188 +00:10:10,010 --> 00:10:12,479 +与移动视图相关联 + +189 +00:10:12,513 --> 00:10:15,282 +从视图层级中移除物体 + +190 +00:10:15,315 --> 00:10:18,218 +总而言之 如果您在物体上 +自行绘制高光 + +191 +00:10:18,252 --> 00:10:20,320 +这三种代理方法 +在控制场景中的高光动画时 + +192 +00:10:20,354 --> 00:10:23,323 +是非常重要的 + +193 +00:10:23,357 --> 00:10:26,927 +将动作变成动画 +将物体变成动画 + +194 +00:10:26,960 --> 00:10:29,096 +通过三种代理方法 + +195 +00:10:29,129 --> 00:10:33,333 +都会展示当前识别的所有物体数组 + +196 +00:10:33,367 --> 00:10:35,702 +文本识别就比较简单了 + +197 +00:10:35,736 --> 00:10:38,705 +因为物体都用自然阅读顺序排列 + +198 +00:10:38,739 --> 00:10:41,775 +意味着用户在数值 0 时就可以 +阅读到物体 + +199 +00:10:41,808 --> 00:10:45,846 +在物体到达数值 1 时就可以 +阅读到等等 + +200 +00:10:45,879 --> 00:10:48,515 +这是如何使用 +DataScannerViewController的概述 + +201 +00:10:48,549 --> 00:10:53,287 +在结束前 我快速说下其它功能 + +202 +00:10:53,320 --> 00:10:55,189 +如捕捉照片 + +203 +00:10:55,222 --> 00:10:57,024 +您可以调用 capturePhoto 方法 + +204 +00:10:57,057 --> 00:11:01,428 +从而异步返回一个 +高质量的 UIImage + +205 +00:11:02,462 --> 00:11:04,431 +如果您没有自行绘制高光 + +206 +00:11:04,464 --> 00:11:07,234 +可能不需要这三种代理方法 + +207 +00:11:07,267 --> 00:11:10,704 +相反 您可以使用 +recognizedItem 属性 + +208 +00:11:10,737 --> 00:11:15,742 +这是一种 AsyncStream +在场景改变时会持续更新 + +209 +00:11:17,845 --> 00:11:19,379 +感谢大家的观看 + +210 +00:11:19,413 --> 00:11:21,882 +记住 iOS SDK 为您提供了 + +211 +00:11:21,915 --> 00:11:23,684 +用 AVFoundation +和 Vision 框架 + +212 +00:11:23,717 --> 00:11:26,854 +搭建计算机视觉工作流的选择 + +213 +00:11:26,887 --> 00:11:29,122 +但可能您要构建一个 +可从视频内容文本中 + +214 +00:11:29,156 --> 00:11:32,025 +扫描文本 +或机器可读代码的 App + +215 +00:11:32,059 --> 00:11:33,527 +如拣配和包装 App + +216 +00:11:33,560 --> 00:11:36,697 +后台仓库 App +或销售时点情报系统 App + +217 +00:11:36,730 --> 00:11:38,932 +如果是这样的话 +那就看下 VisionKit 中的 + +218 +00:11:38,966 --> 00:11:40,434 +DataScannerViewController 吧 + +219 +00:11:40,467 --> 00:11:42,302 +如我今天所说 +它有许多初始化参数 + +220 +00:11:42,336 --> 00:11:45,706 +和代理方法可供选择 + +221 +00:11:45,739 --> 00:11:49,943 +提供多样化的体验 +以匹配您 App 的风格和需求 + +222 +00:11:50,944 --> 00:11:53,113 +最后 强烈推荐大家看下 + +223 +00:11:53,146 --> 00:11:55,849 +“Add Live Text interaction +to your app” 这一讲座 + +224 +00:11:55,883 --> 00:12:00,487 +您可以学习到关于 +VisionKit 静态图像实况文本的功能 + +225 +00:12:01,555 --> 00:12:03,357 +下次见 祝大家平安 + +226 +00:12:03,390 --> 00:12:08,662 +[欢快的音乐] + diff --git a/zho/2022 Session 10026 Add Live Text interaction to your app.srt b/zho/2022 Session 10026 Add Live Text interaction to your app.srt new file mode 100644 index 0000000..e74bf3e --- /dev/null +++ b/zho/2022 Session 10026 Add Live Text interaction to your app.srt @@ -0,0 +1,1323 @@ +1 +00:00:00,100 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,810 +♪ + +3 +00:00:09,810 --> 00:00:11,979 +您好 +我是 Adam Bradford + +4 +00:00:11,979 --> 00:00:13,981 +是 VisionKit 团队的 +工程师 + +5 +00:00:13,981 --> 00:00:16,316 +如果您想在您的 App 中 +添加实时文本 + +6 +00:00:16,316 --> 00:00:18,652 +那么本视频将能够为您提供帮助 + +7 +00:00:18,652 --> 00:00:21,588 +但首先 什么是实时文本? + +8 +00:00:21,588 --> 00:00:24,958 +实时文本能够分析图像 +并为用户提供各种功能 + +9 +00:00:24,958 --> 00:00:29,663 +如选择和复制文本等 +与其内容进行交互 + +10 +00:00:29,663 --> 00:00:33,133 +执行查找和翻译 + +11 +00:00:33,133 --> 00:00:34,801 +提供包括映射地址 拨号 + +12 +00:00:34,801 --> 00:00:37,070 +或跳转到 URL 的 + +13 +00:00:37,070 --> 00:00:39,940 +数据检测工作流程等操作 + +14 +00:00:39,940 --> 00:00:43,177 +实时文本甚至允许二维码交互 + +15 +00:00:43,177 --> 00:00:45,913 +想象一下 +如何将它应用于您的 App 中? + +16 +00:00:45,913 --> 00:00:49,550 +想了解更多吗?请继续观看 + +17 +00:00:49,550 --> 00:00:52,519 +在本次讲座中 首先我将介绍 + +18 +00:00:52,519 --> 00:00:54,721 +实时文本 API 的一般概述 + +19 +00:00:54,721 --> 00:00:57,724 +然后探讨在现有的 App 中 + +20 +00:00:57,724 --> 00:01:00,460 +如何实现此 API + +21 +00:01:00,460 --> 00:01:02,930 +在此之后 +我将深入探讨在您的 App 中 + +22 +00:01:02,930 --> 00:01:06,733 +添加实时文本时 +可能会有所帮助的一些技巧和窍门 + +23 +00:01:06,733 --> 00:01:10,704 +那么让我们开始 +实时文本 API 概述 + +24 +00:01:10,704 --> 00:01:14,908 +在高级别下 在 Swift 中 +可使用实时文本 API + +25 +00:01:14,908 --> 00:01:17,010 +它在静态图像上效果很好 + +26 +00:01:17,010 --> 00:01:20,414 +并且可适用于暂停的视频帧 + +27 +00:01:20,414 --> 00:01:23,250 +如果您需要分析 +实时视频流媒体的视频 + +28 +00:01:23,250 --> 00:01:25,819 +来搜索文本或二维码等项目 + +29 +00:01:25,819 --> 00:01:28,856 +VisionKit 也有 +一个可用的数据扫描仪 + +30 +00:01:28,856 --> 00:01:33,594 +可从我同事 Ron 的相关讲座中 +了解更多信息 + +31 +00:01:33,594 --> 00:01:37,231 +实时文本 API +在配备了 Apple 神经网络引擎 + +32 +00:01:37,231 --> 00:01:39,566 +操作系统为 iOS 16 +以及上的设备中可用 + +33 +00:01:39,566 --> 00:01:44,104 +并在所有支持 +macOS 13 的设备中可用 + +34 +00:01:44,104 --> 00:01:46,240 +它由四个主要类别组成 + +35 +00:01:46,240 --> 00:01:49,176 +若要使用它 首先 您需要一张图像 + +36 +00:01:49,176 --> 00:01:51,945 +然后将该图像 + +37 +00:01:51,945 --> 00:01:54,515 +导入执行异步分析的 +ImageAnalyzer + +38 +00:01:54,515 --> 00:01:56,216 +分析完成后 + +39 +00:01:56,216 --> 00:01:58,018 +根据您所用的平台 +将生成的 ImageAnalysis 对象 + +40 +00:01:58,018 --> 00:02:00,721 +提供给 ImageAnalysisInteraction + +41 +00:02:00,721 --> 00:02:05,526 +或 ImageAnalysisOverlayView + +42 +00:02:05,526 --> 00:02:08,428 +到目前为止看起来比较简单 对吧? + +43 +00:02:08,428 --> 00:02:10,564 +现在 我将演示如何将它 + +44 +00:02:10,564 --> 00:02:13,600 +添加到现有的 App 中 + +45 +00:02:13,600 --> 00:02:16,003 +这是我们的App + +46 +00:02:16,003 --> 00:02:17,437 +是一个简单的图像查看器 + +47 +00:02:17,437 --> 00:02:21,175 +它在滚动视图内有一个图像视图 + +48 +00:02:21,175 --> 00:02:24,745 +请注意 我可以缩放和平移 + +49 +00:02:24,745 --> 00:02:27,648 +但是无论我如何尝试 +我也无法选择任何文本 + +50 +00:02:27,648 --> 00:02:30,384 +或激活任何这些数据检测器 + +51 +00:02:30,384 --> 00:02:33,120 +它没有此功能 + +52 +00:02:33,120 --> 00:02:35,455 +这是 Xcode 中的项目 + +53 +00:02:35,455 --> 00:02:37,624 +要将实时文本添加到此 App 中 + +54 +00:02:37,624 --> 00:02:40,861 +我将修改视图控制器子类 + +55 +00:02:40,861 --> 00:02:43,964 +首先 我需要一个 ImageAnalyzer + +56 +00:02:43,964 --> 00:02:48,235 +和一个 ImageAnalysisInteraction + +57 +00:02:48,235 --> 00:02:50,470 +在这里 +我简单重写了 viewDidLoad + +58 +00:02:50,470 --> 00:02:54,975 +并在 imageview 中 +添加了 interaction + +59 +00:02:54,975 --> 00:02:58,979 +接下来 我需要知道何时执行分析 + +60 +00:03:01,849 --> 00:03:03,517 +请注意 当设置了新图像后 + +61 +00:03:03,517 --> 00:03:05,853 +我首先重置了 +preferredInteractionTypes + +62 +00:03:05,853 --> 00:03:10,290 +和 analysis +其修改的是旧图像 + +63 +00:03:10,290 --> 00:03:13,827 +现在在写新 analysis 前 +所需的内容都已完成 + +64 +00:03:13,827 --> 00:03:17,164 +接下来 我将创建将使用的函数 + +65 +00:03:17,164 --> 00:03:19,833 +然后检查我们的图像是否存在 + +66 +00:03:23,003 --> 00:03:28,542 +如果存在 则创建一个 Task + +67 +00:03:28,542 --> 00:03:31,845 +接下来 创建一个 +configuration 来告诉分析器 + +68 +00:03:31,845 --> 00:03:34,181 +它应该检索什么 + +69 +00:03:34,181 --> 00:03:39,653 +在这种情况下 我将使用 text +和 machineReadableCode + +70 +00:03:39,653 --> 00:03:41,555 +生成 analysis 可抛出 + +71 +00:03:41,555 --> 00:03:43,690 +所以酌情处理 + +72 +00:03:43,690 --> 00:03:46,226 +最后 我已准备好调用 + +73 +00:03:46,226 --> 00:03:48,195 +analyzeImageWithConfiguration 方法 + +74 +00:03:48,195 --> 00:03:51,698 +这将开始分析过程 + +75 +00:03:51,698 --> 00:03:53,700 +分析完成后 + +76 +00:03:53,700 --> 00:03:56,170 +已经过去了一段时间 + +77 +00:03:56,170 --> 00:03:59,006 +App 的状态可能也已经改变 + +78 +00:03:59,006 --> 00:04:01,975 +所以我会检查分析是否已成功 + +79 +00:04:01,975 --> 00:04:05,145 +显示的图像是否未改变 + +80 +00:04:05,145 --> 00:04:07,080 +如果所有这些检查都通过 + +81 +00:04:07,080 --> 00:04:09,683 +我可以简单地在 interaction 中 +设置 analysis + +82 +00:04:09,683 --> 00:04:12,219 +并设置 +preferredInteractionTypes + +83 +00:04:12,219 --> 00:04:13,787 +我在这里 +使用 .automatic + +84 +00:04:13,787 --> 00:04:17,824 +它会提供默认的系统行为 + +85 +00:04:17,824 --> 00:04:20,894 +我觉得可以进行测试了 + +86 +00:04:20,894 --> 00:04:22,896 +哦 看那个 + +87 +00:04:22,896 --> 00:04:26,099 +我看到实时文本按钮出现了没错 + +88 +00:04:26,099 --> 00:04:28,368 +我现在可以选择文本了 + +89 +00:04:28,368 --> 00:04:30,304 +注意 这些界面元素 + +90 +00:04:30,304 --> 00:04:32,406 +会自动定位 + +91 +00:04:32,406 --> 00:04:35,108 +并将它们的位置保持在图像边界内 + +92 +00:04:35,108 --> 00:04:39,780 +和可见区域中 无需我额外操作 + +93 +00:04:39,780 --> 00:04:42,282 +好的 请注意 点击实时文本按钮 + +94 +00:04:42,282 --> 00:04:44,451 +将能够突出显示任何可选项目 + +95 +00:04:44,451 --> 00:04:48,021 +为数据检测器显示下划线 +并显示快速操作 + +96 +00:04:48,021 --> 00:04:51,024 +我点击此快速操作 即可拨打电话 + +97 +00:04:51,024 --> 00:04:54,394 +甚至可以通过长按查看更多选项 + +98 +00:04:54,394 --> 00:04:58,665 +不得不说 这很酷 + +99 +00:04:58,665 --> 00:05:01,101 +只需这几行代码 + +100 +00:05:01,101 --> 00:05:04,404 +我使用了一张普通的图像 +并实现了诸多功能 + +101 +00:05:04,404 --> 00:05:06,740 +这个简单的 App 现在能够 + +102 +00:05:06,740 --> 00:05:10,210 +选择图像上的文本 激活数据检测器 + +103 +00:05:10,210 --> 00:05:14,114 +二维码 查找 翻译文本等 + +104 +00:05:14,114 --> 00:05:16,717 +在我看来 + +105 +00:05:16,717 --> 00:05:18,652 +这区区几行代码实现的功能 +也还不错 + +106 +00:05:18,652 --> 00:05:21,355 +现在您已经了解了 +如何实现实时文本 + +107 +00:05:21,355 --> 00:05:23,891 +我将介绍一些技巧和窍门 + +108 +00:05:23,891 --> 00:05:26,560 +可能能帮助您更好地操作 + +109 +00:05:26,560 --> 00:05:29,096 +我将从探索交互类型开始 + +110 +00:05:29,096 --> 00:05:30,931 +大多数开发人员 +会使用 .automatic + +111 +00:05:30,931 --> 00:05:33,467 +它提供文本选择 但也会 + +112 +00:05:33,467 --> 00:05:36,737 +在启用实时文本按钮后 +突出显示数据检测器 + +113 +00:05:36,737 --> 00:05:40,407 +这将在所检测到的 +任何适用项目下方画一条线 + +114 +00:05:40,407 --> 00:05:43,510 +并允许一键访问来激活 + +115 +00:05:43,510 --> 00:05:45,746 +这与常见的内置 App 的行为 + +116 +00:05:45,746 --> 00:05:48,148 +完全相同 + +117 +00:05:48,148 --> 00:05:50,884 +如果您的 App 只用文本选择 + +118 +00:05:50,884 --> 00:05:54,388 +而无需使用数据检测器 +您可以将类型设置为 .textSelection + +119 +00:05:54,388 --> 00:05:59,159 +它不会随着实时文本 +按钮状态的改变而改变 + +120 +00:05:59,159 --> 00:06:00,827 +如果您的 App 只用数据检测器 + +121 +00:06:00,827 --> 00:06:04,031 +而无需使用文本选择 + +122 +00:06:04,031 --> 00:06:06,133 +将类型设置为 +.dataDetectors + +123 +00:06:06,133 --> 00:06:09,269 +请注意 在此模式下禁用选择 + +124 +00:06:09,269 --> 00:06:11,205 +因此您不会看到实时文本按钮 + +125 +00:06:11,205 --> 00:06:13,674 +但数据检测器将添加下划线 + +126 +00:06:13,674 --> 00:06:17,211 +并可一键访问 + +127 +00:06:17,211 --> 00:06:18,812 +将一个空集设置为 +preferredInteractionTypes + +128 +00:06:18,812 --> 00:06:21,715 +将禁用交互 + +129 +00:06:21,715 --> 00:06:26,053 +最后一点 无论在文本选择 +还是在自动模式下 + +130 +00:06:26,053 --> 00:06:28,622 +长按 + +131 +00:06:28,622 --> 00:06:31,258 +仍然可以激活数据检测器 + +132 +00:06:31,258 --> 00:06:32,726 +此功能受 + +133 +00:06:32,726 --> 00:06:35,829 +allowLongPressForDataDetectorsInTextMode +属性控制 + +134 +00:06:35,829 --> 00:06:39,766 +设置为 true 时 +将启用功能 其为默认设置 + +135 +00:06:39,766 --> 00:06:43,270 +如有必要 设置为 false +即可禁用功能 + +136 +00:06:43,270 --> 00:06:44,438 +我想稍微花点时间 + +137 +00:06:44,438 --> 00:06:46,573 +讲一下底部的这些按钮 + +138 +00:06:46,573 --> 00:06:49,309 +它们统称为补充接口 + +139 +00:06:49,309 --> 00:06:51,278 +其中包括实时文本按钮 + +140 +00:06:51,278 --> 00:06:53,447 +通常位于右下角 + +141 +00:06:53,447 --> 00:06:56,517 +快速操作位于左下角 + +142 +00:06:56,517 --> 00:06:59,987 +快速操作代表 +analysis 中的任何数据检测器 + +143 +00:06:59,987 --> 00:07:02,923 +并在实时文本按钮启用时可见 + +144 +00:07:02,923 --> 00:07:05,092 +大小、位置和可见性 + +145 +00:07:05,092 --> 00:07:07,094 +由 interaction 控制 + +146 +00:07:07,094 --> 00:07:10,297 +默认位置和外观与系统匹配 + +147 +00:07:10,297 --> 00:07:12,366 +您的 App 可能有 +自定义界面元素 + +148 +00:07:12,366 --> 00:07:15,102 +这可能会干扰或使用不同的字体 + +149 +00:07:15,102 --> 00:07:16,470 +和符号权重 + +150 +00:07:16,470 --> 00:07:20,307 +让我们来看看如何自定义此界面 + +151 +00:07:20,307 --> 00:07:23,877 +首先是 +isSupplementaryInterfaceHidden 属性 + +152 +00:07:23,877 --> 00:07:26,914 +如果我想 +让我的 App 仍然可选择文本 + +153 +00:07:26,914 --> 00:07:29,983 +但不显示实时文本按钮 + +154 +00:07:29,983 --> 00:07:31,752 +当我设置 +SupplementaryInterfaceHidden + +155 +00:07:31,752 --> 00:07:34,321 +为 true 您的实时文本按钮 + +156 +00:07:34,321 --> 00:07:37,090 +或快速操作都不会显示 + +157 +00:07:37,090 --> 00:07:40,127 +还有一个的 ContentInsets 属性 + +158 +00:07:40,127 --> 00:07:42,496 +如果您的界面元素 + +159 +00:07:42,496 --> 00:07:43,997 +会重叠在补充接口上 + +160 +00:07:43,997 --> 00:07:46,033 +您可以调整 +ContentInsets + +161 +00:07:46,033 --> 00:07:48,769 +那么在可见的状态下 +实时文本按钮和快速操作都能 + +162 +00:07:48,769 --> 00:07:52,840 +完美适应您现有的 App 内容 + +163 +00:07:52,840 --> 00:07:54,441 +如果您的 App 使用自定义字体 + +164 +00:07:54,441 --> 00:07:56,276 +您希望界面能够与之适应 + +165 +00:07:56,276 --> 00:07:58,245 +设置 SupplementaryInterfaceFont + +166 +00:07:58,245 --> 00:08:00,547 +可为实时文本按钮和快速操作 + +167 +00:08:00,547 --> 00:08:02,516 +设置指定字体 + +168 +00:08:02,516 --> 00:08:04,651 +和指定的符号字体粗细 + +169 +00:08:04,651 --> 00:08:06,987 +请注意 为了按钮大小的一致性 + +170 +00:08:06,987 --> 00:08:10,090 +实时文本将忽略磅值 + +171 +00:08:10,090 --> 00:08:12,025 +换个话题 + +172 +00:08:12,025 --> 00:08:14,428 +如果您没有使用 UIImageview + +173 +00:08:14,428 --> 00:08:18,532 +您可能会发现 +突出显示并不能匹配您的图像 + +174 +00:08:18,532 --> 00:08:20,601 +这是因为使用 UIImageView 后 + +175 +00:08:20,601 --> 00:08:22,970 +VisionKit 可以使用 +其 ContentMode 属性 + +176 +00:08:22,970 --> 00:08:26,673 +为您自动计算 contentsRect + +177 +00:08:26,673 --> 00:08:29,776 +在这里 交互的视图边界 + +178 +00:08:29,776 --> 00:08:32,145 +比其图像内容的边界更大 + +179 +00:08:32,145 --> 00:08:36,049 +但应用的却是 +默认的内容矩形 一个单位矩形 + +180 +00:08:36,049 --> 00:08:39,152 +这很容易通过实现委托方法 + +181 +00:08:39,152 --> 00:08:41,054 +contentsRectForInteraction 来解决 + +182 +00:08:41,054 --> 00:08:43,590 +且会在单位坐标空间中返回一个矩形 + +183 +00:08:43,590 --> 00:08:46,159 +描述图像内容 + +184 +00:08:46,159 --> 00:08:49,830 +与交互边界的关系 来纠正这个问题 + +185 +00:08:49,830 --> 00:08:52,132 +例如 返回一个标示这些值的矩形 + +186 +00:08:52,132 --> 00:08:53,600 +能够纠正这个问题 + +187 +00:08:53,600 --> 00:08:55,903 +但请基于 +您 App 的当前内容和布局 + +188 +00:08:55,903 --> 00:08:59,940 +来返回正确的标准化矩形 + +189 +00:08:59,940 --> 00:09:01,842 +但每当交互的边界发生变化时 + +190 +00:09:01,842 --> 00:09:04,811 +将调用 contentsRectForInteraction + +191 +00:09:04,811 --> 00:09:06,547 +如果您的 contentsRect 已更改 + +192 +00:09:06,547 --> 00:09:08,882 +但交互边界未更改 + +193 +00:09:08,882 --> 00:09:11,285 +您可以通过调用 +setContentsRectNeedsUpdate() + +194 +00:09:11,285 --> 00:09:15,122 +来使交互更新 + +195 +00:09:15,122 --> 00:09:18,825 +采用实时文本时 +您可能会遇到的另一个问题是 + +196 +00:09:18,825 --> 00:09:21,562 +放置此交互的最佳位置是哪里? + +197 +00:09:21,562 --> 00:09:24,965 +理想情况 实时文本交互直接放置在 + +198 +00:09:24,965 --> 00:09:27,167 +托管您的图像内容视图上 + +199 +00:09:27,167 --> 00:09:30,003 +如前所述 UIImageView 将计算 + +200 +00:09:30,003 --> 00:09:32,606 +contentsRect + +201 +00:09:32,606 --> 00:09:36,076 +虽然不是必需的 但还是首选的 + +202 +00:09:36,076 --> 00:09:38,178 +如果您使用的 +是 UIImageview + +203 +00:09:38,178 --> 00:09:40,347 +只需在 ImageView 上设置交互 + +204 +00:09:40,347 --> 00:09:43,450 +VisionKit 将处理其他的内容 + +205 +00:09:43,450 --> 00:09:45,986 +但如果 您的 ImageView 位于 + +206 +00:09:45,986 --> 00:09:47,487 +在 ScrollView 内部 + +207 +00:09:47,487 --> 00:09:50,591 +您可能很想 将交互 +放在 ScrollView 上 + +208 +00:09:50,591 --> 00:09:54,294 +但不建议这样做 且因它将有一个 +不断变化的 contentsRect + +209 +00:09:54,294 --> 00:09:58,765 +可能难以管理 + +210 +00:09:58,765 --> 00:10:00,601 +此处的解决方案是相同的 + +211 +00:10:00,601 --> 00:10:02,269 +将交互放在 + +212 +00:10:02,269 --> 00:10:04,104 +托管您的图像内容的视图上 + +213 +00:10:04,104 --> 00:10:05,839 +即使它在应用缩放的 + +214 +00:10:05,839 --> 00:10:08,942 +ScrollView 内 + +215 +00:10:08,942 --> 00:10:11,144 +接下来我将谈一下手势 + +216 +00:10:11,144 --> 00:10:14,548 +至少可以说 + +217 +00:10:14,548 --> 00:10:16,016 +实时文本有一套 +非常非常丰富的手势识别器 + +218 +00:10:16,016 --> 00:10:18,085 +根据您的 App 的结构 + +219 +00:10:18,085 --> 00:10:20,654 +您可能会发现交互 + +220 +00:10:20,654 --> 00:10:22,523 +响应您的 App 应该处理的 + +221 +00:10:22,523 --> 00:10:25,559 +手势和事件 +或 App 响应交互的 + +222 +00:10:25,559 --> 00:10:26,593 +不要担心 + +223 +00:10:26,593 --> 00:10:29,263 +如果发生了这些问题 + +224 +00:10:29,263 --> 00:10:31,498 +这里有一些技巧可以用来帮助纠正 + +225 +00:10:31,498 --> 00:10:33,367 +纠正此问题的一种常见方法 + +226 +00:10:33,367 --> 00:10:35,169 +就是实现委托方法 + +227 +00:10:35,169 --> 00:10:39,006 +interaction shouldBeginAt point +for interactionType + +228 +00:10:39,006 --> 00:10:42,843 +如果返回 false +则不会执行该操作 + +229 +00:10:42,843 --> 00:10:44,978 +一个比较好的切入点 +是检查 interaction + +230 +00:10:44,978 --> 00:10:47,548 +在 at: point 是否有可交互项 + +231 +00:10:47,548 --> 00:10:50,284 +或者 是否有 +活动中的 text seleciton + +232 +00:10:50,284 --> 00:10:52,286 +此处使用文本选择检查 + +233 +00:10:52,286 --> 00:10:55,489 +所以您能够点击文本 + +234 +00:10:55,489 --> 00:10:58,258 +来取消选择 + +235 +00:10:58,258 --> 00:11:01,195 +另一方面 如果您发现您的交互 + +236 +00:11:01,195 --> 00:11:03,297 +似乎对手势没有反应 + +237 +00:11:03,297 --> 00:11:05,666 +可能是因为您的 App 中 + +238 +00:11:05,666 --> 00:11:08,836 +有手势识别器来处理手势 + +239 +00:11:08,836 --> 00:11:11,738 +在这种情况下 +您可以制定类似的解决方案 + +240 +00:11:11,738 --> 00:11:15,676 +使用您的 gestureRecognizer 的 +gestureRecognizerShouldBegin + +241 +00:11:15,676 --> 00:11:17,044 +委托方法 + +242 +00:11:17,044 --> 00:11:21,014 +在这里 我执行了类似的检查 + +243 +00:11:21,014 --> 00:11:23,250 +如果该位置有交互式项目 + +244 +00:11:23,250 --> 00:11:25,385 +或者启用文本选择 +会返回 false + +245 +00:11:25,385 --> 00:11:26,520 +还有一点需要注意 + +246 +00:11:26,520 --> 00:11:28,589 +在这个例子中 +我首先通过传入 nil + +247 +00:11:28,589 --> 00:11:32,025 +将 gestureRecognizer 的位置 + +248 +00:11:32,025 --> 00:11:33,327 +转换成窗口坐标空间位置 + +249 +00:11:33,327 --> 00:11:36,663 +然后将其转换为交互的视图 + +250 +00:11:36,663 --> 00:11:39,099 +如果您的交互 +位于应用缩放的 ScrollView 内 + +251 +00:11:39,099 --> 00:11:42,870 +这可能是必要的 + +252 +00:11:42,870 --> 00:11:44,638 +如果发现您的定点不匹配 + +253 +00:11:44,638 --> 00:11:46,907 +则可尝试此技巧 + +254 +00:11:46,907 --> 00:11:49,343 +我认为有用的另一类似方法 + +255 +00:11:49,343 --> 00:11:52,446 +是重写 UIView 中的 +hitTest: WithEvent + +256 +00:11:52,446 --> 00:11:54,815 +这里也是类似的操作 + +257 +00:11:54,815 --> 00:11:57,150 +我执行与之前相同类型的检查 + +258 +00:11:57,150 --> 00:12:00,721 +在这种情况下 返回适当的视图 + +259 +00:12:00,721 --> 00:12:05,158 +一如既往 我们希望 +您的 App 尽可能响应迅速 + +260 +00:12:05,158 --> 00:12:06,894 +神经网络引擎的分析非常高效 + +261 +00:12:06,894 --> 00:12:10,130 +在此基础之上 我想分享有一些 +ImageAnalyzer 的提示 + +262 +00:12:10,130 --> 00:12:12,366 +以获得最佳性能 + +263 +00:12:12,366 --> 00:12:14,768 +理想情况下 您的 App 只需 + +264 +00:12:14,768 --> 00:12:16,436 +共享一个 ImageAnalyzer + +265 +00:12:16,436 --> 00:12:19,139 +此外 我们支持多种类型的图像 + +266 +00:12:19,139 --> 00:12:21,675 +您应该始终通过 +传入您拥有的本机类型 + +267 +00:12:21,675 --> 00:12:24,011 +来尽量减少图像转换 + +268 +00:12:24,011 --> 00:12:27,114 +但如果您恰好 +有一个 CVPixelBuffer + +269 +00:12:27,114 --> 00:12:29,349 +将会是最高效的 + +270 +00:12:29,349 --> 00:12:32,886 +此外 为了最好地利用系统资源 + +271 +00:12:32,886 --> 00:12:36,390 +您应仅在图像出现在屏幕上时 +或在此之前 + +272 +00:12:36,390 --> 00:12:38,959 +开始分析 + +273 +00:12:38,959 --> 00:12:41,428 +如果您的 App 包含内容滚动 + +274 +00:12:41,428 --> 00:12:43,530 +例如 包含了一个时间轴 + +275 +00:12:43,530 --> 00:12:47,568 +仅在滚动停止后再开始分析 + +276 +00:12:47,568 --> 00:12:51,004 +现在 实时文本 +并不仅仅出现在此 API 中 + +277 +00:12:51,004 --> 00:12:52,739 +在您的 App 使用的系统中 + +278 +00:12:52,739 --> 00:12:56,543 +已自动为部分架构 +提供实时文本支持 + +279 +00:12:56,543 --> 00:13:00,547 +例如 UITextField +或 UITextView 的 + +280 +00:13:00,547 --> 00:13:04,251 +实时文本支持 +使用相机进行键盘输入 + +281 +00:13:04,251 --> 00:13:08,288 +WebKit 和 Quick Look +也支持实时文本 + +282 +00:13:08,288 --> 00:13:12,159 +如想了解更多信息 请查看这些讲座 + +283 +00:13:12,159 --> 00:13:14,161 +iOS 16 今年的新功能 + +284 +00:13:14,161 --> 00:13:16,964 +我们在 AVKit 中 +添加了实时文本支持 + +285 +00:13:16,964 --> 00:13:20,400 +AVPlayerView +和 ViewController + +286 +00:13:20,400 --> 00:13:22,903 +默认通过 +allowsVideoFrameAnalysis 属性 + +287 +00:13:22,903 --> 00:13:25,739 +在暂停的帧中 + +288 +00:13:25,739 --> 00:13:27,708 +自动支持实时文本 + +289 +00:13:27,708 --> 00:13:29,543 +请注意 这仅适用于 + +290 +00:13:29,543 --> 00:13:32,980 +非 FairPlay 保护的内容 + +291 +00:13:32,980 --> 00:13:35,282 +如果您使用的是 +AVPlayerLayer + +292 +00:13:35,282 --> 00:13:37,684 +那么您负责的是管理分析 + +293 +00:13:37,684 --> 00:13:40,988 +和交互 使用 + +294 +00:13:40,988 --> 00:13:43,223 +currentlyDisplayedPixelBuffer 属性 + +295 +00:13:43,223 --> 00:13:45,092 +来获取当前帧非常重要 + +296 +00:13:45,092 --> 00:13:46,660 +这是保证 + +297 +00:13:46,660 --> 00:13:49,830 +分析正确框架的唯一途径 + +298 +00:13:49,830 --> 00:13:51,598 +如果视频播放速率为零 + +299 +00:13:51,598 --> 00:13:55,969 +这将仅返回一个有效值 此为浅拷贝 + +300 +00:13:55,969 --> 00:13:58,672 +写入将极不安全 + +301 +00:13:58,672 --> 00:14:00,741 +而且 仅适用于 + +302 +00:14:00,741 --> 00:14:04,211 +非 FairPlay 保护的内容 + +303 +00:14:04,211 --> 00:14:06,747 +我们很高兴能帮助实现 + +304 +00:14:06,747 --> 00:14:07,848 +您的 App 的实时文本功能 + +305 +00:14:07,848 --> 00:14:10,851 +代表实时文本团队的每一位成员 + +306 +00:14:10,851 --> 00:14:12,953 +感谢您参加本次讲座 + +307 +00:14:12,953 --> 00:14:16,223 +非常期待看到您如何将它 +用于您 App 中的图像 + +308 +00:14:16,223 --> 00:14:18,692 +一如既往地 祝您从中获得乐趣 + +309 +00:14:18,692 --> 00:14:23,096 +♪ + diff --git a/zho/2022 Session 10027 Optimize your Core ML usage.srt b/zho/2022 Session 10027 Optimize your Core ML usage.srt new file mode 100644 index 0000000..682e116 --- /dev/null +++ b/zho/2022 Session 10027 Optimize your Core ML usage.srt @@ -0,0 +1,2280 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ Mellow instrumental +hip-hop music ♪ + +2 +00:00:03,003 --> 00:00:09,610 +♪ + +3 +00:00:09,610 --> 00:00:11,445 +Hi, my name is Ben, + +4 +00:00:11,445 --> 00:00:13,947 +and I'm an engineer +on the Core ML team. + +5 +00:00:13,947 --> 00:00:16,283 +Today I'm going to show some +of the exciting new features + +6 +00:00:16,283 --> 00:00:18,218 +being added to Core ML. + +7 +00:00:18,218 --> 00:00:20,287 +The focus of these features +is to help you + +8 +00:00:20,287 --> 00:00:23,257 +optimize your Core ML usage. + +9 +00:00:23,257 --> 00:00:25,893 +In this session, +I'll go over performance tools + +10 +00:00:25,893 --> 00:00:28,629 +that are now available to give +you the information you need + +11 +00:00:28,629 --> 00:00:31,565 +to understand and optimize +your model's performance + +12 +00:00:31,565 --> 00:00:34,668 +when using Core ML. + +13 +00:00:34,668 --> 00:00:36,803 +Then I'll go over +some enhanced APIs + +14 +00:00:36,803 --> 00:00:40,540 +which will enable you +to make those optimizations. + +15 +00:00:40,540 --> 00:00:42,376 +And lastly, +I'll give an overview + +16 +00:00:42,376 --> 00:00:44,611 +of some additional +Core ML capabilities + +17 +00:00:44,611 --> 00:00:47,581 +and integration options. + +18 +00:00:47,581 --> 00:00:50,484 +Let me begin with +the performance tools. + +19 +00:00:50,484 --> 00:00:51,752 +To give some background, + +20 +00:00:51,752 --> 00:00:53,887 +I'll start by summarizing +the standard workflow + +21 +00:00:53,887 --> 00:00:56,723 +when using Core ML +within your app. + +22 +00:00:56,723 --> 00:00:59,526 +The first step +is to choose your model. + +23 +00:00:59,526 --> 00:01:01,561 +This may be done +in a variety of ways, + +24 +00:01:01,561 --> 00:01:04,197 +such as using Core ML tools +to convert a PyTorch + +25 +00:01:04,197 --> 00:01:06,900 +or TensorFlow model +to Core ML format, + +26 +00:01:06,900 --> 00:01:09,603 +using an already-existing +Core ML model, + +27 +00:01:09,603 --> 00:01:13,140 +or using Create ML +to train and export your model. + +28 +00:01:13,140 --> 00:01:15,008 +For more details +on model conversion + +29 +00:01:15,008 --> 00:01:16,610 +or to learn about Create ML, + +30 +00:01:16,610 --> 00:01:20,280 +I recommend checking out +these sessions. + +31 +00:01:20,280 --> 00:01:23,951 +The next step is to integrate +that model into your app. + +32 +00:01:23,951 --> 00:01:26,586 +This involves bundling the model +with your application + +33 +00:01:26,586 --> 00:01:29,890 +and using the Core ML APIs +to load and run inference + +34 +00:01:29,890 --> 00:01:33,660 +on that model +during your app's execution. + +35 +00:01:33,660 --> 00:01:39,032 +The last step is to optimize +the way you use Core ML. + +36 +00:01:39,032 --> 00:01:41,435 +First, I'll go over +choosing a model. + +37 +00:01:41,435 --> 00:01:42,736 +There are many aspects +of a model + +38 +00:01:42,736 --> 00:01:44,137 +that you may want to consider + +39 +00:01:44,137 --> 00:01:47,407 +when deciding if you should use +that model within your app. + +40 +00:01:47,407 --> 00:01:49,343 +You also may have multiple +candidates of models + +41 +00:01:49,343 --> 00:01:50,777 +you'd like to select from, + +42 +00:01:50,777 --> 00:01:53,347 +but how do you decide +which one to use? + +43 +00:01:53,347 --> 00:01:55,415 +You need to have a model +whose functionality + +44 +00:01:55,415 --> 00:01:58,919 +will match the requirements of +the feature you wish to enable. + +45 +00:01:58,919 --> 00:02:01,321 +This includes understanding +the model's accuracy + +46 +00:02:01,321 --> 00:02:03,790 +as well as its performance. + +47 +00:02:03,790 --> 00:02:05,625 +A great way to learn about +a Core ML model + +48 +00:02:05,625 --> 00:02:07,728 +is by opening it in Xcode. + +49 +00:02:07,728 --> 00:02:09,262 +Just double-click on any model, + +50 +00:02:09,262 --> 00:02:12,432 +and it will bring up +the following. + +51 +00:02:12,432 --> 00:02:15,102 +At the top, +you'll find the model type, + +52 +00:02:15,102 --> 00:02:19,806 +its size, and the operating +system requirements. + +53 +00:02:19,806 --> 00:02:22,542 +In the General tab, +it shows additional details + +54 +00:02:22,542 --> 00:02:24,611 +captured in +the model's metadata, + +55 +00:02:24,611 --> 00:02:26,546 +its compute +and storage precision, + +56 +00:02:26,546 --> 00:02:30,784 +and info, such as class labels +that it can predict. + +57 +00:02:30,784 --> 00:02:33,153 +The Preview tab +is for testing out your model + +58 +00:02:33,153 --> 00:02:37,624 +by providing example inputs +and seeing what it predicts. + +59 +00:02:37,624 --> 00:02:40,660 +The Predictions tab displays +the model's inputs and outputs, + +60 +00:02:40,660 --> 00:02:42,262 +as well as the types and sizes + +61 +00:02:42,262 --> 00:02:45,532 +that Core ML +will expect at runtime. + +62 +00:02:45,532 --> 00:02:48,935 +And finally, the Utilities tab +can help with model encryption + +63 +00:02:48,935 --> 00:02:52,572 +and deployment tasks. + +64 +00:02:52,572 --> 00:02:55,308 +Overall, these views give you +a quick overview + +65 +00:02:55,308 --> 00:02:58,879 +of your model's functionality +and preview of its accuracy. + +66 +00:02:58,879 --> 00:03:02,416 +But what about +your model's performance? + +67 +00:03:02,416 --> 00:03:04,518 +The cost of loading a model, + +68 +00:03:04,518 --> 00:03:07,220 +the amount of time +a single prediction takes, + +69 +00:03:07,220 --> 00:03:09,489 +or what hardware it utilizes, + +70 +00:03:09,489 --> 00:03:12,426 +may be critical factors +for your use case. + +71 +00:03:12,426 --> 00:03:13,660 +You may have hard targets + +72 +00:03:13,660 --> 00:03:16,430 +related to real-time +streaming data constraints + +73 +00:03:16,430 --> 00:03:19,733 +or need to make key design +decisions around user interface + +74 +00:03:19,733 --> 00:03:22,869 +depending +on perceived latency. + +75 +00:03:22,869 --> 00:03:25,372 +One way to get insight +into the model's performance + +76 +00:03:25,372 --> 00:03:27,841 +is to do an initial integration +into your app + +77 +00:03:27,841 --> 00:03:29,743 +or by creating a small prototype + +78 +00:03:29,743 --> 00:03:32,045 +which you can instrument +and measure. + +79 +00:03:32,045 --> 00:03:34,281 +And since performance +is hardware dependent, + +80 +00:03:34,281 --> 00:03:35,849 +you would likely want +to do these measurements + +81 +00:03:35,849 --> 00:03:39,052 +on a variety +of supported hardware. + +82 +00:03:39,052 --> 00:03:41,721 +Xcode and Core ML +can now help you with this task + +83 +00:03:41,721 --> 00:03:45,058 +even before writing +a single line of code. + +84 +00:03:45,058 --> 00:03:47,961 +Core ML now allows you +to create performance reports. + +85 +00:03:47,961 --> 00:03:49,930 +Let me show you. + +86 +00:03:52,566 --> 00:03:53,967 +[CLICK] + +87 +00:03:53,967 --> 00:03:56,036 +I now have +the Xcode model viewer open + +88 +00:03:56,036 --> 00:03:59,272 +for the YOLOv3 +object detection model. + +89 +00:03:59,272 --> 00:04:01,708 +Between the Predictions +and Utilities tabs, + +90 +00:04:01,708 --> 00:04:04,211 +there is now a Performance tab. + +91 +00:04:04,211 --> 00:04:06,012 +To generate +a performance report, + +92 +00:04:06,012 --> 00:04:10,317 +I'll select the plus icon +at the bottom left, + +93 +00:04:10,317 --> 00:04:12,252 +select the device +I'd like to run on -- + +94 +00:04:12,252 --> 00:04:16,756 +which is my iPhone -- +click next, + +95 +00:04:16,756 --> 00:04:20,293 +then select which compute units +I'd like Core ML to use. + +96 +00:04:20,293 --> 00:04:21,695 +I'm going to leave it on All, + +97 +00:04:21,695 --> 00:04:23,830 +to allow Core ML +to optimize for latency + +98 +00:04:23,830 --> 00:04:26,833 +with all available +compute units. + +99 +00:04:26,833 --> 00:04:31,138 +Now I'll finish +by pressing Run Test. + +100 +00:04:31,138 --> 00:04:32,606 +To ensure the test can run, + +101 +00:04:32,606 --> 00:04:36,776 +make sure the selected device +is unlocked. + +102 +00:04:36,776 --> 00:04:38,979 +It shows a spinning icon +while the performance report + +103 +00:04:38,979 --> 00:04:40,847 +is being generated. + +104 +00:04:40,847 --> 00:04:42,215 +To create the report, + +105 +00:04:42,215 --> 00:04:44,451 +the model is sent over +to the device, + +106 +00:04:44,451 --> 00:04:46,820 +then there are several +iterations of compile, + +107 +00:04:46,820 --> 00:04:50,490 +load, and predictions +which are run with the model. + +108 +00:04:50,490 --> 00:04:51,791 +Once those are complete, + +109 +00:04:51,791 --> 00:04:55,562 +the metrics in the performance +report are calculated. + +110 +00:04:55,562 --> 00:04:57,130 +Now it's run the model +on my iPhone, + +111 +00:04:57,130 --> 00:05:00,767 +and it displays +the performance report. + +112 +00:05:00,767 --> 00:05:02,636 +At the top, +it shows some details + +113 +00:05:02,636 --> 00:05:04,838 +about the device +where the test was run + +114 +00:05:04,838 --> 00:05:09,342 +as well as which compute units +were selected. + +115 +00:05:09,342 --> 00:05:12,145 +Next it shows statistics +about the run. + +116 +00:05:12,145 --> 00:05:16,116 +The median prediction time +was 22.19 milliseconds + +117 +00:05:16,116 --> 00:05:20,153 +and the median load time +was about 400 ms. + +118 +00:05:20,153 --> 00:05:23,390 +Also, if you plan to compile +your model on-device, + +119 +00:05:23,390 --> 00:05:28,795 +this shows the compilation time +was about 940 ms. + +120 +00:05:28,795 --> 00:05:32,399 +A prediction time of around +22 ms tells me that this model + +121 +00:05:32,399 --> 00:05:34,668 +can support about +45 frames per second + +122 +00:05:34,668 --> 00:05:36,670 +if I want to run it +in real time. + +123 +00:05:39,773 --> 00:05:41,775 +Since this model contains +a neural network, + +124 +00:05:41,775 --> 00:05:43,643 +there's a layer view +displayed towards the bottom + +125 +00:05:43,643 --> 00:05:45,812 +of the performance report. + +126 +00:05:45,812 --> 00:05:49,015 +This shows the name +and type of all of the layers, + +127 +00:05:49,015 --> 00:05:53,853 +as well as which compute unit +each layer ran on. + +128 +00:05:53,853 --> 00:05:56,423 +A filled-in checkmark means +that the layer was executed + +129 +00:05:56,423 --> 00:05:59,492 +on that compute unit. + +130 +00:05:59,492 --> 00:06:02,062 +An unfilled checkmark means +that the layer is supported + +131 +00:06:02,062 --> 00:06:03,330 +on that compute unit, + +132 +00:06:03,330 --> 00:06:06,866 +but Core ML did not choose +to run it there. + +133 +00:06:06,866 --> 00:06:09,502 +And an empty diamond means +that the layer is not supported + +134 +00:06:09,502 --> 00:06:12,272 +on that compute unit. + +135 +00:06:12,272 --> 00:06:16,009 +In this case, +54 layers were run on the GPU, + +136 +00:06:16,009 --> 00:06:19,312 +and 32 layers +were run on the Neural Engine. + +137 +00:06:19,312 --> 00:06:20,614 +You can also filter the layers + +138 +00:06:20,614 --> 00:06:23,917 +by a compute unit +by clicking on it. + +139 +00:06:29,923 --> 00:06:31,958 +That was how +you can use Xcode 14 + +140 +00:06:31,958 --> 00:06:35,428 +to generate performance reports +for your Core ML models. + +141 +00:06:35,428 --> 00:06:37,464 +This was shown for running +on an iPhone, + +142 +00:06:37,464 --> 00:06:40,367 +but it will allow you to test +on multiple operating system + +143 +00:06:40,367 --> 00:06:42,235 +and hardware combinations, + +144 +00:06:42,235 --> 00:06:45,505 +without having to write +a single line of code. + +145 +00:06:45,505 --> 00:06:47,274 +Now that you've chosen +your model, + +146 +00:06:47,274 --> 00:06:50,944 +the next step is to integrate +this model into your app. + +147 +00:06:50,944 --> 00:06:53,280 +This involves bundling +the model with your app + +148 +00:06:53,280 --> 00:06:56,316 +and making use of Core ML APIs +to load the model + +149 +00:06:56,316 --> 00:06:59,252 +and make predictions with it. + +150 +00:06:59,252 --> 00:07:01,521 +In this case, I've built an app + +151 +00:07:01,521 --> 00:07:05,325 +that uses Core ML style transfer +models to perform style transfer + +152 +00:07:05,325 --> 00:07:08,061 +on frames from +a live camera session. + +153 +00:07:08,061 --> 00:07:10,764 +It's working properly; +however, the frame rate + +154 +00:07:10,764 --> 00:07:15,101 +is slower than I'd expect, +and I'd like to understand why. + +155 +00:07:15,101 --> 00:07:17,237 +This is where you'd move on +to step three, + +156 +00:07:17,237 --> 00:07:20,674 +which is to optimize +your Core ML usage. + +157 +00:07:20,674 --> 00:07:23,109 +Generating a performance report +can show the performance + +158 +00:07:23,109 --> 00:07:26,846 +a model is capable of achieving +in a stand-alone environment; + +159 +00:07:26,846 --> 00:07:29,816 +however, you also need a way +to profile the performance + +160 +00:07:29,816 --> 00:07:32,952 +of a model that's running +live in your app. + +161 +00:07:32,952 --> 00:07:35,522 +For this, you can now use +the Core ML Instrument + +162 +00:07:35,522 --> 00:07:38,858 +found in the Instruments app +in Xcode 14. + +163 +00:07:38,858 --> 00:07:41,294 +This Instrument allows you +to visualize the performance + +164 +00:07:41,294 --> 00:07:43,563 +of your model when it runs +live in your app, + +165 +00:07:43,563 --> 00:07:46,933 +and helps you identify +potential performance issues. + +166 +00:07:46,933 --> 00:07:50,837 +Let me show +how it can be used. + +167 +00:07:50,837 --> 00:07:52,005 +So I'm in Xcode + +168 +00:07:52,005 --> 00:07:54,240 +with my style transfer app +workspace open, + +169 +00:07:54,240 --> 00:07:56,543 +and I'm ready +to profile the app. + +170 +00:07:56,543 --> 00:07:57,944 +I'll force-click +on the Run button + +171 +00:07:57,944 --> 00:07:59,946 +and select Profile. + +172 +00:08:02,482 --> 00:08:04,517 +This will install +the latest version of the code + +173 +00:08:04,517 --> 00:08:06,820 +on my device +and open Instruments for me + +174 +00:08:06,820 --> 00:08:10,290 +with my targeted device +and app selected. + +175 +00:08:10,290 --> 00:08:12,659 +Since I want to profile +my Core ML usage, + +176 +00:08:12,659 --> 00:08:17,163 +I'm going to select +the Core ML template. + +177 +00:08:17,163 --> 00:08:19,366 +This template includes +the Core ML Instrument, + +178 +00:08:19,366 --> 00:08:21,501 +as well as several +other useful Instruments + +179 +00:08:21,501 --> 00:08:24,771 +which will help you profile +your Core ML usage. + +180 +00:08:24,771 --> 00:08:28,575 +To capture a trace, +I'll simply press Record. + +181 +00:08:32,579 --> 00:08:35,081 +The app is now running +on my iPhone. + +182 +00:08:35,081 --> 00:08:36,916 +I will let it run +for a few seconds + +183 +00:08:36,916 --> 00:08:39,285 +and use a few different styles. + +184 +00:08:39,285 --> 00:08:42,922 +And now I'll end the trace +by pressing the Stop button. + +185 +00:08:42,922 --> 00:08:44,891 +Now I have my Instruments trace. + +186 +00:08:44,891 --> 00:08:48,328 +I'm going to focus on +the Core ML Instrument. + +187 +00:08:48,328 --> 00:08:50,830 +The Core ML Instrument +shows all of the Core ML events + +188 +00:08:50,830 --> 00:08:53,032 +that were captured in the trace. + +189 +00:08:53,032 --> 00:08:56,636 +The initial view groups all +of the events into three lanes: + +190 +00:08:56,636 --> 00:09:01,674 +Activity, Data, and Compute. + +191 +00:09:01,674 --> 00:09:04,577 +The Activity lane shows +top-level Core ML events + +192 +00:09:04,577 --> 00:09:06,312 +which have a one-to-one +relationship + +193 +00:09:06,312 --> 00:09:09,849 +with the actual Core ML APIs +that you would call directly, + +194 +00:09:09,849 --> 00:09:14,387 +such as loads and predictions. + +195 +00:09:14,387 --> 00:09:16,589 +The Data lane shows events +in which Core ML + +196 +00:09:16,589 --> 00:09:19,426 +is performing data checks +or data transformations + +197 +00:09:19,426 --> 00:09:20,960 +to make sure that +it can safely work + +198 +00:09:20,960 --> 00:09:25,165 +with the model's inputs +and outputs. + +199 +00:09:25,165 --> 00:09:27,267 +The Compute lane shows +when Core ML sends + +200 +00:09:27,267 --> 00:09:30,069 +compute requests +to specific compute units, + +201 +00:09:30,069 --> 00:09:33,807 +such as the Neural Engine, +or the GPU. + +202 +00:09:33,807 --> 00:09:36,910 +You can also select +the Ungrouped view + +203 +00:09:36,910 --> 00:09:42,148 +where there is an individual +lane for each event type. + +204 +00:09:42,148 --> 00:09:46,386 +At the bottom, there's the +Model Activity Aggregation view. + +205 +00:09:46,386 --> 00:09:49,489 +This view provides aggregate +statistics for all of the events + +206 +00:09:49,489 --> 00:09:51,524 +displayed in the trace. + +207 +00:09:51,524 --> 00:09:53,159 +For example, in this trace, + +208 +00:09:53,159 --> 00:09:57,063 +the average model load +took 17.17 ms, + +209 +00:09:57,063 --> 00:10:02,101 +and the average prediction +took 7.2 ms. + +210 +00:10:02,101 --> 00:10:05,772 +Another note is that it can sort +the events by duration. + +211 +00:10:05,772 --> 00:10:08,608 +Here, the list is telling me +that more time is being spent + +212 +00:10:08,608 --> 00:10:12,078 +loading the model than actually +making predictions with it, + +213 +00:10:12,078 --> 00:10:15,114 +at a total of 6.41 seconds +of loads, + +214 +00:10:15,114 --> 00:10:19,352 +compared to only 2.69 seconds +of predictions. + +215 +00:10:19,352 --> 00:10:22,689 +Perhaps this has something +to with the low frame rate. + +216 +00:10:22,689 --> 00:10:26,025 +Let me try to find where all +of these loads are coming from. + +217 +00:10:28,027 --> 00:10:30,630 +I am noticing that +I am reloading my Core ML model + +218 +00:10:30,630 --> 00:10:33,099 +prior to calling +each prediction. + +219 +00:10:33,099 --> 00:10:35,134 +This is generally +not good practice + +220 +00:10:35,134 --> 00:10:38,638 +as I can just load the model +once and hold it in memory. + +221 +00:10:38,638 --> 00:10:42,442 +I'm going to jump back into +my code and try to fix this. + +222 +00:10:47,080 --> 00:10:50,083 +I found the area of code +where I load my model. + +223 +00:10:50,083 --> 00:10:52,886 +The issue here is that +this is a computed properly, + +224 +00:10:52,886 --> 00:10:54,654 +which means that each time +I reference the + +225 +00:10:54,654 --> 00:10:58,625 +styleTransferModel variable, +it will recompute the property, + +226 +00:10:58,625 --> 00:11:01,594 +which means reloading the model, +in this case. + +227 +00:11:01,594 --> 00:11:02,762 +I can quickly fix this + +228 +00:11:02,762 --> 00:11:05,932 +by changing this +to be a lazy variable. + +229 +00:11:14,340 --> 00:11:17,010 +Now I'll reprofile the app +to check if this has fixed + +230 +00:11:17,010 --> 00:11:19,178 +the repeated loads issue. + +231 +00:11:27,186 --> 00:11:30,890 +I'll once again select +the Core ML template + +232 +00:11:30,890 --> 00:11:34,227 +and capture a trace. + +233 +00:11:34,227 --> 00:11:36,996 +This is much more in line +with what I'd expect. + +234 +00:11:36,996 --> 00:11:38,164 +The count column tells me + +235 +00:11:38,164 --> 00:11:40,233 +that there are +five load events total, + +236 +00:11:40,233 --> 00:11:42,969 +which matches the number +of styles I used in the app, + +237 +00:11:42,969 --> 00:11:45,605 +and the total duration of loads +is much smaller + +238 +00:11:45,605 --> 00:11:49,509 +than the total duration +of predictions. + +239 +00:11:49,509 --> 00:11:54,747 +Also, as I scroll through... + +240 +00:11:54,747 --> 00:11:57,250 +...it correctly shows repeated +prediction events + +241 +00:11:57,250 --> 00:11:59,252 +without loads +in between each one. + +242 +00:12:02,088 --> 00:12:04,824 +Another note is that so far, +I've only looked at the views + +243 +00:12:04,824 --> 00:12:07,827 +that show all +Core ML model activity. + +244 +00:12:07,827 --> 00:12:11,097 +In this app, there is one +Core ML model per style, + +245 +00:12:11,097 --> 00:12:14,734 +so I may want to breakdown +the Core ML activity by model. + +246 +00:12:14,734 --> 00:12:17,270 +The Instrument +makes this easy to do. + +247 +00:12:17,270 --> 00:12:23,409 +In the main graph, you can click +the arrow at the top left, + +248 +00:12:23,409 --> 00:12:24,978 +and it will make one subtrack + +249 +00:12:24,978 --> 00:12:27,580 +for each model used +in the trace. + +250 +00:12:27,580 --> 00:12:29,782 +Here it displays all of the +different style transfer models + +251 +00:12:29,782 --> 00:12:32,352 +that were used. + +252 +00:12:32,352 --> 00:12:35,822 +The Aggregation view also offers +similar functionality + +253 +00:12:35,822 --> 00:12:39,726 +by allowing you to break down +the statistics by model. + +254 +00:12:43,730 --> 00:12:47,133 +Next I'd like to dive into +a prediction on one of my models + +255 +00:12:47,133 --> 00:12:50,303 +to get a better idea +of how it's being run. + +256 +00:12:50,303 --> 00:12:53,139 +I'll look deeper into +the Watercolor model. + +257 +00:12:54,874 --> 00:12:57,410 +In this prediction, +the Compute lane is telling me + +258 +00:12:57,410 --> 00:12:59,312 +that my model was run +on a combination + +259 +00:12:59,312 --> 00:13:03,016 +of the Neural Engine +and the GPU. + +260 +00:13:03,016 --> 00:13:06,219 +Core ML is sending these compute +requests asynchronously, + +261 +00:13:06,219 --> 00:13:08,821 +so if I'm interested +to see when these compute units + +262 +00:13:08,821 --> 00:13:10,657 +are actively running +the model, + +263 +00:13:10,657 --> 00:13:12,759 +I can combine +the Core ML Instrument + +264 +00:13:12,759 --> 00:13:16,462 +with the GPU Instrument and the +new Neural Engine Instrument. + +265 +00:13:16,462 --> 00:13:19,465 +To do this, I have the three +Instruments pinned here. + +266 +00:13:23,202 --> 00:13:25,705 +The Core ML Instrument shows me +the entire region + +267 +00:13:25,705 --> 00:13:28,641 +where the model ran. + +268 +00:13:33,646 --> 00:13:36,249 +And within this region, +the Neural Engine Instrument + +269 +00:13:36,249 --> 00:13:41,421 +shows the compute first running +on the Neural Engine, + +270 +00:13:41,421 --> 00:13:43,456 +then the GPU Instrument +shows the model + +271 +00:13:43,456 --> 00:13:45,291 +was handed off +from the Neural Engine + +272 +00:13:45,291 --> 00:13:47,994 +to finish running on the GPU. + +273 +00:13:47,994 --> 00:13:50,096 +This gives me a better idea +of how my model + +274 +00:13:50,096 --> 00:13:54,167 +is actually being executed +on the hardware. + +275 +00:13:54,167 --> 00:13:58,671 +To recap, I used the Core ML +Instrument in Xcode 14 + +276 +00:13:58,671 --> 00:14:00,406 +to learn about my model's +performance + +277 +00:14:00,406 --> 00:14:02,742 +when running live in my app. + +278 +00:14:02,742 --> 00:14:04,143 +I then identified an issue + +279 +00:14:04,143 --> 00:14:07,246 +in which I was too frequently +reloading my model. + +280 +00:14:07,246 --> 00:14:10,917 +I fixed the issue in my code, +reprofiled the application, + +281 +00:14:10,917 --> 00:14:14,153 +and verified that the issue +had been fixed. + +282 +00:14:14,153 --> 00:14:17,423 +I was also able to combine +the Core ML, GPU, + +283 +00:14:17,423 --> 00:14:20,226 +and new Neural Engine Instrument +to get more details + +284 +00:14:20,226 --> 00:14:24,931 +on how my model was actually +run on different compute units. + +285 +00:14:24,931 --> 00:14:26,532 +That was an overview +of the new tools + +286 +00:14:26,532 --> 00:14:29,135 +to help you understand +performance. + +287 +00:14:29,135 --> 00:14:31,337 +Next, I'll go over +some enhanced APIs + +288 +00:14:31,337 --> 00:14:34,307 +that can help optimize +that performance. + +289 +00:14:34,307 --> 00:14:36,375 +Let me start by going over +how Core ML + +290 +00:14:36,375 --> 00:14:39,679 +handles model inputs +and outputs. + +291 +00:14:39,679 --> 00:14:41,748 +When you create a Core ML model, + +292 +00:14:41,748 --> 00:14:44,617 +that model has a set +of input and output features, + +293 +00:14:44,617 --> 00:14:47,220 +each with a type and size. + +294 +00:14:47,220 --> 00:14:50,590 +At runtime, you use Core ML APIs +to provide inputs + +295 +00:14:50,590 --> 00:14:52,792 +that conform with +the model's interface + +296 +00:14:52,792 --> 00:14:55,862 +and get outputs +after running inference. + +297 +00:14:55,862 --> 00:14:57,730 +Let me focus on images +and MultiArrays + +298 +00:14:57,730 --> 00:15:00,933 +in a bit more detail. + +299 +00:15:00,933 --> 00:15:04,203 +For images, Core ML supports +8-bit grayscale + +300 +00:15:04,203 --> 00:15:08,207 +and 32-bit color images +with 8 bits per component. + +301 +00:15:08,207 --> 00:15:10,143 +And for multidimensional arrays, + +302 +00:15:10,143 --> 00:15:13,880 +Core ML supports Int32, +Double, and Float32 + +303 +00:15:13,880 --> 00:15:16,082 +as the scalar types. + +304 +00:15:16,082 --> 00:15:18,317 +If your app is already working +with these types, + +305 +00:15:18,317 --> 00:15:21,354 +it's simply a matter of +connecting them to the model. + +306 +00:15:21,354 --> 00:15:24,056 +However, sometimes +your types may differ. + +307 +00:15:24,056 --> 00:15:26,325 +Let me show an example. + +308 +00:15:26,325 --> 00:15:28,661 +I'd like to add a new filter +to my image processing + +309 +00:15:28,661 --> 00:15:30,329 +and style app. + +310 +00:15:30,329 --> 00:15:31,998 +This filter works +to sharpen images + +311 +00:15:31,998 --> 00:15:35,134 +by operating on +a single-channel image. + +312 +00:15:35,134 --> 00:15:37,603 +My app has some pre- +and post-processing operations + +313 +00:15:37,603 --> 00:15:40,439 +on the GPU and represents +this single channel + +314 +00:15:40,439 --> 00:15:43,376 +in Float16 precision. + +315 +00:15:43,376 --> 00:15:46,312 +To do this, +I used coremltools to convert + +316 +00:15:46,312 --> 00:15:51,083 +an image-sharpening torch model +to Core ML format as shown here. + +317 +00:15:51,083 --> 00:15:54,954 +The model was set up to use +Float16 precision computation. + +318 +00:15:54,954 --> 00:15:59,525 +Also, it takes image inputs +and produces image outputs. + +319 +00:15:59,525 --> 00:16:02,628 +I got a model +that looks like this. + +320 +00:16:02,628 --> 00:16:04,831 +Note that it takes +grayscale images + +321 +00:16:04,831 --> 00:16:07,433 +which are 8-bit for Core ML. + +322 +00:16:07,433 --> 00:16:09,802 +To make this work, +I had to write some code + +323 +00:16:09,802 --> 00:16:12,972 +to downcast my input +from OneComponent16Half + +324 +00:16:12,972 --> 00:16:16,042 +to OneComponent8 +and then upcast the output + +325 +00:16:16,042 --> 00:16:19,946 +from OneComponent8 +to OneComponent16Half. + +326 +00:16:19,946 --> 00:16:22,815 +However, +this isn't the whole story. + +327 +00:16:22,815 --> 00:16:25,451 +Since the model was set up +to perform computation + +328 +00:16:25,451 --> 00:16:28,321 +in Float16 precision, +at some point, + +329 +00:16:28,321 --> 00:16:33,359 +Core ML needs to convert +these 8-bit inputs to Float16. + +330 +00:16:33,359 --> 00:16:35,127 +It does the conversion +efficiently, + +331 +00:16:35,127 --> 00:16:36,729 +but when looking +at an Instruments trace + +332 +00:16:36,729 --> 00:16:39,999 +with the app running, +it shows this. + +333 +00:16:39,999 --> 00:16:42,201 +Notice the data steps +Core ML is performing + +334 +00:16:42,201 --> 00:16:47,506 +before and after +Neural Engine computation. + +335 +00:16:47,506 --> 00:16:49,408 +When zooming in +on the Data lane, + +336 +00:16:49,408 --> 00:16:51,377 +it shows Core ML is copying data + +337 +00:16:51,377 --> 00:16:54,280 +to prepare it for computation +on the Neural Engine, + +338 +00:16:54,280 --> 00:16:57,817 +which means converting it +to Float16, in this case. + +339 +00:16:57,817 --> 00:16:59,952 +This seems unfortunate +since the original data + +340 +00:16:59,952 --> 00:17:02,555 +was already Float16. + +341 +00:17:02,555 --> 00:17:05,892 +Ideally, these data +transformations can be avoided + +342 +00:17:05,892 --> 00:17:09,562 +both in-app and inside Core ML +by making the model work + +343 +00:17:09,562 --> 00:17:12,832 +directly with Float16 +inputs and outputs. + +344 +00:17:12,832 --> 00:17:16,002 +Starting in iOS 16 +and macOS Ventura, + +345 +00:17:16,002 --> 00:17:17,770 +Core ML will have native support + +346 +00:17:17,770 --> 00:17:20,573 +for one OneComponent16Half +grayscale images, + +347 +00:17:20,573 --> 00:17:24,543 +and Float16 MultiArrays. + +348 +00:17:24,543 --> 00:17:27,179 +You can create a model +that accepts Float16 inputs + +349 +00:17:27,179 --> 00:17:30,650 +and outputs by specifying +a new color layout for images + +350 +00:17:30,650 --> 00:17:32,685 +or a new data type +for MultiArrays, + +351 +00:17:32,685 --> 00:17:36,088 +while invoking the coremltools +convert method. + +352 +00:17:36,088 --> 00:17:38,991 +In this case, I'm specifying +the input and output + +353 +00:17:38,991 --> 00:17:43,729 +of my model to be grayscale +Float16 images. + +354 +00:17:43,729 --> 00:17:45,798 +Since Float16 support +is available + +355 +00:17:45,798 --> 00:17:49,101 +starting in iOS 16 +and macOS Ventura, + +356 +00:17:49,101 --> 00:17:50,569 +these features +are only available + +357 +00:17:50,569 --> 00:17:56,375 +when the minimum deployment +target is specified as iOS 16. + +358 +00:17:56,375 --> 00:17:59,412 +This is how the reconverted +version of the model looks. + +359 +00:17:59,412 --> 00:18:04,183 +Note that the inputs and outputs +are marked as Grayscale16Half. + +360 +00:18:04,183 --> 00:18:05,918 +With this Float16 support, + +361 +00:18:05,918 --> 00:18:09,288 +my app can directly feed +Float16 images to Core ML, + +362 +00:18:09,288 --> 00:18:11,891 +which will avoid the need +for downcasting the inputs + +363 +00:18:11,891 --> 00:18:16,295 +and upcasting the outputs +in the app. + +364 +00:18:16,295 --> 00:18:18,798 +This is how it looks +in the code. + +365 +00:18:18,798 --> 00:18:20,800 +Since I have my input data +in the form + +366 +00:18:20,800 --> 00:18:24,103 +of a OneComponent16Half +CVPixelBuffer, + +367 +00:18:24,103 --> 00:18:25,771 +I can simply send +the pixel buffer + +368 +00:18:25,771 --> 00:18:27,773 +directly to Core ML. + +369 +00:18:27,773 --> 00:18:31,877 +This does not incur any +data copy or transformation. + +370 +00:18:31,877 --> 00:18:36,782 +I then get a OneComponent16Half +CVPixelBuffer as the output. + +371 +00:18:36,782 --> 00:18:38,384 +This results in simpler code, + +372 +00:18:38,384 --> 00:18:42,188 +and no data transformations +required. + +373 +00:18:42,188 --> 00:18:44,190 +There's also another cool thing +you can do, + +374 +00:18:44,190 --> 00:18:47,259 +and that's to ask Core ML to +fill your preallocated buffers + +375 +00:18:47,259 --> 00:18:50,062 +for outputs instead of having +Core ML allocate + +376 +00:18:50,062 --> 00:18:53,299 +a new buffer +for each prediction. + +377 +00:18:53,299 --> 00:18:56,302 +You can do this by allocating +an output backing buffer + +378 +00:18:56,302 --> 00:18:59,138 +and setting it +on the prediction options. + +379 +00:18:59,138 --> 00:19:02,675 +For my app, I wrote a function +called outputBackingBuffer + +380 +00:19:02,675 --> 00:19:06,679 +which returns a OneComponent1 +HalfCVPixelBuffer. + +381 +00:19:06,679 --> 00:19:08,714 +I then set this on +the prediction options, + +382 +00:19:08,714 --> 00:19:11,317 +and finally call the prediction +method on my model + +383 +00:19:11,317 --> 00:19:14,220 +with those prediction options. + +384 +00:19:14,220 --> 00:19:16,022 +By specifying output backings, + +385 +00:19:16,022 --> 00:19:18,524 +you can gain better control +over the buffer management + +386 +00:19:18,524 --> 00:19:21,427 +for model outputs. + +387 +00:19:21,427 --> 00:19:24,230 +So with those changes made, +to recap, + +388 +00:19:24,230 --> 00:19:26,198 +here's what was shown +in the Instruments trace + +389 +00:19:26,198 --> 00:19:28,334 +when using the original version +of the model + +390 +00:19:28,334 --> 00:19:31,837 +that had 8-bit inputs +and outputs. + +391 +00:19:31,837 --> 00:19:34,340 +And here's how the +final Instruments trace looks + +392 +00:19:34,340 --> 00:19:35,741 +after modifying the code + +393 +00:19:35,741 --> 00:19:38,844 +to provide IOSurface-backed +Float16 buffers + +394 +00:19:38,844 --> 00:19:42,415 +to the new Float16 version +of the model. + +395 +00:19:42,415 --> 00:19:44,617 +The data transformations +that were previously shown + +396 +00:19:44,617 --> 00:19:46,385 +in the Data lane are now gone, + +397 +00:19:46,385 --> 00:19:49,655 +since Core ML no longer +needs to perform them. + +398 +00:19:49,655 --> 00:19:53,659 +To summarize, Core ML now has +end-to-end native support + +399 +00:19:53,659 --> 00:19:55,828 +for Float16 data. + +400 +00:19:55,828 --> 00:19:59,365 +This means you can provide +Float16 inputs to Core ML + +401 +00:19:59,365 --> 00:20:03,135 +and have Core ML +give you back Float16 outputs. + +402 +00:20:03,135 --> 00:20:05,838 +You can also use the new +output backing API + +403 +00:20:05,838 --> 00:20:09,175 +to have Core ML fill up +your preallocated output buffers + +404 +00:20:09,175 --> 00:20:11,644 +instead of making new ones. + +405 +00:20:11,644 --> 00:20:13,212 +And lastly, we recommend + +406 +00:20:13,212 --> 00:20:16,415 +using IOSurface-backed buffers +whenever possible, + +407 +00:20:16,415 --> 00:20:18,818 +as this allows Core ML +to transfer the data + +408 +00:20:18,818 --> 00:20:21,654 +between different compute units +without data copies + +409 +00:20:21,654 --> 00:20:25,357 +by taking advantage +of the unified memory. + +410 +00:20:25,357 --> 00:20:26,826 +Next, I'll go through +a quick tour + +411 +00:20:26,826 --> 00:20:28,661 +of some of the additional +capabilities + +412 +00:20:28,661 --> 00:20:31,430 +being added to Core ML. + +413 +00:20:31,430 --> 00:20:33,732 +First is weight compression. + +414 +00:20:33,732 --> 00:20:35,768 +Compressing the weights +of your model may allow you + +415 +00:20:35,768 --> 00:20:39,939 +to achieve similar accuracy +while having a smaller model. + +416 +00:20:39,939 --> 00:20:43,976 +In iOS 12, Core ML introduced +post-training weight compression + +417 +00:20:43,976 --> 00:20:45,778 +which allows you +to reduce the size + +418 +00:20:45,778 --> 00:20:48,681 +of Core ML +neural network models. + +419 +00:20:48,681 --> 00:20:51,650 +We are now extending +16- and 8-bit support + +420 +00:20:51,650 --> 00:20:54,720 +to the ML Program model type, +and additionally, + +421 +00:20:54,720 --> 00:20:56,689 +introducing a new option +to store weights + +422 +00:20:56,689 --> 00:20:59,625 +in a sparse representation. + +423 +00:20:59,625 --> 00:21:01,527 +With coremltools utilities, + +424 +00:21:01,527 --> 00:21:04,396 +you will now be able +to quantize, palettize, + +425 +00:21:04,396 --> 00:21:09,535 +and sparsify the weights +for your ML Program models. + +426 +00:21:09,535 --> 00:21:12,905 +Next is a new +compute unit option. + +427 +00:21:12,905 --> 00:21:15,741 +Core ML always aims to minimize +inference latency + +428 +00:21:15,741 --> 00:21:18,110 +for the given +compute unit preference. + +429 +00:21:18,110 --> 00:21:20,346 +Apps can specify +this preference by setting + +430 +00:21:20,346 --> 00:21:24,450 +the MLModelConfiguration +computeUnits property. + +431 +00:21:24,450 --> 00:21:27,353 +In addition to the three +existing compute unit options, + +432 +00:21:27,353 --> 00:21:31,357 +there is now a new one +called cpuAndNeuralEngine. + +433 +00:21:31,357 --> 00:21:34,994 +This tells Core ML to not +dispatch computation on the GPU, + +434 +00:21:34,994 --> 00:21:37,363 +which can be helpful +when the app uses the GPU + +435 +00:21:37,363 --> 00:21:40,332 +for other computation +and, hence, prefers Core ML + +436 +00:21:40,332 --> 00:21:44,937 +to limit its focus to +the CPU and the Neural Engine. + +437 +00:21:44,937 --> 00:21:47,540 +Next, we are adding +a new way to initialize + +438 +00:21:47,540 --> 00:21:51,310 +your Core ML model instance that +provides additional flexibility + +439 +00:21:51,310 --> 00:21:54,780 +in terms of model serialization. + +440 +00:21:54,780 --> 00:21:56,982 +This allows you to encrypt +your model data + +441 +00:21:56,982 --> 00:21:58,617 +with custom encryption schemes + +442 +00:21:58,617 --> 00:22:01,387 +and decrypt it +just before loading. + +443 +00:22:01,387 --> 00:22:04,089 +With these new APIs, +you can compile and load + +444 +00:22:04,089 --> 00:22:06,792 +an in-memory +Core ML model specification + +445 +00:22:06,792 --> 00:22:11,931 +without requiring the compiled +model to be on disk. + +446 +00:22:11,931 --> 00:22:14,066 +The last update +is about Swift packages + +447 +00:22:14,066 --> 00:22:16,502 +and how they work with Core ML. + +448 +00:22:16,502 --> 00:22:18,704 +Packages are a great way +to bundle and distribute + +449 +00:22:18,704 --> 00:22:20,573 +reusable code. + +450 +00:22:20,573 --> 00:22:23,342 +With Xcode 14, +you can include Core ML models + +451 +00:22:23,342 --> 00:22:24,877 +in your Swift packages, + +452 +00:22:24,877 --> 00:22:27,012 +and now when someone +imports your package, + +453 +00:22:27,012 --> 00:22:28,881 +your model will just work. + +454 +00:22:28,881 --> 00:22:32,351 +Xcode will compile and bundle +your Core ML model automatically + +455 +00:22:32,351 --> 00:22:34,620 +and create the same +code-generation interface + +456 +00:22:34,620 --> 00:22:36,822 +you're used to working with. + +457 +00:22:36,822 --> 00:22:38,324 +We're excited about this change, + +458 +00:22:38,324 --> 00:22:40,693 +as it'll make it a lot easier +to distribute your models + +459 +00:22:40,693 --> 00:22:43,429 +in the Swift ecosystem. + +460 +00:22:43,429 --> 00:22:46,465 +That brings us to the end +of this session. + +461 +00:22:46,465 --> 00:22:49,868 +Core ML performance reports +and Instrument in Xcode 14 + +462 +00:22:49,868 --> 00:22:51,971 +are here to help you +analyze and optimize + +463 +00:22:51,971 --> 00:22:53,939 +the performance +of the ML-powered features + +464 +00:22:53,939 --> 00:22:56,175 +in your apps. + +465 +00:22:56,175 --> 00:22:59,111 +New Float16 support +and output backing APIs + +466 +00:22:59,111 --> 00:23:01,714 +gives you more control +of how data flows in and out + +467 +00:23:01,714 --> 00:23:03,949 +of Core ML. + +468 +00:23:03,949 --> 00:23:05,918 +Extended support +for weight compression + +469 +00:23:05,918 --> 00:23:09,288 +can help you minimize +the size of your models. + +470 +00:23:09,288 --> 00:23:12,024 +And with in-memory models +and Swift package support, + +471 +00:23:12,024 --> 00:23:13,993 +you have even more options +when it comes + +472 +00:23:13,993 --> 00:23:18,664 +to how you represent, integrate, +and share Core ML models. + +473 +00:23:18,664 --> 00:23:20,499 +This was Ben +from the Core ML team, + +474 +00:23:20,499 --> 00:23:22,334 +and have a great +rest of WWDC. + +475 +00:23:22,334 --> 00:23:26,405 +♪ + diff --git a/zho/2022 Session 10028 Create custom catalogs at scale with ShazamKit.srt b/zho/2022 Session 10028 Create custom catalogs at scale with ShazamKit.srt new file mode 100644 index 0000000..365d7d2 --- /dev/null +++ b/zho/2022 Session 10028 Create custom catalogs at scale with ShazamKit.srt @@ -0,0 +1,1397 @@ +1 +00:00:00,334 --> 00:00:06,340 +♪ instrumental hip hop music ♪ + +2 +00:00:09,309 --> 00:00:14,548 +Hello, I'm Neil Foley, +an engineer on the ShazamKit team. + +3 +00:00:14,581 --> 00:00:19,253 +In 2021, we introduced ShazamKit, +allowing you to match audio + +4 +00:00:19,286 --> 00:00:22,623 +against Shazam's +vast catalog of recorded music. + +5 +00:00:22,656 --> 00:00:25,759 +We also introduced custom catalog +matching, + +6 +00:00:25,792 --> 00:00:28,595 +giving developers the ability +to match their own audio + +7 +00:00:28,629 --> 00:00:31,532 +and provide synced experiences. + +8 +00:00:31,565 --> 00:00:34,134 +Now we have some important +updates that streamline + +9 +00:00:34,168 --> 00:00:37,304 +working with custom catalogs at scale. + +10 +00:00:37,337 --> 00:00:42,376 +In this session, I'm going to use +some of the existing ShazamKit concepts + +11 +00:00:42,409 --> 00:00:46,713 +such as signatures, +catalogs, and media items. + +12 +00:00:46,747 --> 00:00:48,715 +If you're not already familiar with those, + +13 +00:00:48,749 --> 00:00:50,951 +check out the "Explore ShazamKit” + +14 +00:00:50,984 --> 00:00:54,421 +and "Create custom audio experiences +with ShazamKit" talks + +15 +00:00:54,454 --> 00:00:57,357 +from WWDC21. + +16 +00:00:57,391 --> 00:01:01,929 +But as quick overview, +ShazamKit lets you convert audio + +17 +00:01:01,962 --> 00:01:04,198 +into a special format that can be matched. + +18 +00:01:04,231 --> 00:01:07,067 +We call these signatures. + +19 +00:01:07,100 --> 00:01:10,971 +Signatures can be combined +with media items containing metadata + +20 +00:01:11,004 --> 00:01:13,607 +to form a reference signature. + +21 +00:01:13,640 --> 00:01:16,743 +And reference signatures can +be stored together in a file + +22 +00:01:16,777 --> 00:01:19,279 +that we call a custom catalog. + +23 +00:01:19,313 --> 00:01:21,248 +Now that we are all caught up, + +24 +00:01:21,281 --> 00:01:24,384 +I'll take you through building +custom catalogs at scale, + +25 +00:01:24,418 --> 00:01:29,356 +and then I'll talk about some tips +and tricks to make great catalogs. + +26 +00:01:29,389 --> 00:01:32,025 +In today's custom catalog workflow, + +27 +00:01:32,059 --> 00:01:35,629 +if you have a small amount +of content you want to be matched, + +28 +00:01:35,662 --> 00:01:39,099 +working with custom catalogs +can be a simple task. + +29 +00:01:39,132 --> 00:01:42,236 +You just need to follow these steps. + +30 +00:01:42,269 --> 00:01:45,772 +Record your audio in a format +that ShazamKit accepts. + +31 +00:01:47,441 --> 00:01:50,811 +Use the signature generator +to transform it into a signature. + +32 +00:01:52,279 --> 00:01:54,381 +Annotate it with your metadata, + +33 +00:01:54,414 --> 00:01:57,117 +and then store it in a custom catalog. + +34 +00:01:57,150 --> 00:02:00,387 +And that's it, +you can provide a Shazam experience. + +35 +00:02:00,420 --> 00:02:02,890 +But some of those steps can be daunting, + +36 +00:02:02,923 --> 00:02:06,260 +especially if you're not familiar +with audio programming. + +37 +00:02:06,293 --> 00:02:09,997 +Dealing with sample rates and buffers +can be tricky + +38 +00:02:10,030 --> 00:02:12,399 +even for the most experienced developer. + +39 +00:02:12,432 --> 00:02:15,836 +And what happens when you have +a vast amount of content + +40 +00:02:15,869 --> 00:02:19,940 +you'd like to make Shazamable, +like 10 seasons of a TV show? + +41 +00:02:21,808 --> 00:02:24,144 +This workflow can become painful. + +42 +00:02:25,379 --> 00:02:29,616 +And if you have large amounts of content, +it can quickly become unmanageable. + +43 +00:02:30,150 --> 00:02:33,120 +If you're thinking of improving +this workflow for yourself, + +44 +00:02:33,153 --> 00:02:37,291 +you'll probably need to write code to +transform audio into signatures, + +45 +00:02:37,324 --> 00:02:40,961 +more code to load +and associate media items, + +46 +00:02:40,994 --> 00:02:44,865 +and each time you change your content, +you'll have to repeat the work. + +47 +00:02:44,898 --> 00:02:48,502 +This is a big investment +when you just want to match some audio. + +48 +00:02:48,902 --> 00:02:51,972 +And then if you want to sync content +with ShazamKit, + +49 +00:02:52,005 --> 00:02:56,143 +you need complicated logic to figure +out what should be shown and when. + +50 +00:02:56,176 --> 00:03:01,181 +I'll introduce some great enhancements to +ShazamKit that streamline this workflow. + +51 +00:03:01,215 --> 00:03:03,650 +But first a quick demo. + +52 +00:03:03,684 --> 00:03:08,722 +Here I have the FoodMath app that +Alex demonstrated in 2021 + +53 +00:03:08,755 --> 00:03:11,725 +that syncs a maths quiz +with an on screen lesson. + +54 +00:03:11,758 --> 00:03:14,628 +I've updated it with +the latest ShazamKit features, + +55 +00:03:14,661 --> 00:03:19,199 +and I'm going play back the FoodMath +video to see how it syncs. + +56 +00:03:21,502 --> 00:03:23,937 +Skip to 26 seconds. + +57 +00:03:24,872 --> 00:03:29,109 +2, 3 green apples. + +58 +00:03:29,142 --> 00:03:31,044 +How many apples do I have in total? + +59 +00:03:31,078 --> 00:03:34,281 +Your timer starts…now. + +60 +00:03:34,314 --> 00:03:38,685 +[light music] + +61 +00:03:38,719 --> 00:03:41,488 +Okay, time's up. +Let's see how you did. + +62 +00:03:41,522 --> 00:03:44,992 +Skip to 56 seconds. + +63 +00:03:45,025 --> 00:03:47,394 +Today, to spice it up a bit, + +64 +00:03:47,427 --> 00:03:51,164 +when I went to the shop, +started with 2 red apples... + +65 +00:03:51,198 --> 00:03:55,002 +and I bought 2 green apples. + +66 +00:03:55,035 --> 00:03:58,572 +How many apples did I have +in total this time? + +67 +00:03:58,605 --> 00:04:01,208 +Your timer starts…now. + +68 +00:04:07,214 --> 00:04:09,449 +Okay, time's up. + +69 +00:04:09,483 --> 00:04:10,417 +Seems to be working great. + +70 +00:04:11,351 --> 00:04:14,354 +There's rich content synced with the +video and when I said "now," + +71 +00:04:14,388 --> 00:04:17,658 +the menu appeared +at exactly the right time. + +72 +00:04:17,691 --> 00:04:22,496 +Also, when content was no longer +relevant, it disappeared right on cue. + +73 +00:04:22,529 --> 00:04:23,730 +But how does it work? + +74 +00:04:23,764 --> 00:04:26,333 +Let's have a look at the code. + +75 +00:04:26,366 --> 00:04:27,768 +There's just a simple loop. + +76 +00:04:27,801 --> 00:04:31,772 +It uses an AsyncSequence on the session +instead of the delegate callbacks + +77 +00:04:31,805 --> 00:04:33,774 +that we used before. + +78 +00:04:33,807 --> 00:04:38,679 +The sequence returns an enum +representing match, no match, or error. + +79 +00:04:38,712 --> 00:04:44,585 +I'm only interested in matches, so I've +restricted the loop to just that case. + +80 +00:04:44,618 --> 00:04:46,720 +And to build the result for display, + +81 +00:04:46,753 --> 00:04:49,857 +I reduce the media items +to the content that I need. + +82 +00:04:52,226 --> 00:04:54,595 +There's actually +not much more to see in the app, + +83 +00:04:54,628 --> 00:04:58,232 +just SwiftUI views that are driven by +the matchResult that we create. + +84 +00:04:58,265 --> 00:05:03,604 +There's no complicated logic or +timing code and it syncs perfectly. + +85 +00:05:03,637 --> 00:05:08,242 +So the question remains, +how does it sync so well? + +86 +00:05:08,275 --> 00:05:13,480 +FoodMaths' secret is the rich +custom catalog that drives the experience. + +87 +00:05:13,514 --> 00:05:19,052 +I created the catalog with a simple tool +that we've built to complement ShazamKit, + +88 +00:05:19,086 --> 00:05:24,091 +and you can use it too to create +rich experiences in your own apps. + +89 +00:05:24,124 --> 00:05:28,495 +The Shazam CLI ships as part of +macOS 13 + +90 +00:05:28,529 --> 00:05:32,065 +and provides an easy way to sync content. + +91 +00:05:32,099 --> 00:05:34,935 +It can help to automate +some of the repetitive tasks + +92 +00:05:34,968 --> 00:05:37,738 +associated with creating custom catalogs. + +93 +00:05:37,771 --> 00:05:41,308 +Let's update the custom catalog +that I just showed you. + +94 +00:05:41,341 --> 00:05:43,177 +Time for another demo. + +95 +00:05:45,812 --> 00:05:49,983 +Here's a folder containing +the FoodMath video file, + +96 +00:05:50,017 --> 00:05:52,719 +and here's my terminal in the same folder. + +97 +00:05:52,753 --> 00:05:56,256 +I'll use the CLI to convert +the video into a signature + +98 +00:05:56,290 --> 00:05:58,258 +using the signature command. + +99 +00:06:02,663 --> 00:06:07,701 +I just pass the video file as input +and specify our signature output. + +100 +00:06:11,104 --> 00:06:11,939 +Okay. There's our signature. + +101 +00:06:13,073 --> 00:06:16,176 +Now I want combine this signature +with media items + +102 +00:06:16,210 --> 00:06:18,612 +to make a custom catalog. + +103 +00:06:18,645 --> 00:06:21,715 +The CLI accepts a simple +comma separated file + +104 +00:06:21,748 --> 00:06:24,484 +for describing media items +that I'll copy here. + +105 +00:06:33,493 --> 00:06:36,496 +It describes everything +that I need to sync my content. + +106 +00:06:38,999 --> 00:06:43,237 +Here's where I've specified my titles, + +107 +00:06:43,270 --> 00:06:47,508 +and here's a custom JSON field +I've defined for the equation. + +108 +00:06:47,541 --> 00:06:50,644 +The headers map to media item +properties. + +109 +00:06:50,677 --> 00:06:55,249 +For details on the mapping, +run the custom catalog create command + +110 +00:06:55,282 --> 00:06:57,150 +with the help flag. + +111 +00:07:02,222 --> 00:07:07,928 +It describes the relationship between +the csv headers and media item properties. + +112 +00:07:07,961 --> 00:07:12,199 +Now I want to combine them +together into a custom catalog. + +113 +00:07:12,232 --> 00:07:14,701 +So I'll run the create command. + +114 +00:07:19,573 --> 00:07:24,745 +I pass in the signature file and the csv +file and it outputs a catalog. + +115 +00:07:28,282 --> 00:07:30,217 +Okay, now we have our catalog. + +116 +00:07:30,250 --> 00:07:34,788 +Excitingly, I have early access to +the latest FoodMath episode, + +117 +00:07:34,821 --> 00:07:37,691 +so I want to add that to our catalog file. + +118 +00:07:37,724 --> 00:07:39,793 +Let me copy the files here. + +119 +00:07:44,932 --> 00:07:47,501 +Here's our media items +for our new episode. + +120 +00:07:51,004 --> 00:07:54,107 +I'll run the update command +passing in the video, + +121 +00:07:54,141 --> 00:07:58,912 +the new media, and the catalog to update. + +122 +00:08:02,015 --> 00:08:05,052 +Okay, we've updated our catalog. + +123 +00:08:05,085 --> 00:08:08,255 +That's a quick overview +of how to create catalogs, + +124 +00:08:08,288 --> 00:08:12,659 +but if you're like me, +you'll really you'll want to script this. + +125 +00:08:20,701 --> 00:08:24,338 +The FoodMath app +actually has quite a few new episodes, + +126 +00:08:24,371 --> 00:08:27,174 +and I want to +add them all to this catalog. + +127 +00:08:27,207 --> 00:08:31,245 +I've written a really simple script +that loops through all the episode folders + +128 +00:08:31,278 --> 00:08:33,847 +and combines them into a custom catalog. + +129 +00:08:33,881 --> 00:08:35,582 +I'll run it now. + +130 +00:08:49,162 --> 00:08:50,931 +There we go. + +131 +00:08:50,964 --> 00:08:54,535 +We now have one catalog representing +every FoodMath episode + +132 +00:08:54,568 --> 00:09:00,507 +and the script used the display command +to detail what's inside the catalog. + +133 +00:09:00,541 --> 00:09:02,276 +I think we have everything. + +134 +00:09:02,309 --> 00:09:05,078 +The foodmath project is already +referencing our new catalog. + +135 +00:09:05,112 --> 00:09:08,549 +So let's build and run +so that we can enjoy doing some maths. + +136 +00:09:11,852 --> 00:09:14,655 +Skip to 30 seconds. + +137 +00:09:14,688 --> 00:09:16,723 +How many apples do I have in total? + +138 +00:09:16,757 --> 00:09:19,927 +Your timer starts…now. + +139 +00:09:19,960 --> 00:09:24,698 +[upbeat music] + +140 +00:09:24,731 --> 00:09:28,202 +Okay, time's up. +Let's see how you did. + +141 +00:09:28,235 --> 00:09:30,938 +I like that guy. +That's a great episode. + +142 +00:09:30,971 --> 00:09:34,107 +What about a new episode? +Let's try that. + +143 +00:09:37,311 --> 00:09:41,048 +Skip to 15 seconds. + +144 +00:09:41,081 --> 00:09:45,419 +Over the years, I explored what makes +a guacamole truly delicious, + +145 +00:09:45,452 --> 00:09:49,223 +and I wrote down my favorite +guacamole recipe. + +146 +00:09:49,256 --> 00:09:51,825 +It calls for 4 avocados. + +147 +00:09:51,859 --> 00:09:53,527 +Tomorrow +my friend is visiting. + +148 +00:09:53,560 --> 00:09:57,364 +So for the two of us, I only need +to make half of the portion. + +149 +00:09:57,397 --> 00:09:59,466 +How many avocados do I need? + +150 +00:09:59,499 --> 00:10:02,769 +The timer starts…now. + +151 +00:10:02,803 --> 00:10:07,541 +[rapid beeping] + +152 +00:10:10,077 --> 00:10:12,913 +That's correct. +You need two avocados. + +153 +00:10:12,946 --> 00:10:16,049 +Let's make this guacamole together. + +154 +00:10:16,083 --> 00:10:22,256 +[upbeat music] + +155 +00:10:24,358 --> 00:10:26,260 +Let's give this a try. + +156 +00:10:30,631 --> 00:10:33,734 +Mmm. That turned out to be great. +I hope you had some fun + +157 +00:10:33,767 --> 00:10:36,236 +and see you next time. + +158 +00:10:40,140 --> 00:10:41,341 +Oh! + +159 +00:10:41,375 --> 00:10:43,644 +They have a new host. +Interesting. + +160 +00:10:43,677 --> 00:10:48,415 +Anyway, I've created a rich synced +experience in no time at all. + +161 +00:10:48,448 --> 00:10:51,451 +The Shazam CLI supports +a rich set of commands. + +162 +00:10:51,485 --> 00:10:52,819 +Let's go over them. + +163 +00:10:54,021 --> 00:10:56,657 +You can create a signature +from any media file + +164 +00:10:56,690 --> 00:10:58,759 +that has an audio track. + +165 +00:10:58,792 --> 00:11:00,294 +You can create custom catalogs + +166 +00:11:00,327 --> 00:11:03,564 +by combining signatures and media items. + +167 +00:11:03,597 --> 00:11:06,700 +You can display a catalog's content. + +168 +00:11:06,733 --> 00:11:09,503 +Add, remove, and export both signatures + +169 +00:11:09,536 --> 00:11:11,939 +and media items. + +170 +00:11:11,972 --> 00:11:14,107 +Next, on to how the CLI created + +171 +00:11:14,141 --> 00:11:16,476 +the signatures from the FoodMath videos. + +172 +00:11:18,745 --> 00:11:23,984 +SHSignatureGenerator now has +a method signatureFromAsset + +173 +00:11:24,017 --> 00:11:26,954 +that's available on all platforms. + +174 +00:11:26,987 --> 00:11:31,592 +With this method, there's no more manually +pulling audio buffers from media. + +175 +00:11:31,625 --> 00:11:37,531 +Simply pass an AVAsset with an +audio track to turn it into a signature. + +176 +00:11:37,564 --> 00:11:40,801 +If you have multiple tracks in +your asset, they'll be mixed together + +177 +00:11:40,834 --> 00:11:44,037 +ensuring the signature +captures everything. + +178 +00:11:44,071 --> 00:11:48,075 +Okay, now that I have a signature +that represents the media, + +179 +00:11:48,108 --> 00:11:51,545 +how did I accurately sync content? + +180 +00:11:51,578 --> 00:11:54,414 +I used the Timed MediaItem API. + +181 +00:11:54,448 --> 00:11:58,752 +Attaching a time range to the media +item makes it easy to specify + +182 +00:11:58,785 --> 00:12:01,321 +when it starts and when it ends. + +183 +00:12:01,355 --> 00:12:04,491 +Media items can also have +multiple time ranges + +184 +00:12:04,525 --> 00:12:08,862 +to target more than +one portion of a signature. + +185 +00:12:08,896 --> 00:12:12,966 +Imagine that you have a media item +that targets the chorus of a song. + +186 +00:12:13,000 --> 00:12:15,802 +You can add a time range +for each place it's sung. + +187 +00:12:16,970 --> 00:12:19,840 +Specifying the time ranges is only useful + +188 +00:12:19,873 --> 00:12:23,610 +if you're notified when they start +and when they end. + +189 +00:12:23,644 --> 00:12:27,481 +ShazamKit will deliver a match +callback synced with the time range, + +190 +00:12:27,514 --> 00:12:30,784 +one when it starts and one when it ends. + +191 +00:12:30,817 --> 00:12:35,689 +Signatures can contain many media items, +so this callback will contain only + +192 +00:12:35,722 --> 00:12:40,661 +the media items that are in range +at that specific point in time. + +193 +00:12:40,694 --> 00:12:44,398 +There's a few simple rules for which +media items will be returned + +194 +00:12:44,431 --> 00:12:47,901 +in a callback and their order, +so let's go over them. + +195 +00:12:49,269 --> 00:12:54,174 +Media items outside of their time range +will not be returned. + +196 +00:12:54,208 --> 00:12:57,444 +Media items within their +time range will be returned, + +197 +00:12:57,477 --> 00:13:00,013 +with the most recent events +coming first. + +198 +00:13:01,348 --> 00:13:06,420 +And finally, media items with no time +ranges will always be returned last, + +199 +00:13:06,453 --> 00:13:09,056 +but they will be unordered. + +200 +00:13:09,089 --> 00:13:11,592 +Media items that have no time range +can be a great place + +201 +00:13:11,625 --> 00:13:15,963 +to store global information that applies +to the whole reference signature. + +202 +00:13:15,996 --> 00:13:20,501 +In my FoodMath example, I used it +to store the name of the episode. + +203 +00:13:20,534 --> 00:13:23,904 +It appears when no other +media items are in range. + +204 +00:13:25,939 --> 00:13:30,577 +One final point, if all your media items +have time ranges + +205 +00:13:30,611 --> 00:13:32,212 +and none of them are in scope, + +206 +00:13:32,246 --> 00:13:37,351 +ShazamKit will always return a +media item with basic match information. + +207 +00:13:37,384 --> 00:13:40,254 +This way, you will always +get important properties, + +208 +00:13:40,287 --> 00:13:45,259 +such as the predictedCurrentMatch offset +and the frequencySkew. + +209 +00:13:46,026 --> 00:13:49,062 +And in code, it's easy too. + +210 +00:13:49,096 --> 00:13:52,099 +Timed media items +are created by specifying + +211 +00:13:52,132 --> 00:13:55,035 +the timeRanges media item property. + +212 +00:13:55,068 --> 00:13:58,405 +It's an array of Swift ranges. + +213 +00:13:58,438 --> 00:14:02,409 +It can also be read back +using the timeRanges property. + +214 +00:14:02,442 --> 00:14:05,946 +And for Objective-C programmers, +there's a new SHRange class + +215 +00:14:05,979 --> 00:14:08,482 +as a drop in replacement. + +216 +00:14:08,515 --> 00:14:10,717 +Now that you've +seen how to build them, + +217 +00:14:10,751 --> 00:14:15,989 +let's explore some tips and tricks +to make great custom catalogs. + +218 +00:14:16,023 --> 00:14:21,028 +Avoid creating many small signatures +for one piece of media. + +219 +00:14:21,061 --> 00:14:25,399 +A signature is a one to one +mapping to the media that it represents, + +220 +00:14:25,432 --> 00:14:30,737 +so for each piece of audio you have, +be it from a song or video, + +221 +00:14:30,771 --> 00:14:33,774 +create one signature +for the entire duration. + +222 +00:14:34,975 --> 00:14:38,445 +A longer signature provides more +opportunities for ShazamKit to match + +223 +00:14:38,478 --> 00:14:41,615 +audio peaks, resulting in better +accuracy. + +224 +00:14:42,149 --> 00:14:45,052 +It also avoids issues +with query signatures + +225 +00:14:45,085 --> 00:14:48,488 +overlapping multiple reference signatures. + +226 +00:14:50,023 --> 00:14:52,593 +Using the new Timed MediaItem API, + +227 +00:14:52,626 --> 00:14:55,529 +you can target synced content +to individual areas. + +228 +00:14:55,562 --> 00:15:01,101 +There's no need to divide a piece +of audio into multiple signatures. + +229 +00:15:01,134 --> 00:15:04,204 +I showed an example where we +had one piece of media, + +230 +00:15:04,238 --> 00:15:06,373 +but with multiple media items. + +231 +00:15:06,406 --> 00:15:09,443 +But what should we do if we have +a huge amount of content + +232 +00:15:09,476 --> 00:15:11,979 +that we want to make Shazamable? + +233 +00:15:12,012 --> 00:15:14,414 +How should we split it up? + +234 +00:15:14,448 --> 00:15:18,285 +There's a trade-off you need +to make when splitting your content + +235 +00:15:18,318 --> 00:15:20,621 +across custom catalogs. + +236 +00:15:20,654 --> 00:15:23,924 +If you create individual catalogs +for each media asset, + +237 +00:15:23,957 --> 00:15:27,060 +you'll need to know +which piece of audio is being played + +238 +00:15:27,094 --> 00:15:30,197 +so that you can load the correct catalog. + +239 +00:15:30,230 --> 00:15:32,833 +And if you put them all together +in one catalog, + +240 +00:15:32,866 --> 00:15:35,869 +you'll have a larger download +and use more memory, + +241 +00:15:35,903 --> 00:15:39,239 +but you can match +many more pieces of audio. + +242 +00:15:39,273 --> 00:15:44,244 +Our advice is to keep the catalog +files you create tightly focused. + +243 +00:15:44,278 --> 00:15:48,615 +For example, a catalog per music +track or the whole album, + +244 +00:15:48,649 --> 00:15:51,485 +but not the artist's whole discography. + +245 +00:15:51,518 --> 00:15:56,757 +Keeping things separate means that you +can decide what to load at runtime. + +246 +00:15:56,790 --> 00:16:00,627 +You can do that with the custom +catalog add API. + +247 +00:16:02,062 --> 00:16:06,867 +Try it out +and see if helps with your use case. + +248 +00:16:06,900 --> 00:16:11,572 +If you have multiple audio +assets that sound the same, + +249 +00:16:11,605 --> 00:16:15,709 +maybe a show that always starts with +the same intro music, and you want to + +250 +00:16:15,742 --> 00:16:18,312 +provide a custom experience +for each episode, + +251 +00:16:18,345 --> 00:16:21,648 +or a song that's sampled in another track, + +252 +00:16:21,682 --> 00:16:25,285 +maybe consider using +frequency skew as a differentiator. + +253 +00:16:25,319 --> 00:16:30,190 +Skewing audio is raising or +lowing the frequencies in the recording. + +254 +00:16:30,224 --> 00:16:33,427 +When you do this, +you affect how the audio sounds, + +255 +00:16:33,460 --> 00:16:37,965 +but if you do it by a small enough amount, +it can be noticed by ShazamKit + +256 +00:16:37,998 --> 00:16:39,833 +but not by the average human ear. + +257 +00:16:40,801 --> 00:16:42,503 +So if we take an audio recording, + +258 +00:16:42,536 --> 00:16:45,672 +make a custom catalog from it, +and then play it back + +259 +00:16:45,706 --> 00:16:50,143 +with the frequencies slightly shifted: +ShazamKit will still match the audio, + +260 +00:16:50,177 --> 00:16:54,681 +and it will also report the skew amount +through the frequencySkew property. + +261 +00:16:54,715 --> 00:16:56,817 +Here's how to do that in code. + +262 +00:16:58,452 --> 00:17:01,088 +There are limits to how much +you can skew audio + +263 +00:17:01,121 --> 00:17:05,025 +without the change becoming +either noticeable to the human ear + +264 +00:17:05,058 --> 00:17:05,893 +or unrecognizable to ShazamKit. + +265 +00:17:08,595 --> 00:17:11,899 +Keeping the skew +to less than 5 percent should be safe + +266 +00:17:11,932 --> 00:17:16,970 +and provide enough room to +differentiate multiple skewed recordings. + +267 +00:17:17,004 --> 00:17:21,608 +To really take advantage of this, +use the frequencySkew ranges. + +268 +00:17:21,642 --> 00:17:25,012 +Media items will only be +returned if they fall inside + +269 +00:17:25,045 --> 00:17:26,446 +the specified skew ranges. + +270 +00:17:27,781 --> 00:17:29,883 +The range specifies as a percentage + +271 +00:17:29,917 --> 00:17:33,153 +how much the audio +differs from the original. + +272 +00:17:33,187 --> 00:17:38,425 +A value of 0 indicates the +audio is unskewed and a value of .01 + +273 +00:17:38,458 --> 00:17:40,928 +indicates a 1 percent skew. + +274 +00:17:41,528 --> 00:17:46,300 +You can access the property on media items +using the frequencySkewRanges property. + +275 +00:17:48,268 --> 00:17:51,471 +I'll go over the steps to +get this working in your app: + +276 +00:17:51,505 --> 00:17:56,376 +First create a reference signature +of your original audio recording. + +277 +00:17:56,410 --> 00:18:03,183 +Then take a media item and restrict it +by frequency skew to 3 to 4 percent. + +278 +00:18:03,217 --> 00:18:04,618 +Place this inside your custom catalog. + +279 +00:18:05,986 --> 00:18:10,390 +Now play back the audio skewed +by 3 to 4 percent, + +280 +00:18:10,424 --> 00:18:13,260 +and your media item will be returned. + +281 +00:18:13,293 --> 00:18:16,463 +Playing back the audio unskewed +or skewed outside of the range + +282 +00:18:16,496 --> 00:18:18,665 +will not return your media item. + +283 +00:18:18,699 --> 00:18:20,667 +That's frequency skewing. + +284 +00:18:22,002 --> 00:18:25,439 +Now that you've seen the exciting updates +to ShazamKit this year, + +285 +00:18:25,472 --> 00:18:29,009 +you're ready to make +some amazing synced experiences. + +286 +00:18:29,042 --> 00:18:31,311 +So remember these best practices: + +287 +00:18:31,345 --> 00:18:35,182 +First, create one signature +per media asset. + +288 +00:18:35,215 --> 00:18:41,054 +You'll get better accuracy from +ShazamKit and simpler creation pipeline. + +289 +00:18:41,088 --> 00:18:44,191 +Create your signatures +with SHSignatureGenerators + +290 +00:18:44,224 --> 00:18:46,560 +signatureFromAsset. + +291 +00:18:46,593 --> 00:18:48,929 +It accepts a wide variety of media, + +292 +00:18:48,962 --> 00:18:52,566 +meaning you no longer have +to deal with low level audio details. + +293 +00:18:54,568 --> 00:19:00,507 +Target synced content to areas of interest +with the new Timed MediaItem API. + +294 +00:19:00,541 --> 00:19:05,179 +It combines a simple API +with excellent accuracy. + +295 +00:19:05,212 --> 00:19:10,851 +And finally let the Shazam CLI streamline +the way you create custom catalogs. + +296 +00:19:10,884 --> 00:19:15,622 +It's been designed take away the hassle +of dealing with vast amounts of media + +297 +00:19:15,656 --> 00:19:20,694 +and let you focus on the great +experiences you want to make instead. + +298 +00:19:20,727 --> 00:19:23,664 +I hope you enjoyed the latest updates +to ShazamKit, + +299 +00:19:23,697 --> 00:19:27,034 +and I'm excited to see you +make everything Shazamable. + +300 +00:19:27,067 --> 00:19:30,771 +All of the information we discussed +and links to documentation + +301 +00:19:30,804 --> 00:19:32,639 +are attached to this session. + +302 +00:19:32,673 --> 00:19:37,211 +Thanks for joining. +Enjoy the rest of WWDC22. ♪ ♪ + diff --git a/zho/2022 Session 10032 Dive into App Intents.srt b/zho/2022 Session 10032 Dive into App Intents.srt new file mode 100644 index 0000000..0d5e21b --- /dev/null +++ b/zho/2022 Session 10032 Dive into App Intents.srt @@ -0,0 +1,2768 @@ +1 +00:00:00,000 --> 00:00:03,737 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,737 --> 00:00:09,543 +♪ + +3 +00:00:09,543 --> 00:00:11,745 +嗨 朋友们 我是 +Michael Gorbach + +4 +00:00:11,745 --> 00:00:13,714 +来自快捷指令工程团队 + +5 +00:00:13,714 --> 00:00:17,117 +感谢您收看本次对 +App Intents 的深度解析 + +6 +00:00:17,117 --> 00:00:18,118 +App Intents 是 +我们新推出的框架 + +7 +00:00:18,118 --> 00:00:22,489 +用于向系统注册 App 的功能 + +8 +00:00:22,489 --> 00:00:24,224 +以下是今天深度解析讲座的安排 + +9 +00:00:24,224 --> 00:00:26,159 +简单介绍后 + +10 +00:00:26,159 --> 00:00:28,729 +我将讨论意图及其参数 + +11 +00:00:28,729 --> 00:00:31,431 +以及应该如何定义实体 + +12 +00:00:31,431 --> 00:00:33,834 +我将介绍几种您可以创建的 + +13 +00:00:33,834 --> 00:00:35,102 +强大的搜索和过滤功能 + +14 +00:00:35,102 --> 00:00:38,472 +以及您的意图如何与用户进行交互 + +15 +00:00:38,472 --> 00:00:43,277 +最后 我会谈一谈 App Intents +架构和生命周期 + +16 +00:00:43,277 --> 00:00:45,913 +让我们从头开始 + +17 +00:00:45,913 --> 00:00:49,683 +在 iOS 10 中 我们 +引入了 SiriKit Intents 框架 + +18 +00:00:49,683 --> 00:00:51,952 +它可以让您将 App 的功能 + +19 +00:00:51,952 --> 00:00:56,690 +连接到 Siri 域 +例如消息传递 锻炼和支付 + +20 +00:00:56,690 --> 00:00:59,193 +现在我们将引入一个新框架 + +21 +00:00:59,193 --> 00:01:01,528 +它就是 App Intents + +22 +00:01:01,528 --> 00:01:04,097 +它有三个关键组成部分 + +23 +00:01:04,097 --> 00:01:06,400 +意图是内置于 App 中的操作 + +24 +00:01:06,400 --> 00:01:08,602 +它们可以在整个系统中使用 + +25 +00:01:08,602 --> 00:01:12,906 +意图使用实体 +来表述 App 的概念 + +26 +00:01:12,906 --> 00:01:15,175 +App 快捷指令包装意图 + +27 +00:01:15,175 --> 00:01:18,378 +使它们自动化并可被发现 + +28 +00:01:18,378 --> 00:01:19,980 +让我们来谈谈 + +29 +00:01:19,980 --> 00:01:22,583 +利用 App Intents +使您的 App 功能 + +30 +00:01:22,583 --> 00:01:26,653 +在更多地方可用 +并让您的用户受益的几种方法 + +31 +00:01:26,653 --> 00:01:28,755 +借助 App 快捷指令 +每个人都可以 + +32 +00:01:28,755 --> 00:01:31,592 +通过 Siri +以声音使用 App 的功能 + +33 +00:01:31,592 --> 00:01:34,928 +无需提前设置任何东西 + +34 +00:01:34,928 --> 00:01:38,398 +相同的采用方式 +也在用户搜索您的 App + +35 +00:01:38,398 --> 00:01:42,135 +以及您的 App 得到推荐时 +使意图出现在 Spotlight 中 + +36 +00:01:42,135 --> 00:01:45,873 +这将使您的工作处于核心位置 + +37 +00:01:45,873 --> 00:01:49,576 +使用 App Intents +您还可以创建“焦点筛选” + +38 +00:01:49,576 --> 00:01:53,947 +让客户能够针对特定的“焦点” +对您的 App 进行自定义 + +39 +00:01:53,947 --> 00:01:56,450 +例如 他们可能会将 +自己的“日历”App 设置为 + +40 +00:01:56,450 --> 00:02:01,021 +仅在实际工作时显示工作日历 + +41 +00:02:01,021 --> 00:02:02,923 +您可以查看这个讲座来了解更多关于 + +42 +00:02:02,923 --> 00:02:06,660 +如何运用“焦点筛选”的信息 + +43 +00:02:06,660 --> 00:02:08,161 +使用 App 快捷指令 + +44 +00:02:08,161 --> 00:02:11,298 +您的意图会自动 +显示在“快捷指令”App 中 + +45 +00:02:11,298 --> 00:02:14,201 +无需手动添加 + +46 +00:02:14,201 --> 00:02:16,737 +将操作集成到“快捷指令”中 + +47 +00:02:16,737 --> 00:02:18,939 +对客户来说非常有价值 + +48 +00:02:18,939 --> 00:02:20,674 +因为他们可以通过运行快捷指令 + +49 +00:02:20,674 --> 00:02:22,876 +使用您的 App 来自 + +50 +00:02:22,876 --> 00:02:25,913 +整个系统各个位置的功能 + +51 +00:02:25,913 --> 00:02:28,882 +在主屏幕上轻点一下 +即可运行快捷指令 + +52 +00:02:28,882 --> 00:02:32,386 +也可通过 macOS 的菜单栏 +以及其他众多方式运行 + +53 +00:02:32,386 --> 00:02:34,955 +甚至可以通过自动化设置 + +54 +00:02:34,955 --> 00:02:37,991 +使快捷指令自动运行 + +55 +00:02:37,991 --> 00:02:40,727 +将您的 App 接入 +整个“快捷指令”生态系统 + +56 +00:02:40,727 --> 00:02:43,297 +借助 Apple 的 +一系列 App + +57 +00:02:43,297 --> 00:02:46,366 +和其他开发者的强大力量 + +58 +00:02:46,366 --> 00:02:49,236 +对快捷指令进行支持 + +59 +00:02:49,236 --> 00:02:51,271 +将使您的 App 威力倍增 + +60 +00:02:51,271 --> 00:02:53,874 +这是因为快捷指令可以组合 + +61 +00:02:53,874 --> 00:02:55,242 +来自多个 App 的操作 + +62 +00:02:55,242 --> 00:02:59,046 +让用户创造出全新的特性和功能 + +63 +00:02:59,046 --> 00:03:02,816 +而无需您进行任何开发 + +64 +00:03:02,816 --> 00:03:05,052 +如果想学习如何使操作 + +65 +00:03:05,052 --> 00:03:08,655 +与他人配合默契并无缝融入生态系统 + +66 +00:03:08,655 --> 00:03:11,191 +请查看我们的设计演讲 + +67 +00:03:11,191 --> 00:03:13,026 +我们创建 +App Intents 的目标 + +68 +00:03:13,026 --> 00:03:16,163 +是为了让它的开发成为一种快乐 + +69 +00:03:16,163 --> 00:03:18,599 +App Intents 十分简洁 + +70 +00:03:18,599 --> 00:03:21,668 +编写一个简单的意图 +只需要几行代码 + +71 +00:03:21,668 --> 00:03:23,871 +但 API 也可扩展出 + +72 +00:03:23,871 --> 00:03:27,374 +更深入和更定制化的操作 + +73 +00:03:27,374 --> 00:03:29,276 +App Intents 非常现代化 + +74 +00:03:29,276 --> 00:03:30,644 +我们对 Swift 全力投入 + +75 +00:03:30,644 --> 00:03:33,213 +充分利用结果构建器 属性包装器 + +76 +00:03:33,213 --> 00:03:36,049 +面向协议的编程和通用算法 + +77 +00:03:36,049 --> 00:03:37,851 +没有尖端的语言特性 + +78 +00:03:37,851 --> 00:03:41,221 +这些 API 根本不可能存在 + +79 +00:03:41,221 --> 00:03:43,624 +使用 App Intents 也很容易 + +80 +00:03:43,624 --> 00:03:45,259 +因为它既不要求重新架构 + +81 +00:03:45,259 --> 00:03:49,029 +您的产品和目标 也不需要创建框架 + +82 +00:03:49,029 --> 00:03:50,697 +它不需要扩展 + +83 +00:03:50,697 --> 00:03:53,233 +并且可以直接应用于您的 App + +84 +00:03:53,233 --> 00:03:55,802 +同时 App Intents +代码是可维护的 + +85 +00:03:55,802 --> 00:03:58,605 +与 SwiftUI 一样 +App Intents 将您的代码 + +86 +00:03:58,605 --> 00:04:00,574 +视作事实的根本来源 + +87 +00:04:00,574 --> 00:04:04,578 +避免了对独立编辑器 +或定义文件的需求 + +88 +00:04:04,578 --> 00:04:07,881 +让您可以快速创建和迭代采用 + +89 +00:04:07,881 --> 00:04:09,082 +并简化维护 + +90 +00:04:09,082 --> 00:04:12,452 +因为它们都在同一个位置 + +91 +00:04:12,452 --> 00:04:15,389 +话说回来 让我们来 +探讨一下这些新 API + +92 +00:04:15,389 --> 00:04:16,790 +就从意图开始 + +93 +00:04:16,790 --> 00:04:19,960 +它我们新框架的核心组成部分 + +94 +00:04:19,960 --> 00:04:22,663 +App 意图 或简称“意图” + +95 +00:04:22,663 --> 00:04:25,265 +是一个单体的 独立的功能单元 + +96 +00:04:25,265 --> 00:04:27,634 +由您的 App 向系统公开 + +97 +00:04:27,634 --> 00:04:30,537 +比如说 一个意图可以 +创建一个新的日历事件 + +98 +00:04:30,537 --> 00:04:34,007 +打开一个特定的屏幕 +或者下一份订单 + +99 +00:04:34,007 --> 00:04:37,277 +意图可以根据用户请求运行 + +100 +00:04:37,277 --> 00:04:40,180 +例如通过快捷指令或询问 Siri + +101 +00:04:40,180 --> 00:04:41,348 +也可以是自动的 + +102 +00:04:41,348 --> 00:04:45,319 +例如使用“焦点筛选” +或自动化“快捷指令” + +103 +00:04:45,319 --> 00:04:46,587 +当意图运行之后 + +104 +00:04:46,587 --> 00:04:51,024 +要么返回结果 要么出现错误 + +105 +00:04:51,024 --> 00:04:54,294 +意图包含三个关键部分 + +106 +00:04:54,294 --> 00:04:56,797 +元数据 也就是有关意图的信息 + +107 +00:04:56,797 --> 00:04:59,066 +也包括本地化的标题 + +108 +00:04:59,066 --> 00:05:01,802 +参数 这是意图运行时可以使用的 + +109 +00:05:01,802 --> 00:05:03,036 +输入值 + +110 +00:05:03,036 --> 00:05:05,572 +还有 perform 方法 它负责 + +111 +00:05:05,572 --> 00:05:09,042 +意图被执行时的实际工作 + +112 +00:05:09,042 --> 00:05:11,945 +今天我们将从这个“图书馆” +App 出发进行讨论 + +113 +00:05:11,945 --> 00:05:13,480 +因为我很痴迷读书 + +114 +00:05:13,480 --> 00:05:15,516 +这个 App 完全是 +用于追踪我读过的书 + +115 +00:05:15,516 --> 00:05:18,485 +以及想读或正在读的书 + +116 +00:05:18,485 --> 00:05:21,421 +每个类别都作为 +单独选项卡显示在 App 中 + +117 +00:05:21,421 --> 00:05:24,391 +我称这些选项卡为“书架” + +118 +00:05:24,391 --> 00:05:26,593 +我的用户随时都在访问 + +119 +00:05:26,593 --> 00:05:27,694 +“正在阅读”书架 + +120 +00:05:27,694 --> 00:05:29,897 +所以我要公开一个 App 意图 + +121 +00:05:29,897 --> 00:05:34,034 +让打开书架变得更快 更方便 + +122 +00:05:34,034 --> 00:05:36,970 +我准备在这里创建一个 +OpenCurrentlyReading 意图 + +123 +00:05:36,970 --> 00:05:38,472 +通过定义一个 +符合 AppIntent 协议的 + +124 +00:05:38,472 --> 00:05:41,975 +Swift 结构来实现 + +125 +00:05:41,975 --> 00:05:45,479 +我只需要实施一种方法 +即 perform + +126 +00:05:45,479 --> 00:05:48,949 +我的 App 中已经有了 +可以打开标签的导航器 + +127 +00:05:48,949 --> 00:05:50,317 +所以对我来说 实现意图 + +128 +00:05:50,317 --> 00:05:52,853 +只是几行代码的事 + +129 +00:05:52,853 --> 00:05:55,756 +我将使用 @MainActor +来注释 perform 方法 + +130 +00:05:55,756 --> 00:05:59,860 +因为我的导航器需要主线程 + +131 +00:05:59,860 --> 00:06:02,663 +我的意图也需要一个标题 + +132 +00:06:02,663 --> 00:06:04,631 +和我今天要展示的其他字符串一样 + +133 +00:06:04,631 --> 00:06:06,300 +如果将键添加到字符串文件中 + +134 +00:06:06,300 --> 00:06:09,136 +它将自动本地化 + +135 +00:06:09,136 --> 00:06:13,907 +要让一个基本的 App 意图生效 +我只需要做这些就够了 + +136 +00:06:13,907 --> 00:06:15,776 +由于我已经在代码中定义了它 + +137 +00:06:15,776 --> 00:06:19,179 +它将自动出现在快捷指令编辑器中 + +138 +00:06:19,179 --> 00:06:24,084 +在这里 用户可以将它 +添加到快捷指令 + +139 +00:06:24,084 --> 00:06:27,621 +仅仅公开意图 +就可以带来巨大的影响力 + +140 +00:06:27,621 --> 00:06:30,424 +因为一旦客户把意图变成快捷指令 + +141 +00:06:30,424 --> 00:06:33,293 +它就可以在系统中的多个位置使用 + +142 +00:06:33,293 --> 00:06:36,129 +包括屏幕上所有这些 + +143 +00:06:36,129 --> 00:06:39,099 +为了让我的新意图更容易 +得到使用和发现 + +144 +00:06:39,099 --> 00:06:41,635 +我还将添加 +对 App 快捷指令的支持 + +145 +00:06:41,635 --> 00:06:43,003 +只需要一点代码 + +146 +00:06:43,003 --> 00:06:46,240 +我就可以让意图在 +Spotlight 和“快捷指令”App 中 + +147 +00:06:46,240 --> 00:06:47,841 +中自动显示 + +148 +00:06:47,841 --> 00:06:51,044 +我还可以定义用户在借助声音 + +149 +00:06:51,044 --> 00:06:53,981 +使用这个意图时 +对 Siri 说的短语 + +150 +00:06:53,981 --> 00:06:56,517 +请查看“使用 App Intents +实现 App 快捷指令”讲座 + +151 +00:06:56,517 --> 00:07:00,487 +获取全部详细信息 + +152 +00:07:00,487 --> 00:07:02,322 +现在 我已经公开了一个 + +153 +00:07:02,322 --> 00:07:05,025 +可以打开“正在阅读”书架的意图 + +154 +00:07:05,025 --> 00:07:06,860 +接下来 让我们对它进行泛化 + +155 +00:07:06,860 --> 00:07:12,432 +添加一个参数 +使它可以打开任意书架 + +156 +00:07:12,432 --> 00:07:15,235 +我有一个代表货架的枚举 + +157 +00:07:15,235 --> 00:07:17,671 +为了将其用作意图参数 + +158 +00:07:17,671 --> 00:07:21,175 +我需要使它符合 +AppEnum 协议 + +159 +00:07:21,175 --> 00:07:24,044 +AppEnum 需要 +一个字符串原始值 + +160 +00:07:24,044 --> 00:07:26,413 +所以我先把它加上 + +161 +00:07:26,413 --> 00:07:28,916 +它还要求我为每个枚举案例 + +162 +00:07:28,916 --> 00:07:32,753 +提供可本地化的 人可读的标题 + +163 +00:07:32,753 --> 00:07:35,189 +这些必须作为字典文字提供 + +164 +00:07:35,189 --> 00:07:39,626 +因为编译器将在构建时读取此代码 + +165 +00:07:39,626 --> 00:07:42,095 +最后 我将添加 +typeDisplayName + +166 +00:07:42,095 --> 00:07:44,398 +将枚举类型视作一个整体的 + +167 +00:07:44,398 --> 00:07:47,000 +一种用户可见的 可本地化的名称 + +168 +00:07:47,000 --> 00:07:49,436 +我将使用“书架” + +169 +00:07:49,436 --> 00:07:51,939 +在一个意图中 每个参数都借助 + +170 +00:07:51,939 --> 00:07:54,408 +@Parameter 属性包装器的 +使用进行声明 + +171 +00:07:54,408 --> 00:07:57,177 +依靠有关参数的信息进行初始化 + +172 +00:07:57,177 --> 00:07:58,846 +就像标题一样 + +173 +00:07:58,846 --> 00:08:01,515 +在这里 我定义了一个新的书架参数 + +174 +00:08:01,515 --> 00:08:04,818 +由我的 perform 方法 +中读取 + +175 +00:08:04,818 --> 00:08:06,820 +参数支持所有这些类型 + +176 +00:08:06,820 --> 00:08:10,023 +包括数字 字符串 文件等等 + +177 +00:08:10,023 --> 00:08:13,594 +以及您 App 中的实体和枚举 + +178 +00:08:13,594 --> 00:08:17,297 +这是此意图在 +“快捷指令”编辑器中的外观 + +179 +00:08:17,297 --> 00:08:21,201 +请注意 书架参数 +出现在了一个表格行中 + +180 +00:08:21,201 --> 00:08:23,070 +我可以通过使用 +ParameterSummary API + +181 +00:08:23,070 --> 00:08:24,938 +让 UI 更精简 + +182 +00:08:24,938 --> 00:08:29,009 +并使其更适合“快捷指令” + +183 +00:08:29,009 --> 00:08:31,078 +“参数摘要”是在编辑器中 + +184 +00:08:31,078 --> 00:08:33,680 +表述您的意图及其参数的 + +185 +00:08:33,680 --> 00:08:37,684 +一个语句 例如“打开 [书架]” + +186 +00:08:37,684 --> 00:08:39,620 +为了在“快捷指令”中获得最佳效果 + +187 +00:08:39,620 --> 00:08:41,989 +您应当为创建的每一个意图 + +188 +00:08:41,989 --> 00:08:45,459 +提供“参数摘要” + +189 +00:08:45,459 --> 00:08:47,027 +您也可以定义哪些参数 + +190 +00:08:47,027 --> 00:08:50,497 +将显示在折叠区域下 哪些是隐藏的 + +191 +00:08:50,497 --> 00:08:53,166 +这些 API 可以做很酷的事情 + +192 +00:08:53,166 --> 00:08:56,103 +比如依据您意图任何参数的 + +193 +00:08:56,103 --> 00:08:58,372 +实际值来改变摘要 + +194 +00:08:58,372 --> 00:09:00,807 +只需使用 When 和 Otherwise API + +195 +00:09:00,807 --> 00:09:05,512 +或者 Switch Case 和 Default API + +196 +00:09:05,512 --> 00:09:06,947 +为了添加参数摘要 + +197 +00:09:06,947 --> 00:09:09,650 +我实施了这项静态属性 + +198 +00:09:09,650 --> 00:09:11,718 +在这里 我将返回字符串“打开” + +199 +00:09:11,718 --> 00:09:15,756 +并插入书架参数 + +200 +00:09:15,756 --> 00:09:18,759 +要让“打开书架”生效 +我需要做的最后一件事 + +201 +00:09:18,759 --> 00:09:21,495 +就是确保意图在运行时 + +202 +00:09:21,495 --> 00:09:25,866 +打开“图书馆”App 就像这样 + +203 +00:09:25,866 --> 00:09:28,836 +打开 App 的操作由静态属性 + +204 +00:09:28,836 --> 00:09:30,838 +openAppWhenRun 控制 + +205 +00:09:30,838 --> 00:09:33,941 +它默认设置为假 +这对大多数意图而言都有效 + +206 +00:09:33,941 --> 00:09:36,176 +但对于那些需要在 UI 中 +打开某些内容的意图 + +207 +00:09:36,176 --> 00:09:40,214 +比如眼下这一个 +就需要将其设置为真 + +208 +00:09:40,214 --> 00:09:43,083 +我刚才创建了一个打开书架的意图 + +209 +00:09:43,083 --> 00:09:47,187 +它非常简单 +因为书架的集合是固定的 + +210 +00:09:47,187 --> 00:09:50,257 +那么如果我想创建一个意图来打开 + +211 +00:09:50,257 --> 00:09:53,193 +集合为动态而非固定的“书本” +该怎么做呢? + +212 +00:09:53,193 --> 00:09:55,729 +为此 我需要实体 + +213 +00:09:55,729 --> 00:09:59,666 +实体是您的 App +向 App Intents 公开的概念 + +214 +00:09:59,666 --> 00:10:02,202 +当值为动态或由用户定义时 + +215 +00:10:02,202 --> 00:10:05,072 +您应该使用实体而非枚举 + +216 +00:10:05,072 --> 00:10:09,209 +例如“备忘录”中的笔记 +或“照片”中的图片或相册 + +217 +00:10:09,209 --> 00:10:11,512 +要提供实体的实例 + +218 +00:10:11,512 --> 00:10:13,514 +您的 App 可以实施查询 + +219 +00:10:13,514 --> 00:10:17,818 +并返回实体作为意图的结果 + +220 +00:10:17,818 --> 00:10:21,321 +首先 我要在 App 中 +创建打开一本书的意图 + +221 +00:10:21,321 --> 00:10:25,158 +在“快捷指令”编辑器中 +它看起来应该是这样 + +222 +00:10:25,158 --> 00:10:27,261 +当用户轻点“书本”参数时 + +223 +00:10:27,261 --> 00:10:29,263 +就会获得一个选取书目的选择器 + +224 +00:10:29,263 --> 00:10:30,964 +也包括由我的 App 提供的 + +225 +00:10:30,964 --> 00:10:34,401 +一组推荐实体 + +226 +00:10:34,401 --> 00:10:36,703 +用户还可以使用选择器顶部的搜索栏 + +227 +00:10:36,703 --> 00:10:41,375 +在自己的图书馆中找到任何书籍 + +228 +00:10:41,375 --> 00:10:43,343 +在我建立意图本身之前 + +229 +00:10:43,343 --> 00:10:45,312 +我需要先创建一个书本实体 + +230 +00:10:45,312 --> 00:10:47,614 +及相应的查询 + +231 +00:10:47,614 --> 00:10:50,484 +一个实体至少包含三个部分 + +232 +00:10:50,484 --> 00:10:53,153 +标识符 显示表述 + +233 +00:10:53,153 --> 00:10:56,190 +和实体类型名称 + +234 +00:10:56,190 --> 00:10:58,926 +要添加实体 首先要使结构 + +235 +00:10:58,926 --> 00:11:01,528 +符合 AppEntity 协议 + +236 +00:11:01,528 --> 00:11:03,997 +在这里 我将为 BookEntity +定义一个新结构 + +237 +00:11:03,997 --> 00:11:08,569 +但也可以用我模型中 +现有的类型执行符合 + +238 +00:11:08,569 --> 00:11:11,371 +通过符合实体来向可识别协议 + +239 +00:11:11,371 --> 00:11:14,041 +提供标识符 + +240 +00:11:14,041 --> 00:11:17,110 +App Intents 使用此标识符 +来引用您的实体 + +241 +00:11:17,110 --> 00:11:20,881 +因为它在您的 App +和系统其他部分之间传递 + +242 +00:11:20,881 --> 00:11:23,717 +标识符应当是稳定而持久的 + +243 +00:11:23,717 --> 00:11:25,752 +因为它可能被保存在由您的 + +244 +00:11:25,752 --> 00:11:29,156 +客户创建的快捷指令中 + +245 +00:11:29,156 --> 00:11:31,058 +显示表述的作用是 + +246 +00:11:31,058 --> 00:11:33,560 +向用户展示此实体 + +247 +00:11:33,560 --> 00:11:35,596 +它可以像一串文本一样简单 + +248 +00:11:35,596 --> 00:11:37,531 +比如书名 + +249 +00:11:37,531 --> 00:11:41,635 +您也可以为它提供副标题和图像 + +250 +00:11:41,635 --> 00:11:44,071 +typeDisplayName 是一种 +人可读的字符串 + +251 +00:11:44,071 --> 00:11:46,440 +用来表述实体的类型 + +252 +00:11:46,440 --> 00:11:49,209 +在这个案例中 它就是“书本” + +253 +00:11:49,209 --> 00:11:51,545 +现在 为了完善书本实体 + +254 +00:11:51,545 --> 00:11:54,181 +我需要添加查询 + +255 +00:11:54,181 --> 00:11:56,617 +查询为系统提供了一个接口 + +256 +00:11:56,617 --> 00:12:00,020 +用于从您的 App 中检索实体 + +257 +00:12:00,020 --> 00:12:03,156 +查询可以通过几种方式寻找实体 + +258 +00:12:03,156 --> 00:12:05,292 +所有查询都需要能够基于标识符 + +259 +00:12:05,292 --> 00:12:07,361 +对实体进行查找 + +260 +00:12:07,361 --> 00:12:09,796 +字符串查询支持搜索 + +261 +00:12:09,796 --> 00:12:11,899 +稍后您还会看到属性查询 + +262 +00:12:11,899 --> 00:12:13,934 +它的灵活度更大 + +263 +00:12:13,934 --> 00:12:17,337 +所有查询都可以提供建议实体 + +264 +00:12:17,337 --> 00:12:21,708 +允许用户从列表中选择 + +265 +00:12:21,708 --> 00:12:24,611 +每个实体都应当与一个查询相关联 + +266 +00:12:24,611 --> 00:12:29,016 +使系统可以查找该实体的实例 + +267 +00:12:29,016 --> 00:12:31,585 +您可以通过 +创建 Swift 结构来提供 + +268 +00:12:31,585 --> 00:12:35,222 +符合 EntityQuery 协议的查询 + +269 +00:12:35,222 --> 00:12:38,292 +基础查询只需要实施一种方法 + +270 +00:12:38,292 --> 00:12:39,960 +在给定标识符数组时 + +271 +00:12:39,960 --> 00:12:42,863 +用于解析实体 + +272 +00:12:42,863 --> 00:12:45,666 +我实现的方式是访问模型数据库 + +273 +00:12:45,666 --> 00:12:49,970 +并找到与标识符匹配的任何书目 + +274 +00:12:49,970 --> 00:12:53,373 +现在 我需要将查询连接到实体 + +275 +00:12:53,373 --> 00:12:56,410 +可以通过在 +BookEntity 类型上实施 + +276 +00:12:56,410 --> 00:12:58,278 +defaultQuery 静态属性 + +277 +00:12:58,278 --> 00:13:03,183 +并返回 BookQuery 的 +一个实例来完成 + +278 +00:13:03,183 --> 00:13:05,152 +当用户选择一本书时 + +279 +00:13:05,152 --> 00:13:08,121 +它的标识符将被保存到快捷指令中 + +280 +00:13:08,121 --> 00:13:09,556 +快捷指令运行时 + +281 +00:13:09,556 --> 00:13:12,492 +App Intents 会将标识符 +传递给我的查询 + +282 +00:13:12,492 --> 00:13:16,797 +用于检索 +BookEntity 实例 + +283 +00:13:16,797 --> 00:13:18,198 +现在 BookEntity 类型 + +284 +00:13:18,198 --> 00:13:20,667 +已经符合 +AppEntity 协议 + +285 +00:13:20,667 --> 00:13:24,671 +我可以将它用作 +OpenBook 意图中的参数 + +286 +00:13:24,671 --> 00:13:26,940 +perform 方法 +使用我的导航器 + +287 +00:13:26,940 --> 00:13:28,942 +找到这本书 + +288 +00:13:32,546 --> 00:13:34,648 +为了支持书本选择器 + +289 +00:13:34,648 --> 00:13:38,485 +我的查询还需要提供建议结果 + +290 +00:13:38,485 --> 00:13:42,022 +为此 我需要在 +查询中实施另一种方法 + +291 +00:13:42,022 --> 00:13:45,092 +返回我的“图书馆” +App 里添加的所有书 + +292 +00:13:45,092 --> 00:13:49,997 +快捷指令将用这些结果填充选择器 + +293 +00:13:49,997 --> 00:13:53,700 +请注意 “快捷指令” +UI 顶部有一个搜索框 + +294 +00:13:53,700 --> 00:13:55,669 +我的 App 中 +可能有大量书本实体 + +295 +00:13:55,669 --> 00:13:58,739 +所以我非常需要 +在 App 进程中运行 + +296 +00:13:58,739 --> 00:14:00,908 +直接针对数据库的搜索 + +297 +00:14:00,908 --> 00:14:04,411 +StringQuery API +可以帮我做到 + +298 +00:14:04,411 --> 00:14:06,813 +采用 StringQuery 子协议需要我 + +299 +00:14:06,813 --> 00:14:08,515 +实施另一种方法 + +300 +00:14:08,515 --> 00:14:10,717 +即 entities (matching string:) + +301 +00:14:10,717 --> 00:14:13,287 +来返回给定字符串的结果 + +302 +00:14:13,287 --> 00:14:16,690 +在这里 我实现了简单的 +不区分大小写的 + +303 +00:14:16,690 --> 00:14:18,392 +书名匹配 + +304 +00:14:18,392 --> 00:14:19,960 +但我也可以做实现更复杂的功能 + +305 +00:14:19,960 --> 00:14:22,396 +比如说 使用作者或系列名称 + +306 +00:14:22,396 --> 00:14:24,598 +来进行搜索 + +307 +00:14:24,598 --> 00:14:28,168 +如果我的书总量很大 +但收藏夹里的数量少一些 + +308 +00:14:28,168 --> 00:14:31,238 +在 suggestedEntities 中可以 +只返回收藏夹内容 + +309 +00:14:31,238 --> 00:14:33,574 +并借助 entities (matching string:) + +310 +00:14:33,574 --> 00:14:38,912 +允许用户在更长的列表中进行搜索 + +311 +00:14:38,912 --> 00:14:41,882 +我已经公开了一种 +在 App 中打开书本的方法 + +312 +00:14:41,882 --> 00:14:45,485 +并在此过程中创建了 +书本实体和书本查询 + +313 +00:14:45,485 --> 00:14:49,323 +现在就可以使用同样的 +实体和查询来创建更多意图 + +314 +00:14:49,323 --> 00:14:51,758 +我的下一个任务是创建 + +315 +00:14:51,758 --> 00:14:53,894 +将书本添加到图书馆的意图 + +316 +00:14:53,894 --> 00:14:56,630 +客户在线浏览的同时 +可以使用共享表单快捷指令 + +317 +00:14:56,630 --> 00:14:58,232 +快速添加书本 + +318 +00:14:58,232 --> 00:15:00,534 +也可以呼唤 HomePod 上的 +Siri 来添加书本 + +319 +00:15:00,534 --> 00:15:03,003 +甚至不需要看屏幕 + +320 +00:15:03,003 --> 00:15:06,673 +像这样创建直接操作模型 + +321 +00:15:06,673 --> 00:15:11,879 +而不显示 UI 的意图 +可以真正为您的用户赋权 + +322 +00:15:11,879 --> 00:15:14,715 +这是我对 +AddBook 意图的实现 + +323 +00:15:14,715 --> 00:15:16,817 +参数是书名和 + +324 +00:15:16,817 --> 00:15:19,520 +可选的作者姓名 + +325 +00:15:19,520 --> 00:15:21,622 +它还包含了可选的备注 + +326 +00:15:21,622 --> 00:15:24,791 +用于记录是哪个朋友推荐了这本书 + +327 +00:15:24,791 --> 00:15:27,728 +perform 方法 +通过使用 async/await 的 + +328 +00:15:27,728 --> 00:15:31,765 +API 调用来查找 +并将书本添加到图书馆 + +329 +00:15:31,765 --> 00:15:36,670 +如果找不到匹配项 将引发错误 + +330 +00:15:36,670 --> 00:15:39,473 +为了将这个错误本地化 +我使错误类型符合 + +331 +00:15:39,473 --> 00:15:43,944 +CustomLocalizedStringResourceConvertible 协议 + +332 +00:15:43,944 --> 00:15:47,214 +我将从属性返回本地化的字符串键 + +333 +00:15:47,214 --> 00:15:50,951 +并将键添加到我的字符串文件中 + +334 +00:15:50,951 --> 00:15:54,288 +配合 Siri 小组件等等工具 +“添加书本”意图 + +335 +00:15:54,288 --> 00:15:56,857 +已经非常有用了 + +336 +00:15:56,857 --> 00:15:58,759 +但如果将它与其他意图相结合 + +337 +00:15:58,759 --> 00:16:01,628 +它的灵活度将进一步提高 + +338 +00:16:01,628 --> 00:16:02,896 +只需稍加改动 + +339 +00:16:02,896 --> 00:16:05,165 +我就可以使“添加书本”意图与 + +340 +00:16:05,165 --> 00:16:07,634 +我之前创建的“打开书本”组合 + +341 +00:16:07,634 --> 00:16:10,938 +将结果从一个传递到另一个 + +342 +00:16:10,938 --> 00:16:13,807 +为此 我将让“添加书本”意图 + +343 +00:16:13,807 --> 00:16:17,110 +返回一个值作为其结果的一部分 + +344 +00:16:17,110 --> 00:16:19,213 +请注意我的 +perform 方法的返回类型 + +345 +00:16:19,213 --> 00:16:20,981 +已经选取了一个新协议 + +346 +00:16:20,981 --> 00:16:23,951 +来表述我返回的值 + +347 +00:16:23,951 --> 00:16:27,421 +现在 用户可以将这个意图的结果值 + +348 +00:16:27,421 --> 00:16:31,859 +与以书本实体为参数的 +其他意图连接起来 + +349 +00:16:31,859 --> 00:16:34,928 +“添加书本”意图 +和“打开书本”意图 + +350 +00:16:34,928 --> 00:16:36,396 +就很自然地配合起来 + +351 +00:16:36,396 --> 00:16:38,866 +让您可以创建快捷指令来添加一本书 + +352 +00:16:38,866 --> 00:16:41,435 +随后立即在库中打开它 + +353 +00:16:41,435 --> 00:16:44,505 +一种常见模式是从意图返回结果 + +354 +00:16:44,505 --> 00:16:46,874 +并在 App 中打开它 + +355 +00:16:46,874 --> 00:16:49,343 +App Intents 中有一种 +名为 openIntent 的内置方式 + +356 +00:16:49,343 --> 00:16:51,578 +来表述这种模式 + +357 +00:16:51,578 --> 00:16:53,881 +如果我添加了 +openIntent 则客户会在 + +358 +00:16:53,881 --> 00:16:57,484 +“快捷指令”中获得一个 +名为“运行时打开”的新开关 + +359 +00:16:57,484 --> 00:16:59,086 +如果他们关掉开关 + +360 +00:16:59,086 --> 00:17:00,254 +他们将能够在不被打断的情况下 + +361 +00:17:00,254 --> 00:17:04,625 +在后台将这一意图 +作为快捷指令的一部分使用 + +362 +00:17:04,625 --> 00:17:07,528 +如果他们打开开关 新添加的书 + +363 +00:17:07,528 --> 00:17:12,399 +将立即在“图书馆”App 中打开 + +364 +00:17:12,399 --> 00:17:15,269 +采用 openIntent 就像 + +365 +00:17:15,269 --> 00:17:17,671 +为“打开书本”意图创建实例 + +366 +00:17:17,671 --> 00:17:20,908 +并将其作为部分结果返回一样简单 + +367 +00:17:20,908 --> 00:17:22,309 +当意图运行时 + +368 +00:17:22,309 --> 00:17:24,278 +如果“运行时打开”状态为开 + +369 +00:17:24,278 --> 00:17:27,147 +“打开书本”意图将在 + +370 +00:17:27,147 --> 00:17:31,351 +“添加书本”意图完成后自动执行 + +371 +00:17:31,351 --> 00:17:35,055 +借助实体和查询 +还可以实现更多功能 + +372 +00:17:35,055 --> 00:17:36,623 +使用以下这组 API + +373 +00:17:36,623 --> 00:17:39,326 +AppIntents +开启了一些在 + +374 +00:17:39,326 --> 00:17:43,497 +SiriKit Intents 框架下 +从未有过的强大性能 + +375 +00:17:43,497 --> 00:17:45,999 +让我们来看看如何公开 + +376 +00:17:45,999 --> 00:17:47,301 +更多实体信息 + +377 +00:17:47,301 --> 00:17:52,306 +并允许客户据此进行查找和筛选 + +378 +00:17:52,306 --> 00:17:55,175 +到目前为止 我已经将所有基础请求 + +379 +00:17:55,175 --> 00:17:56,677 +添加到了我的书本实体中 + +380 +00:17:56,677 --> 00:17:58,145 +但要想让用户更深入地将书本 + +381 +00:17:58,145 --> 00:18:00,247 +整合到快捷指令中 + +382 +00:18:00,247 --> 00:18:05,085 +我将需要公开更多书的信息 + +383 +00:18:05,085 --> 00:18:07,120 +实体支持属性 + +384 +00:18:07,120 --> 00:18:09,423 +属性则持有您想向用户公开的 + +385 +00:18:09,423 --> 00:18:11,992 +关于该实体的额外信息 + +386 +00:18:11,992 --> 00:18:13,994 +在本例中 我将添加书本的作者 + +387 +00:18:13,994 --> 00:18:16,997 +出版日期 阅读日期和推荐人 + +388 +00:18:16,997 --> 00:18:22,069 +这样用户就可以 +在快捷指令中使用这些属性 + +389 +00:18:22,069 --> 00:18:24,071 +我将使用名为 +@Property 的属性包装器 + +390 +00:18:24,071 --> 00:18:27,341 +来将属性 +添加到 BookEntity + +391 +00:18:27,341 --> 00:18:30,244 +属性支持与参数相同的所有类型 + +392 +00:18:30,244 --> 00:18:35,516 +且每个种类都有本地化的标题 + +393 +00:18:35,516 --> 00:18:37,251 +有了这些新属性 + +394 +00:18:37,251 --> 00:18:40,387 +我的客户现在可以在 +“快捷指令”中使用魔法变量 + +395 +00:18:40,387 --> 00:18:42,689 +提取与书本实体配合时的 + +396 +00:18:42,689 --> 00:18:45,292 +每一条新信息 + +397 +00:18:45,292 --> 00:18:47,661 +当使用此前创建的 +“添加书本”意图时 + +398 +00:18:47,661 --> 00:18:49,997 +用户可以在快捷指令中用到 + +399 +00:18:49,997 --> 00:18:53,000 +新增书籍的作者或出版日期 + +400 +00:18:55,135 --> 00:18:57,671 +当您将属性与查询结合使用时 + +401 +00:18:57,671 --> 00:19:00,607 +借助这个灵活的谓词编辑器 UI + +402 +00:19:00,607 --> 00:19:03,076 +您的 App 将在 +“快捷指令”中自动获得 + +403 +00:19:03,076 --> 00:19:06,547 +难以置信的强大“查找与筛选”操作 + +404 +00:19:06,547 --> 00:19:09,316 +现在 我的客户将能够基于 + +405 +00:19:09,316 --> 00:19:13,053 +阅读日期 标题 作者等条件 +查找和筛选书本 + +406 +00:19:13,053 --> 00:19:14,555 +比如说 要找到 + +407 +00:19:14,555 --> 00:19:18,759 +Delia Owens 的所有书 +可以说是小菜一碟 + +408 +00:19:18,759 --> 00:19:20,661 +使用排序依据和限制选项 + +409 +00:19:20,661 --> 00:19:22,729 +您可以支持更高阶的查询 + +410 +00:19:22,729 --> 00:19:25,065 +比如找到 Delia Owens + +411 +00:19:25,065 --> 00:19:27,868 +最近出版的三本书 + +412 +00:19:27,868 --> 00:19:30,003 +客户可以使用这些组成部件 + +413 +00:19:30,003 --> 00:19:32,372 +做一些很酷的事 比如查找 + +414 +00:19:32,372 --> 00:19:36,043 +自己的收藏中最常见的三位作者 + +415 +00:19:36,043 --> 00:19:37,277 +为了实现这些 + +416 +00:19:37,277 --> 00:19:39,680 +我需要采用另一种查询 + +417 +00:19:39,680 --> 00:19:41,915 +即属性查询 + +418 +00:19:41,915 --> 00:19:44,918 +属性查询并非基于字符串 + +419 +00:19:44,918 --> 00:19:50,390 +或标识符对实体进行查找 +而是基于实体内的属性 + +420 +00:19:50,390 --> 00:19:53,594 +实施属性查询分为三个步骤 + +421 +00:19:53,594 --> 00:19:55,929 +首先 声明查询属性 + +422 +00:19:55,929 --> 00:19:58,365 +指定如何通过属性对实体 + +423 +00:19:58,365 --> 00:20:00,634 +进行搜索 + +424 +00:20:00,634 --> 00:20:02,469 +接下来 填加排序选项 + +425 +00:20:02,469 --> 00:20:06,373 +定义如何对查询结果进行排序 + +426 +00:20:06,373 --> 00:20:09,476 +最后 实施 +entities(matching:) + +427 +00:20:09,476 --> 00:20:12,212 +并运行搜索 + +428 +00:20:12,212 --> 00:20:13,447 +查询属性 + +429 +00:20:13,447 --> 00:20:16,216 +声明了 AppIntents +可以在与此查询关联的 + +430 +00:20:16,216 --> 00:20:19,520 +实体上进行搜索的所有方式 + +431 +00:20:19,520 --> 00:20:21,989 +每种都列出了实体的一个属性 + +432 +00:20:21,989 --> 00:20:23,790 +和可用于它的比较运算符 + +433 +00:20:23,790 --> 00:20:26,126 +例如包含 等于 + +434 +00:20:26,126 --> 00:20:28,529 +或小于 + +435 +00:20:28,529 --> 00:20:31,532 +在这里 我为日期属性列出了 + +436 +00:20:31,532 --> 00:20:33,333 +“小于”和“大于”比较器 + +437 +00:20:33,333 --> 00:20:38,672 +为书名属性列出了 +“包含”和“等于” + +438 +00:20:38,672 --> 00:20:41,508 +查询属性将每个属性组合 + +439 +00:20:41,508 --> 00:20:45,546 +和比较器映射为您选择的类型 + +440 +00:20:45,546 --> 00:20:48,048 +这被称为比较器映射类型 + +441 +00:20:48,048 --> 00:20:51,952 +在这里 因为使用了 CoreData +所以我选 NSPredicate 来用 + +442 +00:20:51,952 --> 00:20:55,222 +如果使用的是 +自定义数据库或 REST API + +443 +00:20:55,222 --> 00:20:57,524 +可以设计自己的比较器类型 + +444 +00:20:57,524 --> 00:21:00,594 +并且选择使用它 + +445 +00:21:00,594 --> 00:21:04,198 +这是用于设置书本查询属性的代码 + +446 +00:21:04,198 --> 00:21:08,669 +我使 BooksQuery +符合 EntityPropertyQuery 协议 + +447 +00:21:08,669 --> 00:21:11,572 +然后使用 QueryProperties +结果构建器 + +448 +00:21:11,572 --> 00:21:15,275 +实施静态变量属性 + +449 +00:21:15,275 --> 00:21:18,145 +每个条目都指定一个可查询的 + +450 +00:21:18,145 --> 00:21:20,380 +属性 keyPath 在它内部 + +451 +00:21:20,380 --> 00:21:24,184 +是适用于该属性的所有比较器 + +452 +00:21:24,184 --> 00:21:26,687 +对于每个比较器 +我都提供一个 NSPredicate + +453 +00:21:26,687 --> 00:21:31,458 +因为我选择了 NSPredicate +作为比较器映射类型 + +454 +00:21:31,458 --> 00:21:35,195 +当系统要求我的 App +返回查询结果时 + +455 +00:21:35,195 --> 00:21:37,097 +它将再次提供我在这里 + +456 +00:21:37,097 --> 00:21:39,967 +创建的 NSPredicates + +457 +00:21:39,967 --> 00:21:42,703 +排序的定义也与之类似 + +458 +00:21:42,703 --> 00:21:44,404 +这是一张所有属性的列表 + +459 +00:21:44,404 --> 00:21:46,640 +我的模型可以用这些属性 +对书本进行排序 + +460 +00:21:46,640 --> 00:21:48,842 +在这个案例中 我允许按书名 + +461 +00:21:48,842 --> 00:21:52,179 +阅读日期和出版日期排序 + +462 +00:21:52,179 --> 00:21:55,215 +最后 我实施 entities(matching:) + +463 +00:21:55,215 --> 00:21:59,152 +它会查询我的数据库 +并返回匹配的实体 + +464 +00:21:59,152 --> 00:22:02,523 +此方法采用了比较器映射类型的 + +465 +00:22:02,523 --> 00:22:05,926 +一个我在之前定义 +查询参数时使用的数组 + +466 +00:22:05,926 --> 00:22:07,895 +在这个案例里 +就是 NSPredicate + +467 +00:22:07,895 --> 00:22:11,031 +这些谓词描述了我想通过 + +468 +00:22:11,031 --> 00:22:15,035 +实体属性的哪些标准来查询 + +469 +00:22:15,035 --> 00:22:16,470 +它也采用了一种模式 + +470 +00:22:16,470 --> 00:22:18,505 +来指示是否要使用 + +471 +00:22:18,505 --> 00:22:22,543 +“和”及“或”来合并谓词 +进行排序的关键路径 + +472 +00:22:22,543 --> 00:22:26,380 +以及结果数量的可选限制 + +473 +00:22:26,380 --> 00:22:28,649 +我在实施时使用这些参数 + +474 +00:22:28,649 --> 00:22:34,454 +对 CoreData 数据库 +执行查询 + +475 +00:22:34,454 --> 00:22:37,391 +那么客户可以使用 +此属性查询做什么呢? + +476 +00:22:37,391 --> 00:22:40,961 +可以从库中随机挑选一本书来读 + +477 +00:22:40,961 --> 00:22:42,496 +也可以找到所有出版于 + +478 +00:22:42,496 --> 00:22:45,832 +20 世纪初的书 + +479 +00:22:45,832 --> 00:22:48,268 +可以借助“快捷指令”生态系统 + +480 +00:22:48,268 --> 00:22:51,572 +通过将自己的 App 与其他人的连接 +使自己的 App 变得更有用 + +481 +00:22:51,572 --> 00:22:53,574 +例如 可以使用电子表格 App + +482 +00:22:53,574 --> 00:22:57,477 +将今年阅读的所有书 +导出为 CSV 文件 + +483 +00:22:57,477 --> 00:22:59,780 +也可以使用绘图 App 制作图表 + +484 +00:22:59,780 --> 00:23:03,283 +呈现过去的 10 年里 +每年读书的数量 + +485 +00:23:03,283 --> 00:23:04,918 +而这仅仅是个开始 + +486 +00:23:04,918 --> 00:23:07,321 +这种深入的 +App Intents 运用 + +487 +00:23:07,321 --> 00:23:09,256 +真正让客户使用您的 App + +488 +00:23:09,256 --> 00:23:11,325 +去完成他们期待它实现的功能 + +489 +00:23:11,325 --> 00:23:14,328 +让您的 App 成为他们 +工作流程的关键部分 + +490 +00:23:14,328 --> 00:23:15,863 +所有这些集成 + +491 +00:23:15,863 --> 00:23:17,931 +比如制作图表 + +492 +00:23:17,931 --> 00:23:21,735 +都是您不必费心去构建的功能 + +493 +00:23:21,735 --> 00:23:23,504 +当您的意图被执行时 + +494 +00:23:23,504 --> 00:23:25,772 +您的 App 可能需要 +与用户进行交互 + +495 +00:23:25,772 --> 00:23:29,142 +去展示或说出结果 或解决歧义 + +496 +00:23:29,142 --> 00:23:32,946 +无论是 Siri 请求 +还是快捷指令 + +497 +00:23:32,946 --> 00:23:36,517 +App Intents +支持几种此类交互 + +498 +00:23:36,517 --> 00:23:38,852 +“对话”用于意图完成时向用户 + +499 +00:23:38,852 --> 00:23:41,455 +提供文本和语音反馈 + +500 +00:23:41,455 --> 00:23:43,991 +“片段”则用于提供视觉反馈 + +501 +00:23:43,991 --> 00:23:46,260 +“请求值”和“消歧义” + +502 +00:23:46,260 --> 00:23:50,364 +用于要求用户澄清意图参数的值 + +503 +00:23:50,364 --> 00:23:53,734 +“确认”用于对参数值进行验证 + +504 +00:23:53,734 --> 00:23:55,169 +或与用户核实 + +505 +00:23:55,169 --> 00:23:59,439 +意图是否具有交易性或破坏性 + +506 +00:23:59,439 --> 00:24:02,543 +“对话”向运行意图者 + +507 +00:24:02,543 --> 00:24:04,578 +提供口头或文字回应 + +508 +00:24:04,578 --> 00:24:06,713 +提供对话对于使意图在 + +509 +00:24:06,713 --> 00:24:10,184 +语音体验中发挥作用真的非常重要 + +510 +00:24:10,184 --> 00:24:12,119 +在我之前创建的“添加书本”意图中 + +511 +00:24:12,119 --> 00:24:13,820 +我将添加 +needsValueDialog + +512 +00:24:13,820 --> 00:24:16,223 +在询问书名时说出 + +513 +00:24:16,223 --> 00:24:20,027 +还要添加针对 +perform 方法返回结果的对话 + +514 +00:24:20,027 --> 00:24:22,729 +对话将在我们的不同平台上 +由“快捷指令”或 Siri + +515 +00:24:22,729 --> 00:24:25,866 +来朗读或显示 + +516 +00:24:25,866 --> 00:24:30,404 +您可以将“片段” +视为“对话”的视觉等价物 + +517 +00:24:30,404 --> 00:24:32,539 +它让您能够为意图的结果 + +518 +00:24:32,539 --> 00:24:34,942 +添加视觉表述 + +519 +00:24:34,942 --> 00:24:38,212 +要使用片段 +只需添加您选择的 SwiftUI 视图 + +520 +00:24:38,212 --> 00:24:42,349 +作为意图结果的尾随闭包 + +521 +00:24:42,349 --> 00:24:46,019 +与小部件一样 +SwiftUI 视图将被归档 + +522 +00:24:46,019 --> 00:24:51,258 +并发送给“快捷指令”或 Siri + +523 +00:24:51,258 --> 00:24:54,561 +App Intents 还支持 +通过抛出 requestValue + +524 +00:24:54,561 --> 00:24:56,730 +向用户询问值 + +525 +00:24:56,730 --> 00:24:59,433 +比如说 当您需要 +一个有时是可选的参数值时 + +526 +00:24:59,433 --> 00:25:02,769 +这就能派上用场 + +527 +00:25:02,769 --> 00:25:06,106 +在这里 当字符串搜索 +返回不止一本书时 + +528 +00:25:06,106 --> 00:25:08,275 +requestValue +就可以帮上忙 + +529 +00:25:08,275 --> 00:25:10,544 +在这种情况下 +我提示并询问作者姓名 + +530 +00:25:10,544 --> 00:25:12,779 +来缩小书本的搜索范围 + +531 +00:25:12,779 --> 00:25:15,482 +requestValue 给出了 +一个可以引发的错误 + +532 +00:25:15,482 --> 00:25:17,017 +它将提示用户 + +533 +00:25:17,017 --> 00:25:21,955 +并使用更新的作者姓名 +重新运行该操作 + +534 +00:25:21,955 --> 00:25:24,024 +同时 “消歧义” + +535 +00:25:24,024 --> 00:25:25,926 +在您需要用户在参数的一组值之间 + +536 +00:25:25,926 --> 00:25:29,329 +进行选择时非常有用 + +537 +00:25:29,329 --> 00:25:31,465 +它为我提供了一种更好的方式 + +538 +00:25:31,465 --> 00:25:35,802 +来处理“添加书本” +操作中的多个可能结果 + +539 +00:25:35,802 --> 00:25:39,206 +在这里 我从生成的书本中 +获取了作者姓名列表 + +540 +00:25:39,206 --> 00:25:43,076 +并要求对这些可能的值进行消歧 + +541 +00:25:43,076 --> 00:25:45,078 +用户将被要求在它们之中进行选择 + +542 +00:25:45,078 --> 00:25:49,149 +而我会得到结果 + +543 +00:25:49,149 --> 00:25:53,687 +最后 App Intents 支持 +两种不同的确认方式 + +544 +00:25:53,687 --> 00:25:57,624 +第一种是参数值的确认 + +545 +00:25:57,624 --> 00:25:59,193 +您可能会在心里对值已有大概猜想 + +546 +00:25:59,193 --> 00:26:02,162 +但仍想证实的情况下 + +547 +00:26:02,162 --> 00:26:04,331 +使用这种确认方式 + +548 +00:26:04,331 --> 00:26:05,599 +在添加书本时 + +549 +00:26:05,599 --> 00:26:08,836 +有时我调用的按书名查找网络服务 + +550 +00:26:08,836 --> 00:26:10,237 +会返回几个匹配项 + +551 +00:26:10,237 --> 00:26:13,106 +但其中有一项在目前看来更受欢迎 + +552 +00:26:13,106 --> 00:26:15,275 +在这样的情况下 我会假设 + +553 +00:26:15,275 --> 00:26:17,978 +用户打算添加那本受欢迎的书 + +554 +00:26:17,978 --> 00:26:21,381 +但我会加上“确认”来保证我猜对了 + +555 +00:26:21,381 --> 00:26:23,684 +为此 我将在书名参数上 + +556 +00:26:23,684 --> 00:26:26,286 +调用 requestConfirmation + +557 +00:26:26,286 --> 00:26:28,856 +第二种方式是确认 + +558 +00:26:28,856 --> 00:26:31,024 +意图的结果 + +559 +00:26:31,024 --> 00:26:33,927 +举例来说 它非常适合用于下订单 + +560 +00:26:33,927 --> 00:26:35,963 +如果我想通过 +“图书馆”App 获利 + +561 +00:26:35,963 --> 00:26:38,265 +并通过书店添加订购 + +562 +00:26:38,265 --> 00:26:41,401 +我需要确保订单信息正确 + +563 +00:26:41,401 --> 00:26:44,104 +为此 我可以在意图上 +调用 requestConfirmation + +564 +00:26:44,104 --> 00:26:47,708 +来传递要下的订单 + +565 +00:26:47,708 --> 00:26:52,346 +我也会在这里指定片段 +来显示订单的预览 + +566 +00:26:52,346 --> 00:26:55,048 +我在调用前加上了 try +因为 requestConfirmation + +567 +00:26:55,048 --> 00:26:57,718 +在用户取消而不是确认的情况下 + +568 +00:26:57,718 --> 00:27:00,888 +将引发错误 + +569 +00:27:00,888 --> 00:27:02,956 +在结束讲座前 我还想向您介绍 + +570 +00:27:02,956 --> 00:27:05,826 +App Intents 架构的 +几个方面 + +571 +00:27:05,826 --> 00:27:09,630 +这些是您在采用此框架时 +就应该了解的 + +572 +00:27:09,630 --> 00:27:12,733 +实际上 有两种构建 +App Intents 的途径 + +573 +00:27:12,733 --> 00:27:16,036 +在您的 App 中 +或者在单独的扩展程序中 + +574 +00:27:16,036 --> 00:27:18,805 +直接在您的 App 中实施意图 + +575 +00:27:18,805 --> 00:27:20,841 +是最简单的 + +576 +00:27:20,841 --> 00:27:23,110 +这种方法很好用 因为您不需要框架 + +577 +00:27:23,110 --> 00:27:25,245 +不用复制代码 + +578 +00:27:25,245 --> 00:27:28,649 +也不需要跨流程进行协调 + +579 +00:27:28,649 --> 00:27:31,485 +使用您的 App 还能够 +提供更高的内存限制 + +580 +00:27:31,485 --> 00:27:34,121 +让您有能力完成一些 + +581 +00:27:34,121 --> 00:27:36,023 +在扩展程序中更难实现的功能 + +582 +00:27:36,023 --> 00:27:39,626 +比如播放音频 + +583 +00:27:39,626 --> 00:27:41,495 +如果在意图返回“真”的情况下 +实施 openAppWhenRun + +584 +00:27:41,495 --> 00:27:45,632 +您的 App 就可以在前台运行 + +585 +00:27:45,632 --> 00:27:48,602 +否则 它将在后台运行 + +586 +00:27:48,602 --> 00:27:50,170 +在后台运行时 + +587 +00:27:50,170 --> 00:27:52,072 +您的 App 将以特殊模式启动 + +588 +00:27:52,072 --> 00:27:55,576 +无需调出场景来将性能最大化 + +589 +00:27:55,576 --> 00:27:58,579 +事实上 如果您在 App 中 + +590 +00:27:58,579 --> 00:27:59,680 +实施后台 App 意图 + +591 +00:27:59,680 --> 00:28:05,452 +我们强烈建议您也实施场景支持 + +592 +00:28:05,452 --> 00:28:08,822 +或者 您也可以在扩展程序中 +构建您的 App 意图 + +593 +00:28:08,822 --> 00:28:10,924 +这种方式有几个优点 + +594 +00:28:10,924 --> 00:28:11,825 +它更轻量 + +595 +00:28:11,825 --> 00:28:15,262 +因为扩展程序进程 +只处理 App 意图 + +596 +00:28:15,262 --> 00:28:18,365 +也不需要启动您的 App + +597 +00:28:18,365 --> 00:28:20,734 +如果您正在处理“焦点”意图 + +598 +00:28:20,734 --> 00:28:23,203 +使用扩展程序也意味着您可以 + +599 +00:28:23,203 --> 00:28:25,839 +在“焦点”改变时 立即使意图 + +600 +00:28:25,839 --> 00:28:28,141 +在扩展程序上执行 而无需要求 + +601 +00:28:28,141 --> 00:28:32,045 +App 首先在前台运行 + +602 +00:28:32,045 --> 00:28:33,647 +扩展程序的工作量更大 + +603 +00:28:33,647 --> 00:28:35,749 +因为您需要添加一个新目标 + +604 +00:28:35,749 --> 00:28:37,251 +将部分代码转移到框架中 + +605 +00:28:37,251 --> 00:28:39,253 +并处理您的 App +和扩展程序之间的 + +606 +00:28:39,253 --> 00:28:43,023 +协调配合 + +607 +00:28:43,023 --> 00:28:45,058 +要创建 +App Intents 扩展程序 + +608 +00:28:45,058 --> 00:28:47,261 +在 Xcode 中转到 +“文件” “新目标” + +609 +00:28:47,261 --> 00:28:52,065 +并选择“App Intents +扩展程序” + +610 +00:28:52,065 --> 00:28:56,737 +使用 App Intents 时 +您的代码是唯一的事实来源 + +611 +00:28:56,737 --> 00:28:59,606 +App Intents +通过静态提取构建时 + +612 +00:28:59,606 --> 00:29:02,943 +您的意图 实体 查询和参数信息 + +613 +00:29:02,943 --> 00:29:06,914 +实现了这种优雅的开发者体验 + +614 +00:29:06,914 --> 00:29:10,050 +Xcode 将在您的 App 中 +生成元数据文件 + +615 +00:29:10,050 --> 00:29:12,653 +或构建过程中的扩展包 + +616 +00:29:12,653 --> 00:29:15,789 +包含了从 Swift +编译器接收到的信息 + +617 +00:29:15,789 --> 00:29:18,292 +因为它基于您的代码运行 + +618 +00:29:18,292 --> 00:29:21,395 +为确保这些都能起作用 +请将您的 App Intents 类型 + +619 +00:29:21,395 --> 00:29:25,732 +直接保留在目标或扩展程序里 +而非框架中 + +620 +00:29:25,732 --> 00:29:27,467 +同样 您的本地化字符串 + +621 +00:29:27,467 --> 00:29:29,403 +应该可以在与您的 +App Intents 类型 + +622 +00:29:29,403 --> 00:29:34,508 +同处一个包的字符串文件中找到 + +623 +00:29:34,508 --> 00:29:36,777 +对于已有使用 +SiriKit Intents 框架的 + +624 +00:29:36,777 --> 00:29:39,780 +App 并考虑升级的人来说 + +625 +00:29:39,780 --> 00:29:42,850 +如果您采用意图与小部件 + +626 +00:29:42,850 --> 00:29:45,319 +或消息和媒体等域进行集成 + +627 +00:29:45,319 --> 00:29:48,755 +请继续使用 +SiriKit Intents 框架 + +628 +00:29:48,755 --> 00:29:51,825 +但如果您要为 Siri 和 +“快捷指令”添加自定义意图 + +629 +00:29:51,825 --> 00:29:55,162 +您应当更进一步 +升级到 App Intents + +630 +00:29:55,162 --> 00:29:57,164 +您可以通过在 +SiriKit Intents 定义文件中 + +631 +00:29:57,164 --> 00:29:59,399 +点按“转换为 App Intents”按钮 + +632 +00:29:59,399 --> 00:30:04,438 +开始升级过程 + +633 +00:30:04,438 --> 00:30:06,940 +使用 App Intents 将 +您的 App 集成到“快捷指令”中 + +634 +00:30:06,940 --> 00:30:10,777 +是将您作为开发人员的 +影响力最大化的绝佳方法 + +635 +00:30:10,777 --> 00:30:14,214 +只需通过少量工作 +来运用 App Intents + +636 +00:30:14,214 --> 00:30:17,784 +您就将为客户创造大量的价值 + +637 +00:30:17,784 --> 00:30:18,886 +感谢您参与今天的讲座 + +638 +00:30:18,886 --> 00:30:21,755 +我非常希望您能 +立刻试用 App Intents + +639 +00:30:21,755 --> 00:30:23,323 +并为我们提供反馈 + +640 +00:30:23,323 --> 00:30:25,192 +我对这个新框架可以如何帮助您 + +641 +00:30:25,192 --> 00:30:27,995 +通过 App 为人们带来 +惊喜和快乐 并为其赋权 + +642 +00:30:27,995 --> 00:30:29,496 +充满了期待 + +643 +00:30:29,496 --> 00:30:33,367 +阅读愉快 希望您能 +在 WWDC 有绝佳的体验 + +644 +00:30:33,367 --> 00:30:37,638 +♪ + diff --git a/zho/2022 Session 10035 What's new in MapKit.srt b/zho/2022 Session 10035 What's new in MapKit.srt new file mode 100644 index 0000000..8185e2a --- /dev/null +++ b/zho/2022 Session 10035 What's new in MapKit.srt @@ -0,0 +1,3141 @@ +1 +00:00:01,001 --> 00:00:07,007 +[古怪的音乐] + +2 +00:00:09,309 --> 00:00:12,746 +Eric: 大家好 欢迎来到 WWDC + +3 +00:00:12,779 --> 00:00:13,947 +我是 Eric + +4 +00:00:13,981 --> 00:00:16,250 +我是地图 App 团队的工程师 + +5 +00:00:16,283 --> 00:00:19,786 +今天 我和同事 Yingxiu 一起 + +6 +00:00:19,820 --> 00:00:21,922 +与大家共同探索下 +MapKit 的新内容 + +7 +00:00:23,357 --> 00:00:27,427 +Apple 发布全新的地图 App +及其沉浸式的 + +8 +00:00:27,461 --> 00:00:29,663 +Look Around 功能 +已有三年 + +9 +00:00:31,031 --> 00:00:33,367 +最初这一新地图和 Look Around + +10 +00:00:33,400 --> 00:00:36,837 +仅支持美国地区 现已新增 + +11 +00:00:36,870 --> 00:00:38,405 +覆盖加拿大 + +12 +00:00:38,438 --> 00:00:41,341 +大多数欧洲国家 日本等地区 + +13 +00:00:42,910 --> 00:00:45,712 +去年 Apple 地图 App +进行了全新升级 + +14 +00:00:45,746 --> 00:00:49,983 +推出了增强的 3D 地图体验 +有详细的 车辆变道 + +15 +00:00:50,017 --> 00:00:51,885 +人行横道 自行车道等信息 + +16 +00:00:51,919 --> 00:00:55,589 +以及精美绝伦的 3D 地标模型 +如轮渡大厦 + +17 +00:00:57,457 --> 00:00:59,526 +地图上这些详尽的细节 + +18 +00:00:59,560 --> 00:01:01,728 +为用户提供了 + +19 +00:01:01,762 --> 00:01:04,264 +前所未见的内容和精确体验 + +20 +00:01:04,298 --> 00:01:06,633 +3D 的地形高差 + +21 +00:01:06,667 --> 00:01:09,469 +所带来的逼真感也是无可比拟的 + +22 +00:01:10,704 --> 00:01:13,674 +今年 MapKit 可以将 +Apple 地图 App 的功能 + +23 +00:01:13,707 --> 00:01:15,576 +也集成到您的 App 中 + +24 +00:01:15,609 --> 00:01:19,012 +让您的用户也能极尽细节地 +探索世界 + +25 +00:01:20,247 --> 00:01:24,484 +今天的内容将包括 +MapKit 几个新功能 + +26 +00:01:24,518 --> 00:01:27,721 +首先 我们谈下如何用 +地图配置 API + +27 +00:01:27,754 --> 00:01:30,858 +应用这一全新的地图 + +28 +00:01:31,992 --> 00:01:35,863 +接下来 我们将会介绍 +我们针对 Overlay APIs 所做的 + +29 +00:01:35,896 --> 00:01:39,533 +各种改进 从而将您的内容 +与地图无缝集成 + +30 +00:01:40,834 --> 00:01:43,136 +我们还会讨论全新的 +混合模式支持 + +31 +00:01:43,170 --> 00:01:47,040 +以及您可以如何利用这一模式 +以进一步增强 + +32 +00:01:47,074 --> 00:01:49,510 +地图内容的显示 + +33 +00:01:49,543 --> 00:01:53,113 +然后 我们会介绍通过使用我们 +全新的 Selectable Map Features API + +34 +00:01:53,146 --> 00:01:56,450 +增加您地图互动性的方法 + +35 +00:01:57,384 --> 00:02:01,154 +最后 我们会探讨如何直接在您的 +应用程序中 + +36 +00:02:01,188 --> 00:02:03,190 +整合沉浸式的 +Look Around 体验 + +37 +00:02:04,124 --> 00:02:08,395 +我们本次的内容非常丰富 +准备好进入第一个话题 … + +38 +00:02:08,428 --> 00:02:12,332 +集成新地图和 +使用地图配置 API + +39 +00:02:13,600 --> 00:02:16,170 +在您的 iOS macOS +和 tvOS App 中 + +40 +00:02:16,203 --> 00:02:18,505 +集成新地图 + +41 +00:02:18,539 --> 00:02:20,307 +实在是太容易了 + +42 +00:02:20,340 --> 00:02:23,610 +您只要使用新的 SDK +重新编译您的 App + +43 +00:02:23,644 --> 00:02:27,347 +就能自动获得全新的 +Apple 地图 feature + +44 +00:02:27,381 --> 00:02:30,083 +包括在可用地区的 3D 城市体验 + +45 +00:02:30,717 --> 00:02:34,588 +对大部分 App 来说 +只需要简单的重新编译即可 + +46 +00:02:36,089 --> 00:02:39,059 +当然 在部分情况下 +您可能需要对地图的显示 + +47 +00:02:39,092 --> 00:02:40,727 +有更多的控制 + +48 +00:02:41,495 --> 00:02:46,033 +在 iOS 15 中 您是通过 +MKMapView 的不同属性 + +49 +00:02:46,066 --> 00:02:47,267 +来配置地图的 + +50 +00:02:48,202 --> 00:02:53,173 +而在 iOS 16 中 +我们软性摒弃了这些属性 + +51 +00:02:53,207 --> 00:02:56,376 +推出了全新的 +地图配置 API + +52 +00:02:56,410 --> 00:02:57,344 +来取代这些属性 + +53 +00:02:58,779 --> 00:03:03,984 +MKMapConfiguration 是 +全新地图配置 API 的核心类 + +54 +00:03:04,017 --> 00:03:07,454 +MKMapConfiguration 是 +一个抽象基类 + +55 +00:03:07,487 --> 00:03:09,489 +它有三个具体子类 + +56 +00:03:11,058 --> 00:03:16,296 +MKImageryMapConfiguration 用于 +显示卫星风格的影像 + +57 +00:03:16,330 --> 00:03:20,167 +MKHybridMapConfiguration 用于 +在影像的地图上添加地图特征 + +58 +00:03:20,200 --> 00:03:24,505 +比如 道路标签和兴趣点 + +59 +00:03:26,006 --> 00:03:30,644 +MKStandardMapConfiguration 用于 +显示完全用图形描绘的地图 + +60 +00:03:31,411 --> 00:03:35,549 +这三种地图配置听起来应该不陌生 +因为它们 + +61 +00:03:35,582 --> 00:03:37,251 +和我们已有的地图类型一样 + +62 +00:03:40,153 --> 00:03:44,691 +地图配置的基类支持 +elevationStyle 属性 + +63 +00:03:44,725 --> 00:03:47,294 +它的值可以是 flat 或 realistic + +64 +00:03:48,562 --> 00:03:52,533 +flat 风格的地图是平面的 + +65 +00:03:52,566 --> 00:03:57,137 +道路 包括桥梁和立交桥 +都是扁平呈现的 + +66 +00:03:57,171 --> 00:03:59,673 +elevationStyle 属性的默认值是 flat + +67 +00:04:00,741 --> 00:04:03,110 +realistic 风格的地图中 + +68 +00:04:03,143 --> 00:04:06,346 +地形是按现实世界的 +实际海拔来呈现 + +69 +00:04:06,380 --> 00:04:08,782 +如丘陵和山脉 + +70 +00:04:08,815 --> 00:04:12,553 +道路展现了现实世界中的高度细节 + +71 +00:04:13,754 --> 00:04:17,591 +现在 我们来仔细看看 +地图配置的子类 + +72 +00:04:18,825 --> 00:04:22,496 +MKImageryMapConfiguration 只显示卫星影像 + +73 +00:04:22,529 --> 00:04:26,667 +没有额外的地图 feature +因此没有其它属性 + +74 +00:04:28,068 --> 00:04:31,104 +MKHybridMapConfiguration 有额外的属性 + +75 +00:04:31,138 --> 00:04:33,907 +用来控制过滤特定类别的兴趣点 + +76 +00:04:33,941 --> 00:04:35,909 +以及是否显示交通路况 + +77 +00:04:37,911 --> 00:04:41,949 +MKStandardConfiguration 支持 +emphasisStyle 属性 + +78 +00:04:41,982 --> 00:04:44,051 +它的值可以是 default 或者 muted + +79 +00:04:45,485 --> 00:04:48,755 +从其命名可以知道 除非另作说明 + +80 +00:04:48,789 --> 00:04:50,324 +否则默认使用 default 风格 + +81 +00:04:51,458 --> 00:04:55,762 +muted 风格柔化了 +地图细节的对比度 + +82 +00:04:55,796 --> 00:04:59,633 +可以让用户的注意力更多地 +集中到您显示在地图上的 + +83 +00:04:59,666 --> 00:05:02,102 +额外的图形信息上 + +84 +00:05:02,903 --> 00:05:06,540 +MKStandardMapConfiguration 也有额外的属性 + +85 +00:05:06,573 --> 00:05:09,343 +用来控制过滤特定类别的兴趣点 + +86 +00:05:09,376 --> 00:05:11,278 +以及是否显示交通路况 + +87 +00:05:12,379 --> 00:05:15,682 +我们可以总结下可用的地图配置类 + +88 +00:05:15,716 --> 00:05:16,850 +及其属性 + +89 +00:05:18,819 --> 00:05:21,421 +这个全新的 API 确保您只能 + +90 +00:05:21,455 --> 00:05:23,824 +用支持的选项组合进行配置 + +91 +00:05:23,857 --> 00:05:27,661 +您也可以以原子操作的方式 +改变地图配置 + +92 +00:05:27,694 --> 00:05:31,331 +我们认为这是对当前 API 的 +重大改进 + +93 +00:05:32,799 --> 00:05:34,535 +概括下我们刚刚的内容 + +94 +00:05:34,568 --> 00:05:36,370 +这一表格展示了 + +95 +00:05:36,403 --> 00:05:40,507 +新的 MKMapConfiguration 类和 +MKMapType 属性之间的关联 + +96 +00:05:42,109 --> 00:05:44,611 +全新的 3D 城市体验的地图 + +97 +00:05:44,645 --> 00:05:46,914 +对硬件有一定要求 + +98 +00:05:46,947 --> 00:05:53,020 +在 iOS 中 新地图需要 +搭载 A12 或更新芯片的 iPhone 和 iPad + +99 +00:05:53,053 --> 00:05:55,722 +在 macOS 中 新地图需要 + +100 +00:05:55,756 --> 00:05:57,958 +搭载 M1 或更新芯片的电脑 + +101 +00:05:59,593 --> 00:06:02,829 +在 3D 城市体验不可用地区 + +102 +00:06:02,863 --> 00:06:06,266 +地图会自动调整为 + +103 +00:06:06,300 --> 00:06:08,001 +扁平风格新地图 + +104 +00:06:09,236 --> 00:06:11,772 +在不支持的硬件上 + +105 +00:06:11,805 --> 00:06:13,807 +新地图都会以扁平风格显示 + +106 +00:06:15,375 --> 00:06:19,813 +在搭载 M1 的Mac 中 +您只需在 Xcode 中改变 OS 版本 + +107 +00:06:19,847 --> 00:06:21,815 +就可以模拟两种不同的体验 + +108 +00:06:22,683 --> 00:06:24,585 +我们鼓励您这两种体验都尝试一下 + +109 +00:06:24,618 --> 00:06:26,753 +确保您的 App 在所有设备中 + +110 +00:06:26,787 --> 00:06:28,055 +都能完美运行 + +111 +00:06:29,423 --> 00:06:31,925 +3D 城市体验在全球许多大都市区 + +112 +00:06:31,959 --> 00:06:34,361 +均可使用 + +113 +00:06:35,362 --> 00:06:38,098 +我们还会陆续增加新的城市到该列表中 + +114 +00:06:38,131 --> 00:06:41,735 +您可以去这个讲座的 +相关链接的网页上 + +115 +00:06:41,768 --> 00:06:45,272 +了解更多 3D 城市体验的信息 + +116 +00:06:45,305 --> 00:06:48,942 +那些链接中也包括了如何集成新地图 + +117 +00:06:48,976 --> 00:06:51,011 +和使用地图配置 API 的内容 + +118 +00:06:52,646 --> 00:06:55,115 +现在我们来说下 Overlay + +119 +00:06:55,148 --> 00:06:59,520 +MapKit 在很多年前就已经支持 +多种样式的 Overlay + +120 +00:06:59,553 --> 00:07:01,021 +在 iOS 16 中 + +121 +00:07:01,054 --> 00:07:03,257 +我们改进了已有的 API + +122 +00:07:03,290 --> 00:07:06,894 +让您的 Overlay 可以与地图无缝集成 + +123 +00:07:06,927 --> 00:07:10,163 +我们首先快速回顾下 Overlay 层级 + +124 +00:07:11,632 --> 00:07:14,434 +Overlay 可以在两个不同的层级上渲染 + +125 +00:07:14,468 --> 00:07:17,004 +aboveRoads 和 aboveLabels + +126 +00:07:17,037 --> 00:07:20,374 +MapKit 的 Overlay 插入函数都支持 + +127 +00:07:20,407 --> 00:07:23,477 +在插入时指定渲染的层级 + +128 +00:07:24,778 --> 00:07:28,949 +aboveLabels 将您的 Overlay 渲染到 +所有元素之上 包括标签 + +129 +00:07:29,716 --> 00:07:32,953 +由于标签提供了重要的上下文信息 + +130 +00:07:32,986 --> 00:07:36,857 +我们建议您只在极端情况下 +使用 aboveLabels 的方式 + +131 +00:07:36,890 --> 00:07:40,661 +比如,您完全不希望数据 +与地图有交互的情况下 + +132 +00:07:40,694 --> 00:07:43,263 +如果您想要实现的是让内容 + +133 +00:07:43,297 --> 00:07:45,065 +显示在地图之上 + +134 +00:07:45,098 --> 00:07:48,202 +您可能需要把 +emphasisStyle 属性设置为 muted + +135 +00:07:48,235 --> 00:07:50,938 +或我们稍后讲到的混合模式 + +136 +00:07:52,840 --> 00:07:56,610 +aboveRoads 指的是 Overlay +呈现在地形之上 + +137 +00:07:56,643 --> 00:08:00,080 +包括道路 地表覆盖 +或者水域 + +138 +00:08:00,113 --> 00:08:04,418 +然而 它会在标签以及 + +139 +00:08:04,451 --> 00:08:06,119 +树木和建筑的之下显示 + +140 +00:08:06,153 --> 00:08:07,888 +稍后我们会再详细了解 + +141 +00:08:07,921 --> 00:08:10,991 +aboveRoads 是 iOS 16 中 +全新的默认模式 + +142 +00:08:11,925 --> 00:08:16,230 +接下来 我们来谈谈 +iOS 16 中推出的新功能 + +143 +00:08:16,263 --> 00:08:17,698 +透明建筑 + +144 +00:08:18,832 --> 00:08:21,101 +不管您的 Overlay 级别 + +145 +00:08:21,134 --> 00:08:23,504 +是 aboveRoads 还是 aboveLabels + +146 +00:08:23,537 --> 00:08:26,373 +您的 Overlay 在 +无倾斜的顶视图中 + +147 +00:08:26,406 --> 00:08:28,475 +总是渲染在建筑之上 + +148 +00:08:28,509 --> 00:08:30,711 +然而 我们针对在倾斜地图中 + +149 +00:08:30,744 --> 00:08:32,846 +使用 aboveRoads 的体验 + +150 +00:08:32,880 --> 00:08:34,648 +做了一些改进 + +151 +00:08:35,883 --> 00:08:38,318 +地面物体 如树木 建筑 + +152 +00:08:38,352 --> 00:08:41,088 +在 Overlay 之上显示时 + +153 +00:08:41,121 --> 00:08:43,023 +会自动以透明的方式渲染 + +154 +00:08:43,056 --> 00:08:45,592 +从而不会完全遮挡 Overlay + +155 +00:08:45,626 --> 00:08:49,730 +其 α 值会随着地图的倾斜角度 +不同而发生改变 + +156 +00:08:49,763 --> 00:08:54,067 +如果我们把地图还原为顶视图 +此时倾斜角度为 0° + +157 +00:08:54,101 --> 00:08:57,371 +这些遮挡的地面物体 +将会从视图中消失 + +158 +00:08:57,404 --> 00:08:59,306 +让您的 Overlay 完全可见 + +159 +00:09:00,607 --> 00:09:04,811 +透明建筑也适用于半透明的 Overlay + +160 +00:09:04,845 --> 00:09:07,748 +Overlay 的 α 值 +会与透明建筑的 + +161 +00:09:07,781 --> 00:09:11,218 +α 值叠加在一起 + +162 +00:09:11,251 --> 00:09:13,921 +针对 Overlay 我们还做了一个改变 + +163 +00:09:14,855 --> 00:09:17,024 +在真实地形的地图中 + +164 +00:09:17,057 --> 00:09:18,458 +添加 Overlay 时 + +165 +00:09:18,492 --> 00:09:22,996 +MapKit 会自动将地图 +转换为扁平风格 + +166 +00:09:23,030 --> 00:09:26,266 +在您移除了所有 Overlay 之后 + +167 +00:09:26,300 --> 00:09:27,668 +地图又会自动还原为立体风格 + +168 +00:09:28,635 --> 00:09:32,506 +这一规则有一例外 +就是 MapKit 的 directions API + +169 +00:09:32,539 --> 00:09:35,609 +生成的 Overlay + +170 +00:09:35,642 --> 00:09:39,012 +这些 Overlay 会自动贴合地形显示 + +171 +00:09:39,680 --> 00:09:42,282 +现在 有请 Yingxiu 来为大家展示 + +172 +00:09:42,316 --> 00:09:45,452 +Yingxiu: 谢谢 Eric +大家好 我是 Yingxiu + +173 +00:09:45,485 --> 00:09:47,387 +我是地图 App 团队的工程师 + +174 +00:09:47,421 --> 00:09:50,224 +我会为大家展示我们 +全新的 MapKit 功能 + +175 +00:09:50,257 --> 00:09:54,094 +以及用我们最新的 API 搭建 + +176 +00:09:54,127 --> 00:09:56,363 +一个完美的地图体验有多简单 + +177 +00:09:56,396 --> 00:09:57,865 +我会用我们的示例 App 来展示 + +178 +00:09:57,898 --> 00:09:59,499 +用户如何租踏板车 + +179 +00:09:59,533 --> 00:10:01,168 +环游旧金山 + +180 +00:10:04,571 --> 00:10:06,740 +我们用一个 table view 来显示 + +181 +00:10:06,773 --> 00:10:09,109 +这个 App 的各个功能 + +182 +00:10:10,077 --> 00:10:14,915 +“Operating Area” 可以让用户 +看到哪里能租到踏板车 + +183 +00:10:14,948 --> 00:10:19,753 +“Ride” 可以带用户环游金门大桥 + +184 +00:10:19,786 --> 00:10:22,689 +“Explore” 为用户提供 +旧金山市中心的互动地图 + +185 +00:10:22,723 --> 00:10:25,425 +用户可通过这一地图 + +186 +00:10:25,459 --> 00:10:28,028 +探索海边的景点 + +187 +00:10:28,662 --> 00:10:32,833 +“Highlights” 可以让用户 +近距离查看那些必去的景点 + +188 +00:10:33,534 --> 00:10:36,870 +我们在这一讲座中 +会实现和升级这些功能 + +189 +00:10:36,904 --> 00:10:38,572 +现在开始吧 + +190 +00:10:42,576 --> 00:10:45,412 +首先 我以 Operating Area 功能为例 + +191 +00:10:45,445 --> 00:10:49,316 +给大家看下应用新地图 +有多简单 + +192 +00:10:49,349 --> 00:10:50,784 +然后为您介绍 + +193 +00:10:50,817 --> 00:10:53,453 +我们针对 Overlay 所做的一些改进 + +194 +00:10:54,254 --> 00:10:57,457 +我已经在 Xcode 中 +打开了这一项目 + +195 +00:10:57,491 --> 00:11:00,294 +我们用 iOS 16 SDK 重新编译 + +196 +00:11:00,327 --> 00:11:01,862 +看下结果如何 + +197 +00:11:05,399 --> 00:11:06,333 +好了 + +198 +00:11:06,366 --> 00:11:09,403 +我们已经集成了全新的地图 feature + +199 +00:11:09,436 --> 00:11:11,471 +新的地图视图有着非常丰富的细节 + +200 +00:11:11,505 --> 00:11:13,540 +以及地形上的光照和 + +201 +00:11:13,574 --> 00:11:16,476 +山丘阴影的效果 + +202 +00:11:16,510 --> 00:11:20,581 +让我们继续放大 您可以看到 + +203 +00:11:26,053 --> 00:11:27,087 +建筑 树木 以及地标 + +204 +00:11:29,089 --> 00:11:33,093 +现在我们添加一个多边形 Overlay +将我们的操作区可视化 + +205 +00:11:37,164 --> 00:11:41,869 +我已经有了操作区的多边形数据 + +206 +00:11:41,902 --> 00:11:47,140 +视图加载后 我们首先设置 +region 和 cameraBoundary + +207 +00:11:47,174 --> 00:11:49,309 +确保我们对着正确的区域 + +208 +00:11:50,544 --> 00:11:52,913 +然后 只要添加 Overlay 就可以了 + +209 +00:11:53,914 --> 00:11:55,782 +我们先编译运行一下看看 + +210 +00:11:57,818 --> 00:12:01,522 +多边形的 Overlay 从上往下看时是不透明的 + +211 +00:12:01,555 --> 00:12:08,362 +当我们继续放大 并倾斜视角 + +212 +00:12:08,395 --> 00:12:09,897 +建筑开始显现 + +213 +00:12:09,930 --> 00:12:13,700 +随着倾斜角度增大 +透明度也会增加 + +214 +00:12:13,734 --> 00:12:18,238 +这一效果仅在使用 +aboveRoads Overlay 层级时才会出现 + +215 +00:12:18,272 --> 00:12:21,141 +如果您想有 +透明的建筑和树木透明度 + +216 +00:12:21,175 --> 00:12:23,510 +要记得选择正确的 Overlay 层级 + +217 +00:12:25,412 --> 00:12:28,916 +Overlay 看起来不错 但我希望 +地图在不倾斜的时候 + +218 +00:12:28,949 --> 00:12:30,651 +也能显示 + +219 +00:12:30,684 --> 00:12:33,287 +我们回到代码 将其设置为半透明 + +220 +00:12:37,324 --> 00:12:39,693 +我们调整 α 值为 0.8 + +221 +00:12:44,131 --> 00:12:45,999 +现在我们就有了一个透明得 Overlay + +222 +00:12:46,033 --> 00:12:49,736 +即使没有倾斜 我也能看到 +道路和建筑 + +223 +00:12:49,770 --> 00:12:53,240 +如果我继续放大 倾斜地图 + +224 +00:12:53,273 --> 00:12:55,642 +透明度还是会增加 + +225 +00:12:55,676 --> 00:12:57,411 +看起来很不错 + +226 +00:12:57,444 --> 00:12:59,680 +这就是多边形 Overlay + +227 +00:12:59,713 --> 00:13:03,417 +接下来 我向大家展示 +如何整合真实地形 + +228 +00:13:03,450 --> 00:13:05,719 +来显示有高低差的路线 + +229 +00:13:05,752 --> 00:13:08,355 +以实现我们的 “Ride” 功能 + +230 +00:13:08,388 --> 00:13:10,657 +让用户可以游览金门大桥 + +231 +00:13:14,962 --> 00:13:17,831 +我们首先配置地图视图 + +232 +00:13:17,865 --> 00:13:20,334 +我们可以用代码改变 elevationStyle + +233 +00:13:20,367 --> 00:13:23,303 +也可以打开 Interface Builder + +234 +00:13:23,337 --> 00:13:24,605 +右边的 Inspector 面板 + +235 +00:13:26,874 --> 00:13:30,110 +就可以看到可用的地图视图的配置选项 + +236 +00:13:30,143 --> 00:13:32,579 +在 “elevation” 处勾选 “realistic” + +237 +00:13:34,214 --> 00:13:36,016 +现在,让我们添加路线 + +238 +00:13:38,752 --> 00:13:41,121 +我们希望在用户打开 显示路线 开关时 + +239 +00:13:41,154 --> 00:13:44,324 +能显示一条路线 + +240 +00:13:44,358 --> 00:13:47,761 +我们也会让相机对焦到路线上 +并随着路线移动 + +241 +00:13:52,599 --> 00:13:56,069 +因为我们要显示的 +是金门大桥的路线 + +242 +00:13:56,103 --> 00:13:59,239 +我们用 Presidio Park 入口 +作为起点 + +243 +00:13:59,273 --> 00:14:01,909 +Battery Spencer 作为终点 + +244 +00:14:05,112 --> 00:14:08,015 +地图视图加载后 +我们创建标注 + +245 +00:14:08,048 --> 00:14:10,651 +以标记起点和终点 + +246 +00:14:16,557 --> 00:14:18,759 +设置坐标和名称 + +247 +00:14:18,792 --> 00:14:21,428 +并加到一个标记数组中 + +248 +00:14:21,461 --> 00:14:23,497 +然后把数组添加到地图视图 + +249 +00:14:31,839 --> 00:14:34,308 +现在 我们可以看看路线折线了 + +250 +00:14:37,211 --> 00:14:39,580 +但是普通的Overlay 会让地图扁平化 + +251 +00:14:39,613 --> 00:14:42,249 +MapKit 的 Direction API +返回的折线 + +252 +00:14:42,282 --> 00:14:44,284 +将保留逼真的地形 + +253 +00:14:45,986 --> 00:14:50,490 +在这个 IBAction 函数中 +如果开关打开 + +254 +00:14:50,524 --> 00:14:54,027 +我们将用前面定义的坐标 +建立位置标记 + +255 +00:14:57,998 --> 00:15:02,736 +然后我们用源位置和目标位置 + +256 +00:15:02,769 --> 00:15:06,206 +创建寻路请求 + +257 +00:15:06,240 --> 00:15:08,675 +最后 获取路线 + +258 +00:15:11,812 --> 00:15:13,847 +如果获取操作成功 + +259 +00:15:13,881 --> 00:15:16,483 +只要将路线折线添加为 Overlay 即可 + +260 +00:15:21,889 --> 00:15:22,723 +好了 + +261 +00:15:22,756 --> 00:15:24,725 +我们重新编译下 看看结果如何吧 + +262 +00:15:29,830 --> 00:15:33,100 +您能看到标记自动升级到 + +263 +00:15:33,133 --> 00:15:35,135 +新的有斜度的外观 + +264 +00:15:35,169 --> 00:15:38,572 +并且完美呈现了正确的高度 + +265 +00:15:38,605 --> 00:15:40,474 +当我打开路线显示 + +266 +00:15:40,507 --> 00:15:41,909 +摄像头倾斜 + +267 +00:15:41,942 --> 00:15:43,977 +然后 就有了更完美的视角 + +268 +00:15:46,079 --> 00:15:48,415 +如您所见 路线是跟随 + +269 +00:15:48,448 --> 00:15:50,083 +地形升高的 + +270 +00:15:50,117 --> 00:15:51,518 +当导航到复杂的十字路口时 + +271 +00:15:51,552 --> 00:15:54,121 +这就非常便捷了 + +272 +00:15:54,154 --> 00:15:57,157 +它还能跟随桥梁上的道路 + +273 +00:15:57,191 --> 00:15:59,159 +还有 注意桥柱间呈现的 + +274 +00:15:59,193 --> 00:16:01,261 +路线的细节 + +275 +00:16:03,830 --> 00:16:06,733 +最后 地图真正倾斜后 + +276 +00:16:06,767 --> 00:16:08,302 +您可以看到树木前面呈现的 + +277 +00:16:08,335 --> 00:16:11,004 +蜿蜒的路线 + +278 +00:16:11,038 --> 00:16:14,575 +看 没有树木的地方 + +279 +00:16:14,608 --> 00:16:16,176 +路线颜色也消失了 + +280 +00:16:16,210 --> 00:16:18,779 +我们缩小看看这里是什么 + +281 +00:16:22,850 --> 00:16:26,153 +好 这部分的路线是穿过隧道的 + +282 +00:16:26,186 --> 00:16:28,555 +所以会以透明的方式显示 + +283 +00:16:28,589 --> 00:16:32,259 +搭载 A12 的 iOS 设备支持 + +284 +00:16:32,292 --> 00:16:35,662 +ElevationRealisticStyle 和 +有高低差的路线 + +285 +00:16:35,696 --> 00:16:39,166 +如果我在更早的设备上 +运行同样的 App + +286 +00:16:39,199 --> 00:16:44,872 +就会自动转变为 2D 地图上的 +2D 路线 + +287 +00:16:44,905 --> 00:16:47,174 +在 3D 城市体验中添加有高低差的路线 + +288 +00:16:47,207 --> 00:16:49,409 +就是如此简单 + +289 +00:16:49,443 --> 00:16:51,945 +接下来 再次有请 Eric + +290 +00:16:51,979 --> 00:16:53,247 +Eric: 谢谢 Yingxiu + +291 +00:16:53,280 --> 00:16:55,249 +这场骑踏板车环游金门大桥的旅程 + +292 +00:16:55,282 --> 00:16:57,384 +实在是令人叹为观止 + +293 +00:16:57,417 --> 00:17:00,821 +以上是 MapKit 中关于 +Overlay 的新内容 + +294 +00:17:02,556 --> 00:17:05,459 +接下来要介绍的是混合模式 + +295 +00:17:05,492 --> 00:17:09,730 +这一全新 API 为您的 Overlay 的外观 +和体验提供了更多的控制 + +296 +00:17:09,763 --> 00:17:12,833 +解锁了一系列创新的可能性 + +297 +00:17:14,067 --> 00:17:16,103 +我相信你们大多数人已经熟悉 + +298 +00:17:16,136 --> 00:17:18,705 +照片编辑类 App +和 Apple CoreGraphics API 中的 + +299 +00:17:18,739 --> 00:17:21,275 +混合模式 + +300 +00:17:21,308 --> 00:17:23,177 +在一个混合操作中 + +301 +00:17:23,210 --> 00:17:25,078 +两个图层会按照 + +302 +00:17:25,112 --> 00:17:26,647 +混合模式指定的 + +303 +00:17:26,680 --> 00:17:28,815 +一套公式来进行叠加 + +304 +00:17:28,849 --> 00:17:32,486 +现在 我们来看看一个 +如何在 MapKit 环境下 + +305 +00:17:32,519 --> 00:17:34,121 +使用混合模式的案例 + +306 +00:17:35,522 --> 00:17:38,458 +在这个场景中 我想要重高亮 + +307 +00:17:38,492 --> 00:17:41,128 +地图中间的 + +308 +00:17:41,161 --> 00:17:43,096 +旧金山的 Presidio National Park 区域 + +309 +00:17:43,130 --> 00:17:45,599 +首先 创建一个 + +310 +00:17:45,632 --> 00:17:47,568 +裁剪成 Presidio 形状的 Overlay + +311 +00:17:47,601 --> 00:17:50,003 +覆盖整个地图区域 + +312 +00:17:51,338 --> 00:17:53,273 +我还没有使用混合模式 + +313 +00:17:53,307 --> 00:17:55,442 +这只是一个简单的 Overlay + +314 +00:17:55,475 --> 00:17:58,011 +就像一个很大的方形甜甜圈 + +315 +00:17:58,045 --> 00:18:00,747 +接下来 我在 Overlay 中 + +316 +00:18:00,781 --> 00:18:04,384 +使用色相混合模式 并用灰色填充 + +317 +00:18:04,418 --> 00:18:06,320 +这可以减少 Presidio 以外的 + +318 +00:18:06,353 --> 00:18:08,288 +地图的饱和度 + +319 +00:18:08,322 --> 00:18:11,091 +接下来 复制这一 Overlay + +320 +00:18:11,124 --> 00:18:13,460 +使用强光混合模式 + +321 +00:18:13,493 --> 00:18:14,928 +并用深灰色填充 + +322 +00:18:16,263 --> 00:18:18,732 +这可以使 Presidio 周围的区域 + +323 +00:18:18,765 --> 00:18:20,567 +颜色加深 + +324 +00:18:20,601 --> 00:18:22,236 +这看起来已经很不错了 + +325 +00:18:22,269 --> 00:18:23,937 +但是 我们还要添加一个 Overlay + +326 +00:18:23,971 --> 00:18:27,641 +这次 我们增加 +Presidio 形状的 Overlay + +327 +00:18:27,674 --> 00:18:29,810 +使用饱和混合模式 + +328 +00:18:29,843 --> 00:18:31,311 +并用黄色填充 + +329 +00:18:32,279 --> 00:18:36,316 +额 这不是我想要的效果 + +330 +00:18:36,350 --> 00:18:38,886 +这颜色太亮了 + +331 +00:18:38,919 --> 00:18:40,687 +我们试下别的 + +332 +00:18:40,721 --> 00:18:43,924 +我们试下颜色加深混合模式 +使用灰色填充 + +333 +00:18:44,992 --> 00:18:47,327 +哇喔 看起来好多了 + +334 +00:18:47,361 --> 00:18:48,795 +完美 + +335 +00:18:48,829 --> 00:18:50,697 +现在 我们来看看代码 + +336 +00:18:52,099 --> 00:18:54,434 +要使用刚刚看到的效果 + +337 +00:18:54,468 --> 00:18:57,738 +我们在 MKOverlayRenderer 中 +增加一个 + +338 +00:18:57,771 --> 00:18:59,573 +blendMode 属性 + +339 +00:18:59,606 --> 00:19:01,341 +您只需要在 overlay 渲染器里设置 + +340 +00:19:01,375 --> 00:19:05,245 +想要的CoreGraphics 混合模式 +就可以了 + +341 +00:19:06,113 --> 00:19:09,917 +如之前所说 混合模式 +和顺序相关 + +342 +00:19:09,950 --> 00:19:11,885 +栈底部的 Overlay + +343 +00:19:11,919 --> 00:19:13,720 +与地图混合 + +344 +00:19:13,754 --> 00:19:16,290 +倒数第二个 Overlay +在前一个混合操作的基础上 + +345 +00:19:16,323 --> 00:19:18,926 +再次混合 + +346 +00:19:18,959 --> 00:19:21,128 +以此类推 + +347 +00:19:21,161 --> 00:19:23,764 +在 MapKit 中 Overlay 的顺序 + +348 +00:19:23,797 --> 00:19:25,799 +是在插入时决定的 + +349 +00:19:25,832 --> 00:19:29,403 +MKMapView 提供了很多 overlay 插入函数 + +350 +00:19:29,436 --> 00:19:33,106 +它们都支持在绝对的或相对的位置插入 overlay + +351 +00:19:35,576 --> 00:19:38,278 +MapKit 支持各种不同的混合模式 + +352 +00:19:38,312 --> 00:19:41,114 +我们今天无法逐一介绍 + +353 +00:19:41,148 --> 00:19:42,783 +我鼓励大家讲座之后 +可以都尝试一下 + +354 +00:19:43,317 --> 00:19:45,752 +以上就是混合模式的内容了 + +355 +00:19:45,786 --> 00:19:47,087 +如您所见 + +356 +00:19:47,120 --> 00:19:49,456 +混合模式是控制地图样式的 + +357 +00:19:49,489 --> 00:19:51,258 +强大工具 + +358 +00:19:51,291 --> 00:19:54,328 +您可以使用它来 +高亮某些地理区域 + +359 +00:19:54,361 --> 00:19:57,397 +同时降低其它区域的对比度 +来突现出那些区域 + +360 +00:19:57,431 --> 00:19:58,599 +它能做的还不仅于此 + +361 +00:20:00,133 --> 00:20:03,637 +接下来 我们来看下Selectable Map Features的功能 + +362 +00:20:03,670 --> 00:20:06,006 +这一功能呼声很高 + +363 +00:20:06,039 --> 00:20:07,941 +我很高兴终于能与大家见面了 + +364 +00:20:09,943 --> 00:20:12,846 +如果您的 App 中 +已经使用了 MapKit + +365 +00:20:12,880 --> 00:20:16,683 +那您可能会用标注来显示城市位置 + +366 +00:20:16,717 --> 00:20:19,353 +兴趣点或者是某些实体 + +367 +00:20:20,554 --> 00:20:22,890 +除非您使用了兴趣点过滤 + +368 +00:20:22,923 --> 00:20:25,893 +您用来添加的标记的地图中 +已经包含了一些 + +369 +00:20:25,926 --> 00:20:28,862 +Apple 提供的简单标注 + +370 +00:20:29,830 --> 00:20:32,866 +到目前为止 您的用户只能 + +371 +00:20:32,900 --> 00:20:34,868 +与您提供的标注互动 + +372 +00:20:35,636 --> 00:20:39,506 +在 iOS 16 中 +这一切即将改变 + +373 +00:20:39,540 --> 00:20:42,643 +使用我们全新的 +Selectable Map Features功能 API + +374 +00:20:42,676 --> 00:20:47,181 +您现在可以让用户 +选择地图上的功能 + +375 +00:20:48,715 --> 00:20:51,952 +Selectable Map Features 里的 +Feature 类型有 兴趣点 + +376 +00:20:51,985 --> 00:20:55,689 +如商店 餐厅和地标建筑 + +377 +00:20:55,722 --> 00:20:59,059 +地理区域 +如城市和省份 + +378 +00:20:59,092 --> 00:21:02,629 +以及地表特征 如山脉和湖泊 + +379 +00:21:03,897 --> 00:21:07,000 +在您的 App 中使用 +Selectable Map Features功能 + +380 +00:21:07,034 --> 00:21:10,737 +您只需要如下几个步骤 + +381 +00:21:10,771 --> 00:21:14,441 +首先 配置您希望可选的 feature 类型 + +382 +00:21:14,474 --> 00:21:17,277 +如我刚刚介绍的 +一共有三个主要的 feature 类型 + +383 +00:21:17,311 --> 00:21:19,279 +您如果让这三种类型 +全部在 App 里都可以交互 + +384 +00:21:19,313 --> 00:21:21,782 +可能没有什么意义 + +385 +00:21:22,616 --> 00:21:24,318 +对于兴趣点 feature + +386 +00:21:24,351 --> 00:21:27,087 +您也可以使用我们现有的 +过滤 API + +387 +00:21:27,120 --> 00:21:30,490 +来限制可以显示的兴趣点类别 + +388 +00:21:30,524 --> 00:21:31,959 +从而实现可选的 feature + +389 +00:21:33,627 --> 00:21:36,964 +其次 实现 MKMapView 的 +代理回调函数 + +390 +00:21:36,997 --> 00:21:38,932 +来处理选择事件 + +391 +00:21:38,966 --> 00:21:42,369 +您可以自由选择处理这些事件 + +392 +00:21:42,402 --> 00:21:45,372 +您可能想控制选择的 feature 如何呈现 + +393 +00:21:45,405 --> 00:21:47,674 +或者您可能想显示额外的 UI + +394 +00:21:47,708 --> 00:21:49,510 +来响应选择事件 + +395 +00:21:50,944 --> 00:21:53,480 +其三 您会希望在 + +396 +00:21:53,514 --> 00:21:54,982 +您的 App 的用户界面上 + +397 +00:21:55,015 --> 00:21:56,917 +请求和现实额外的地点信息 + +398 +00:21:57,618 --> 00:21:59,586 +嵌入在地图 feature 中的信息 + +399 +00:21:59,620 --> 00:22:01,522 +仅限于屏幕的可见范围之内 + +400 +00:22:02,756 --> 00:22:06,059 +为了给用户提供所选地点的 +更多内容 + +401 +00:22:06,093 --> 00:22:08,428 +您需要请求额外信息 + +402 +00:22:09,196 --> 00:22:11,632 +让我们通过各个步骤的实现 + +403 +00:22:11,665 --> 00:22:13,267 +来了解这个全新的 API + +404 +00:22:14,768 --> 00:22:17,137 +首先配置哪个地图 feature + +405 +00:22:17,171 --> 00:22:18,839 +是可选的 + +406 +00:22:18,872 --> 00:22:22,376 +使用新的 +selectableMapFeatures 属性 + +407 +00:22:23,977 --> 00:22:27,714 +您可以使用包含兴趣点 + +408 +00:22:27,748 --> 00:22:29,850 +地理区域和地表特征的任意组合 + +409 +00:22:29,883 --> 00:22:32,619 +一旦配置好了可选的地图 feature + +410 +00:22:32,653 --> 00:22:35,389 +如果用户点击这些 feature + +411 +00:22:35,422 --> 00:22:38,258 +您就会收到新的代理回调 + +412 +00:22:38,292 --> 00:22:41,695 +让您可以自定义选择行为 + +413 +00:22:41,728 --> 00:22:45,732 +您收到的第一个回调就是 +新的 didSelect annotation 回调 + +414 +00:22:46,333 --> 00:22:50,404 +这一回调函数可供您 + +415 +00:22:50,437 --> 00:22:51,839 +使用稍后介绍的全新请求 API + +416 +00:22:51,872 --> 00:22:54,842 +来请求地图条目有关的额外数据 + +417 +00:22:56,210 --> 00:23:00,914 +您收到的第二个回调是 +已有的 viewFor annotation 回调 + +418 +00:23:00,948 --> 00:23:03,183 +您可以用它来定制视图 + +419 +00:23:03,217 --> 00:23:06,053 +从而在选定状态中显示 + +420 +00:23:06,086 --> 00:23:07,955 +我们为这个已有的 API + +421 +00:23:07,988 --> 00:23:10,991 +增加了一个全新的标注类型 + +422 +00:23:11,024 --> 00:23:13,760 +称之为 MKMapFeatureAnnotation + +423 +00:23:13,794 --> 00:23:16,463 +在用户选择地图 feature 时 + +424 +00:23:16,496 --> 00:23:18,699 +这个类会被传给标注视图 + +425 +00:23:19,800 --> 00:23:23,003 +MKMapFeatureAnnotation 类有许多属性 + +426 +00:23:23,036 --> 00:23:25,138 +您可以通过查看 featureType 属性 + +427 +00:23:25,172 --> 00:23:26,640 +来判断 feature 的类型是兴趣点 + +428 +00:23:26,673 --> 00:23:28,041 +地理区域 + +429 +00:23:28,075 --> 00:23:30,344 +还是地表特征 + +430 +00:23:31,345 --> 00:23:33,814 +如果地图 feature 是兴趣点 + +431 +00:23:33,847 --> 00:23:35,616 +通过 pointOfInterestCategory 属性 + +432 +00:23:35,649 --> 00:23:37,818 +您可知道这是哪种类型的兴趣点 + +433 +00:23:37,851 --> 00:23:40,287 +通过 iconStyle 属性 + +434 +00:23:40,320 --> 00:23:42,756 +您可获得关于图标的额外信息 + +435 +00:23:42,789 --> 00:23:45,125 +比如 背景颜色 + +436 +00:23:45,158 --> 00:23:46,727 +和图标图片 + +437 +00:23:48,262 --> 00:23:51,598 +我们来看一个 +如何使用 viewFor annotation 回调 + +438 +00:23:51,632 --> 00:23:53,600 +来自定义标注视图的案例 + +439 +00:23:55,102 --> 00:23:57,738 +如果您想要获得和地图 App + +440 +00:23:57,771 --> 00:24:00,007 +一样的选择样式 您只需要 + +441 +00:24:00,040 --> 00:24:01,108 +返回 nil + +442 +00:24:02,309 --> 00:24:04,845 +如果您想自定义选择样式 + +443 +00:24:04,878 --> 00:24:06,947 +您可以返回一个标注视图 + +444 +00:24:06,980 --> 00:24:09,783 +这和您实现自己的标注是相同的方式 + +445 +00:24:10,784 --> 00:24:13,554 +MKMarkerAnnotationView 是一个不错的选择 + +446 +00:24:13,587 --> 00:24:15,689 +它能为您提供和地图 App + +447 +00:24:15,722 --> 00:24:17,024 +一样的气泡样式 + +448 +00:24:17,057 --> 00:24:18,525 +和渐变效果 + +449 +00:24:18,559 --> 00:24:21,428 +您也可以指定颜色和图标 + +450 +00:24:22,429 --> 00:24:26,333 +在这个示例中 我用了 +从 feature 的图标风格中 + +451 +00:24:26,366 --> 00:24:29,870 +获得的图片 仅仅改了一下颜色 + +452 +00:24:29,903 --> 00:24:31,872 +让其与 App 的色调相匹配 + +453 +00:24:33,040 --> 00:24:35,008 +如果您想全部都自定义 + +454 +00:24:35,042 --> 00:24:37,444 +可以使用您创建的 + +455 +00:24:37,477 --> 00:24:39,079 +任何标注视图子类 + +456 +00:24:40,047 --> 00:24:42,950 +如您刚看到的 您可以使用 +feature 标注 + +457 +00:24:42,983 --> 00:24:45,986 +来获取选中 feature 的视觉信息 + +458 +00:24:46,854 --> 00:24:51,925 +通过将 feature 标注传递给 +全新的 MKMapItemRequest API + +459 +00:24:51,959 --> 00:24:55,028 +您也可以为选中的 feature +获取一个地图条目 + +460 +00:24:57,231 --> 00:25:00,901 +地图条目里有关于地点的 +额外的元数据 + +461 +00:25:00,934 --> 00:25:06,139 +如地址 名称 电话号码 URL + +462 +00:25:07,508 --> 00:25:11,144 +如果您的用户想要了解的 +额外的元数据 + +463 +00:25:11,178 --> 00:25:13,881 +在 MapKit 中不可用时 + +464 +00:25:13,914 --> 00:25:15,983 +地图条目也提供了 +跳转至地图 App 的功能 + +465 +00:25:17,184 --> 00:25:20,220 +这部分 我再次有请 Yingxiu +为我们演示 + +466 +00:25:20,254 --> 00:25:21,688 +Yingxiu: 谢谢 Eric + +467 +00:25:22,956 --> 00:25:26,159 +Eric 刚刚和大家介绍了 +Selectable Map Features + +468 +00:25:26,193 --> 00:25:30,063 +我来给大家演示下 +使用这个 API 有多么简单 + +469 +00:25:33,000 --> 00:25:36,470 +让我们继续实现示例 App 的 +Explore 功能 + +470 +00:25:36,503 --> 00:25:40,107 +我们想要用户可以探索海边的 + +471 +00:25:40,140 --> 00:25:41,575 +一些有趣的地方 + +472 +00:25:41,608 --> 00:25:43,076 +如果他们点击兴趣点 + +473 +00:25:43,110 --> 00:25:44,978 +将会弹出标注 + +474 +00:25:45,012 --> 00:25:48,315 +我们会为点击的位置播放镜头动画 + +475 +00:25:48,348 --> 00:25:50,617 +在底部显示信息卡 + +476 +00:25:52,452 --> 00:25:55,422 +首先 我们过滤地图上的兴趣点 + +477 +00:25:55,455 --> 00:25:59,059 +移除与我们的行程不相关的类别 + +478 +00:26:00,661 --> 00:26:03,230 +除了在代码中应用过滤 + +479 +00:26:03,263 --> 00:26:07,167 +我们还可以在 +Interface Builder 的 Inspector 中设置 + +480 +00:26:07,201 --> 00:26:09,069 +我们选择地图视图 + +481 +00:26:09,102 --> 00:26:11,371 +打开右边的 Inspector + +482 +00:26:13,307 --> 00:26:16,243 +我们选择排除过滤器 + +483 +00:26:18,278 --> 00:26:21,048 +然后选择不需要的类别 + +484 +00:26:21,081 --> 00:26:25,319 +比如 机场 + +485 +00:26:25,352 --> 00:26:31,925 +汽车租赁 医院和洗衣店 + +486 +00:26:33,227 --> 00:26:36,163 +现在地图视图上只剩下 + +487 +00:26:36,196 --> 00:26:37,664 +我们想要的那些兴趣点了 + +488 +00:26:42,436 --> 00:26:45,639 +启用 Selectable Map Features 很简单 + +489 +00:26:45,672 --> 00:26:47,908 +我们只需要指定 + +490 +00:26:47,941 --> 00:26:50,911 +一个想要的可选 feature 的选项集 + +491 +00:26:54,848 --> 00:26:59,152 +在这个示例 App 中 +我们只用了兴趣点 + +492 +00:26:59,186 --> 00:27:00,921 +但别忘了 我们也支持 + +493 +00:27:00,954 --> 00:27:02,489 +可选的地表特征 + +494 +00:27:02,523 --> 00:27:03,991 +和地理区域 + +495 +00:27:10,397 --> 00:27:15,169 +我们可以用已有的 +代理方法 mapView viewForAnnotation + +496 +00:27:15,202 --> 00:27:17,404 +来为 feature 标注创建一个视图 + +497 +00:27:19,039 --> 00:27:22,242 +这里 我们暂时只返回 nil + +498 +00:27:26,280 --> 00:27:29,883 +以使用 MapKit 默认提供的 +有着渐变色的标注 + +499 +00:27:30,651 --> 00:27:32,986 +我们稍后会回来进行定制 + +500 +00:27:35,756 --> 00:27:38,158 +如果标注处于选中的状态 + +501 +00:27:38,192 --> 00:27:41,962 +新的代理回调 +mapView didSelectAnnotation 会 + +502 +00:27:41,995 --> 00:27:44,598 +通知我们 + +503 +00:27:46,200 --> 00:27:49,636 +我们用这一功能来实现镜头动画 + +504 +00:27:49,670 --> 00:27:51,839 +并放大选中的 feature + +505 +00:27:53,640 --> 00:27:58,111 +首先 我们把 annotation 转换为 featureAnnotation + +506 +00:27:58,145 --> 00:28:00,814 +然后创建一个地图条目请求 + +507 +00:28:04,751 --> 00:28:08,856 +这是一个通过 feature 标注 +获得额外地点信息的 + +508 +00:28:08,889 --> 00:28:10,691 +全新 API + +509 +00:28:11,992 --> 00:28:13,994 +我们发送请求 + +510 +00:28:19,099 --> 00:28:21,802 +一旦获取信息成功 + +511 +00:28:21,835 --> 00:28:24,204 +我们会通过镜头动画移动到地图条目上 + +512 +00:28:27,007 --> 00:28:29,543 +镜头动画结束后 + +513 +00:28:29,576 --> 00:28:31,879 +我们会把 feature 条目的细节 + +514 +00:28:31,912 --> 00:28:33,647 +显示在一张信息卡上 + +515 +00:28:34,781 --> 00:28:36,984 +重新编译看看效果如何 + +516 +00:28:41,555 --> 00:28:44,892 +我们选一个海边的兴趣点 + +517 +00:28:47,261 --> 00:28:49,229 +渐变的标注出来了 + +518 +00:28:49,263 --> 00:28:51,932 +镜头移动到标注位置 + +519 +00:28:51,965 --> 00:28:53,667 +然后信息卡出现 + +520 +00:28:54,601 --> 00:28:55,802 +这是一个博物馆 + +521 +00:28:55,836 --> 00:28:57,037 +这是 URL + +522 +00:28:57,070 --> 00:28:59,039 +如果感兴趣的话 +我们可以进一步了解 + +523 +00:28:59,773 --> 00:29:01,708 +这里有详细地址 + +524 +00:29:03,443 --> 00:29:05,279 +如果这是个地标建筑 + +525 +00:29:05,312 --> 00:29:07,748 +就能看到其精美的图解 + +526 +00:29:14,655 --> 00:29:16,223 +现在回到代码 + +527 +00:29:16,256 --> 00:29:18,125 +为选中的状态 + +528 +00:29:18,158 --> 00:29:19,293 +自定义我们的标注 + +529 +00:29:22,663 --> 00:29:25,899 +我们创建一个 MKMarkerAnnotationView +来替代 nil + +530 +00:29:26,700 --> 00:29:29,703 +我们把 annotation 转换为 featureAnnotation + +531 +00:29:29,736 --> 00:29:33,674 +这样可以使用其中的具体数据 +来自定义视图 + +532 +00:29:34,875 --> 00:29:37,978 +我们给标注加上略带紫色的色彩 + +533 +00:29:38,011 --> 00:29:41,181 +让它和 App 的风格一致 + +534 +00:29:42,950 --> 00:29:45,552 +我们也可以定制标注的字形 + +535 +00:29:47,054 --> 00:29:51,158 +SelectedGlyphImage +是被选中状态的标注字形 + +536 +00:29:52,659 --> 00:29:54,895 +GlyphImage 尺寸则要小一些 + +537 +00:29:54,928 --> 00:29:58,332 +是未被选中状态的标注字形 + +538 +00:29:59,333 --> 00:30:02,202 +我们推荐给它们指定相同的字形 + +539 +00:30:02,236 --> 00:30:06,573 +这样从非选中状态到选中状态的 +过渡才比较自然 + +540 +00:30:08,242 --> 00:30:12,346 +我们使用 featureAnnotation 中的 +iconStyle 图像 + +541 +00:30:13,881 --> 00:30:17,951 +MKIconStyle 是 iOS 16 中的 +一种新的类型 + +542 +00:30:17,985 --> 00:30:22,689 +用来保存选中的兴趣点的图标和颜色信息 + +543 +00:30:22,723 --> 00:30:24,758 +重新编译 看看效果如何 + +544 +00:30:29,696 --> 00:30:30,931 +不错 + +545 +00:30:30,964 --> 00:30:32,332 +现在我们有了一个 + +546 +00:30:32,366 --> 00:30:34,334 +与 App 色调相匹配的标注了 + +547 +00:30:34,368 --> 00:30:36,503 +它仍然使用了 Apple 的图标 + +548 +00:30:40,374 --> 00:30:43,143 +现在您了解了如何在您自己的 App 中 + +549 +00:30:43,177 --> 00:30:46,113 +使用 Selectable Map Features +和自定义标注了 + +550 +00:30:46,146 --> 00:30:48,382 +现在 我们重新有请 Eric + +551 +00:30:49,183 --> 00:30:50,384 +Eric: 谢谢 Yingxiu + +552 +00:30:50,417 --> 00:30:53,554 +如您所见 Selectable Map Features API + +553 +00:30:53,587 --> 00:30:55,689 +让您的用户可以用一种全新的方式 + +554 +00:30:55,722 --> 00:30:57,424 +与地图互动 + +555 +00:30:57,457 --> 00:30:59,359 +MapFeatureAnnotation 类 + +556 +00:30:59,393 --> 00:31:02,262 +与 MapView 代理回调函数 +相结合 + +557 +00:31:02,296 --> 00:31:05,065 +让您可以自定义 +选中项的外观和特性 + +558 +00:31:05,098 --> 00:31:08,235 +而 MapItemRequest 让您可以 +获得一个地图条目的 feature 信息 + +559 +00:31:08,268 --> 00:31:10,437 +从而可以访问 + +560 +00:31:10,470 --> 00:31:11,705 +关于选中的地图 feature 的 + +561 +00:31:11,738 --> 00:31:13,440 +额外信息 + +562 +00:31:14,074 --> 00:31:16,977 +接下来 我们来看看 +Look Around 功能 + +563 +00:31:18,245 --> 00:31:21,782 +iOS 13 的 地图 App +就推出了 Look Around + +564 +00:31:21,815 --> 00:31:24,117 +倍受欢迎 + +565 +00:31:24,151 --> 00:31:25,319 +您可以使用 Look Around + +566 +00:31:25,352 --> 00:31:27,621 +获得沉浸式的实地体验 + +567 +00:31:27,654 --> 00:31:30,958 +Look Around 的影像 +极尽细节 + +568 +00:31:30,991 --> 00:31:33,994 +利用 3D 模型提供了其它地图 + +569 +00:31:34,027 --> 00:31:35,362 +都无法比拟的真实感 + +570 +00:31:37,331 --> 00:31:39,199 +Look Around 已开放 + +571 +00:31:39,233 --> 00:31:41,468 +全球多个地区 包括这些城市 + +572 +00:31:41,502 --> 00:31:43,036 +和国家 + +573 +00:31:44,872 --> 00:31:47,908 +我们会持续增加新地区的支持 + +574 +00:31:47,941 --> 00:31:51,111 +您可以在本次讲座附带的链接中的 +可用特性网页上 + +575 +00:31:51,144 --> 00:31:54,715 +查找 Look Around 部分的内容 +来了解更多 + +576 +00:31:54,748 --> 00:31:58,919 +在 iOS 16中 我们将 Look Around +加入到了 MapKit 中 + +577 +00:31:58,952 --> 00:32:01,889 +只需简单三步即可应用 + +578 +00:32:03,590 --> 00:32:05,692 +首先 检查数据在目标区域 + +579 +00:32:05,726 --> 00:32:07,694 +是否可用 + +580 +00:32:08,362 --> 00:32:11,131 +即使 Look Around +在您的目标区域可用 + +581 +00:32:11,164 --> 00:32:13,934 +但并不是每个位置的街道 +都可见 + +582 +00:32:13,967 --> 00:32:15,736 +因此 Look Around 影像 + +583 +00:32:15,769 --> 00:32:18,305 +也有可能不可用 + +584 +00:32:18,338 --> 00:32:21,475 +确认 Look Around 数据可用后 + +585 +00:32:21,508 --> 00:32:22,910 +您需要将该数据 + +586 +00:32:22,943 --> 00:32:25,045 +传送到 Look Around View Controller + +587 +00:32:25,078 --> 00:32:26,713 +或 Look Around Snapshotter + +588 +00:32:27,848 --> 00:32:30,684 +最后 如果 Look Around 数据可用 + +589 +00:32:30,717 --> 00:32:32,386 +您可以更新 App 界面 + +590 +00:32:32,419 --> 00:32:35,155 +来显示 Look Around 预览 + +591 +00:32:35,189 --> 00:32:37,791 +我们看看完成这三个步骤 + +592 +00:32:37,824 --> 00:32:39,826 +您所要用到的新的 API + +593 +00:32:41,762 --> 00:32:44,631 +尝试显示 Look Around 预览 +的第一步是 + +594 +00:32:44,665 --> 00:32:46,800 +检查数据的可用性 + +595 +00:32:46,834 --> 00:32:50,304 +因此 您需要 +创建 MKLookAroundSceneRequest + +596 +00:32:50,337 --> 00:32:54,208 +这是 iOS 16 新推出的类 + +597 +00:32:54,241 --> 00:32:57,845 +您可以通过坐标或地图条目 + +598 +00:32:57,878 --> 00:32:59,313 +初始化一个新的实例 + +599 +00:33:00,547 --> 00:33:03,984 +接下来 是获取场景属性 + +600 +00:33:04,017 --> 00:33:07,855 +这是一个可选的异步属性 + +601 +00:33:07,888 --> 00:33:11,525 +如果数据可用 +会返回一个场景实例 + +602 +00:33:11,558 --> 00:33:12,926 +如果数据不可用 + +603 +00:33:12,960 --> 00:33:15,128 +返回的是 nil + +604 +00:33:15,162 --> 00:33:17,297 +如果请求出错 + +605 +00:33:17,331 --> 00:33:18,765 +会抛出一个错误 + +606 +00:33:20,200 --> 00:33:22,402 +MKLookAroundScene 是无属性的 + +607 +00:33:22,436 --> 00:33:23,871 +黑盒对象 + +608 +00:33:23,904 --> 00:33:25,205 +它的功能是作为一个令牌 + +609 +00:33:25,239 --> 00:33:27,908 +确保 Look Around 在 + +610 +00:33:27,941 --> 00:33:29,510 +请求区域的可用性 + +611 +00:33:30,978 --> 00:33:33,914 +要显示一个可交互的 Look Around +场景预览 + +612 +00:33:33,947 --> 00:33:35,883 +您只需将场景 + +613 +00:33:35,916 --> 00:33:38,652 +作为构造参数传给 + +614 +00:33:38,685 --> 00:33:41,121 +新的 MKLookAroundViewController 实例 + +615 +00:33:41,154 --> 00:33:43,857 +或者将其赋给已有实例的 + +616 +00:33:43,891 --> 00:33:46,527 +可以读写的 scene 属性 + +617 +00:33:46,560 --> 00:33:49,596 +或者 如您需要静态图像 + +618 +00:33:49,630 --> 00:33:51,331 +也可以将场景 + +619 +00:33:51,365 --> 00:33:53,934 +作为构造参数传给 + +620 +00:33:53,967 --> 00:33:55,702 +新的 MKLookAroundViewSnapshotter +实例 + +621 +00:33:55,736 --> 00:33:58,639 +随后读取其 snapshot 异步属性 + +622 +00:34:00,174 --> 00:34:01,942 +MKLookAroundViewController 类 + +623 +00:34:01,975 --> 00:34:04,311 +可让嵌入较小尺寸的 +Look Around 静态预览 + +624 +00:34:04,344 --> 00:34:07,814 +变得更加简单 + +625 +00:34:07,848 --> 00:34:09,683 +用户还可以点击预览 + +626 +00:34:09,716 --> 00:34:12,219 +进入全屏的 Look Around +交互会话 + +627 +00:34:13,687 --> 00:34:16,557 +现在 我们再次有请 Yingxiu + +628 +00:34:16,590 --> 00:34:20,160 +为我们演示将其整合到一起 +是多么简单 + +629 +00:34:20,928 --> 00:34:22,930 +Yingxiu: 谢谢 Eric + +630 +00:34:22,963 --> 00:34:26,300 +Eric 给我们展示了 MapKit 中 + +631 +00:34:26,333 --> 00:34:27,868 +强大的 Look Around 体验支持 + +632 +00:34:27,901 --> 00:34:30,370 +接下来 我为大家演示 +将其整合到我们的示例 App 中 + +633 +00:34:30,404 --> 00:34:32,472 +有多么简单 + +634 +00:34:32,506 --> 00:34:36,743 +在此之前 我们先了解 +示例 App 的最后一个功能 Highlights + +635 +00:34:36,777 --> 00:34:39,880 +用户可以看到必去地点的 +真实场景 + +636 +00:34:44,251 --> 00:34:47,254 +在屏幕顶部的分段控件中 +已经有了旧金山的一些 + +637 +00:34:47,287 --> 00:34:49,723 +地标性建筑的名称 + +638 +00:34:50,757 --> 00:34:52,359 +用户点击的时候 + +639 +00:34:52,392 --> 00:34:54,728 +我们希望可以将镜头移动到 + +640 +00:34:54,761 --> 00:34:55,929 +选中的位置 + +641 +00:34:57,030 --> 00:35:01,201 +并且在底部显示 +Look around 预览 + +642 +00:35:01,235 --> 00:35:03,637 +供用户跳转到全屏界面 + +643 +00:35:04,404 --> 00:35:05,372 +我们开始吧 + +644 +00:35:06,907 --> 00:35:08,909 +首先 需要为我们的容器视图 + +645 +00:35:08,942 --> 00:35:10,310 +添加一个 Look Around 预览 + +646 +00:35:22,723 --> 00:35:24,558 +我们先到尺寸检查器 + +647 +00:35:27,661 --> 00:35:33,400 +为其指定一个位置和尺寸 + +648 +00:35:37,171 --> 00:35:39,373 +一开始这个预览窗口要隐藏起来 + +649 +00:35:39,406 --> 00:35:45,512 +所以我们打开属性检查器 +勾选 Hidden + +650 +00:35:48,415 --> 00:35:51,518 +接下来 我们要 +创建 Look Around View Controller + +651 +00:36:00,027 --> 00:36:02,362 +将其嵌入容器视图 + +652 +00:36:09,303 --> 00:36:11,138 +和其它 segue 一样 + +653 +00:36:11,171 --> 00:36:13,207 +我需要为其指定一个标识符 + +654 +00:36:15,008 --> 00:36:16,443 +我们命名为 + +655 +00:36:16,476 --> 00:36:22,583 +“presentLookAroundEmbedded” + +656 +00:36:27,988 --> 00:36:30,057 +然后导入到代码中 + +657 +00:36:44,071 --> 00:36:46,640 +命名为“preview” + +658 +00:36:46,673 --> 00:36:49,476 +稍后会再让其显示 + +659 +00:36:53,547 --> 00:36:56,817 +现在 我们已经声明了一个 +Look Around view controller + +660 +00:36:56,850 --> 00:36:59,653 +只需要在 prepare 函数中获得 +View Controller 的实例 + +661 +00:37:04,391 --> 00:37:06,960 +确保 segue 标识符匹配 + +662 +00:37:12,432 --> 00:37:16,170 +然后 在分段控件的 action 函数中 + +663 +00:37:16,203 --> 00:37:19,740 +我们用地标名称 +创建一个本地搜索 + +664 +00:37:24,511 --> 00:37:27,748 +如果请求成功 将会获得 + +665 +00:37:27,781 --> 00:37:30,484 +用于接下来的镜头动画 + +666 +00:37:30,517 --> 00:37:32,452 +和 Look Around 场景的 +地图条目 + +667 +00:37:35,589 --> 00:37:37,124 +镜头动画方面 + +668 +00:37:37,157 --> 00:37:40,861 +我们首先需要用新的 API +创建一个镜头 MKMapCamera + +669 +00:37:44,665 --> 00:37:47,568 +来看向地图条目 + +670 +00:37:47,601 --> 00:37:50,637 +我们使用地图视图边框大小 +作为可见大小 + +671 +00:37:50,671 --> 00:37:52,873 +将允许倾斜设置为 true + +672 +00:37:56,610 --> 00:37:59,179 +这样就能对地标使用倾斜视图 + +673 +00:37:59,213 --> 00:38:01,248 +而其它地区使用顶视图 + +674 +00:38:02,482 --> 00:38:04,551 +把镜头赋给 camera 就行了 + +675 +00:38:07,120 --> 00:38:09,389 +镜头动画结束以后 + +676 +00:38:09,423 --> 00:38:11,859 +就可以显示其 +Look Around 预览了 + +677 +00:38:15,262 --> 00:38:18,432 +首先 我们需要确定 +这一地图条目的 + +678 +00:38:18,465 --> 00:38:20,801 +Look Around 数据是否可用 + +679 +00:38:20,834 --> 00:38:22,536 +为此 我们需要用 + +680 +00:38:22,569 --> 00:38:24,738 +新的 LookAroundSceneRequest 类 + +681 +00:38:25,339 --> 00:38:28,609 +创建我们的请求 传入地图条目 + +682 +00:38:29,610 --> 00:38:31,645 +然后执行请求 + +683 +00:38:36,650 --> 00:38:39,620 +如果获取场景的请求成功 + +684 +00:38:39,653 --> 00:38:40,787 +只要将场景 + +685 +00:38:40,821 --> 00:38:43,724 +赋给我们的 Look Around View Controller + +686 +00:38:43,757 --> 00:38:47,294 +如果没有错误 +但场景返回 nil + +687 +00:38:47,327 --> 00:38:51,331 +意味着 Look Around 数据 +在请求的位置不可用 + +688 +00:38:53,567 --> 00:38:55,802 +最后 不要忘了显示预览 + +689 +00:38:57,271 --> 00:38:59,106 +我们看下在 App 中 +的效果如何吧 + +690 +00:39:04,144 --> 00:39:06,346 +我们试下轮渡大厦 + +691 +00:39:08,582 --> 00:39:09,483 +来了 + +692 +00:39:09,516 --> 00:39:11,919 +轮渡大厦是地标建筑 +所以我们能看到 + +693 +00:39:11,952 --> 00:39:14,254 +这一精美绝伦的 + +694 +00:39:14,288 --> 00:39:16,056 +镜头视角 + +695 +00:39:16,089 --> 00:39:17,891 +最后 Look Around 预览出现 + +696 +00:39:18,825 --> 00:39:21,495 +我们试下另一个地方 龙门 + +697 +00:39:23,263 --> 00:39:25,098 +龙门不是地标建筑 + +698 +00:39:25,132 --> 00:39:26,767 +所以我们看到的是 +顶视图 + +699 +00:39:29,469 --> 00:39:31,939 +我们点击预览 进入全屏 + +700 +00:39:34,174 --> 00:39:37,177 +这是一个交互式视图 +所以我可以操作导航 + +701 +00:39:42,015 --> 00:39:45,319 +在 Look Around 全屏视图中 + +702 +00:39:45,352 --> 00:39:47,187 +我能看到这些精美的图标 +和标注 + +703 +00:39:51,792 --> 00:39:54,795 +在您的 App 中添加 +强大的 Look Around 体验 + +704 +00:39:54,828 --> 00:39:56,063 +就是如此简单 + +705 +00:39:56,096 --> 00:39:57,998 +我们再次有请 Eric + +706 +00:39:58,699 --> 00:39:59,967 +Eric: 谢谢 Yingxiu + +707 +00:40:00,000 --> 00:40:01,768 +Look Around 的 +Interface Builder 支持 + +708 +00:40:01,802 --> 00:40:03,170 +让其开发更便捷 + +709 +00:40:03,904 --> 00:40:06,573 +我们今天探索了很多话题 + +710 +00:40:07,541 --> 00:40:09,810 +包括自动集成新地图 + +711 +00:40:09,843 --> 00:40:12,112 +新的地图配置 API + +712 +00:40:12,145 --> 00:40:14,448 +Overlay 的新行为和改进 + +713 +00:40:14,481 --> 00:40:17,417 +以及类似 Selectable Map Features + +714 +00:40:17,451 --> 00:40:19,219 +和 Look Around 这样的新特性 + +715 +00:40:19,253 --> 00:40:20,954 +我们相信大家都一致认同 + +716 +00:40:20,988 --> 00:40:24,958 +可以通过地图体验 +让您的 App 更上一层楼 + +717 +00:40:24,992 --> 00:40:27,160 +我们迫不及待想看到您的成果了 + +718 +00:40:28,028 --> 00:40:29,730 +在结束之前 还有几点 + +719 +00:40:29,763 --> 00:40:30,898 +我想跟大家分享 + +720 +00:40:32,332 --> 00:40:34,801 +一如往常 您的反馈可以帮助我们 + +721 +00:40:34,835 --> 00:40:37,838 +进行下一步的优化 + +722 +00:40:37,871 --> 00:40:40,741 +所以请使用反馈助理 + +723 +00:40:40,774 --> 00:40:43,911 +给我们发送 bug 报告 +以及对您 App + +724 +00:40:43,944 --> 00:40:45,279 +最有用的功能 + +725 +00:40:46,980 --> 00:40:50,050 +另外 我们更新了现有的示例代码 + +726 +00:40:50,083 --> 00:40:52,319 +里面包含了我们刚刚所讨论的内容 + +727 +00:40:52,352 --> 00:40:53,954 +欢迎大家去查看 + +728 +00:40:55,322 --> 00:40:58,792 +最后 我们发布了 +全新的 REST API + +729 +00:40:58,825 --> 00:41:00,527 +您也可以去了解一下 + +730 +00:41:00,561 --> 00:41:02,796 +我们相信 如果您想将您的 + +731 +00:41:02,829 --> 00:41:05,332 +地理编码 ETA 确认或者其它调用 +转到服务器上的话 + +732 +00:41:05,365 --> 00:41:09,603 +这些 API 就能提供帮助 + +733 +00:41:10,904 --> 00:41:13,140 +更多细节 请查看题为 + +734 +00:41:13,173 --> 00:41:16,543 +“Meet Apple Maps Server APIs” +的讲座 + +735 +00:41:17,678 --> 00:41:20,814 +我再次谨代表地图团队 +感谢大家的观看 + +736 +00:41:20,848 --> 00:41:22,850 +齐: 祝您有一个愉快的 WWDC 之旅 + +737 +00:41:22,883 --> 00:41:25,853 +[古怪的音乐] + diff --git a/zho/2022 Session 10038 What's new with SKAdNetwork.srt b/zho/2022 Session 10038 What's new with SKAdNetwork.srt new file mode 100644 index 0000000..5f196cc --- /dev/null +++ b/zho/2022 Session 10038 What's new with SKAdNetwork.srt @@ -0,0 +1,1299 @@ +1 +00:00:00,334 --> 00:00:06,340 +[激动人心的音乐] + +2 +00:00:09,743 --> 00:00:13,146 +您好 欢迎来到 WWDC + +3 +00:00:13,180 --> 00:00:17,751 +我是 Nikhil 今天我将与您分享 +SKAdNetwork 的变化 + +4 +00:00:17,784 --> 00:00:19,653 +在探索未来之前 + +5 +00:00:19,686 --> 00:00:23,590 +让我们记住我们在哪里 +我们是如何来到这里的 + +6 +00:00:23,624 --> 00:00:28,061 +在 Apple 我们相信 +隐私是一项基本人权 + +7 +00:00:28,095 --> 00:00:32,733 +我们在这里所做的一切 +与保护隐私密不可分 + +8 +00:00:32,766 --> 00:00:36,236 +这就是我们创建 +SKAdNetwork 的原因 + +9 +00:00:36,270 --> 00:00:41,642 +SKAdNetwork 是 Apple 专注于 +隐私保护的安装归因系统 + +10 +00:00:41,675 --> 00:00:44,478 +归因数据被发送回给广告商 + +11 +00:00:44,511 --> 00:00:47,948 +同时保护用户的隐私 + +12 +00:00:47,981 --> 00:00:51,118 +SKAdNetwork 需要三个参与者 + +13 +00:00:51,151 --> 00:00:56,056 +广告网络 发行商 App +和广告商 App + +14 +00:00:56,089 --> 00:01:00,928 +我们也来定义一些 SKAdNetwork 中 +常用的术语吧 + +15 +00:01:00,961 --> 00:01:02,429 +展示 + +16 +00:01:02,462 --> 00:01:06,099 +本次讨论中的展示是从发行商 App + +17 +00:01:06,133 --> 00:01:09,603 +到 SKAdNetwork 的输入 + +18 +00:01:09,636 --> 00:01:10,804 +互动 + +19 +00:01:10,838 --> 00:01:15,375 +当用户与广告商 App 交互时 +便会产生互动 + +20 +00:01:15,409 --> 00:01:18,145 +广告商 App 会以 + +21 +00:01:18,178 --> 00:01:21,849 +转化值更新的形式获取这些互动 + +22 +00:01:21,882 --> 00:01:26,720 +最后是转化 也称为回传 + +23 +00:01:26,753 --> 00:01:31,792 +回传包含发送到广告网络的归因数据 + +24 +00:01:31,825 --> 00:01:35,229 +归因数据向广告网络提供了一个信号 + +25 +00:01:35,262 --> 00:01:39,766 +表明这是对原始广告的成功转化 + +26 +00:01:39,800 --> 00:01:45,005 +广告网络为广告商 App +生成签名展示 + +27 +00:01:45,038 --> 00:01:50,110 +发行商 App 会使用这种展示 +并显示广告 + +28 +00:01:50,143 --> 00:01:54,815 +然后用户点击广告并安装 App + +29 +00:01:54,848 --> 00:01:56,517 +当第一次启动时 + +30 +00:01:56,550 --> 00:02:00,654 +该 App 调用一个 API 来发出转化信号 + +31 +00:02:00,687 --> 00:02:05,025 +然后 App 可以重复调用此 API +来更新转化值 + +32 +00:02:05,058 --> 00:02:10,330 +并捕获不同级别的互动 +和广告支出回报 + +33 +00:02:10,364 --> 00:02:13,166 +一旦定时器到期 我们就将包含 + +34 +00:02:13,200 --> 00:02:16,703 +归因数据的回传发送给广告网络 + +35 +00:02:17,704 --> 00:02:22,342 +让我们快速回顾一下 SKAdNetwork +的版本历史 + +36 +00:02:22,376 --> 00:02:28,682 +2.0 版本引入了保护隐私的广告归因 + +37 +00:02:28,715 --> 00:02:34,421 +2.2 允许发行商 App +显示自定义广告 + +38 +00:02:34,454 --> 00:02:39,726 +3.0 增加了助攻广告的回传 + +39 +00:02:39,760 --> 00:02:45,199 +在 iOS 15.0 中 我们为所有版本的 + +40 +00:02:45,232 --> 00:02:48,802 +SKAdNetwork 的引入了 +给开发者的回传 + +41 +00:02:49,269 --> 00:02:53,407 +有关 SKAdNetwork 历史版本的 +更多信息 + +42 +00:02:53,440 --> 00:02:58,412 +请参阅 WWDC 2021 的课程 +“探索保护隐私的广告归因” + +43 +00:02:59,413 --> 00:03:05,519 +现在让我们谈谈 +即将到来的 SKAdNetwork 4.0 + +44 +00:03:05,552 --> 00:03:08,522 +看看它都有哪些新功能 + +45 +00:03:08,555 --> 00:03:12,326 +我们将从 API 的一些变化开始 + +46 +00:03:12,359 --> 00:03:16,230 +这些变化旨在为广告商 +提供更多的数据 + +47 +00:03:16,263 --> 00:03:20,601 +接下来 我们将着眼于广告的转化 + +48 +00:03:20,634 --> 00:03:25,205 +然后我们将继续讨论网页广告的归因 + +49 +00:03:25,239 --> 00:03:30,511 +并以讨论 SKAdNetwork 的 +测试框架来结尾 + +50 +00:03:30,544 --> 00:03:34,615 +分级的 ID 和转化值是 + +51 +00:03:34,648 --> 00:03:37,951 +SKAdNetwork 4.0 的第一个新功能 + +52 +00:03:38,785 --> 00:03:44,024 +在深入研究这个新功能之前 +我想先定义一下群体匿名 + +53 +00:03:44,057 --> 00:03:49,229 +群体匿名是 SKAdNetwork +提供归因数据时 + +54 +00:03:49,263 --> 00:03:53,433 +我们用来指代隐私保护方式的术语 + +55 +00:03:53,467 --> 00:03:56,470 +安装数量决定了向您的 App 的用户 + +56 +00:03:56,503 --> 00:04:00,140 +提供的隐私保护级别 + +57 +00:04:00,174 --> 00:04:03,510 +数量较低时 我们在回传中 + +58 +00:04:03,544 --> 00:04:06,113 +向广告商发送更少的归因数据 + +59 +00:04:06,146 --> 00:04:11,018 +当安装数量较低时 +我们会采取额外的步骤 + +60 +00:04:11,051 --> 00:04:15,122 +通过限制发回的 +可跟踪信息来保护隐私 + +61 +00:04:15,155 --> 00:04:16,924 +随着数量的增加 + +62 +00:04:16,957 --> 00:04:20,561 +用户的独特性开始融入人群中 + +63 +00:04:20,594 --> 00:04:23,330 +我们会发回更多的数据 + +64 +00:04:23,363 --> 00:04:26,366 +最后 当数量达到最高级别时 + +65 +00:04:26,400 --> 00:04:32,005 +我们能够在保护隐私的同时 +发送最多的数据 + +66 +00:04:32,039 --> 00:04:37,411 +在 SKAdNetwork 4.0 中 +我们有办法可以在保护隐私的同时 + +67 +00:04:37,444 --> 00:04:41,548 +发送更多数据 + +68 +00:04:41,582 --> 00:04:45,919 +为此 我们正在更改活动标识符字段 + +69 +00:04:45,953 --> 00:04:49,356 +目前 这是一个 2 位字段 + +70 +00:04:49,389 --> 00:04:52,893 +我们将此字段的范围 +增加到 4 位数 + +71 +00:04:52,926 --> 00:04:56,463 +并将其改名为源标识符 + +72 +00:04:56,496 --> 00:05:00,133 +新的名称反映了 +我们看待该字段的方式 + +73 +00:05:00,167 --> 00:05:04,471 +即该字段能够代表 +您想用它代表的任何内容 + +74 +00:05:04,505 --> 00:05:08,208 +而不仅仅是用于识别活动 + +75 +00:05:09,209 --> 00:05:11,411 +虽然这是一个数字 + +76 +00:05:11,445 --> 00:05:15,249 +但我们鼓励大家 +将其视为三个层次的数字 + +77 +00:05:15,282 --> 00:05:19,319 +即 2 3 和 4 位数 + +78 +00:05:19,353 --> 00:05:21,788 +将源标识符字段 + +79 +00:05:21,822 --> 00:05:24,691 +视为一组层次化的数字有助于 + +80 +00:05:24,725 --> 00:05:28,428 +为不同的数字赋予意义 + +81 +00:05:28,462 --> 00:05:33,433 +例如 前 2 位数代表广告活动 + +82 +00:05:33,467 --> 00:05:38,138 +第 3 位数代表用户所在的位置 + +83 +00:05:38,172 --> 00:05:42,776 +第 4 位数代表广告在屏幕上的位置 + +84 +00:05:42,809 --> 00:05:47,714 +或者 前 2 位数可以代表广告处理类型 + +85 +00:05:47,748 --> 00:05:51,785 +第 3 位数可以代表一天中的时段 + +86 +00:05:51,818 --> 00:05:56,123 +第 4 位数可以代表广告显示的尺寸 + +87 +00:05:56,156 --> 00:05:58,492 +这些都只是示例 + +88 +00:05:58,525 --> 00:06:02,796 +最终 我们希望在这里 +向您开放该字段 + +89 +00:06:02,829 --> 00:06:05,666 +以更好地满足您的使用需求 + +90 +00:06:05,699 --> 00:06:08,802 +回到提供更多数据这个主题上 + +91 +00:06:08,836 --> 00:06:12,105 +我们也在改进转化值 + +92 +00:06:12,139 --> 00:06:15,709 +目前这是一个 6 位值 + +93 +00:06:15,742 --> 00:06:21,915 +在 SKAdNetwork 4.0 中 +我们引入了两个转化值 + +94 +00:06:21,949 --> 00:06:25,853 +细粒度值和粗粒度值 + +95 +00:06:25,886 --> 00:06:29,690 +细粒度值与当前的转化值相同 + +96 +00:06:29,723 --> 00:06:34,127 +粗粒度值可以有三个不同的值 + +97 +00:06:34,161 --> 00:06:37,264 +假设我们有一个转化值是 高 42 + +98 +00:06:37,297 --> 00:06:41,034 +其中 高 是粗略值 42 是精细值 + +99 +00:06:41,068 --> 00:06:44,304 +接收粗略值所需的安装计数 + +100 +00:06:44,338 --> 00:06:48,242 +小于精细值所需的安装计数 + +101 +00:06:48,275 --> 00:06:53,547 +因此 App 接收前者的速度 +将比后者快得多 + +102 +00:06:53,580 --> 00:06:58,952 +然而请注意 只有其中一个 +将被发回广告商 + +103 +00:06:58,986 --> 00:07:02,890 +我们来看看群体匿名 +如何影响这些新字段 + +104 +00:07:04,224 --> 00:07:09,663 +使用我们前面的 +5739 示例作为源标识符 + +105 +00:07:09,696 --> 00:07:11,865 +在群体匿名的低级别时 + +106 +00:07:11,899 --> 00:07:16,737 +预期您可以收到源标识符的 +2 位数组成部分 + +107 +00:07:16,770 --> 00:07:19,806 +在本例中为 39 + +108 +00:07:19,840 --> 00:07:24,678 +在中等级别 预期您可以 +收到前 3 位数的组成部分 + +109 +00:07:24,711 --> 00:07:27,548 +在最高级别 预期您可以收到 + +110 +00:07:27,581 --> 00:07:31,752 +完整的 4 位数源标识符 + +111 +00:07:31,785 --> 00:07:34,154 +随着群体匿名级别的增加 + +112 +00:07:34,188 --> 00:07:38,926 +将返回更多的源标识符数字 + +113 +00:07:38,959 --> 00:07:44,064 +以我们之前的高 42 转化值为例 + +114 +00:07:44,097 --> 00:07:46,233 +在群体匿名的低级别时 + +115 +00:07:46,266 --> 00:07:50,938 +您将不会在回传中收到转化值 + +116 +00:07:50,971 --> 00:07:54,975 +在中等级别 您会得到粗略的转化值 + +117 +00:07:55,008 --> 00:07:56,276 +在最高级别 + +118 +00:07:56,310 --> 00:08:01,148 +您将在回传中接收细粒度的转化值 + +119 +00:08:01,181 --> 00:08:07,421 +随着群体匿名级别的增加 +返回的转化值会发生变化 + +120 +00:08:07,454 --> 00:08:10,290 +我们来看看 API 的变化 + +121 +00:08:10,324 --> 00:08:15,562 +如果您使用 +SKAdImpression 实例显示广告 + +122 +00:08:15,596 --> 00:08:22,035 +就可以在 SKAdImpression 实例上 +设置新的 sourceIdentifier 属性 + +123 +00:08:23,036 --> 00:08:26,240 +如果要通过字典对象来设置展示 + +124 +00:08:26,273 --> 00:08:32,846 +您可以使用新的 sourceIdentifier 键 +来设置源标识符 + +125 +00:08:33,847 --> 00:08:39,319 +对于广告主 App +您将调用新的 updateConversionValue 方法 + +126 +00:08:39,353 --> 00:08:43,190 +该方法现在已更新为 +除了已有的细粒度转化值外 + +127 +00:08:43,223 --> 00:08:47,494 +还新增了粗粒度转化值 如下所示 + +128 +00:08:47,528 --> 00:08:51,965 +我们建议您在更新回传的转化值后 + +129 +00:08:51,999 --> 00:08:56,069 +使用完成处理程序 +来执行任何后续任务 + +130 +00:08:56,103 --> 00:08:59,673 +下面是关于采用新的分级 ID + +131 +00:08:59,706 --> 00:09:02,476 +和转化值 API 的一些建议 + +132 +00:09:02,509 --> 00:09:05,846 +根据安装的隐私级别 + +133 +00:09:05,879 --> 00:09:08,949 +将返回源标识符的不同部分 + +134 +00:09:08,982 --> 00:09:14,288 +在为展示设置源标识符时 +请考虑这一点 + +135 +00:09:14,321 --> 00:09:18,659 +粗转化值的粒度 + +136 +00:09:18,692 --> 00:09:20,527 +比细转化值低得多 + +137 +00:09:20,561 --> 00:09:25,199 +在给它们的值赋予归因涵义时 +请考虑这一点 + +138 +00:09:25,232 --> 00:09:29,136 +转化值可以递增,也可以递减 + +139 +00:09:29,169 --> 00:09:32,139 +最后 请更新服务器 + +140 +00:09:32,172 --> 00:09:35,876 +使其在处理 SKAdNetwork 4.0 回传时 + +141 +00:09:35,909 --> 00:09:39,613 +能够解析新的源标识符 + +142 +00:09:39,646 --> 00:09:42,449 +和粗略的转化值 + +143 +00:09:42,482 --> 00:09:46,220 +这就是我们对分级 ID +和转化值的介绍 + +144 +00:09:46,253 --> 00:09:51,258 +在保护隐私的同时 +为广告商提供更多数据 + +145 +00:09:51,291 --> 00:09:57,898 +我们来关注归因流的 +另一个关键领域 转化 + +146 +00:09:57,931 --> 00:10:01,835 +今天的 SKAdNetwork +使用单一的转化模型 + +147 +00:10:03,103 --> 00:10:06,673 +从安装开始 我们更新转化值 + +148 +00:10:06,707 --> 00:10:09,610 +以获取各种客户的互动 + +149 +00:10:09,643 --> 00:10:12,112 +经过一段时间后 + +150 +00:10:12,145 --> 00:10:15,549 +我们将回传的内容发送给广告网络 + +151 +00:10:15,582 --> 00:10:18,018 +我们来看一个例子 + +152 +00:10:18,051 --> 00:10:19,720 +这个 App 叫 Food Truck + +153 +00:10:19,753 --> 00:10:22,623 +Food Truck 可以让您 +控制您的快餐车 + +154 +00:10:22,656 --> 00:10:27,761 +定制 控制和创建您自己 +独特的甜甜圈交付体验 + +155 +00:10:27,794 --> 00:10:29,663 +作为 Food Truck 的开发商 + +156 +00:10:29,696 --> 00:10:33,467 +我想知道我这个广告支出的价值 + +157 +00:10:33,500 --> 00:10:37,938 +作为一个示例 +当用户启动 Food Truck 时 + +158 +00:10:37,971 --> 00:10:41,508 +我将更新转化值以标记这一事件 + +159 +00:10:41,542 --> 00:10:44,411 +当他们拿到第一批订单之后 + +160 +00:10:44,444 --> 00:10:47,614 +我会再次更新转化值 + +161 +00:10:47,648 --> 00:10:52,853 +由于这批甜甜圈 +需要一定的时间来制作 + +162 +00:10:52,886 --> 00:10:55,789 +用户需要等待 + +163 +00:10:55,822 --> 00:10:58,926 +制作的这段时间里 在某个地方 + +164 +00:10:58,959 --> 00:11:03,997 +转化以回传的形式发送给 +广告网络 也可以选择发送给我 + +165 +00:11:04,031 --> 00:11:07,868 +然而 当用户最终交付甜甜圈时 + +166 +00:11:07,901 --> 00:11:12,773 +我将无法评估这一事件以及 +后面所有的用户操作 + +167 +00:11:12,806 --> 00:11:16,844 +因为回传已经发送过了 + +168 +00:11:16,877 --> 00:11:21,181 +换句话说 我们丢失了再次互动的信息 + +169 +00:11:21,215 --> 00:11:24,451 +这就是我们正在改进的 + +170 +00:11:24,484 --> 00:11:30,290 +我们把单次回传 +改为三次回传 + +171 +00:11:30,324 --> 00:11:33,227 +回传与特定的时间窗口相绑定 + +172 +00:11:33,260 --> 00:11:36,463 +并在这些窗口结束时发送 + +173 +00:11:36,496 --> 00:11:39,466 +我们来回顾一下前面的例子 + +174 +00:11:39,499 --> 00:11:42,503 +和之前一样 用户启动 Food Truck + +175 +00:11:42,536 --> 00:11:47,441 +然后拿到第一批订单 + +176 +00:11:47,474 --> 00:11:52,513 +第一次回传的时间窗口已过 +我们将其发送出去 + +177 +00:11:52,546 --> 00:11:54,748 +用户交付甜甜圈 + +178 +00:11:54,781 --> 00:11:57,784 +而在之前的例子中 +我们无法获知这一情况 + +179 +00:11:57,818 --> 00:12:01,588 +现在我们发现自己处于 +第二个回传的时间窗口中 + +180 +00:12:01,622 --> 00:12:05,259 +我们更新转化值来捕获这一点 + +181 +00:12:05,292 --> 00:12:10,664 +第二次回传的时间窗口过去了 +我们将其发送出去 + +182 +00:12:10,697 --> 00:12:15,769 +用户用 App 中的工具 +创建了一个全新的甜甜圈配方 + +183 +00:12:15,802 --> 00:12:19,339 +然后再次制作并交付一批新的甜甜圈 + +184 +00:12:19,373 --> 00:12:24,011 +第三个时间窗口也过去了 +然后第三个回传被发送出去 + +185 +00:12:24,044 --> 00:12:27,247 +现在有了更多的机会来评估转化值 + +186 +00:12:27,281 --> 00:12:30,484 +并且可以多次地接收到这些值 + +187 +00:12:30,517 --> 00:12:33,820 +关于多次转化有几点需要注意 + +188 +00:12:33,854 --> 00:12:37,691 +只有第一次回传会收到细粒度转化值 + +189 +00:12:37,724 --> 00:12:42,462 +额外的回传可以携带粗粒度转化值 + +190 +00:12:42,496 --> 00:12:47,034 +只有冠军广告网络和开发者 +会收到额外的回传 + +191 +00:12:47,067 --> 00:12:53,307 +接下来 让我们看一下 +网页上广告的 SKAdNetwork 归因 + +192 +00:12:53,340 --> 00:13:00,047 +我们知道发行商 App 里的广告 +会在 App Store 中打开产品页面 + +193 +00:13:00,080 --> 00:13:04,017 +然后 App Store 与 SKAdNetwork 合作 +对安装进行归因 + +194 +00:13:05,519 --> 00:13:10,324 +同时提供我们用户所需要的隐私保护 + +195 +00:13:10,357 --> 00:13:15,329 +我们希望将同样的隐私保护 +扩展到网页上显示的广告 + +196 +00:13:15,362 --> 00:13:18,265 +我们来看看这是如何工作的吧 + +197 +00:13:18,298 --> 00:13:22,503 +用户点击 Safari 中的一个广告链接 + +198 +00:13:22,536 --> 00:13:28,842 +Safari 会启动 App Store +并显示广告 App 的产品页面 + +199 +00:13:28,876 --> 00:13:30,744 +这里发生了两件事 + +200 +00:13:30,777 --> 00:13:35,015 +App Store 从广告网络服务器 +获取广告展示 + +201 +00:13:35,048 --> 00:13:39,019 +然后用户安装 App + +202 +00:13:39,052 --> 00:13:42,289 +接下来的事情都和之前的归因一样了 + +203 +00:13:42,322 --> 00:13:47,561 +最终 SKAdNetwork 会发送回传 + +204 +00:13:47,594 --> 00:13:50,964 +我们来看看链接是怎么构成的 + +205 +00:13:50,998 --> 00:13:56,803 +href 部分包含广告 App 的 +App Store 链接 + +206 +00:13:56,837 --> 00:14:00,541 +attributionDestination 告诉 +Apple 从哪里获取 + +207 +00:14:00,574 --> 00:14:03,510 +签名的广告展示 + +208 +00:14:03,544 --> 00:14:07,114 +而 attributionSourceNonce 可以 +帮助广告网络 + +209 +00:14:07,147 --> 00:14:09,917 +准确地找到广告展示并发回 + +210 +00:14:11,318 --> 00:14:15,022 +请注意 此链接可以放在第一方站点上 + +211 +00:14:15,055 --> 00:14:18,792 +也可以放在嵌入的跨站点 iframe 中 + +212 +00:14:18,825 --> 00:14:22,763 +我们来仔细看看 URL 的构建 + +213 +00:14:22,796 --> 00:14:28,936 +我们从 attributionDestination 提取 eTLD+1 组件 + +214 +00:14:28,969 --> 00:14:32,039 +在此基础上 +我们再添加 well-known 限定符 + +215 +00:14:32,072 --> 00:14:34,608 +和另外两个路径组件 + +216 +00:14:34,641 --> 00:14:39,580 +这为我们提供了一个 URL +我们会向该 URL 发出 HTTP POST 请求 + +217 +00:14:39,613 --> 00:14:42,749 +以获得签名展示 + +218 +00:14:42,783 --> 00:14:47,521 +请注意 协议和高亮显示的 +路径组件是固定的 + +219 +00:14:47,554 --> 00:14:53,060 +由广告网络 +提供主机名称的部分 + +220 +00:14:54,061 --> 00:14:58,232 +SKAdNetwork 将向这个 URL + +221 +00:14:58,265 --> 00:15:01,635 +发出 HTTP POST 请求 + +222 +00:15:01,668 --> 00:15:05,138 +POST 主体是 JSON 格式 + +223 +00:15:05,172 --> 00:15:10,277 +您会发现 source_nonce +与原始广告链接中的相同 + +224 +00:15:10,310 --> 00:15:13,580 +该值是广告网络用来识别 + +225 +00:15:13,614 --> 00:15:16,750 +其需要提供的签名展示 + +226 +00:15:17,751 --> 00:15:22,422 +我们来看看我们会 +从这个 POST 请求中得到什么 + +227 +00:15:22,456 --> 00:15:28,061 +这是一个签名展示 +可供 SKAdNetwork 使用 + +228 +00:15:28,095 --> 00:15:31,231 +注意展示中的 +source domain 字段 + +229 +00:15:31,265 --> 00:15:34,468 +这是 App 驱动的 +SKAdNetwork 流中 + +230 +00:15:34,501 --> 00:15:38,772 +源 App ID 的链接模拟 + +231 +00:15:38,805 --> 00:15:43,810 +看看如何开始使用这个 +进入 SKAdNetwork 系统的新条目 + +232 +00:15:43,844 --> 00:15:46,513 +广告网络必须做以下工作 + +233 +00:15:46,547 --> 00:15:52,486 +创建链接的唯一标识部分 +和链接本身 + +234 +00:15:52,519 --> 00:15:56,123 +把前面介绍的组合成的 URL + +235 +00:15:56,156 --> 00:15:59,660 +作为能够提供已签名展示的端点 + +236 +00:15:59,693 --> 00:16:02,863 +更新回传服务器 + +237 +00:16:02,896 --> 00:16:05,532 +以解析新的可选的 +source_domain 字段 + +238 +00:16:05,566 --> 00:16:09,036 +对于想要使用 +SKAdNetwork 链接的网页 + +239 +00:16:09,069 --> 00:16:14,341 +只需嵌入广告网络 +提供给广告链接即可 + +240 +00:16:14,374 --> 00:16:19,913 +这就是 SKAdNetwork 网页广告归因 +的介绍了 + +241 +00:16:19,947 --> 00:16:23,817 +看到这一功能在更广泛的 +广告生态系统中被采用 + +242 +00:16:23,851 --> 00:16:28,021 +我们感到无比兴奋 + +243 +00:16:28,055 --> 00:16:34,595 +接下来 我们将介绍 +如何测试您的 SKAdNetwork 实现 + +244 +00:16:34,628 --> 00:16:40,133 +SKAdNetwork 在上层处理展示和回传 + +245 +00:16:40,167 --> 00:16:45,072 +通过与开发者社区的合作 +我们了解到 展示 + +246 +00:16:45,105 --> 00:16:49,643 +签名和配置一直都是容易出错的地方 + +247 +00:16:49,676 --> 00:16:54,848 +能够以一种测试友好的方式 + +248 +00:16:54,882 --> 00:16:57,451 +接收和验证回传 +也是我们有待改进的领域 + +249 +00:16:57,484 --> 00:17:01,355 +为了改善开发者 +使用 SKAdNetwork 的体验 + +250 +00:17:01,388 --> 00:17:08,095 +我们在 Xcode 13.3 中发布了 +SKAdNetwork 测试框架的更新 + +251 +00:17:08,128 --> 00:17:12,132 +这是 StoreKitTest 中的 +一个单元测试框架 + +252 +00:17:12,165 --> 00:17:15,035 +很多人已经在使用它 + +253 +00:17:15,068 --> 00:17:19,540 +来测试 StoreKit 实现的各个部分 + +254 +00:17:19,573 --> 00:17:23,076 +我们来看看如何校验展示 + +255 +00:17:23,110 --> 00:17:28,515 +您创建并配置了 +一个 SKAdImpression 实例 + +256 +00:17:28,549 --> 00:17:32,386 +并提供了用于生成签名的 + +257 +00:17:32,419 --> 00:17:34,922 +私钥所对应的公钥 + +258 +00:17:34,955 --> 00:17:40,427 +然后调用 SKAdTestSession +实例上的 validate 方法 + +259 +00:17:40,460 --> 00:17:43,397 +这将验证您的展示 + +260 +00:17:43,430 --> 00:17:49,369 +如果展示配置错误或者签名无效 +会抛出一个错误 + +261 +00:17:49,403 --> 00:17:53,006 +另一个主要的测试 +是回传的接收 + +262 +00:17:53,040 --> 00:17:54,808 +这里有两个步骤 + +263 +00:17:54,842 --> 00:17:59,746 +步骤 1 +将测试回传添加到测试会话中 + +264 +00:17:59,780 --> 00:18:03,150 +您将创建 +一个 SKAdTestPostback 的实例 + +265 +00:18:03,183 --> 00:18:07,621 +并使用您希望在回传中使用的值 +对其进行配置 + +266 +00:18:07,654 --> 00:18:10,390 +要特别注意回传 URL + +267 +00:18:10,424 --> 00:18:13,961 +因为这是回传将被发送到的地方 + +268 +00:18:13,994 --> 00:18:18,465 +它可以指向远程服务器或本地服务器 + +269 +00:18:18,498 --> 00:18:20,801 +然后 您将使用 SKAdTestSession 上的 + +270 +00:18:20,834 --> 00:18:25,739 +setPostbacks 方法将其添加到 +您的测试会话中 + +271 +00:18:25,772 --> 00:18:29,776 +步骤 2 实际操作发送回传 + +272 +00:18:29,810 --> 00:18:33,413 +这里需要做的就是 +在 SKAdTestSession 上 + +273 +00:18:33,447 --> 00:18:37,718 +调用 flushPostbacks 方法 +您的回传将被立即发送出去 + +274 +00:18:38,919 --> 00:18:43,357 +注意 SKAdTestSession +将通过网络把回传发送到 + +275 +00:18:43,390 --> 00:18:47,628 +撰写回传时指定的服务器 + +276 +00:18:47,661 --> 00:18:52,866 +这些是今年晚些时候 SKAdNetwork +测试框架会增加的一些内容 + +277 +00:18:52,900 --> 00:18:56,170 +支持新的源标识符字段 + +278 +00:18:56,203 --> 00:18:59,873 +支持精细和粗略转化值 + +279 +00:18:59,907 --> 00:19:03,043 +支持测试多个转化 + +280 +00:19:03,076 --> 00:19:08,015 +以上是关于 SKAdNetwork +测试框架更新的简要介绍 + +281 +00:19:08,048 --> 00:19:11,919 +这些更新会首先在 Xcode 13.3 中发布 + +282 +00:19:11,952 --> 00:19:15,656 +今天 我们讨论了分级 ID 和转化值 + +283 +00:19:15,689 --> 00:19:19,359 +旨在更快地向您提供更多数据 + +284 +00:19:19,393 --> 00:19:22,029 +然后我们讨论了多次转化 + +285 +00:19:22,062 --> 00:19:26,366 +让您可以在更长的时间内 +衡量多次互动 + +286 +00:19:26,400 --> 00:19:29,703 +然后我们讨论了链接驱动的归因 + +287 +00:19:29,736 --> 00:19:32,873 +以及我们如何为其和 +SKAdNetwork 之间搭建桥梁 + +288 +00:19:32,906 --> 00:19:36,476 +以提供同样的隐私保护 + +289 +00:19:36,510 --> 00:19:42,115 +最后我们讨论了 Xcode 中的 +SKAdNetwork 测试框架 + +290 +00:19:42,149 --> 00:19:47,754 +至此 我们的 SKAdNetwork 4.0 之旅 +就结束了 + +291 +00:19:47,788 --> 00:19:51,592 +最后 我们所构建的一切 + +292 +00:19:51,625 --> 00:19:54,428 +都是基于开发者社区的反馈 + +293 +00:19:54,461 --> 00:19:58,332 +听到您为我们的用户建立的 +隐私第一的广告体验 + +294 +00:19:58,365 --> 00:20:04,338 +我感到非常满足和欣慰 + +295 +00:20:04,371 --> 00:20:06,373 +谢谢 + +296 +00:20:06,406 --> 00:20:10,410 +[激动人心的音乐] + diff --git a/zho/2022 Session 10040 Explore in-app purchase integration and migration.srt b/zho/2022 Session 10040 Explore in-app purchase integration and migration.srt new file mode 100644 index 0000000..5fc0043 --- /dev/null +++ b/zho/2022 Session 10040 Explore in-app purchase integration and migration.srt @@ -0,0 +1,3336 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,011 +Gabriel Ting: +大家好 欢迎大家收看我们的课程 + +3 +00:00:11,044 --> 00:00:14,214 +探索 App 内购买项目集成和迁移 + +4 +00:00:14,248 --> 00:00:17,584 +本次课程分为两部分 +一部分专门介绍 + +5 +00:00:17,618 --> 00:00:20,287 +迁移到 App Store Server API +另一部分专门介绍 + +6 +00:00:20,320 --> 00:00:22,956 +迁移到 App Store Server +Notifications Version 2 + +7 +00:00:22,990 --> 00:00:24,458 +我叫 Gabriel 我会向大家介绍 + +8 +00:00:24,491 --> 00:00:27,628 +如何迁移到 App Store Server API + +9 +00:00:27,661 --> 00:00:29,830 +我叫 Alex 我将带大家了解 + +10 +00:00:29,863 --> 00:00:33,200 +迁移到 App Store Server +Notifications Version 2 的过程 + +11 +00:00:33,233 --> 00:00:36,670 +我们先来简单介绍一下 +App Store Server API + +12 +00:00:36,703 --> 00:00:38,639 +和 App Store Server Notifications + +13 +00:00:38,672 --> 00:00:42,342 +我们去年引入了 +App Store Server API + +14 +00:00:42,376 --> 00:00:45,946 +将其作为一种强大 安全和高效的 +从服务器获取数据和执行操作的方法 + +15 +00:00:45,979 --> 00:00:48,482 +我们的目标是为大家提供 +所需的数据 + +16 +00:00:48,515 --> 00:00:51,885 +这些数据是以 JSON Web Signature +或 JWS 格式签名的 + +17 +00:00:51,919 --> 00:00:55,022 +这样你就可以验证你收到的数据 +是未经篡改的 + +18 +00:00:55,055 --> 00:00:58,125 +为你准备的 +以及由 App Store 签名的 + +19 +00:00:58,158 --> 00:01:00,894 +例如我们的 App Store Server API +的一个接口: + +20 +00:01:00,928 --> 00:01:03,864 +Get Transaction History 接口 +与新的筛选和排序功能相结合 + +21 +00:01:03,897 --> 00:01:07,134 +可以让你只用一个 +originalTransactionId + +22 +00:01:07,167 --> 00:01:10,337 +就能获取任何指定的交易集 + +23 +00:01:10,370 --> 00:01:13,473 +在 App Store Notifications +Version 2 的窗格中 + +24 +00:01:13,507 --> 00:01:16,944 +随着表示订阅状态数量的增加 + +25 +00:01:16,977 --> 00:01:19,012 +Notifications Version 2 将实时更新 + +26 +00:01:19,046 --> 00:01:22,416 +订阅的所有可能状态 + +27 +00:01:22,449 --> 00:01:25,152 +我们的目标是主动提供你需要了解的 + +28 +00:01:25,185 --> 00:01:27,454 +有关订阅者情况的所有信息 + +29 +00:01:27,487 --> 00:01:29,990 +而无需向我们索取信息 + +30 +00:01:30,023 --> 00:01:33,427 +在本课程中 Alex 将详细介绍这一点 + +31 +00:01:33,460 --> 00:01:36,363 +如果你对轻松高效地 +使用这些功能感兴趣 + +32 +00:01:36,396 --> 00:01:37,731 +本课程的内容就非常适合你 + +33 +00:01:37,764 --> 00:01:41,068 +我们将带你了解 +如何使用 App Store Server API + +34 +00:01:41,101 --> 00:01:43,570 +和 App Store Server +Notifications Version 2 + +35 +00:01:43,604 --> 00:01:46,840 +以及一些迁移技巧和最佳实践 + +36 +00:01:46,874 --> 00:01:48,642 +关于这些课程的其他信息 + +37 +00:01:48,675 --> 00:01:51,612 +请参阅下面列出的其他课程 + +38 +00:01:53,080 --> 00:01:57,551 +我们先来讨论迁移到 +App Store Server API 的问题吧 + +39 +00:01:57,584 --> 00:02:02,422 +首先 我们将讨论如何使用 +App Store Server API + +40 +00:02:02,456 --> 00:02:06,960 +其次 我们将深入研究 +签署 JSON Web Tokens 的一些细节 + +41 +00:02:06,994 --> 00:02:09,696 +第三 我们将演示如何验证 +你从 App Store 收到的 + +42 +00:02:09,730 --> 00:02:13,166 +签名交易是否是真实的 + +43 +00:02:13,200 --> 00:02:16,103 +最后 我们将讨论如何 +从 verifyReceipt + +44 +00:02:16,136 --> 00:02:19,106 +迁移到 App Store Server API + +45 +00:02:19,139 --> 00:02:20,474 +我们开始吧 + +46 +00:02:20,507 --> 00:02:23,143 +首先 我们要讨论的是如何 +在不同的 StoreKit 版本中 + +47 +00:02:23,177 --> 00:02:27,247 +使用 App Store Server API +首先是原始 StoreKit + +48 +00:02:27,281 --> 00:02:30,651 +然后是 StoreKit 2 +然后讨论如何同时支持 + +49 +00:02:30,684 --> 00:02:34,821 +两个顾客端使用支持 +StoreKit 2 的 iOS 版本 + +50 +00:02:34,855 --> 00:02:38,358 +即 iOS 15 或更高版本 +以及那些不支持 StoreKit 2 的顾客端 + +51 +00:02:39,092 --> 00:02:41,128 +首先 让我们看看 +App Store Server API 的 + +52 +00:02:41,161 --> 00:02:43,630 +请求是什么样子的 + +53 +00:02:43,664 --> 00:02:47,701 +我们可以看到 这里列出的五个 API +都使用 originalTransactionID + +54 +00:02:47,734 --> 00:02:49,102 +作为路径参数 + +55 +00:02:49,136 --> 00:02:51,471 +让你可以使用从收据 + +56 +00:02:51,505 --> 00:02:54,474 +签名交易 签名续订和通知接收到的 + +57 +00:02:54,508 --> 00:02:58,345 +originalTransactionId 中 +轻松调用这些 API + +58 +00:02:58,378 --> 00:03:00,881 +接下来是 Look Up Order ID 端点 + +59 +00:03:00,914 --> 00:03:04,017 +此端点转而使用顾客提供的 orderId + +60 +00:03:04,051 --> 00:03:05,819 +来支持查询 + +61 +00:03:05,853 --> 00:03:09,089 +这是为了更好地帮助顾客 +直接提出问题 + +62 +00:03:09,122 --> 00:03:13,026 +因为顾客在每笔交易的顾客收据中 +都会收到 orderId + +63 +00:03:13,060 --> 00:03:16,029 +但没有提供 originalTransactionId + +64 +00:03:16,063 --> 00:03:18,765 +这样可以确保 +你可以直接使用顾客手头的数据 + +65 +00:03:18,799 --> 00:03:21,635 +来响应顾客的查询 + +66 +00:03:21,668 --> 00:03:24,271 +这里列出的最后一个端点与通知相关 + +67 +00:03:24,304 --> 00:03:27,307 +Alex 将在本次课程中讨论这个部分 + +68 +00:03:28,442 --> 00:03:31,778 +接下来 +让我们看看在原始 StoreKit 中 + +69 +00:03:31,812 --> 00:03:33,413 +可以从哪里获得 +originalTransactionId + +70 +00:03:33,447 --> 00:03:36,116 +使用统一 App 收据调用 +verifyReceipt 时 + +71 +00:03:36,149 --> 00:03:39,853 +originalTransactionId 会返回到 + +72 +00:03:39,887 --> 00:03:41,455 +该用户购买的 + +73 +00:03:41,488 --> 00:03:44,358 +每笔交易收据的 in_app 字段 + +74 +00:03:44,391 --> 00:03:48,262 +以及 latest_receipt_info 和 +pending_renewal_info 中 + +75 +00:03:48,295 --> 00:03:51,498 +现在我们知道了如何从 +Original StoreKit 交易中 + +76 +00:03:51,532 --> 00:03:54,668 +获取 originalTransactionId +那么让我们看看 + +77 +00:03:54,701 --> 00:03:57,638 +顾客 App Store Server 和 +你的服务器之间的整个流程 + +78 +00:03:59,173 --> 00:04:02,609 +首先 在你的服务器上获取 App 收据 + +79 +00:04:02,643 --> 00:04:06,580 +接下来 拿到 App 收据 +并从服务器上调用 verifyReceipt + +80 +00:04:08,549 --> 00:04:11,018 +这样就能返回解码后的收据 + +81 +00:04:11,051 --> 00:04:14,555 +从解码的收据中 +以我之前展示的完全相同的方式 + +82 +00:04:14,588 --> 00:04:17,624 +收集所有的 originalTransactionId + +83 +00:04:17,658 --> 00:04:20,661 +接下来 你可以使用收集到的 +任何 originalTransactionId + +84 +00:04:20,694 --> 00:04:24,331 +调用 Get Transaction History 端点 + +85 +00:04:24,364 --> 00:04:27,835 +这将把该用户的交易历史记录 +作为签名交易返回 + +86 +00:04:27,868 --> 00:04:31,171 +这些交易包括非消耗品 退款消耗品 + +87 +00:04:31,205 --> 00:04:34,575 +不续订订阅和自动续订订阅 + +88 +00:04:34,608 --> 00:04:38,712 +然后 如果你要获取特定订阅的 + +89 +00:04:38,745 --> 00:04:43,083 +最新签名交易和签名续订信息 +请使用 + +90 +00:04:43,116 --> 00:04:45,953 +相应的 originalTransactionId 调用 +Get All Subscription Statuses 接口 + +91 +00:04:45,986 --> 00:04:48,388 +这将返回与给定的 +originalTransactionId 对应的 + +92 +00:04:48,422 --> 00:04:52,526 +订阅的所有签名交易和续订信息 + +93 +00:04:52,559 --> 00:04:55,796 +接下来 +让我们看看在 StoreKit 2 交易用例中 + +94 +00:04:55,829 --> 00:04:58,031 +originalTransactionId 的位置 + +95 +00:04:58,065 --> 00:05:01,435 +这是顾客端上的代码 用于从交易中 + +96 +00:05:01,468 --> 00:05:03,003 +获取 originalTransactionId + +97 +00:05:03,036 --> 00:05:05,038 +在支持 StoreKit 2 的设备上 + +98 +00:05:05,072 --> 00:05:08,242 +即 iOS 15 或更高版本 + +99 +00:05:08,275 --> 00:05:11,278 +你可以在经过验证 已解码的交易中 + +100 +00:05:11,311 --> 00:05:15,082 +获取 OriginalID 属性 +以获取 OriginalTransactionID + +101 +00:05:15,115 --> 00:05:19,920 +现在 看看服务器端 +这是一个签名 JWS 交易的例子 + +102 +00:05:19,953 --> 00:05:24,057 +它是你从 App Store Server API +和 App Store Server Notifications 中 + +103 +00:05:24,091 --> 00:05:28,195 +收到的签名交易 +和签名续订的数据类型 + +104 +00:05:28,228 --> 00:05:32,132 +这里 我们看到 +originalTransactionId 是一个顶级字段 + +105 +00:05:34,434 --> 00:05:37,204 +接下来 让我们看看 +顾客 App Store Server + +106 +00:05:37,237 --> 00:05:41,275 +和 StoreKit 2 交易服务器之间的 +整个流程 + +107 +00:05:41,308 --> 00:05:44,478 +首先 在设备上获取签名交易 + +108 +00:05:44,511 --> 00:05:48,081 +使用 StoreKit 2 +你可以在设备上验证此交易 + +109 +00:05:48,115 --> 00:05:51,185 +使用设备上的状态侦听器 +交易侦听器 + +110 +00:05:51,218 --> 00:05:54,488 +或最后一笔交易 +将让你随时了解最新的交易情况 + +111 +00:05:54,521 --> 00:05:58,492 +取消和退款 然后将这些信息 +发送到你的服务器进行记录 + +112 +00:05:58,525 --> 00:06:01,061 +例如 这些更新包括 + +113 +00:06:01,094 --> 00:06:04,231 +订阅续订 订阅报价赎回 过期等 + +114 +00:06:05,532 --> 00:06:07,367 +将交易发送到你的服务器 + +115 +00:06:07,401 --> 00:06:09,970 +结合 +App Store Server Notifications + +116 +00:06:10,003 --> 00:06:12,439 +Alex 将在接下来的部分详细介绍 + +117 +00:06:12,472 --> 00:06:15,108 +你无需调用 App Store Server API + +118 +00:06:15,142 --> 00:06:19,479 +就可以了解订阅的最新状态 + +119 +00:06:19,513 --> 00:06:22,516 +如果确实需要对订阅执行操作 + +120 +00:06:22,549 --> 00:06:25,452 +例如延长订阅的续订日期 + +121 +00:06:25,485 --> 00:06:29,423 +你可以使用签名交易中的 +originalTransactionId + +122 +00:06:29,456 --> 00:06:33,293 +调用相应的端点并获取所需的数据 + +123 +00:06:33,327 --> 00:06:36,196 +现在我们已经了解了如何在 +原始 StoreKit 和 StoreKit 2 中 + +124 +00:06:36,230 --> 00:06:39,433 +使用 App Store Server API +接下来让我们一起讨论下 + +125 +00:06:39,466 --> 00:06:42,336 +如何同时支持 StoreKit +和 StoreKit 2 + +126 +00:06:42,369 --> 00:06:44,605 +你可以在完全不采用 +StoreKit 2 的情况下 + +127 +00:06:44,638 --> 00:06:47,241 +使用 App Store Server API + +128 +00:06:47,274 --> 00:06:50,077 +如前所述 +你可以从原始 StoreKit 的收据中 + +129 +00:06:50,110 --> 00:06:52,779 +获得 OriginalTransactionID + +130 +00:06:52,813 --> 00:06:57,651 +你还可以从 JWS 交易中获取 +StoreKit 2 的 originalTransactionID + +131 +00:06:59,386 --> 00:07:04,258 +你也可以独立于任何其他 API +使用 App Store Server API + +132 +00:07:04,291 --> 00:07:07,928 +它不依赖于使用其他 API 的特定版本 + +133 +00:07:07,961 --> 00:07:09,963 +就 App Store Server Notifications +而言 + +134 +00:07:09,997 --> 00:07:13,567 +它可以与 Version 1 +或 Version 2 通知一起使用 + +135 +00:07:13,600 --> 00:07:16,670 +我们建议使用 Version 2 因为它会在 + +136 +00:07:16,703 --> 00:07:21,241 +订阅发生变化时 +使用安全的 JWS 等格式通知你 + +137 +00:07:21,275 --> 00:07:24,945 +Alex 将在本课程的这个部分 +对此进行详细介绍 + +138 +00:07:24,978 --> 00:07:27,648 +但是 你可以单独使用 +App Store Server API + +139 +00:07:27,681 --> 00:07:31,218 +使用 Version 1 通知或完全没有通知 + +140 +00:07:31,251 --> 00:07:34,688 +接下来 让我们讨论一下 +在完成了我之前介绍的 + +141 +00:07:34,721 --> 00:07:38,292 +迁移步骤之后如何处理新的购买 + +142 +00:07:38,325 --> 00:07:41,728 +为了在使用原始 StoreKit 的设备上 +支持新的购买 + +143 +00:07:41,762 --> 00:07:45,299 +你可以在收到新收据时 +将其发送到你的服务器上 + +144 +00:07:45,332 --> 00:07:48,202 +并执行与我之前展示的 +完全相同的步骤 + +145 +00:07:48,235 --> 00:07:50,637 +同时收集新数据 + +146 +00:07:50,671 --> 00:07:52,806 +使用新收据调用 verifyReceipt + +147 +00:07:52,840 --> 00:07:57,277 +并使用 latest_receipt 中的 +新 originalTransactionId + +148 +00:07:57,311 --> 00:08:01,148 +获得解码的收据 将这些 +originalTransactionId 与收据的 + +149 +00:08:01,181 --> 00:08:03,050 +in_app 部分中的其他 +originalTransactionId 相关联 + +150 +00:08:03,083 --> 00:08:06,019 +以将你的交易信息分在一个组 + +151 +00:08:06,053 --> 00:08:08,722 +然后 你可以获取新的 +originalTransactionId + +152 +00:08:08,755 --> 00:08:11,325 +并根据需要调用 +App Store Server API + +153 +00:08:11,358 --> 00:08:14,561 +例如 如果需要调用 +Get All Subscription Statuses 端点 + +154 +00:08:14,595 --> 00:08:17,998 +以获取相应订阅的最新状态 + +155 +00:08:18,031 --> 00:08:20,968 +现在 我们已经介绍了 +如何将 App Store Server API + +156 +00:08:21,001 --> 00:08:23,437 +与原始 StoreKit 和 StoreKit 2 +一起使用 + +157 +00:08:23,470 --> 00:08:26,673 +那么让我们深入了解签署 +JSON Web Tokens 的一些细节 + +158 +00:08:26,707 --> 00:08:29,776 +这是调用 +App Store Server API 的要求 + +159 +00:08:29,810 --> 00:08:33,514 +为了验证你的开发人员帐户 + +160 +00:08:33,547 --> 00:08:36,583 +是 App Store Server API 的调用方 + +161 +00:08:36,617 --> 00:08:39,887 +我们用JSON Web Tokens +也就是 JWTs 来验证请求 + +162 +00:08:39,920 --> 00:08:42,256 +此令牌必须作为 +服务器调用中的授权头 + +163 +00:08:42,289 --> 00:08:45,559 +包含在每个请求中 + +164 +00:08:45,592 --> 00:08:49,429 +JWT 由 header 有效载荷和签名组成 + +165 +00:08:49,463 --> 00:08:54,001 +接下来 我们将讨论如何构造 +特定于 APP 的 JWT + +166 +00:08:55,068 --> 00:08:57,871 +在这里 我们可以看到 +JSON Web Token 是如何组成的 + +167 +00:08:57,905 --> 00:09:00,541 +以及 header 和有效载荷的结构 + +168 +00:09:00,574 --> 00:09:04,778 +令牌本身可以分为三个部分 +由句点分隔 + +169 +00:09:04,811 --> 00:09:09,016 +Base 64 编码的 header +Base 64 编码的有效载荷 + +170 +00:09:09,049 --> 00:09:11,952 +然后是签名 +由 Base 64 编码的 header + +171 +00:09:11,985 --> 00:09:16,690 +和有效载荷组成 签名使用签名密钥 + +172 +00:09:16,723 --> 00:09:19,593 +header 由这些字段组成 其中包含 + +173 +00:09:19,626 --> 00:09:21,929 +有关如何对数据进行签名的元数据 + +174 +00:09:21,962 --> 00:09:24,598 +这里的一个重要字段是密钥 ID + +175 +00:09:24,631 --> 00:09:27,501 +它是你在 App Store Connect 中的 +私钥 ID + +176 +00:09:27,534 --> 00:09:31,038 +这需要与你用来签署 JWT 的 +密钥相匹配 + +177 +00:09:32,706 --> 00:09:34,741 +有效载荷包含有关 + +178 +00:09:34,775 --> 00:09:37,411 +特定 App 的附加信息 + +179 +00:09:37,444 --> 00:09:40,314 +有关如何获取 API 密钥的 + +180 +00:09:40,347 --> 00:09:43,684 +其他信息和指导 请参阅文章 + +181 +00:09:43,717 --> 00:09:46,553 +“Creating API Keys to Use With +the App Store Server API ” + +182 +00:09:46,587 --> 00:09:48,388 +关于每个字段的详细信息 + +183 +00:09:48,422 --> 00:09:52,025 +请参阅文章“Generating Tokens +for API Requests” + +184 +00:09:53,260 --> 00:09:57,030 +一旦获得了包含所有适当信息的 +header 和有效载荷 + +185 +00:09:57,064 --> 00:09:58,699 +接下来将使用与 keyId 对应的证书 + +186 +00:09:58,732 --> 00:10:01,969 +对 JWT 进行签名 + +187 +00:10:02,002 --> 00:10:06,340 +这是你可以使用的核心伪代码 +无论使用何种语言 + +188 +00:10:06,373 --> 00:10:09,209 +首先 确保你拥有与我们刚才查看的 + +189 +00:10:09,243 --> 00:10:12,679 +header 中提供的密钥 ID +相对应的私钥 + +190 +00:10:12,713 --> 00:10:16,383 +然后 用你的私钥 header 和有效载荷 + +191 +00:10:16,416 --> 00:10:19,119 +调用你的 JWT 库公开的签名函数 + +192 +00:10:19,152 --> 00:10:21,522 +由于 header 包含签名算法 + +193 +00:10:21,555 --> 00:10:25,158 +JWT 库根据提供的算法对其进行签名 + +194 +00:10:27,127 --> 00:10:31,298 +最后 下面是在验证对 +Get All Subscription Statuses 端点的 + +195 +00:10:31,331 --> 00:10:34,434 +cURL 调用时该令牌的用法示例 + +196 +00:10:34,468 --> 00:10:36,870 +用你生成的令牌值 + +197 +00:10:36,904 --> 00:10:38,906 +和所需的 OriginalTransactionID 值 + +198 +00:10:38,939 --> 00:10:41,909 +分别替换 $ +和 $ + +199 +00:10:41,942 --> 00:10:45,479 +接下来 让我们谈谈如何验证 +你收到的签名交易 + +200 +00:10:45,512 --> 00:10:49,316 +是为你所用 +并且是由 App Store 签名的 + +201 +00:10:49,349 --> 00:10:51,552 +签名交易本质上 + +202 +00:10:51,585 --> 00:10:54,454 +是 JavaScript 对象表示法或 JSON + +203 +00:10:54,488 --> 00:10:57,157 +这些对象是经过加密签名的 +如果在 App Store + +204 +00:10:57,191 --> 00:11:00,494 +和服务器之间被篡改 你可以检测出来 + +205 +00:11:00,527 --> 00:11:04,831 +签名交易是以 JSON Web Signature +或 JWS 格式签署的 + +206 +00:11:04,865 --> 00:11:09,303 +App Store 发送给你的签名交易 +将以 JWS 格式送达 + +207 +00:11:09,336 --> 00:11:12,906 +通过验证你收到的 JWS +你可以验证数据 + +208 +00:11:12,940 --> 00:11:16,810 +是否来自 App Store +且内容是否未被篡改 + +209 +00:11:16,844 --> 00:11:20,514 +现在 让我们看看如何验证签名交易 + +210 +00:11:20,547 --> 00:11:23,183 +首先是 Base 64 解码 header + +211 +00:11:23,217 --> 00:11:27,721 +然后 可以通过算法声明 +确定使用哪种签名算法 + +212 +00:11:27,754 --> 00:11:31,425 +这将作为验证 JWS 的一部分 + +213 +00:11:31,458 --> 00:11:34,928 +X5c 证书中的证书链 +是由 Apple 颁发的 + +214 +00:11:34,962 --> 00:11:37,464 +证书的验证表明数据 + +215 +00:11:37,497 --> 00:11:39,900 +已正确签名且未被篡改 + +216 +00:11:39,933 --> 00:11:42,302 +有关如何验证 JWS 的更多信息 + +217 +00:11:42,336 --> 00:11:46,773 +请参阅 App Store 开发人员文档 + +218 +00:11:46,807 --> 00:11:50,344 +本质上 x5c 链是一个证书链 + +219 +00:11:50,377 --> 00:11:53,413 +证书链的成功验证表明 + +220 +00:11:53,447 --> 00:11:57,351 +数据是可信的 +并且数据是由 Apple 签名的 + +221 +00:11:57,384 --> 00:12:01,421 +顺序对证书链很重要 首先是根证书 + +222 +00:12:01,455 --> 00:12:04,391 +此根证书之后可能会有其他证书 + +223 +00:12:04,424 --> 00:12:08,028 +其中每个证书都由前一个证书签名 + +224 +00:12:08,061 --> 00:12:12,065 +我将链中的最后一个证书 +称为叶子证书 + +225 +00:12:13,467 --> 00:12:16,503 +第一个证书称为根证书 + +226 +00:12:16,537 --> 00:12:18,105 +是自签名的 + +227 +00:12:18,138 --> 00:12:20,908 +此证书应与你从 Apple 证书颁发机构 + +228 +00:12:20,941 --> 00:12:22,743 +获得的根证书相匹配 + +229 +00:12:22,776 --> 00:12:27,014 +如果证书不匹配 则该链不应被信任 + +230 +00:12:27,047 --> 00:12:29,683 +叶子证书是证书链中的 +最后一个证书 + +231 +00:12:29,716 --> 00:12:33,020 +是用于签署 JWS 的证书 + +232 +00:12:33,053 --> 00:12:35,489 +下面是 App Store 发送的 + +233 +00:12:35,522 --> 00:12:38,692 +JWS header 的一个示例 + +234 +00:12:38,725 --> 00:12:42,296 +首先是用于签署 JWS 的算法 + +235 +00:12:42,329 --> 00:12:47,334 +接下来是 x5c 证书链 +证书按顺序列出 + +236 +00:12:48,168 --> 00:12:51,972 +现在 让我们从高层次的角度来看 +生成 x5c 证书链 + +237 +00:12:52,005 --> 00:12:53,941 +是什么样子的 + +238 +00:12:53,974 --> 00:12:57,711 +我们从 Apple 证书颁发机构的 +根证书开始 + +239 +00:12:57,744 --> 00:13:02,216 +然后使用根证书 +对中间签名证书进行签名 + +240 +00:13:02,249 --> 00:13:07,020 +接着使用中间签名证书 +对叶子证书进行签名 + +241 +00:13:08,455 --> 00:13:12,426 +现在我们已经介绍了 +生成 x5c 证书链的过程 + +242 +00:13:12,459 --> 00:13:14,828 +接下来让我们看看验证链的过程 + +243 +00:13:14,862 --> 00:13:17,631 +从叶子证书开始 我们确保它是由 + +244 +00:13:17,664 --> 00:13:20,467 +中间签名证书签名的 + +245 +00:13:20,501 --> 00:13:23,170 +然后 我们确保中间签名证书 + +246 +00:13:23,203 --> 00:13:25,439 +由根证书签名 + +247 +00:13:25,472 --> 00:13:27,140 +此外 根证书应与 Apple 证书颁发机构 + +248 +00:13:27,174 --> 00:13:29,810 +提供的证书相匹配 + +249 +00:13:29,843 --> 00:13:31,845 +如果所有这些步骤都成功 + +250 +00:13:31,879 --> 00:13:35,516 +则整个链被验证为合法 + +251 +00:13:35,549 --> 00:13:38,919 +我们来讨论一下验证证书链的方法 + +252 +00:13:38,952 --> 00:13:43,657 +下面是使用 OpenSSL +验证 x5c 证书链的命令 + +253 +00:13:43,690 --> 00:13:46,727 +大体上讲 verify 命令 +将其分解为几个部分 + +254 +00:13:46,760 --> 00:13:49,830 +允许你传入证书进行验证 + +255 +00:13:49,863 --> 00:13:53,267 +trusted 标志 +允许你提供可信任的证书 + +256 +00:13:53,300 --> 00:13:57,738 +换句话说 +该证书将用于验证以下证书 + +257 +00:13:57,771 --> 00:14:00,574 +在这种情况下 我们传入的是 +你从 Apple 证书颁发机构 + +258 +00:14:00,607 --> 00:14:04,344 +获得的根证书 因此是可信任的 + +259 +00:14:04,378 --> 00:14:07,381 +我们将用它来验证 WWDR 证书 + +260 +00:14:07,414 --> 00:14:09,416 +这是证书链中的下一个证书 + +261 +00:14:10,951 --> 00:14:14,955 +untrusted 标志允许你使用信任的证书 + +262 +00:14:14,988 --> 00:14:18,892 +提供要验证的一个或多个证书 + +263 +00:14:18,926 --> 00:14:21,728 +这里 我们首先从 Apple 证书颁发机构 + +264 +00:14:21,762 --> 00:14:25,666 +传入 WWDR 证书 +该证书由根证书签名 + +265 +00:14:25,699 --> 00:14:29,937 +这应该与 x5c 链中的 +第二个证书相匹配 + +266 +00:14:29,970 --> 00:14:33,240 +最后 这里的叶子证书 +是最后一个证书 + +267 +00:14:33,273 --> 00:14:36,743 +由前一个证书签名 + +268 +00:14:36,777 --> 00:14:41,215 +如果验证成功 则返回成功代码 + +269 +00:14:41,248 --> 00:14:44,551 +然后 你可以继续使用解码后的信息 + +270 +00:14:44,585 --> 00:14:46,787 +如果验证失败 + +271 +00:14:46,820 --> 00:14:49,389 +请根据返回的错误代码确定问题 + +272 +00:14:49,423 --> 00:14:53,927 +如果无法验证 此数据可能被篡改 +不应使用 + +273 +00:14:53,961 --> 00:14:56,496 +有关使用 OpenSSL +验证 x5c 证书链的完整说明 + +274 +00:14:56,530 --> 00:15:01,602 +请参考 App Store 开发者文档 + +275 +00:15:02,402 --> 00:15:06,840 +这里有一些关于如何验证 +签名交易的伪代码 + +276 +00:15:06,874 --> 00:15:10,210 +首先 获取你想要验证的 JWS + +277 +00:15:10,244 --> 00:15:14,448 +然后 获取 JWS 库验证所需的证书 + +278 +00:15:14,481 --> 00:15:17,417 +使用适当的证书 + +279 +00:15:17,451 --> 00:15:19,520 +调用 JWS 库的 verify function + +280 +00:15:19,553 --> 00:15:22,756 +签署 JWS 的证书是叶子证书 + +281 +00:15:22,789 --> 00:15:25,826 +尽管有些库需要传递整个链 + +282 +00:15:27,828 --> 00:15:31,865 +如果调用成功 则可以继续执行任务 + +283 +00:15:31,899 --> 00:15:35,502 +如果这是调用 +App Store Server API 的结果 + +284 +00:15:35,536 --> 00:15:38,238 +则可以继续存储已验证的数据 + +285 +00:15:38,272 --> 00:15:41,408 +至于通知的情况 +Alex 将在他的视频部分 + +286 +00:15:41,441 --> 00:15:44,211 +进行更多的讨论 + +287 +00:15:44,244 --> 00:15:48,115 +如果 JWS 无法验证 请不要使用 JWS + +288 +00:15:48,148 --> 00:15:52,319 +这可能意味着它已被篡改 +或者不是由 App Store 发送的 + +289 +00:15:52,352 --> 00:15:57,024 +Alex 将深入探讨如何在使用通知时 +更好地确保安全性 + +290 +00:15:57,057 --> 00:15:59,326 +有关验证和处理 JWS 的完整说明 + +291 +00:15:59,359 --> 00:16:03,764 +请参考 App Store 开发者文档 + +292 +00:16:04,498 --> 00:16:08,068 +现在 让我们回顾一下 +从 verifyReceipt + +293 +00:16:08,101 --> 00:16:10,437 +迁移到 App Store Server API 的 +一些用例 + +294 +00:16:10,470 --> 00:16:13,207 +首先 让我们看看你想要检查 + +295 +00:16:13,240 --> 00:16:16,009 +任何给定订阅者的最新状态 + +296 +00:16:16,043 --> 00:16:20,347 +这使你可以随时了解 +单个订阅的任何更改情况 + +297 +00:16:20,380 --> 00:16:22,716 +以前 要获取订阅者的最新状态 + +298 +00:16:22,749 --> 00:16:25,519 +必须调用 verifyReceipt + +299 +00:16:25,552 --> 00:16:28,188 +并根据到期意图 宽限期 + +300 +00:16:28,222 --> 00:16:32,192 +到期日期等字段确定订阅的状态 + +301 +00:16:32,226 --> 00:16:36,330 +现在 使用 App Store Server API + +302 +00:16:36,363 --> 00:16:38,966 +可以调用 +Get All Subscription Statuses 端点 + +303 +00:16:38,999 --> 00:16:41,335 +来获取订阅的最新状态 + +304 +00:16:41,368 --> 00:16:43,103 +其中的状态字段包含当前状态 + +305 +00:16:43,136 --> 00:16:45,873 +以及最新的签名交易和续订信息 + +306 +00:16:45,906 --> 00:16:48,575 +让我们来看看如何执行这一流程 + +307 +00:16:48,609 --> 00:16:51,545 +首先 对于你拥有的 +任何解码后的收据 + +308 +00:16:51,578 --> 00:16:55,716 +你可以按照我之前展示的方式 +从中获取 originalTransactionId + +309 +00:16:55,749 --> 00:16:58,752 +然后 可以调用 +originalTransactionId 的 + +310 +00:16:58,785 --> 00:17:01,989 +Get All Subscription Statuses 端点 +该端点将返回 + +311 +00:17:02,022 --> 00:17:04,825 +该交易的最新签名交易和续订信息 + +312 +00:17:04,858 --> 00:17:08,562 +接下来 +我们来看获取最新交易的案例 + +313 +00:17:08,595 --> 00:17:12,466 +获取最新的交易信息会通知你 +用户购买了哪些内容 + +314 +00:17:12,499 --> 00:17:16,904 +续订了哪些内容 +用户的订阅是否有任何更改等 + +315 +00:17:16,937 --> 00:17:19,940 +以前 要获取用户的最新交易信息 + +316 +00:17:19,973 --> 00:17:21,742 +必须调用 verifyReceipt + +317 +00:17:21,775 --> 00:17:24,778 +并使用 in_app 数组 +并检查 Latest_Receipt_INFO + +318 +00:17:24,811 --> 00:17:27,915 +其中包含用户的所有交易 + +319 +00:17:27,948 --> 00:17:31,118 +使用 App Store Server API +获取最新的交易 + +320 +00:17:31,151 --> 00:17:33,887 +Get Transaction History 端点 + +321 +00:17:33,921 --> 00:17:36,423 +允许你获取用户的 +完整购买历史记录 + +322 +00:17:36,456 --> 00:17:40,160 +此外 分页与 WWDC22 演讲 +“What's new with in-app purchase”中 + +323 +00:17:40,194 --> 00:17:43,897 +介绍的新的筛选和排序功能相结合 + +324 +00:17:43,931 --> 00:17:47,601 +确保你可以高效地准确获取 +所需的数据 + +325 +00:17:48,902 --> 00:17:51,004 +让我们来看看可能需要的流程 + +326 +00:17:51,038 --> 00:17:53,874 +对于属于该用户的任何 +OriginalTransactionID + +327 +00:17:53,907 --> 00:17:56,710 +你可以调用 +Get Transaction History 端点 + +328 +00:17:56,743 --> 00:17:59,479 +该端点将该用户的交易历史记录 +作为签名交易返回 + +329 +00:17:59,513 --> 00:18:04,518 +并根据你的规范进行 +筛选 排序和分页 + +330 +00:18:06,153 --> 00:18:09,189 +最后 我们看看采用 +appAccountToken 的情况 + +331 +00:18:09,223 --> 00:18:12,226 +appAccountToken 字段允许你 +提供一个 UUID + +332 +00:18:12,259 --> 00:18:15,762 +将 StoreKit 2 交易与用户关联起来 + +333 +00:18:15,796 --> 00:18:18,098 +然后 在签名交易 签名续订 + +334 +00:18:18,131 --> 00:18:22,336 +和该交易的通知上 +将出现 appAccountToken + +335 +00:18:22,369 --> 00:18:25,806 +以前 原始 StoreKit +不支持 appAccountToken + +336 +00:18:25,839 --> 00:18:28,976 +因为这是 StoreKit2 的新功能 + +337 +00:18:29,009 --> 00:18:33,380 +现在 我们在原始 StoreKit 的 +applicationUsername 字段中 + +338 +00:18:33,413 --> 00:18:36,016 +增加了对提供 UUID 的支持 + +339 +00:18:36,049 --> 00:18:38,118 +以支持与 +Original StoreKit 客户的兼容 + +340 +00:18:38,151 --> 00:18:40,888 +在这种情况下 UUID 将支持 + +341 +00:18:40,921 --> 00:18:43,457 +appAccountToken 的所有功能 + +342 +00:18:43,490 --> 00:18:47,728 +然后 appAccountToken +以 verifyReceipt 的形式 + +343 +00:18:47,761 --> 00:18:51,231 +返回给 Original StoreKit 用户 +并在调用 App Store Server API + +344 +00:18:51,265 --> 00:18:53,267 +和 App Store Server API 的通知中 + +345 +00:18:53,300 --> 00:18:55,903 +显示给原始 +StoreKit 和 StoreKit 2 用户 + +346 +00:18:56,670 --> 00:18:59,706 +本课程的 App Store Server API 部分 +到此为止 + +347 +00:18:59,740 --> 00:19:04,511 +接下来 Alex 将介绍迁移到 +App Store Notifications Version 2 的内容 + +348 +00:19:04,545 --> 00:19:05,479 +Alex: 谢谢 Gabriel + +349 +00:19:05,512 --> 00:19:07,848 +我是 Alex 很高兴今天能在这里 + +350 +00:19:07,881 --> 00:19:11,518 +讨论 App Store +Notifications Version 2 + +351 +00:19:11,552 --> 00:19:15,789 +首先 我们将讨论如何使用 +Version 2 通知 + +352 +00:19:15,822 --> 00:19:21,395 +接下来是 Version 2 通知的不同之处 +以及如何构建在其他可用模型的基础上 + +353 +00:19:21,428 --> 00:19:24,898 +第三 我们将讨论 +在错过通知的情况下进行修复 + +354 +00:19:24,932 --> 00:19:29,102 +以及一些有助于 +完成这项任务的新资源 + +355 +00:19:29,136 --> 00:19:32,606 +最后是 通知如何提供 +对顾客行为的洞察 + +356 +00:19:32,639 --> 00:19:34,842 +并为了解订阅生命周期 + +357 +00:19:34,875 --> 00:19:37,377 +创造更多机会 + +358 +00:19:37,411 --> 00:19:40,681 +让我们简单介绍一下什么是通知 + +359 +00:19:40,714 --> 00:19:42,616 +以及谁可以使用它们 + +360 +00:19:42,649 --> 00:19:45,419 +App Store Server Notifications 是 + +361 +00:19:45,452 --> 00:19:48,989 +我们在 App 用户执行某些操作时 +向你发送的消息 + +362 +00:19:49,022 --> 00:19:52,025 +这些通知大致分为两类 + +363 +00:19:52,059 --> 00:19:54,428 +订阅更新和退款更新 + +364 +00:19:54,461 --> 00:19:57,564 +虽然我们一直在努力覆盖其他场景 + +365 +00:19:57,598 --> 00:20:00,868 +我们提供这些通知 +以帮助填补你在 App 中 + +366 +00:20:00,901 --> 00:20:03,504 +可能无法执行的用户操作的空白 + +367 +00:20:03,537 --> 00:20:06,640 +例如 我们最常见的一个用例 + +368 +00:20:06,673 --> 00:20:08,408 +是订阅的续订 + +369 +00:20:08,442 --> 00:20:12,012 +当此交易可用时 +用户可能不在 App 中 + +370 +00:20:12,045 --> 00:20:15,015 +订阅更新时 +App Store 服务器通知 + +371 +00:20:15,048 --> 00:20:17,618 +通过主动将最新的交易信息 + +372 +00:20:17,651 --> 00:20:20,654 +直接发送至你的服务器 +来帮助解决这个问题 + +373 +00:20:20,687 --> 00:20:24,558 +Version 2 通知与 StoreKit 2 模型 + +374 +00:20:24,591 --> 00:20:27,828 +以及 Gabriel 刚刚讲的 +App Store Server API 有很多相似之处 + +375 +00:20:27,861 --> 00:20:31,465 +然而 虽然它们可以很好地协同工作 +但它们都是 + +376 +00:20:31,498 --> 00:20:33,567 +可以在不同时间使用的独立工具 + +377 +00:20:33,600 --> 00:20:36,403 +最重要的是 你可以 +继续支持 StoreKit 2 不可用的客户端 + +378 +00:20:36,436 --> 00:20:40,107 +iOS 15 之前的客户端 + +379 +00:20:40,140 --> 00:20:43,377 +同时使用 Version 2 服务器通知 + +380 +00:20:43,410 --> 00:20:46,213 +我们已经努力使 +Version 2 通知成为了 + +381 +00:20:46,246 --> 00:20:49,316 +我们最深入 灵活的工具之一 + +382 +00:20:49,349 --> 00:20:52,553 +用于在整个订阅生命周期中提供 +有关用户的信息 + +383 +00:20:52,586 --> 00:20:54,855 +我们将在稍后的演示中 +更深入地讨论该问题 + +384 +00:20:54,888 --> 00:20:58,559 +但通知提供的信息也可以抓取 + +385 +00:20:58,592 --> 00:21:01,295 +应用程序之外执行的操作 + +386 +00:21:01,328 --> 00:21:03,664 +我希望我已经引起了你对通知 + +387 +00:21:03,697 --> 00:21:06,867 +尤其是 Version 2 通知的概念的兴趣 + +388 +00:21:06,900 --> 00:21:09,069 +在我们深入讨论之前 +虽然这个演示文稿 + +389 +00:21:09,102 --> 00:21:11,471 +能引导你了解接收通知的入门 +及最佳解决方案 + +390 +00:21:11,505 --> 00:21:14,508 +但它并不能说明全部情况 + +391 +00:21:14,541 --> 00:21:16,443 +请参阅近期的一些视频 + +392 +00:21:16,476 --> 00:21:20,447 +了解有关通知以及它们 +如何满足各种用例的更多信息 + +393 +00:21:20,480 --> 00:21:23,116 +我们来看看如何设置 Version 2 通知 + +394 +00:21:23,150 --> 00:21:25,152 +我们将逐步了解如何设置通知 + +395 +00:21:25,185 --> 00:21:27,621 +直到接收你的第一个通知 + +396 +00:21:27,654 --> 00:21:32,092 +首先 转到 App Store Connect 中的 +应用页面 + +397 +00:21:32,125 --> 00:21:37,064 +向下滚动 你会看到一个 +App Store Server Notifications 的部分 + +398 +00:21:37,097 --> 00:21:41,101 +大家会看到生产和沙盒的选项 + +399 +00:21:41,134 --> 00:21:43,704 +每个环境都可以包含一个单独的 URL + +400 +00:21:43,737 --> 00:21:47,107 +和一个单独的通知版本 + +401 +00:21:47,140 --> 00:21:50,711 +下面是用于 +产品设置选项页面的示例 + +402 +00:21:50,744 --> 00:21:53,480 +沙盒设置是完全相同的 + +403 +00:21:53,514 --> 00:21:57,184 +特别是 +如果你是 Version 1 通知的用户 + +404 +00:21:57,217 --> 00:22:01,555 +我们建议你首先在沙盒环境下 +尝试 Version 2 通知 + +405 +00:22:01,588 --> 00:22:04,591 +这是在不影响产品设置的情况下 + +406 +00:22:04,625 --> 00:22:07,528 +熟悉通知的好途径 + +407 +00:22:07,561 --> 00:22:11,198 +选择 Set Up Sandbox 按钮 +提供服务器的 URL + +408 +00:22:11,231 --> 00:22:13,834 +然后选择 Version 2 Notifications + +409 +00:22:15,169 --> 00:22:18,005 +在触发通知之前 +请确认你的服务器端点 + +410 +00:22:18,038 --> 00:22:21,108 +有一个有效的 HTTPS 证书 + +411 +00:22:21,141 --> 00:22:25,245 +还要确认你已允许 Apple 的 +公共 IP 访问你的服务器 + +412 +00:22:25,279 --> 00:22:27,848 +在设置通知时 一些最常见的故障 + +413 +00:22:27,881 --> 00:22:30,050 +与防火墙和证书有关 + +414 +00:22:30,083 --> 00:22:33,420 +作为初始故障排除步骤 +这些也非常适合检查 + +415 +00:22:33,453 --> 00:22:36,423 +你是否突然停止接收通知 + +416 +00:22:36,456 --> 00:22:39,393 +现在你已准备好接收第一个通知了 + +417 +00:22:39,426 --> 00:22:41,628 +在沙盒中 +可以通过多种操作来触发通知 + +418 +00:22:41,662 --> 00:22:44,898 +例如购买应用内订阅 + +419 +00:22:44,932 --> 00:22:47,134 +然而 为了便于在测试时使用 + +420 +00:22:47,167 --> 00:22:49,403 +我们建议使用新的 +Request a Test notification 端点 + +421 +00:22:49,436 --> 00:22:54,007 +来触发通知 这是 +App Store Server API 的一部分 + +422 +00:22:54,041 --> 00:22:57,110 +该端点有助于自动化通知测试过程 + +423 +00:22:57,144 --> 00:22:59,613 +触发 Request a Test Notification +端点后 + +424 +00:22:59,646 --> 00:23:02,583 +你应该很快就会收到通知 + +425 +00:23:02,616 --> 00:23:04,685 +如果你在接收通知方面遇到问题 + +426 +00:23:04,718 --> 00:23:07,554 +请参考新的 +Get Test Notification Status 端点 + +427 +00:23:07,588 --> 00:23:10,991 +该端点可以提供有关 +通知未能传递原因的简要状态 + +428 +00:23:11,024 --> 00:23:14,194 +例如 SSL_ISSUE 这样的状态 + +429 +00:23:14,228 --> 00:23:17,831 +可能就是提示再次检查你的 +HTTPS 证书 + +430 +00:23:17,865 --> 00:23:20,267 +我们建议在执行配置更改时 + +431 +00:23:20,300 --> 00:23:22,536 +触发测试通知 + +432 +00:23:22,569 --> 00:23:25,272 +这是确认你在更改后 +仍能收到通知的 + +433 +00:23:25,305 --> 00:23:26,907 +好方法 + +434 +00:23:26,940 --> 00:23:30,811 +现在 让我们继续了解 +你刚刚收到的通知 + +435 +00:23:32,179 --> 00:23:34,515 +就像我们之前从 Gabriel 那里 +看到的交易一样 + +436 +00:23:34,548 --> 00:23:37,885 +通知也是 JWS 格式的 + +437 +00:23:37,918 --> 00:23:42,322 +让我们来看看如何解码 +及验证通知有效载荷 + +438 +00:23:42,356 --> 00:23:44,625 +首先 收到通知时 + +439 +00:23:44,658 --> 00:23:49,263 +你希望提取 JSON 正文的 +signedPayload 字段 + +440 +00:23:49,296 --> 00:23:52,866 +接下来 你将执行与前面 +Gabriel 介绍的完全相同的步骤 + +441 +00:23:52,900 --> 00:23:55,135 +来验证签名交易 + +442 +00:23:55,169 --> 00:23:57,538 +你将按照相同的步骤 +来验证签名数据 + +443 +00:23:57,571 --> 00:24:00,841 +无论它是来自通知的 +签名通知有效载荷 + +444 +00:24:00,874 --> 00:24:04,945 +还是来自 +App Store Server API 的签名交易 + +445 +00:24:04,978 --> 00:24:09,750 +接下来 重要的是要验证通知 +是针对哪个 App 的 + +446 +00:24:09,783 --> 00:24:12,553 +如果你有多个应用程序 +共享同一个端点 + +447 +00:24:12,586 --> 00:24:15,856 +那么这是确定目标 App 的好方法 + +448 +00:24:15,889 --> 00:24:19,293 +同样重要的是 要确认 +通知针对的 App 是你的 App + +449 +00:24:19,326 --> 00:24:24,264 +而且通知针对的不是其他开发者 + +450 +00:24:24,298 --> 00:24:27,701 +最后 一项更实用的检查是确保 + +451 +00:24:27,734 --> 00:24:30,137 +通知的环境与你的预期环境相匹配 + +452 +00:24:30,170 --> 00:24:32,606 +无论是生产环境还是沙盒环境 + +453 +00:24:32,639 --> 00:24:35,709 +由于 App Store Connect 允许 +每个环境使用单独的 URL + +454 +00:24:35,742 --> 00:24:37,945 +因此可以强制执行此要求 + +455 +00:24:37,978 --> 00:24:41,481 +或者 如果 URL 是共享的 + +456 +00:24:41,515 --> 00:24:46,019 +要保证你是基于环境单独存储 +和处理通知 + +457 +00:24:46,053 --> 00:24:50,691 +此时 JWS 已完全验证 +并可以存储以供进一步处理 + +458 +00:24:50,724 --> 00:24:53,260 +除了一些基本检查外 + +459 +00:24:53,293 --> 00:24:56,463 +我们建议你的服务器异步处理通知 + +460 +00:24:56,496 --> 00:25:00,834 +如果通知的处理时间过长 +我们的服务器将记录超时 + +461 +00:25:00,868 --> 00:25:03,670 +并假设通知未成功传递 + +462 +00:25:03,704 --> 00:25:06,840 +然后我们将重新发送通知 + +463 +00:25:06,874 --> 00:25:10,577 +因此 将耗时的处理移到此功能之外 + +464 +00:25:10,611 --> 00:25:13,247 +有助于确保 App Store 服务器 +将你的通知 + +465 +00:25:13,280 --> 00:25:16,216 +记录为成功发送 并且重试时 + +466 +00:25:16,250 --> 00:25:19,553 +无需服务器再重新处理通知 + +467 +00:25:19,586 --> 00:25:24,558 +现在 我们回顾一下 +验证后的通知正文 + +468 +00:25:24,591 --> 00:25:28,695 +第一个字段是 +通知类型和可选子类型 + +469 +00:25:28,729 --> 00:25:32,032 +结合在一起之后 +它们将告诉你通知适用的场景 + +470 +00:25:32,065 --> 00:25:35,903 +这些字段还有助于显示 +自上次通知以来发生了哪些更改 + +471 +00:25:35,936 --> 00:25:38,872 +并提供有关 +发生这些更改原因的信息 + +472 +00:25:38,906 --> 00:25:43,377 +notificationUUID 是 +每个通知的唯一标识符 + +473 +00:25:43,410 --> 00:25:45,479 +如果服务器重试通知 + +474 +00:25:45,512 --> 00:25:49,583 +则重试通知包含 +相同的 notificationUUID + +475 +00:25:49,616 --> 00:25:52,920 +这有助于检测服务器处理通知 + +476 +00:25:52,953 --> 00:25:57,858 +但没有及时响应成功的 +HTTP 响应代码的情况 + +477 +00:25:57,891 --> 00:26:01,428 +我们建议基于此字段添加 +由于重试导致的 + +478 +00:26:01,461 --> 00:26:03,497 +重复通知检测 + +479 +00:26:03,530 --> 00:26:06,967 +signedDate 字段告诉你 +通知是何时创建的 + +480 +00:26:07,000 --> 00:26:10,470 +这对于检测重试通知特别有用 + +481 +00:26:10,504 --> 00:26:13,507 +接下来是 appAppleId 和 bundleId + +482 +00:26:13,540 --> 00:26:16,310 +这些对于检测目标应用程序很重要 + +483 +00:26:16,343 --> 00:26:19,146 +正如我们前面所讨论的 +检查这些字段并确认它们 + +484 +00:26:19,179 --> 00:26:23,884 +与预期值匹配是很重要的 +以防止重放攻击 + +485 +00:26:23,917 --> 00:26:26,854 +此外 确保通知的环境 + +486 +00:26:26,887 --> 00:26:29,756 +与预期的环境相匹配 +沙盒通知不会被记录为 + +487 +00:26:29,790 --> 00:26:32,292 +生产数据 反之亦然 + +488 +00:26:33,861 --> 00:26:38,599 +最后 实际的 signedTransactionInfo +和可选的 signedRenewalInfo + +489 +00:26:38,632 --> 00:26:41,001 +这将是签署时的 + +490 +00:26:41,034 --> 00:26:43,103 +标的购买的最新状态 + +491 +00:26:43,136 --> 00:26:45,439 +此时 解析完通知后 + +492 +00:26:45,472 --> 00:26:48,242 +你只剩下最新的交易和更新信息 + +493 +00:26:48,275 --> 00:26:51,411 +以及状态更改的最新原因 + +494 +00:26:51,445 --> 00:26:55,082 +既然我们已经介绍了 +特定通知的设置和接收 + +495 +00:26:55,115 --> 00:26:57,451 +我们通过与 Version 1 通知的比较 + +496 +00:26:57,484 --> 00:27:00,854 +来测试 Version 2 通知模型 + +497 +00:27:00,888 --> 00:27:03,557 +通知如何组合在一起 +来跟踪订阅生命周期 + +498 +00:27:03,590 --> 00:27:06,660 +以及Version 2 通知背后的设计决策 + +499 +00:27:06,693 --> 00:27:09,530 +Version 2 +在发送有关购买状态的信息时 + +500 +00:27:09,563 --> 00:27:10,931 +采用了不同的原理 + +501 +00:27:10,964 --> 00:27:14,301 +与每次通知都发送所有 +最近的历史记录不同 + +502 +00:27:14,334 --> 00:27:17,938 +版本 2 的通知只专注于 +发送最新的信息 + +503 +00:27:17,971 --> 00:27:19,506 +即最新的交易信息 + +504 +00:27:19,540 --> 00:27:23,343 +订阅的情况 还有待续订信息 + +505 +00:27:24,912 --> 00:27:26,980 +通过通知 我们可以提供 + +506 +00:27:27,014 --> 00:27:30,050 +关于订阅生命周期的每一步的信息 + +507 +00:27:30,083 --> 00:27:33,453 +因此 通知只包含关于 + +508 +00:27:33,487 --> 00:27:36,123 +最新的购买或订阅的信息 + +509 +00:27:36,156 --> 00:27:39,226 +这些通知一起创建了 + +510 +00:27:39,259 --> 00:27:41,161 +订阅状态的完整时间线 + +511 +00:27:41,195 --> 00:27:44,598 +如果你需要查看整个交易历史记录 + +512 +00:27:44,631 --> 00:27:46,834 +但无权访问通知历史记录 + +513 +00:27:46,867 --> 00:27:49,169 +则可以使用 +Get transaction history 端点 + +514 +00:27:49,203 --> 00:27:54,074 +它能让你在分页和可筛选的上下文中 +查询用户的整个交易历史记录 + +515 +00:27:54,107 --> 00:27:58,879 +第二 Version 1 通知不需要 +客户端使用 StoreKit 2 + +516 +00:27:58,912 --> 00:28:01,515 +没错 Version 2 也是如此 + +517 +00:28:01,548 --> 00:28:04,852 +事实上 无论客户端使用什么框架 + +518 +00:28:04,885 --> 00:28:09,122 +你都可以从今天开始 +享受 Version 2 通知的优点 + +519 +00:28:09,156 --> 00:28:13,994 +最后 Version 2 +通知通过添加其他的类型 + +520 +00:28:14,027 --> 00:28:16,897 +以及添加新的子类型字段 +来提高所提供的详细程度 + +521 +00:28:16,930 --> 00:28:19,299 +并扩展所涵盖的案例 + +522 +00:28:19,333 --> 00:28:21,535 +通过这种方式 +我们能够覆盖更多的场景 + +523 +00:28:21,568 --> 00:28:24,605 +并在订阅生命周期的每个步骤中 +提供通知 + +524 +00:28:24,638 --> 00:28:28,041 +我们添加的一些值得注意的场景 +包括到期 + +525 +00:28:28,075 --> 00:28:31,411 +与自动续订状态更改相关的 +更详细的信息 + +526 +00:28:31,445 --> 00:28:34,281 +以及与退款流程相关的更多场景 + +527 +00:28:34,314 --> 00:28:37,651 +现在 为了说明所涵盖场景的复杂性 + +528 +00:28:37,684 --> 00:28:40,921 +并提供一个更具体的示例 + +529 +00:28:40,954 --> 00:28:43,156 +让我们从头到尾看看通知是如何 +通知订阅所采取的 + +530 +00:28:43,190 --> 00:28:45,325 +每个步骤的 + +531 +00:28:45,359 --> 00:28:49,162 +让我们想象一个订阅前的用户 + +532 +00:28:49,196 --> 00:28:52,833 +订阅后 用户进入续订订阅状态 + +533 +00:28:52,866 --> 00:28:55,969 +并发送带有子类型 +INITIAL_BUY 的订阅通知 + +534 +00:28:56,003 --> 00:29:00,107 +或者如果使用了报价 则发送 +带有子类型 INITIAL_BUY 的 OFFER_REDEEMED + +535 +00:29:00,140 --> 00:29:03,343 +通知中包含第一个签名交易 + +536 +00:29:03,377 --> 00:29:06,246 +以及签名续订信息 + +537 +00:29:06,280 --> 00:29:10,384 +时间流逝 订阅更新 保持更新状态 + +538 +00:29:10,417 --> 00:29:12,920 +每次续订时 我们发送一个包含 + +539 +00:29:12,953 --> 00:29:16,723 +下一个签名交易信息的 +DID_RENEW 通知 + +540 +00:29:16,757 --> 00:29:19,159 +每当用户取消自动续订时 + +541 +00:29:19,193 --> 00:29:22,029 +他们就会进入即将到期的订阅状态 + +542 +00:29:22,062 --> 00:29:23,463 +那么将收到一个子类型为 +AUTO_RENEW_DISABLED 的 + +543 +00:29:23,497 --> 00:29:26,700 +DID_CHANGE_RENEWAL_STATUS + +544 +00:29:28,402 --> 00:29:31,405 +如果他们不启用自动续订 + +545 +00:29:31,438 --> 00:29:34,241 +那么到期后 他们就会进入过期状态 + +546 +00:29:34,274 --> 00:29:36,643 +你将收到带有子类型 +VOLUNTARY 的 EXPIRED + +547 +00:29:36,677 --> 00:29:38,278 +现在 你可能会疑惑 + +548 +00:29:38,312 --> 00:29:40,714 +其他所有的通知类型在哪里呢 + +549 +00:29:43,050 --> 00:29:46,520 +下面是通过通知看到的 +订阅生命周期 + +550 +00:29:46,553 --> 00:29:49,289 +有很多在进行 + +551 +00:29:49,323 --> 00:29:52,626 +这张图还不能说明全部 + +552 +00:29:52,659 --> 00:29:57,130 +例如 这里不包括退款 撤销生命周期 + +553 +00:29:57,164 --> 00:29:59,566 +这个图表说明了 Version 2 通知 +所涵盖的大量场景 + +554 +00:29:59,600 --> 00:30:02,603 +它们可用于通知你 + +555 +00:30:02,636 --> 00:30:05,439 +订阅生命周期的每个步骤 + +556 +00:30:06,507 --> 00:30:08,342 +我要说的另一点是我们努力包含 + +557 +00:30:08,375 --> 00:30:10,477 +所有可能的过渡状态 + +558 +00:30:10,511 --> 00:30:14,147 +这有助于通过 +成为跟踪订阅的单一来源 + +559 +00:30:14,181 --> 00:30:16,950 +来提高通知的效用 + +560 +00:30:16,984 --> 00:30:19,987 +并提高你看到 +订阅者使用历程的信心 + +561 +00:30:20,020 --> 00:30:22,623 +然而 即使所有数据都在这里 + +562 +00:30:22,656 --> 00:30:25,158 +你也不需要使用所有可用的类型 + +563 +00:30:25,192 --> 00:30:28,662 +例如 即使只是处理 +与续订偏好更改相关的通知 + +564 +00:30:28,695 --> 00:30:31,064 +也可以提供价值 + +565 +00:30:31,098 --> 00:30:33,166 +特别是 如果各位刚刚开始 + +566 +00:30:33,200 --> 00:30:37,271 +那么请从对自己的情况 +最有用的通知类型开始 + +567 +00:30:37,304 --> 00:30:40,207 +现在 我们讨论一下 +设置好服务器后会发生什么 + +568 +00:30:40,240 --> 00:30:44,011 +一切都很顺利 但是 唉 服务器罢工了 + +569 +00:30:44,044 --> 00:30:47,014 +不管是几天 几分钟 +还是你认为你可能只错过了一分钟 + +570 +00:30:47,047 --> 00:30:50,884 +让我们通过一些步骤来帮助 +解决此问题 + +571 +00:30:50,918 --> 00:30:52,719 +我们来想象一下你的服务器 + +572 +00:30:52,753 --> 00:30:56,690 +它已成功设置 并且正在接收通知 + +573 +00:30:56,723 --> 00:31:01,695 +在某些情况下 +服务器出现问题 无法接收通知 + +574 +00:31:01,728 --> 00:31:04,031 +我们仍试图向你的服务器发送消息 + +575 +00:31:04,064 --> 00:31:06,333 +但现在这些请求开始失败了 + +576 +00:31:06,366 --> 00:31:08,368 +有几种方法可以处理这种情况 + +577 +00:31:08,402 --> 00:31:10,170 +首先就是等待 + +578 +00:31:10,204 --> 00:31:13,006 +如果我们没有从你的服务器 +收到成功的状态代码 + +579 +00:31:13,040 --> 00:31:14,441 +或根本无法连接到它 + +580 +00:31:14,474 --> 00:31:18,645 +我们将根据记录的重试策略 +来重试通知 + +581 +00:31:18,679 --> 00:31:21,815 +对于 Version 2 通知 +我们在每次尝试后重试 + +582 +00:31:21,849 --> 00:31:24,985 +首先延迟 1 小时 然后延迟 12 小时 + +583 +00:31:25,018 --> 00:31:28,789 +延迟 24 小时 48 小时 +最后延迟 72 小时 + +584 +00:31:28,822 --> 00:31:31,225 +对于 1小时内的中断来说 +等待非常有效 + +585 +00:31:31,258 --> 00:31:34,661 +因为通知将在首次故障 +1 小时后重试 + +586 +00:31:36,029 --> 00:31:37,865 +在某个时刻 服务器恢复了 + +587 +00:31:37,898 --> 00:31:41,101 +你开始再次接收通知 + +588 +00:31:41,134 --> 00:31:46,306 +首先 你会收到一个 +与错过的通知无关的新通知 + +589 +00:31:46,340 --> 00:31:49,776 +通知会延迟重试 +所以一旦你的服务器上线 + +590 +00:31:49,810 --> 00:31:52,679 +并不会立即收到所有错过的通知 + +591 +00:31:53,914 --> 00:31:57,718 +一段时间后 你开始收到错过的通知 + +592 +00:31:57,751 --> 00:31:59,853 +并穿插着新的通知 + +593 +00:32:01,221 --> 00:32:04,391 +这就产生了一个问题 +那就是如何检测通知 + +594 +00:32:04,424 --> 00:32:07,628 +是原始通知还是重试通知 + +595 +00:32:07,661 --> 00:32:09,496 +让我们检查一个通知 + +596 +00:32:10,531 --> 00:32:13,600 +在这个通知里 +我们只显示了几个字段 + +597 +00:32:14,935 --> 00:32:17,838 +通知包含一个 signedDate 字段 + +598 +00:32:17,871 --> 00:32:20,007 +通过比较签名日期 + +599 +00:32:20,040 --> 00:32:23,677 +与收到通知的时间 +这个字段可用于检测重试 + +600 +00:32:23,710 --> 00:32:26,980 +如果你看到签名日期 + +601 +00:32:27,014 --> 00:32:28,916 +明显早于你收到通知的日期 + +602 +00:32:28,949 --> 00:32:31,518 +这表明你可能遇到了中断 + +603 +00:32:32,619 --> 00:32:36,256 +想象在这种情况下 +标记为 6 和 3 的通知 + +604 +00:32:36,290 --> 00:32:38,225 +是针对同一个订阅的 + +605 +00:32:38,258 --> 00:32:41,862 +这可以通过比较 +originalTransactionIds 来确定 + +606 +00:32:41,895 --> 00:32:46,567 +在这种情况下 仅仅因为通知 3 +是在通知 6 之后收到的 + +607 +00:32:46,600 --> 00:32:51,238 +并不意味着它包含 +比通知 6 更新的信息 + +608 +00:32:51,271 --> 00:32:54,241 +其他时候 你的服务器 +可能已收到通知 + +609 +00:32:54,274 --> 00:32:58,712 +但它未能响应成功的 +HTTP 200 状态代码 + +610 +00:32:58,745 --> 00:33:02,015 +这可能会导致通知 +重新发送到你的服务器 + +611 +00:33:02,049 --> 00:33:06,119 +如前所述 +请确保检查 notificationUUID 字段 + +612 +00:33:06,153 --> 00:33:08,155 +以重复这些请求 + +613 +00:33:08,188 --> 00:33:11,058 +即使你成功记录了通知 + +614 +00:33:11,091 --> 00:33:13,994 +也可能会看到大量的重试通知 + +615 +00:33:14,027 --> 00:33:15,929 +在这种情况下 确保每次 + +616 +00:33:15,963 --> 00:33:19,900 +收到通知时都使用 +HTTP 200 响应来回应 + +617 +00:33:19,933 --> 00:33:23,103 +此外 确保及时地这样做 + +618 +00:33:23,136 --> 00:33:27,474 +并且在成功响应之前 +没有进行大量处理 + +619 +00:33:27,508 --> 00:33:30,777 +以防止我们记录超时 +并重新发送通知 + +620 +00:33:30,811 --> 00:33:35,949 +有时 尤其是较长的中断 +下一次重试可能在数小时或数天之后 + +621 +00:33:35,983 --> 00:33:39,553 +或者对于较长时间的停机 +可能已无法重试 + +622 +00:33:39,586 --> 00:33:42,155 +从错过的通知中恢复的下一个选项 + +623 +00:33:42,189 --> 00:33:44,691 +是 Get Notification History 端点 + +624 +00:33:45,826 --> 00:33:48,729 +我们刚刚介绍了新的 +Get Notification History 端点 + +625 +00:33:48,762 --> 00:33:52,232 +它提供了我们发送给你的服务器的 +六个月的通知历史记录 + +626 +00:33:52,266 --> 00:33:54,601 +请参阅视频 +“What's new with in-app purchases” + +627 +00:33:54,635 --> 00:33:56,069 +了解这个端点 + +628 +00:33:56,103 --> 00:33:58,372 +以及我们介绍的其他很棒的功能 + +629 +00:33:58,405 --> 00:34:01,642 +在这里 我们将重点介绍 +使用此端点时的最佳实践 + +630 +00:34:01,675 --> 00:34:04,411 +以及它可以提供帮助的场景 + +631 +00:34:04,444 --> 00:34:05,913 +故障解决后 + +632 +00:34:05,946 --> 00:34:08,849 +请注意故障的开始和结束时间戳 + +633 +00:34:08,882 --> 00:34:11,318 +Get Notification History 端点 + +634 +00:34:11,351 --> 00:34:13,053 +允许在特定的时间范围内进行查询 + +635 +00:34:13,086 --> 00:34:15,455 +通过指定中断的开始和结束时间 + +636 +00:34:15,489 --> 00:34:18,325 +你可以只处理可能错过的通知 + +637 +00:34:18,358 --> 00:34:21,295 +而不需要翻阅整个历史记录 + +638 +00:34:21,328 --> 00:34:22,996 +这将有助于提高恢复速度 + +639 +00:34:23,030 --> 00:34:26,600 +并减少重新处理已记录通知的工作 + +640 +00:34:27,534 --> 00:34:29,803 +接下来 +Get Notification History 端点 + +641 +00:34:29,837 --> 00:34:32,306 +允许你根据通知的类型进行筛选 + +642 +00:34:32,339 --> 00:34:35,042 +如果你经历了长时间的中断 +并预计会收到大量通知 + +643 +00:34:35,075 --> 00:34:38,111 +请考虑按类型过滤 + +644 +00:34:38,145 --> 00:34:42,482 +并从可能产生直接影响的类型开始 +如 DID_RENEW 和 EXPIRED + +645 +00:34:42,516 --> 00:34:46,854 +这些将帮助你首先 +对最相关的案例采取行动 + +646 +00:34:46,887 --> 00:34:49,223 +在传递通知类型时有一个提示 + +647 +00:34:49,256 --> 00:34:51,758 +如果忽略 notificationSubtype 字段 + +648 +00:34:51,792 --> 00:34:55,596 +将只返回同样没有子类型的通知 + +649 +00:34:55,629 --> 00:34:59,766 +因此 对于 DID_RENEW notificationType +所显示的示例 + +650 +00:34:59,800 --> 00:35:01,935 +它不会返回子类型为 +BILLING_RECOVERY 的 + +651 +00:35:01,969 --> 00:35:03,370 +DID_RENEW 通知 + +652 +00:35:05,105 --> 00:35:07,908 +最后 Get Notification History 端点 + +653 +00:35:07,941 --> 00:35:11,712 +允许使用 originalTransactionId +过滤到特定用户 + +654 +00:35:11,745 --> 00:35:13,614 +回顾订阅生命周期 + +655 +00:35:13,647 --> 00:35:16,016 +我们努力确保通知 + +656 +00:35:16,049 --> 00:35:17,985 +覆盖用户使用的每一步 + +657 +00:35:18,018 --> 00:35:21,555 +因此 如果你发现自己的程序 +以意想不到的方式跳跃 + +658 +00:35:21,588 --> 00:35:24,825 +例如从更新订阅直接跳到过期 + +659 +00:35:24,858 --> 00:35:27,961 +这可能表明你错过了该用户的通知 + +660 +00:35:27,995 --> 00:35:30,364 +在顾客支持环境中 如果用户帐户 + +661 +00:35:30,397 --> 00:35:33,734 +处于与你的预期不同的状态 +这也很有用 + +662 +00:35:33,767 --> 00:35:37,771 +在这些情况下 你可以发送一个 +查询该用户的通知历史记录 + +663 +00:35:38,906 --> 00:35:42,176 +让我们回顾一下 +Get Notification History 端点的响应 + +664 +00:35:42,209 --> 00:35:44,878 +为简单起见 响应中仅显示某些值 + +665 +00:35:46,613 --> 00:35:50,484 +响应中恢复的值 +在 notificationHistory 数组中 + +666 +00:35:52,119 --> 00:35:55,589 +数组中的每个条目都表示一个通知 + +667 +00:35:56,823 --> 00:35:59,660 +签名有效载荷字段 + +668 +00:35:59,693 --> 00:36:00,894 +包含发送给你的确切通知 + +669 +00:36:02,162 --> 00:36:05,199 +其次 我们有第一个 +sendattemptresult 字段 + +670 +00:36:05,232 --> 00:36:08,001 +该字段包含基于服务器记录的 + +671 +00:36:08,035 --> 00:36:11,638 +初始通知尝试结果的几个值之一 + +672 +00:36:11,672 --> 00:36:14,741 +在成功的情况下 这个值将是 SUCCESS + +673 +00:36:14,775 --> 00:36:16,777 +然而 正如我们刚才所讨论的 + +674 +00:36:16,810 --> 00:36:19,780 +有时服务器无法收到通知 + +675 +00:36:19,813 --> 00:36:22,482 +这些消息旨在作为一般指南帮助你 + +676 +00:36:22,516 --> 00:36:25,819 +指出问题的方向 以简化解决过程 + +677 +00:36:25,853 --> 00:36:28,522 +例如 我们在这里看到 SSL_ISSUE + +678 +00:36:28,555 --> 00:36:31,024 +这表明服务器上的 SSL 证书 + +679 +00:36:31,058 --> 00:36:33,126 +或进程有问题 + +680 +00:36:33,160 --> 00:36:36,697 +除了看到通知未到达外 +此字段还提高了 + +681 +00:36:36,730 --> 00:36:39,233 +诊断服务器问题的可见性 + +682 +00:36:39,266 --> 00:36:42,803 +我们还在 +Get Test Notification Status 端点中 + +683 +00:36:42,836 --> 00:36:45,806 +提供了相同的字段 + +684 +00:36:45,839 --> 00:36:48,976 +这些可用于在引导流程 +或故障排除期间提供帮助 + +685 +00:36:49,009 --> 00:36:52,446 +或在追溯确定中断的 +根本原因期间提供帮助 + +686 +00:36:52,479 --> 00:36:55,949 +通知或许不能涵盖 +用户历史记录的所有情况 + +687 +00:36:55,983 --> 00:36:58,652 +你可能刚刚采用了通知 + +688 +00:36:58,685 --> 00:37:00,354 +并有历史记录未覆盖的现有用户 + +689 +00:37:00,387 --> 00:37:03,290 +你还可能希望在 +Get Notification history 端点中 + +690 +00:37:03,323 --> 00:37:06,894 +检查比通知保留周期更长的 +历史记录 + +691 +00:37:06,927 --> 00:37:09,763 +这就是 Get Transaction History +端点的作用所在 + +692 +00:37:09,796 --> 00:37:11,899 +正如我们之前在 Gabriel 的 +演讲中看到的那样 + +693 +00:37:11,932 --> 00:37:14,401 +此端点通过在你开始使用通知之前 +为你的顾客 + +694 +00:37:14,434 --> 00:37:18,605 +提供涵盖案例的历史记录 +来解决这些问题 + +695 +00:37:18,639 --> 00:37:21,909 +现在 我们来看看通知如何提供 + +696 +00:37:21,942 --> 00:37:25,179 +超越购买历史记录的洞察和机会 + +697 +00:37:25,212 --> 00:37:29,082 +Version 2 通知中新增的内容之一 +是子类型字段 + +698 +00:37:29,116 --> 00:37:32,386 +它向 notificationType 字段 +添加了额外的环境 + +699 +00:37:32,419 --> 00:37:35,389 +该字段用于在某些场景中 +提供更详细的信息 + +700 +00:37:35,422 --> 00:37:38,058 +比如 EXPIRED +或 DID_CHANGE_RENEWAL_STATUS + +701 +00:37:38,091 --> 00:37:41,929 +例如 使用 EXPIRED +你所采取的操作通常是相同的 + +702 +00:37:41,962 --> 00:37:45,332 +将订阅标记为⾮活跃状态 +并撤销对产品的访问权限 + +703 +00:37:45,365 --> 00:37:49,102 +但是 了解用户过期的原因通常很有用 + +704 +00:37:49,136 --> 00:37:51,772 +是由于账单问题 自愿选择 + +705 +00:37:51,805 --> 00:37:53,841 +还是接受不了的涨价 + +706 +00:37:53,874 --> 00:37:56,877 +另一个通知 +DID_CHANGE_RENEWAL_STATUS + +707 +00:37:56,910 --> 00:37:59,246 +是在使用通知时获得额外信息 + +708 +00:37:59,279 --> 00:38:01,815 +和机会的一个很好的例子 + +709 +00:38:01,849 --> 00:38:04,251 +从表面上看 它的优先级似乎不高 + +710 +00:38:04,284 --> 00:38:06,286 +不需要立即采取行动 + +711 +00:38:06,320 --> 00:38:09,022 +撤销产品访问权的重要通知 + +712 +00:38:09,056 --> 00:38:11,058 +是 EXPIRED 通知 + +713 +00:38:11,091 --> 00:38:14,127 +别被骗了 这里有很多机会 + +714 +00:38:14,161 --> 00:38:16,430 +第一 此通知是尝试 + +715 +00:38:16,463 --> 00:38:20,167 +在订阅到期之前 +赢回顾客的绝佳机会 + +716 +00:38:20,200 --> 00:38:22,536 +特别是由于停用自动续订 +可能发生在应用程序之外 + +717 +00:38:22,569 --> 00:38:25,038 +这可能是在到期日期前 + +718 +00:38:25,072 --> 00:38:29,443 +续订状态更改中 +被通知的唯一触发器 + +719 +00:38:29,476 --> 00:38:32,546 +此通知还提供对顾客行为的洞察 + +720 +00:38:32,579 --> 00:38:34,014 +此通知可用于确定订阅者 + +721 +00:38:34,047 --> 00:38:36,550 +在续订期间何时取消 + +722 +00:38:36,583 --> 00:38:37,885 +是续订的前一天吗 + +723 +00:38:37,918 --> 00:38:39,786 +新订阅者是否会在注册你的服务后 + +724 +00:38:39,820 --> 00:38:42,256 +立即停用自动续订呢 + +725 +00:38:42,289 --> 00:38:43,824 +此类信息对于了解取消的原因 + +726 +00:38:43,857 --> 00:38:47,427 +以及改进你的产品非常重要 + +727 +00:38:47,461 --> 00:38:50,130 +最后 在没有通知的情况下 + +728 +00:38:50,163 --> 00:38:52,900 +某些场景可能永远不会 +反映在用户的历史记录中 + +729 +00:38:52,933 --> 00:38:57,237 +例如 用户可以在 +订阅期到期之前停用 + +730 +00:38:57,271 --> 00:38:59,940 +但随后重新激活自动续订 + +731 +00:38:59,973 --> 00:39:02,242 +因为这一切都发生在订阅期内 + +732 +00:39:02,276 --> 00:39:05,345 +所以不会对订阅的长期状态 +产生影响 + +733 +00:39:05,379 --> 00:39:07,981 +这些决策对于了解你的顾客 +可能很重要 + +734 +00:39:08,015 --> 00:39:09,483 +通知提供了检测 + +735 +00:39:09,516 --> 00:39:13,654 +和记录这些类型场景的信息 + +736 +00:39:13,687 --> 00:39:16,924 +总体而言 通知通过 +在顾客使用的每一步提供信息 + +737 +00:39:16,957 --> 00:39:19,459 +来增强和创造了解顾客行为的机会 + +738 +00:39:19,493 --> 00:39:23,530 +覆盖比以往任何时候都多的场景 + +739 +00:39:23,564 --> 00:39:26,900 +总之 今天我们已经介绍了 +App Store Server API + +740 +00:39:26,934 --> 00:39:29,269 +和 App Store Server Notifications + +741 +00:39:29,303 --> 00:39:30,871 +这些功能可用于改进 + +742 +00:39:30,904 --> 00:39:33,207 +管理和跟踪购买的功能 + +743 +00:39:33,240 --> 00:39:37,177 +它们使用了更新的消息类型 +覆盖了比以往任何时候都多的案例 + +744 +00:39:37,211 --> 00:39:39,046 +这些系统可用于所有的客户 + +745 +00:39:39,079 --> 00:39:42,616 +并与 Original StoreKit +和 StoreKit 2 交叉兼容 + +746 +00:39:42,649 --> 00:39:46,086 +可以提高你 +监控订阅生命周期的能力 + +747 +00:39:46,119 --> 00:39:49,489 +最后 这些工具在沙盒和生产中 +都是可用的 + +748 +00:39:49,523 --> 00:39:51,458 +并且是任何系统的重要补充 + +749 +00:39:51,491 --> 00:39:54,795 +谢谢你加入我们 +祝你的 WWDC 之旅一切顺利 + diff --git "a/zho/2022 Session 10041 What\342\200\231s new in Wallet and Apple Pay.srt" "b/zho/2022 Session 10041 What\342\200\231s new in Wallet and Apple Pay.srt" new file mode 100644 index 0000000..f13ed1f --- /dev/null +++ "b/zho/2022 Session 10041 What\342\200\231s new in Wallet and Apple Pay.srt" @@ -0,0 +1,3285 @@ +1 +00:00:00,267 --> 00:00:03,337 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,337 --> 00:00:09,910 +♪ + +3 +00:00:09,910 --> 00:00:11,812 +Lais Minchillo: +嗨 我叫 Lais + +4 +00:00:11,812 --> 00:00:13,847 +David Silver:我是 David +我们将为您介绍 + +5 +00:00:13,847 --> 00:00:17,885 +今年 钱包 +和 Apple Pay 的新功能 + +6 +00:00:17,885 --> 00:00:20,521 +我们在 2014 年 +推出了 Apple Pay + +7 +00:00:20,521 --> 00:00:23,657 +为在实体店 在线商店和 App 内进行 + +8 +00:00:23,657 --> 00:00:27,928 +快速 安全 私密的支付 +设定了新的基准 + +9 +00:00:27,928 --> 00:00:31,231 +从那时起 我们在全球范围内 +推广了 Apple Pay + +10 +00:00:31,231 --> 00:00:35,202 +Apple Pay 现已在 +72 个国家和地区提供服务 + +11 +00:00:35,202 --> 00:00:38,739 +每天处理超过一百万笔交易 + +12 +00:00:38,739 --> 00:00:42,042 +今天 我们将为 +钱包和 Apple Pay + +13 +00:00:42,042 --> 00:00:43,710 +引入令人兴奋的新功能和 API + +14 +00:00:43,710 --> 00:00:45,812 +Lais 会为您具体介绍 + +15 +00:00:45,812 --> 00:00:47,181 +Lais :谢谢您 David + +16 +00:00:47,181 --> 00:00:50,284 +让我们来看看这场讲座的主要议程 + +17 +00:00:50,284 --> 00:00:53,921 +首先 我们将聊一聊快速更新 + +18 +00:00:53,921 --> 00:00:56,823 +我们增加了在单笔交易中 + +19 +00:00:56,823 --> 00:00:59,293 +向多个商户支付的支持 + +20 +00:00:59,293 --> 00:01:02,663 +我们还大大改善了 +包括订阅服务在内的 + +21 +00:01:02,663 --> 00:01:05,299 +自动支付的支持 + +22 +00:01:05,299 --> 00:01:07,467 +通过订单跟踪 您可以增强 + +23 +00:01:07,467 --> 00:01:10,737 +客户的购后体验 + +24 +00:01:10,737 --> 00:01:14,107 +最后 David 将聊一聊 +用钱包中的 ID + +25 +00:01:14,107 --> 00:01:17,311 +进行身份验证 + +26 +00:01:17,311 --> 00:01:20,147 +我们要先分享一些 +令人振奋的更新内容 + +27 +00:01:20,147 --> 00:01:23,250 +iPhone 上的 Tap to Pay +于今年早些时候发布 + +28 +00:01:23,250 --> 00:01:27,120 +并在美国 iOS 15.4 平台上发布 + +29 +00:01:27,120 --> 00:01:29,990 +iPhone 上的 Tap to Pay +提供了一种安全 私密 便捷的 + +30 +00:01:29,990 --> 00:01:33,126 +非接触式支付方式 + +31 +00:01:33,126 --> 00:01:35,696 +您可以轻松地将它 +集成到您的 App 中 + +32 +00:01:35,696 --> 00:01:39,366 +无缝且安全地接收非接触式支付 + +33 +00:01:39,366 --> 00:01:41,168 +这种支付方式 +包括 Apple Pay + +34 +00:01:41,168 --> 00:01:43,504 +非接触式信用卡和借记卡 + +35 +00:01:43,504 --> 00:01:45,639 +和其他数字钱包 + +36 +00:01:45,639 --> 00:01:46,907 +只需在 iPhone 上轻触一下 + +37 +00:01:46,907 --> 00:01:49,009 +交易就能完成 + +38 +00:01:49,009 --> 00:01:51,044 +无需额外的硬件 + +39 +00:01:51,044 --> 00:01:53,146 +或支付终端 + +40 +00:01:53,146 --> 00:01:55,582 +同时 在 macOS 13 中 + +41 +00:01:55,582 --> 00:01:58,886 +我们重新设计了 +Apple Pay 的体验 + +42 +00:01:58,886 --> 00:02:01,321 +去年 iOS 的付款表单重新设计 + +43 +00:02:01,321 --> 00:02:02,756 +取得了巨大的成功 + +44 +00:02:02,756 --> 00:02:06,627 +今年我们将为 macOS +引入类似的体验 + +45 +00:02:06,627 --> 00:02:09,029 +我们使用了 SwiftUI +来重新设计 + +46 +00:02:09,029 --> 00:02:11,365 +从而让我们 +为 macOS 与 iOS + +47 +00:02:11,365 --> 00:02:13,700 +同时引入了新功能 + +48 +00:02:13,700 --> 00:02:16,370 +我们今天介绍的 +所有 Apple Pay 功能 + +49 +00:02:16,370 --> 00:02:19,640 +在 Mac 上也支持 + +50 +00:02:19,640 --> 00:02:23,110 +我们将引入 +新的 SwiftUI API + +51 +00:02:23,110 --> 00:02:26,446 +在您的 +SwiftUI App 中集成 + +52 +00:02:26,446 --> 00:02:29,283 +“添加到 Apple 钱包” +或 “Apple Pay” 按钮会更容易 + +53 +00:02:29,283 --> 00:02:31,652 +这些新的 API 将大大减少 + +54 +00:02:31,652 --> 00:02:33,921 +您需要编写的代码量 + +55 +00:02:33,921 --> 00:02:36,056 +让我们看看如何添加按钮 + +56 +00:02:36,056 --> 00:02:39,193 +以提示用户添加航空通票 + +57 +00:02:39,193 --> 00:02:41,962 +首先 创建航空通票 + +58 +00:02:41,962 --> 00:02:45,365 +您应该处理好未成功加载的情况 + +59 +00:02:45,365 --> 00:02:47,901 +例如 航空通票数据不正确 + +60 +00:02:47,901 --> 00:02:51,338 +或未正确签名 就可能发生这种情况 + +61 +00:02:51,338 --> 00:02:56,109 +接下来 使用通票数组调用 +AddPassToWalletButton + +62 +00:02:56,109 --> 00:02:59,479 +在这个例子中 只有一个元素的数组 + +63 +00:02:59,479 --> 00:03:02,983 +但是同一个按钮上可以有多个通票 + +64 +00:03:02,983 --> 00:03:05,919 +结果作为 Bool 传入 +您可以根据 + +65 +00:03:05,919 --> 00:03:08,488 +用户是否添加了通票 +来保存 记录或触发 + +66 +00:03:08,488 --> 00:03:12,025 +App 中的其他操作 + +67 +00:03:12,025 --> 00:03:15,162 +在此示例中 我将它保存到状态变量 + +68 +00:03:15,162 --> 00:03:16,630 +这样就完成了 + +69 +00:03:16,630 --> 00:03:19,600 +您还可以在一组最小值中 + +70 +00:03:19,600 --> 00:03:21,935 +自定义按钮的大小和样式 + +71 +00:03:21,935 --> 00:03:28,642 +这是默认尺寸 +宽 250 高 50 + +72 +00:03:28,642 --> 00:03:30,911 +您也可以把按钮变宽 + +73 +00:03:32,513 --> 00:03:33,881 +或变高 + +74 +00:03:35,883 --> 00:03:37,284 +以上就是如何 +在 SwiftUI 中添加 + +75 +00:03:37,284 --> 00:03:40,854 +“添加到 Apple 钱包”按钮 + +76 +00:03:40,854 --> 00:03:45,192 +接下来 看看如何添加 +“使用 Apple Pay 支付”按钮 + +77 +00:03:45,192 --> 00:03:47,394 +首先 使用 PKPaymentRequest 类 + +78 +00:03:47,394 --> 00:03:49,863 +创建一个支付请求 + +79 +00:03:49,863 --> 00:03:52,900 +在上面设置您通常的配置 + +80 +00:03:52,900 --> 00:03:57,037 +然后创建一个 +authorizationChange 方法 + +81 +00:03:57,037 --> 00:03:59,006 +这两个部分完成后 + +82 +00:03:59,006 --> 00:04:01,742 +就可以添加代码来显示按钮 + +83 +00:04:01,742 --> 00:04:04,344 +添加对 +PayWithApplePayButton 的调用 + +84 +00:04:04,344 --> 00:04:07,915 +传入标签 paymentRequest 对象 + +85 +00:04:07,915 --> 00:04:10,784 +和 authorizationChange 方法 + +86 +00:04:10,784 --> 00:04:13,086 +如果要处理前设备 +不支持 Apple Pay 的情况 + +87 +00:04:13,086 --> 00:04:16,657 +通过当前设备 您可以传入回退视图 + +88 +00:04:16,657 --> 00:04:18,525 +就像“添加航空通票”按钮一样 + +89 +00:04:18,525 --> 00:04:23,463 +您同样可以自定义其大小和样式 + +90 +00:04:23,463 --> 00:04:26,700 +总共有 17 个不同的标签 + +91 +00:04:26,700 --> 00:04:28,635 +因此 您能够自定义支付按钮 + +92 +00:04:28,635 --> 00:04:31,371 +以与您的用例保持一致 + +93 +00:04:31,371 --> 00:04:38,645 +这些适用于 +iOS iPadOS macOS 和 watchOS + +94 +00:04:38,645 --> 00:04:42,950 +接下来 再来看看多商户支付 + +95 +00:04:42,950 --> 00:04:46,286 +在 iOS 16 中 +我们引入了在同一笔交易中 + +96 +00:04:46,286 --> 00:04:48,922 +为各个不同商户 + +97 +00:04:48,922 --> 00:04:50,724 +单独请求交易令牌的功能 + +98 +00:04:50,724 --> 00:04:53,894 +这种功能对于在线市场 + +99 +00:04:53,894 --> 00:04:56,597 +旅行预订和票务服务等很有帮助 + +100 +00:04:56,597 --> 00:04:59,199 +我们来详细看看这个例子 + +101 +00:04:59,199 --> 00:05:01,935 +想象一下 +Allison 正在计划一次旅行 + +102 +00:05:01,935 --> 00:05:04,505 +她访问一家旅行社网站 + +103 +00:05:04,505 --> 00:05:06,073 +网站方便地为她提供了 + +104 +00:05:06,073 --> 00:05:08,141 +客户需要预订的一切 + +105 +00:05:08,141 --> 00:05:12,412 +机票 酒店住宿和汽车租赁 + +106 +00:05:12,412 --> 00:05:16,049 +Allison 总共 +只需要支付 500 美元 + +107 +00:05:16,049 --> 00:05:18,085 +Allison 向 +旅行社网站提供了 + +108 +00:05:18,085 --> 00:05:20,454 +她完整的信用卡信息 + +109 +00:05:20,454 --> 00:05:23,257 +现在 您可能会认为旅行社 + +110 +00:05:23,257 --> 00:05:26,293 +将从 Allison 的信用卡 +扣除 500 美元 + +111 +00:05:26,293 --> 00:05:29,196 +然后支付给其他相关公司 + +112 +00:05:29,196 --> 00:05:31,865 +但通常情况下 旅行社只需 + +113 +00:05:31,865 --> 00:05:34,434 +简单地将信用卡信息传递给每家公司 + +114 +00:05:34,434 --> 00:05:38,605 +让各家公司进行各自的收费 + +115 +00:05:38,605 --> 00:05:40,741 +这行么做得通 但是 + +116 +00:05:40,741 --> 00:05:42,676 +把她的信用卡信息泄露出去 + +117 +00:05:42,676 --> 00:05:46,413 +对 Allison 的隐私 +和安全不利 + +118 +00:05:46,413 --> 00:05:49,750 +现在 有了新的多商户支付 API + +119 +00:05:49,750 --> 00:05:52,019 +就可以为交易中涉及的每个商户 + +120 +00:05:52,019 --> 00:05:55,355 +请求支付令牌 + +121 +00:05:55,355 --> 00:05:57,157 +有了支付令牌 + +122 +00:05:57,157 --> 00:06:00,327 +各家公司可以 +分别向 Allison 收取 + +123 +00:06:00,327 --> 00:06:03,263 +她授权的相关金额 + +124 +00:06:03,263 --> 00:06:05,933 +Allison 现在可以预订 +并支付旅行费用 + +125 +00:06:05,933 --> 00:06:09,269 +同时也能享受 +Apple Pay 提供的 + +126 +00:06:09,269 --> 00:06:12,005 +隐私和安全优势 + +127 +00:06:12,005 --> 00:06:14,541 +付款表已经更新 能够向客户显示 + +128 +00:06:14,541 --> 00:06:18,345 +交易中涉及的子商户明细 + +129 +00:06:18,345 --> 00:06:20,314 +客户可以点击“总金额” + +130 +00:06:20,314 --> 00:06:22,549 +前往到付款摘要 + +131 +00:06:22,549 --> 00:06:25,052 +摘要中 客户可以看到涉及到交易的 + +132 +00:06:25,052 --> 00:06:27,521 +所有商户的分类 + +133 +00:06:27,521 --> 00:06:30,591 +以及每个商户授权的金额 + +134 +00:06:30,591 --> 00:06:32,392 +现在 让我们看看如何在应用中 + +135 +00:06:32,392 --> 00:06:35,529 +添加多商户支付 + +136 +00:06:35,529 --> 00:06:37,764 +首先 使用 PKPaymentRequest 类 + +137 +00:06:37,764 --> 00:06:40,234 +创建一个支付请求 + +138 +00:06:40,234 --> 00:06:43,203 +在上面设置您通常的配置 + +139 +00:06:43,203 --> 00:06:48,342 +然后 为您的付款 +添加汇总项目 包括总额 + +140 +00:06:48,342 --> 00:06:50,978 +接下来 使用新的 +PKPaymentTokenContext 类 + +141 +00:06:50,978 --> 00:06:54,414 +为交易中涉及的每个额外商户 + +142 +00:06:54,414 --> 00:06:58,385 +创建一个支付令牌 context + +143 +00:06:58,385 --> 00:07:01,121 +提供每个商户的详细信息 + +144 +00:07:01,121 --> 00:07:04,424 +以及为每个商户授权的金额 + +145 +00:07:04,424 --> 00:07:09,463 +最后 在支付请求上 +设置支付令牌 contexts + +146 +00:07:09,463 --> 00:07:11,632 +请记住 所有 + +147 +00:07:11,632 --> 00:07:14,168 +支付令牌 +context 的金额总和 + +148 +00:07:14,168 --> 00:07:17,070 +必须小于或等于 + +149 +00:07:17,070 --> 00:07:19,506 +支付请求本身的总金额 + +150 +00:07:19,506 --> 00:07:23,043 +此外 在 App 中 +为商家请求支付令牌时 + +151 +00:07:23,043 --> 00:07:26,013 +您应该始终为同一个商户 + +152 +00:07:26,013 --> 00:07:28,882 +使用相同的外部标识符 + +153 +00:07:28,882 --> 00:07:30,918 +要在网页上采用 + +154 +00:07:30,918 --> 00:07:32,553 +多商户支付的 Apple Pay + +155 +00:07:32,553 --> 00:07:36,657 +请查看 Apple Pay JS API 文档 + +156 +00:07:36,657 --> 00:07:39,159 +接下来看一看 + +157 +00:07:39,159 --> 00:07:41,962 +我们对自动支付的改进 + +158 +00:07:41,962 --> 00:07:45,732 +在 iOS 16 中 我们引入了 + +159 +00:07:45,732 --> 00:07:48,702 +用户可以通过钱包应用查看和管理 + +160 +00:07:48,702 --> 00:07:50,671 +他们设置的自动向商家支付的功能 + +161 +00:07:50,671 --> 00:07:51,738 +在这个版本中 + +162 +00:07:51,738 --> 00:07:54,641 +我们支持两种类型的自动支付 + +163 +00:07:54,641 --> 00:07:57,044 +定期自动扣除 其中包括 + +164 +00:07:57,044 --> 00:08:00,547 +订阅 分期付款或定期计费 + +165 +00:08:00,547 --> 00:08:02,583 +和自动充值支付 + +166 +00:08:02,583 --> 00:08:05,419 +例如商店卡余额充值 + +167 +00:08:05,419 --> 00:08:08,222 +我们将引入新的 API +以让您在提出支付请求时 + +168 +00:08:08,222 --> 00:08:12,125 +向客户请求设置自动支付 + +169 +00:08:12,125 --> 00:08:15,562 +我们还推出了 +Apple Pay 商户令牌 + +170 +00:08:15,562 --> 00:08:19,533 +这是一种与客户的 Apple ID 绑定的 +新型支付令牌 + +171 +00:08:19,533 --> 00:08:22,169 +可以帮助您在现有基础上 + +172 +00:08:22,169 --> 00:08:24,438 +更可靠地向客户收费 + +173 +00:08:24,438 --> 00:08:27,040 +我们来详细看一下 +Apple Pay 商户令牌 + +174 +00:08:27,040 --> 00:08:29,543 +看看它们是如何发挥作用的 + +175 +00:08:29,543 --> 00:08:32,446 +想象一下 Julie 正在用 +iPhone 上的 Apple Pay + +176 +00:08:32,446 --> 00:08:34,982 +支付读书俱乐部的会员费 + +177 +00:08:34,982 --> 00:08:37,351 +读书俱乐部提出付款请求 + +178 +00:08:37,351 --> 00:08:39,553 +当 Julie 授权付款时 + +179 +00:08:39,553 --> 00:08:41,922 +读书俱乐部收到付款令牌 + +180 +00:08:41,922 --> 00:08:44,525 +每个月 俱乐部都可以用付款令牌 + +181 +00:08:44,525 --> 00:08:46,527 +向 Julie 收取会员资格费用 + +182 +00:08:46,527 --> 00:08:49,796 +此付款令牌 +链接到 Julie 的设备 + +183 +00:08:49,796 --> 00:08:51,865 +用于授权支付 + +184 +00:08:51,865 --> 00:08:55,235 +但如果 Julie 买了一台 +新的 iPhone 会怎样? + +185 +00:08:55,235 --> 00:08:57,738 +有了新的自动支付功能 + +186 +00:08:57,738 --> 00:08:59,640 +如果 Julie 的支付网络支持 + +187 +00:08:59,640 --> 00:09:01,642 +俱乐部会将收到 + +188 +00:09:01,642 --> 00:09:04,545 +Apple Pay 商户令牌 + +189 +00:09:04,545 --> 00:09:07,848 +此支付令牌与 Julie 的 +Apple ID 绑定 + +190 +00:09:07,848 --> 00:09:09,650 +而不是与她的 iPhone 绑定 + +191 +00:09:09,650 --> 00:09:14,221 +这样就能更好地保证正在进行的授权 + +192 +00:09:14,221 --> 00:09:16,823 +也就是说 如果 +Julie 升级了 iPhone + +193 +00:09:16,823 --> 00:09:18,759 +或重置了她当前的手机 + +194 +00:09:18,759 --> 00:09:21,595 +读书俱乐部依旧能可靠地 + +195 +00:09:21,595 --> 00:09:23,997 +向 Julie 收取 +每月的会员资格费用 + +196 +00:09:23,997 --> 00:09:26,667 +如果您接受 Apple Pay +进行这些类型的付款 + +197 +00:09:26,667 --> 00:09:30,003 +采用自动支付是一个好主意 +能够确保 + +198 +00:09:30,003 --> 00:09:32,973 +您可以持续可靠地向客户收费 + +199 +00:09:32,973 --> 00:09:36,510 +且能避免服务中的任何中断 + +200 +00:09:36,510 --> 00:09:38,979 +我们在这个版本中支持的 + +201 +00:09:38,979 --> 00:09:41,982 +第一种自动支付方式是定期自动扣除 + +202 +00:09:41,982 --> 00:09:45,219 +定期自动扣除的金额 +可以是固定或可变的 + +203 +00:09:45,219 --> 00:09:47,354 +按定期计划收取 + +204 +00:09:47,354 --> 00:09:51,158 +如每周 每月或每年收费 + +205 +00:09:51,158 --> 00:09:53,560 +这些付款可以在特定日期结束 + +206 +00:09:53,560 --> 00:09:57,064 +也可以一直持续到取消 + +207 +00:09:57,064 --> 00:10:01,568 +我们也支持试用期或优惠期 + +208 +00:10:01,568 --> 00:10:03,971 +定期自动扣除可以完美用于 + +209 +00:10:03,971 --> 00:10:06,273 +订阅 分期付款计划 + +210 +00:10:06,273 --> 00:10:08,509 +和定期计费 + +211 +00:10:08,509 --> 00:10:11,011 +让我们看看如何在 App 中 + +212 +00:10:11,011 --> 00:10:14,548 +用自动支付设置定期自动扣除 + +213 +00:10:14,548 --> 00:10:17,184 +首先使用 +PKRecurringPaymentSummaryItem 类 + +214 +00:10:17,184 --> 00:10:19,219 +指定自动扣除的金额 + +215 +00:10:19,219 --> 00:10:22,656 +和持续时间 + +216 +00:10:22,656 --> 00:10:24,157 +对于定期自动扣除 + +217 +00:10:24,157 --> 00:10:27,127 +您可以同时指定常规计费周期 + +218 +00:10:27,127 --> 00:10:30,998 +也可以指定优惠期或试用期 + +219 +00:10:30,998 --> 00:10:34,401 +您可以使用 +startDate 和 endDate 属性 + +220 +00:10:34,401 --> 00:10:36,970 +来指示试用期何时结束 + +221 +00:10:36,970 --> 00:10:40,474 +常规计费周期何时开始 + +222 +00:10:40,474 --> 00:10:43,710 +接下来 使用新的 +PKRecurringPaymentRequest 类 + +223 +00:10:43,710 --> 00:10:47,514 +创建一个定期自动扣除请求 + +224 +00:10:47,514 --> 00:10:49,816 +提供付款说明 + +225 +00:10:49,816 --> 00:10:51,785 +正常计费周期 + +226 +00:10:51,785 --> 00:10:54,788 +以及前往网页的管理 URL + +227 +00:10:54,788 --> 00:10:57,891 +客户可以在这个页面上更新或删除 + +228 +00:10:57,891 --> 00:10:59,927 +定期自动扣除服务 + +229 +00:10:59,927 --> 00:11:03,430 +您还可以选择提供试用计费期 + +230 +00:11:03,430 --> 00:11:05,766 +以及计费协议文本 + +231 +00:11:05,766 --> 00:11:09,303 +以帮助向客户解释付款条款 + +232 +00:11:09,303 --> 00:11:13,874 +最后 您可以选择 +提供令牌通知 URL + +233 +00:11:13,874 --> 00:11:16,910 +如果发布了令牌 +您的服务器可以接收 + +234 +00:11:16,910 --> 00:11:19,780 +关于 Apple Pay +商家支付令牌的 + +235 +00:11:19,780 --> 00:11:21,415 +生命周期 + +236 +00:11:21,415 --> 00:11:23,951 +例如 如果卡颁发者或用户 + +237 +00:11:23,951 --> 00:11:27,688 +删除令牌 您可以收到通知 + +238 +00:11:27,688 --> 00:11:30,057 +有关商户令牌生命周期通知的 + +239 +00:11:30,057 --> 00:11:32,025 +更多信息 + +240 +00:11:32,025 --> 00:11:36,930 +请参阅 Apple Pay 商户令牌 +管理 API 文档 + +241 +00:11:36,930 --> 00:11:40,300 +最后 在 paymentRequest 对象上 + +242 +00:11:40,300 --> 00:11:42,336 +设置定期自动扣除请求 + +243 +00:11:42,336 --> 00:11:45,606 +关于汇总项目 简要说明一下 +您的定期自动扣除 + +244 +00:11:45,606 --> 00:11:48,575 +不会自动添加到付款请求的 + +245 +00:11:48,575 --> 00:11:49,776 +汇总项目上 + +246 +00:11:49,776 --> 00:11:54,081 +因此 请务必将定期自动扣除的项 +添加到汇总项数组中 + +247 +00:11:54,081 --> 00:11:56,016 +支付请求的总额 + +248 +00:11:56,016 --> 00:11:57,451 +应该是向客户收取的 + +249 +00:11:57,451 --> 00:11:59,353 +第一笔金额 + +250 +00:11:59,353 --> 00:12:02,089 +所以在这个例子中 总金额设置为 + +251 +00:12:02,089 --> 00:12:03,957 +显示试用期的金额 + +252 +00:12:03,957 --> 00:12:07,794 +因为这是向客户收取的第一笔金额 + +253 +00:12:07,794 --> 00:12:09,530 +付款表单将向客户显示 + +254 +00:12:09,530 --> 00:12:11,965 +定期自动扣除的详细信息 + +255 +00:12:11,965 --> 00:12:14,301 +他们可以点击“账单详情”部分 + +256 +00:12:14,301 --> 00:12:17,137 +进一步阅读 + +257 +00:12:17,137 --> 00:12:20,307 +接下来是我们在这个版本中支持的 + +258 +00:12:20,307 --> 00:12:22,075 +第二种自动支付方式 + +259 +00:12:22,075 --> 00:12:24,278 +自动充值支付 + +260 +00:12:24,278 --> 00:12:25,646 +通过这种付款方式 + +261 +00:12:25,646 --> 00:12:27,581 +每当余额低于 + +262 +00:12:27,581 --> 00:12:30,584 +一定阈值金额时 + +263 +00:12:30,584 --> 00:12:32,853 +就会自动为余额充值 + +264 +00:12:32,853 --> 00:12:35,622 +自动充值支付非常适合 + +265 +00:12:35,622 --> 00:12:39,459 +商店卡充值和预付余额之类的付款 + +266 +00:12:39,459 --> 00:12:42,596 +要请求设置自动充值支付 + +267 +00:12:42,596 --> 00:12:46,033 +首先使用新的 +PKAutomaticReloadPaymentSummaryItem 类 + +268 +00:12:46,033 --> 00:12:51,238 +指定充值和阈值金额 + +269 +00:12:51,238 --> 00:12:55,209 +接下来 使用新的 +PKAutomaticReloadPaymentRequest 类 + +270 +00:12:55,209 --> 00:12:59,580 +创建一个自动充值支付请求 + +271 +00:12:59,580 --> 00:13:02,916 +传入支付描述 账单 + +272 +00:13:02,916 --> 00:13:04,518 +和管理 URL + +273 +00:13:04,518 --> 00:13:06,820 +和前文定期自动扣除部分一样 + +274 +00:13:06,820 --> 00:13:10,157 +您还可以选择提供计费协议文本 + +275 +00:13:10,157 --> 00:13:13,660 +和一个令牌通知 URL + +276 +00:13:13,660 --> 00:13:16,830 +最后 在支付请求对象上 + +277 +00:13:16,830 --> 00:13:19,066 +设置自动充值支付请求 + +278 +00:13:19,066 --> 00:13:22,436 +同样 请确保在汇总项目中包含 + +279 +00:13:22,436 --> 00:13:24,137 +自动充值支付项 + +280 +00:13:24,137 --> 00:13:27,941 +并适当设置支付请求的总额 + +281 +00:13:27,941 --> 00:13:31,044 +关于在网络页面上 +使用 Apple Pay 自动支付 + +282 +00:13:31,044 --> 00:13:35,249 +查看 Apple Pay JS API 文档 + +283 +00:13:35,249 --> 00:13:37,551 +这是您客户的付款表单 + +284 +00:13:37,551 --> 00:13:41,855 +自动充值支付是这样显示的 + +285 +00:13:41,855 --> 00:13:44,224 +最后 当您在应用中采用自动支付时 + +286 +00:13:44,224 --> 00:13:47,194 +您需要记住以下几点 + +287 +00:13:47,194 --> 00:13:50,230 +以便为客户提供最佳体验 + +288 +00:13:50,230 --> 00:13:52,165 +记住要包括自动付款的汇总项目 + +289 +00:13:52,165 --> 00:13:56,470 +因为这些项目不会自动添加 + +290 +00:13:56,470 --> 00:13:59,039 +付款请求的总金额应该是 + +291 +00:13:59,039 --> 00:14:02,342 +将向客户收取的第一笔金额 + +292 +00:14:02,342 --> 00:14:05,179 +计费协议文本应当简短 + +293 +00:14:05,179 --> 00:14:09,516 +付款单将仅显示前 500 个字符 + +294 +00:14:09,516 --> 00:14:12,452 +计费协议文本不应当取代 + +295 +00:14:12,452 --> 00:14:14,988 +您的正常账单和法律协议 + +296 +00:14:14,988 --> 00:14:16,557 +是否遵守当地的定期自动扣除法规 + +297 +00:14:16,557 --> 00:14:19,226 +取决于您的主张 + +298 +00:14:19,226 --> 00:14:22,129 +如果您要向客户展示法律协议 + +299 +00:14:22,129 --> 00:14:24,231 +请先向客户展示法律协议 + +300 +00:14:24,231 --> 00:14:27,167 +再展示付款单 + +301 +00:14:27,167 --> 00:14:30,070 +在单笔交易中 + +302 +00:14:30,070 --> 00:14:32,439 +您只能请求一种类型的自动付款 + +303 +00:14:32,439 --> 00:14:34,975 +此外 自动支付不能用于 + +304 +00:14:34,975 --> 00:14:37,811 +多商户支付 + +305 +00:14:37,811 --> 00:14:40,881 +最后 如果您希望接收 + +306 +00:14:40,881 --> 00:14:44,251 +Apple Pay 商户令牌的 +生命周期通知 + +307 +00:14:44,251 --> 00:14:47,387 +请务必提供令牌通知 URL + +308 +00:14:47,387 --> 00:14:50,924 +并在服务器上采用 + +309 +00:14:50,924 --> 00:14:52,392 +Apple Pay 商户令牌 +管理 API + +310 +00:14:52,392 --> 00:14:54,328 +我们认为您 +会喜欢这些新的 API + +311 +00:14:54,328 --> 00:14:57,197 +也会享受 Apple Pay +商户令牌带来的好处 + +312 +00:14:57,197 --> 00:14:58,999 +以上是我们的一些合作伙伴 + +313 +00:14:58,999 --> 00:15:03,537 +他们也将要支持自动支付 + +314 +00:15:03,537 --> 00:15:06,106 +Apple Pay 商户令牌 +将得到 + +315 +00:15:06,106 --> 00:15:10,010 +American Express Discover +Mastercard 和 Visa 的支持 + +316 +00:15:10,010 --> 00:15:14,314 +未来还将支持其他支付网络 + +317 +00:15:14,314 --> 00:15:16,783 +我们也将引入订单跟踪 + +318 +00:15:16,783 --> 00:15:20,254 +以提升购后体验 + +319 +00:15:20,254 --> 00:15:24,458 +iOS 16 新增了订单跟踪功能 + +320 +00:15:24,458 --> 00:15:26,894 +以便用户跟踪与商家下的订单 + +321 +00:15:26,894 --> 00:15:29,296 +现在 钱包能提供直观的概览 + +322 +00:15:29,296 --> 00:15:32,599 +展示正在进行中的订单 +最近完成的订单 + +323 +00:15:32,599 --> 00:15:34,301 +和历史订单 + +324 +00:15:34,301 --> 00:15:38,105 +现在展示的是 +正在进行中的烘焙食品订单 + +325 +00:15:38,105 --> 00:15:42,242 +这个订单仍在处理中 +稍后再谈这个话题 + +326 +00:15:42,242 --> 00:15:46,013 +现在 我想在 +Pet Avenue 给我的猫 + +327 +00:15:46,013 --> 00:15:47,581 +买一些玩具和配饰 + +328 +00:15:47,581 --> 00:15:50,284 +我选择使用 +Apple Pay 结账 + +329 +00:15:50,284 --> 00:15:52,486 +在我授权付款后不久 + +330 +00:15:52,486 --> 00:15:55,923 +我收到一条通知 +在钱包中跟踪我的订单 + +331 +00:15:55,923 --> 00:15:58,125 +点击该通知 + +332 +00:15:58,125 --> 00:16:00,394 +可以看到订单的详细信息 + +333 +00:16:00,394 --> 00:16:02,629 +我可以检查当前状态 + +334 +00:16:02,629 --> 00:16:04,264 +可以看到订单状态 + +335 +00:16:04,264 --> 00:16:06,900 +包括物流运输和跟踪信息 + +336 +00:16:06,900 --> 00:16:09,803 +以及我订购的订单项列表 + +337 +00:16:09,803 --> 00:16:13,974 +接下来 我有多种联系方式 +可以联系 Pet Avenue + +338 +00:16:13,974 --> 00:16:18,679 +检查付款信息 +然后返回 Pet Avenue App + +339 +00:16:18,679 --> 00:16:21,114 +好了 +想象一下 Pet Avenue + +340 +00:16:21,114 --> 00:16:25,385 +处理新订单的速度非常快 +他们刚刚运送了我的物品 + +341 +00:16:25,385 --> 00:16:27,754 +Pet Avenue 发货后 + +342 +00:16:27,754 --> 00:16:30,390 +他们已更新了可用信息 + +343 +00:16:30,390 --> 00:16:33,193 +我可以看到状态更改为“在路上” + +344 +00:16:33,193 --> 00:16:36,363 +预计到货日期为 6 月 10 日 + +345 +00:16:36,363 --> 00:16:38,398 +页面还包含一条自定义消息 + +346 +00:16:38,398 --> 00:16:41,668 +以及货件的跟踪信息 + +347 +00:16:41,668 --> 00:16:43,570 +哦 还记得我的烘焙食品吗? + +348 +00:16:43,570 --> 00:16:46,273 +我刚收到通知 他们可以取货了 + +349 +00:16:46,273 --> 00:16:48,008 +让我们来看一下 + +350 +00:16:48,008 --> 00:16:50,611 +我订购了自提的烘焙食品 + +351 +00:16:50,611 --> 00:16:52,913 +我已经可以取货了 太好了 + +352 +00:16:52,913 --> 00:16:55,682 +Bake My Breath Away +提供了我的取货窗口 + +353 +00:16:55,682 --> 00:16:57,184 +取货说明 + +354 +00:16:57,184 --> 00:16:59,853 +和取货时需出示的条形码 + +355 +00:16:59,853 --> 00:17:03,524 +我们已经知道了 +订单跟踪与 Apple Pay 无缝衔接 + +356 +00:17:03,524 --> 00:17:06,293 +让我们看看如何将订单跟踪 + +357 +00:17:06,293 --> 00:17:08,962 +集成到客户体验中 + +358 +00:17:08,962 --> 00:17:10,998 +要开始订单跟踪 + +359 +00:17:10,998 --> 00:17:13,734 +首先 您必须在开发者帐户中 + +360 +00:17:13,734 --> 00:17:15,769 +创建一个 +Order Type ID + +361 +00:17:15,769 --> 00:17:19,673 +Order Type ID +将您的组织标识为 + +362 +00:17:19,673 --> 00:17:22,142 +提供订单信息的实体 + +363 +00:17:22,142 --> 00:17:24,912 +您可以注册多个 +Order Type ID + +364 +00:17:24,912 --> 00:17:26,980 +例如 代表多个商家 + +365 +00:17:26,980 --> 00:17:29,883 +提供订单信息 + +366 +00:17:29,883 --> 00:17:32,986 +然后 创建一个 +Order Type ID 证书 + +367 +00:17:32,986 --> 00:17:35,689 +您将使用证书来构建 + +368 +00:17:35,689 --> 00:17:38,158 +订单包和更新订单 + +369 +00:17:38,158 --> 00:17:41,228 +订单以订单包的形式分发 + +370 +00:17:41,228 --> 00:17:44,665 +订单包包括订单的 + +371 +00:17:44,665 --> 00:17:46,033 +所有元数据和信息 + +372 +00:17:46,033 --> 00:17:48,702 +订单包可以代表广泛的场景 + +373 +00:17:48,702 --> 00:17:53,106 +包括运输 取货和多重履行订单 + +374 +00:17:53,106 --> 00:17:55,776 +订单包也包括图像 + +375 +00:17:55,776 --> 00:17:58,679 +比如您的徽标和行式项目图片 + +376 +00:17:58,679 --> 00:18:00,447 +您还可以添加本地化 + +377 +00:18:00,447 --> 00:18:03,951 +以支持不同范围的客户 + +378 +00:18:03,951 --> 00:18:06,787 +每个订单包都必须经过加密签名 + +379 +00:18:06,787 --> 00:18:08,956 +以验证订单包来源 + +380 +00:18:08,956 --> 00:18:10,691 +一切就绪后 + +381 +00:18:10,691 --> 00:18:14,094 +订单包被压缩以进行分发 + +382 +00:18:14,094 --> 00:18:15,696 +请查看这个讲座附带的 + +383 +00:18:15,696 --> 00:18:17,297 +示例订单包 + +384 +00:18:17,297 --> 00:18:19,399 +有关订单包的更多信息 + +385 +00:18:19,399 --> 00:18:22,236 +请参阅开发人员文档 + +386 +00:18:22,236 --> 00:18:25,839 +将订单添加到 钱包 +可与 Apple Pay 无缝协作 + +387 +00:18:25,839 --> 00:18:28,041 +当您的客户授权付款时 + +388 +00:18:28,041 --> 00:18:31,445 +您的应用或网页将接收到支付信息 + +389 +00:18:31,445 --> 00:18:34,848 +然后将支付信息 +发送到服务器进行处理 + +390 +00:18:34,848 --> 00:18:37,551 +如果支付信息处理成功 + +391 +00:18:37,551 --> 00:18:41,221 +您的服务器会创建 +一个订单和一些元数据 + +392 +00:18:41,221 --> 00:18:43,790 +然后 服务器返回订单细节 + +393 +00:18:43,790 --> 00:18:47,528 +到 App 或网页 以显示结果 + +394 +00:18:47,528 --> 00:18:50,998 +订单详细信息使设备能够以异步方式 + +395 +00:18:50,998 --> 00:18:53,333 +从服务器请求订单 + +396 +00:18:53,333 --> 00:18:57,371 +然后 服务器将订单包返回给设备 + +397 +00:18:57,371 --> 00:18:59,373 +当服务器创建订单时 + +398 +00:18:59,373 --> 00:19:01,408 +分配一个 Order ID + +399 +00:19:01,408 --> 00:19:04,478 +这个 ID 在 Order Type ID 命名空间中 +不可与其他重复 + +400 +00:19:04,478 --> 00:19:08,582 +您的服务器还必须生成 +安全的身份验证令牌 + +401 +00:19:08,582 --> 00:19:12,653 +身份验证令牌是共享密钥 +是订单详细信息的一部分 + +402 +00:19:12,653 --> 00:19:15,455 +当设备请求订单时 + +403 +00:19:15,455 --> 00:19:17,858 +将使用令牌来验证这个设备 + +404 +00:19:17,858 --> 00:19:19,293 +让我们来看一个 + +405 +00:19:19,293 --> 00:19:22,129 +返回支付授权结果的例子 + +406 +00:19:22,129 --> 00:19:24,331 +当您的客户授权付款时 + +407 +00:19:24,331 --> 00:19:27,568 +App 将付款信息发送到服务器 + +408 +00:19:27,568 --> 00:19:29,937 +并要求服务器创建一个订单 + +409 +00:19:29,937 --> 00:19:32,940 +请检查服务器结果是否表示成功 + +410 +00:19:32,940 --> 00:19:36,043 +并处理服务器返回的任何错误 + +411 +00:19:36,043 --> 00:19:39,279 +如果服务器结果确实表明成功 + +412 +00:19:39,279 --> 00:19:41,181 +则使用适当的授权结果 + +413 +00:19:41,181 --> 00:19:44,051 +完成付款 + +414 +00:19:44,051 --> 00:19:46,253 +要返回包含订单详细信息的 + +415 +00:19:46,253 --> 00:19:47,988 +支付授权结果 + +416 +00:19:47,988 --> 00:19:51,625 +首先 从服务器结果中 +提取订单详细信息 + +417 +00:19:51,625 --> 00:19:55,829 +然后创建一个 +PKPaymentOrderDetails 对象 + +418 +00:19:55,829 --> 00:19:59,266 +这个对象带有 +Order Type ID 或 Order ID + +419 +00:19:59,266 --> 00:20:03,504 +到服务器的 URL +和身份验证令牌 + +420 +00:20:03,504 --> 00:20:06,740 +将 PKPaymentOrderDetails 对象 +分配到 + +421 +00:20:06,740 --> 00:20:12,212 +PKPaymentAuthorizationResult 上的 +新 orderDetails 属性 + +422 +00:20:12,212 --> 00:20:13,614 +这样就完成了 + +423 +00:20:13,614 --> 00:20:17,217 +您也可以在网页上使用 +订单详细信息完成付款 + +424 +00:20:17,217 --> 00:20:22,189 +和刚才一样 +从服务器结果中提取订单详细信息 + +425 +00:20:22,189 --> 00:20:24,458 +然后在完成支付的数据中 + +426 +00:20:24,458 --> 00:20:27,794 +列入订单细节 + +427 +00:20:27,794 --> 00:20:29,530 +要更新订单 + +428 +00:20:29,530 --> 00:20:31,965 +创建一个指示支持 + +429 +00:20:31,965 --> 00:20:34,201 +自动更新的订单包 + +430 +00:20:34,201 --> 00:20:36,069 +添加订单后 + +431 +00:20:36,069 --> 00:20:38,872 +设备将注册订单的更新 + +432 +00:20:38,872 --> 00:20:42,976 +您的服务器必须存储有关注册的信息 + +433 +00:20:42,976 --> 00:20:45,979 +以后 当服务器更新订单时 + +434 +00:20:45,979 --> 00:20:49,216 +使用注册信息通知 + +435 +00:20:49,216 --> 00:20:52,519 +已注册更新订单的设备 + +436 +00:20:52,519 --> 00:20:55,155 +当设备收到推送通知时 + +437 +00:20:55,155 --> 00:20:58,759 +设备将再次向您的服务器请求订单 + +438 +00:20:58,759 --> 00:21:01,428 +然后 服务器将更新后的订单包 + +439 +00:21:01,428 --> 00:21:03,630 +返回给设备 + +440 +00:21:03,630 --> 00:21:05,232 +只有您和您的客户 + +441 +00:21:05,232 --> 00:21:07,267 +才可知道客户订购了什么 + +442 +00:21:07,267 --> 00:21:10,270 +我们在设计订单跟踪时 +考虑到了客户隐私 + +443 +00:21:10,270 --> 00:21:12,973 +订单信息直接在 + +444 +00:21:12,973 --> 00:21:15,509 +设备和服务器之间交换 + +445 +00:21:15,509 --> 00:21:18,078 +订单通过 iCloud 同步时 + +446 +00:21:18,078 --> 00:21:20,247 +内容是端到端加密的 + +447 +00:21:20,247 --> 00:21:21,915 +请遵循这些做法 + +448 +00:21:21,915 --> 00:21:24,718 +以为客户提供最好的体验 + +449 +00:21:24,718 --> 00:21:27,721 +将您的应用与您提供的订单关联起来 + +450 +00:21:27,721 --> 00:21:30,991 +如果您的应用提供通知并已安装应用 + +451 +00:21:30,991 --> 00:21:34,027 +您可以禁用订单跟踪通知 + +452 +00:21:34,027 --> 00:21:37,698 +这么做可以防止重复通知 + +453 +00:21:37,698 --> 00:21:40,901 +利用您对客户偏好的了解 + +454 +00:21:40,901 --> 00:21:44,204 +只提供相关的本地化内容 + +455 +00:21:44,204 --> 00:21:46,874 +请注意订单包的大小 + +456 +00:21:46,874 --> 00:21:48,375 +尽量减小订单包 + +457 +00:21:48,375 --> 00:21:51,044 +以降低昂贵的网络成本 + +458 +00:21:51,044 --> 00:21:52,379 +当您更新订单时 + +459 +00:21:52,379 --> 00:21:56,216 +及时通知已注册更新的设备 + +460 +00:21:56,216 --> 00:22:00,187 +钱包中的订单 +应与订单的实际状态相匹配 + +461 +00:22:00,187 --> 00:22:05,025 +还要确保检查 HIG +以进行订单跟踪 + +462 +00:22:05,025 --> 00:22:07,794 +平台可以使订单跟踪的集成 + +463 +00:22:07,794 --> 00:22:09,162 +更加简单 + +464 +00:22:09,162 --> 00:22:13,000 +我们很高兴地宣布 +Shopify 及 Narvar 和 Route + +465 +00:22:13,000 --> 00:22:15,469 +将在今秋支持订单跟踪 + +466 +00:22:15,469 --> 00:22:18,172 +请留意未来几个月 + +467 +00:22:18,172 --> 00:22:19,840 +更多支持订单跟踪的平台 + +468 +00:22:19,840 --> 00:22:21,842 +订单跟踪是增强客户 + +469 +00:22:21,842 --> 00:22:24,945 +购后体验的好方法 + +470 +00:22:24,945 --> 00:22:26,580 +通过自动更新 + +471 +00:22:26,580 --> 00:22:28,649 +您的客户将能及时了解 + +472 +00:22:28,649 --> 00:22:31,018 +他们订单的最新状态 + +473 +00:22:31,018 --> 00:22:33,954 +我们相信您的客户会喜欢这种体验 + +474 +00:22:33,954 --> 00:22:36,723 +我们期待能尽快向您订购产品 + +475 +00:22:36,723 --> 00:22:39,259 +接下来 David 将继续讲座 + +476 +00:22:39,259 --> 00:22:41,061 +David:谢谢 Lais + +477 +00:22:41,061 --> 00:22:44,364 +我非常高兴能与大家聊一聊 + +478 +00:22:44,364 --> 00:22:48,302 +我们在 iOS 16 的钱包中 +添加了 ID 的新功能 + +479 +00:22:48,302 --> 00:22:52,940 +今年早些时候 我们在 iOS 15.4 中 +推出了钱包中的 ID + +480 +00:22:52,940 --> 00:22:55,309 +美国境内支持这个功能的各州 + +481 +00:22:55,309 --> 00:22:58,679 +用户能将驾照或身份证添加到钱包 + +482 +00:22:58,679 --> 00:23:01,982 +钱包中的 ID 是由 + +483 +00:23:01,982 --> 00:23:04,151 +发行实体身份证的机构发行 + +484 +00:23:04,151 --> 00:23:07,421 +在美国 就是各州的机动车管理局 + +485 +00:23:07,421 --> 00:23:10,324 +或同等机构 + +486 +00:23:10,324 --> 00:23:14,661 +在 iOS 16 中 +我们增加了一个新的 API + +487 +00:23:14,661 --> 00:23:17,931 +允许 App 和 App Clips +从钱包中的 ID 请求信息 + +488 +00:23:17,931 --> 00:23:21,635 +以验证用户的年龄或身份 + +489 +00:23:21,635 --> 00:23:24,104 +您的 App 将请求信息 + +490 +00:23:24,104 --> 00:23:26,807 +用户会审查并批准请求 + +491 +00:23:26,807 --> 00:23:29,343 +然后 App 会将响应发送到服务器 + +492 +00:23:29,343 --> 00:23:32,246 +进行解密和验证 + +493 +00:23:32,246 --> 00:23:34,181 +您可以从用户 ID + +494 +00:23:34,181 --> 00:23:35,782 +请求许多数据元素 + +495 +00:23:35,782 --> 00:23:39,753 +包括他们的姓名、地址 + +496 +00:23:39,753 --> 00:23:42,155 +出生日期、照片 + +497 +00:23:42,155 --> 00:23:43,757 +也叫肖像 + +498 +00:23:43,757 --> 00:23:46,627 +颁发身份证件的颁发机构 + +499 +00:23:46,627 --> 00:23:49,997 +身份证号码和有效期 + +500 +00:23:49,997 --> 00:23:52,599 +以及 如果有的话 +用户的的身份证件 + +501 +00:23:52,599 --> 00:23:54,668 +授予的驾驶特权 + +502 +00:23:54,668 --> 00:23:58,705 +ID 的常见的用例 +是验证用户的年龄 + +503 +00:23:58,705 --> 00:24:02,643 +查看实体身份证 +能够看到用户出生日期 + +504 +00:24:02,643 --> 00:24:04,978 +但要验证用户年龄 + +505 +00:24:04,978 --> 00:24:08,115 +具体出生日期是不必要的 + +506 +00:24:08,115 --> 00:24:10,617 +如果要验证我的年龄 +实际上不需要知道 + +507 +00:24:10,617 --> 00:24:12,986 +我出生的确切日期或年份 + +508 +00:24:12,986 --> 00:24:14,755 +甚至不需要知道我多少岁 + +509 +00:24:14,755 --> 00:24:17,724 +只需要知道我是否达到年龄标准 + +510 +00:24:17,724 --> 00:24:21,495 +使用钱包中的 ID +您可以直接验证年龄 + +511 +00:24:21,495 --> 00:24:23,964 +您的应用可以请求布尔数据元素 + +512 +00:24:23,964 --> 00:24:27,100 +表明用户是否超过一定年龄 + +513 +00:24:27,100 --> 00:24:29,269 +这种验证年龄的方式 + +514 +00:24:29,269 --> 00:24:33,507 +比查看具体出生日期更保护隐私 + +515 +00:24:33,507 --> 00:24:36,777 +当您的应用调用 API 时 +用户会收到一张表单 + +516 +00:24:36,777 --> 00:24:39,379 +显示您在请求什么信息 + +517 +00:24:39,379 --> 00:24:41,081 +表单还会显示您是否打算 + +518 +00:24:41,081 --> 00:24:42,549 +存储这些信息 + +519 +00:24:42,549 --> 00:24:44,818 +以及您打算存储多长时间 + +520 +00:24:44,818 --> 00:24:47,120 +这样 用户可以更明智地决定 + +521 +00:24:47,120 --> 00:24:49,823 +是否与您的 App 共享信息 + +522 +00:24:49,823 --> 00:24:52,092 +用户使用 Face ID +或 Touch ID 明确批准之前 + +523 +00:24:52,092 --> 00:24:56,330 +设备不会共享信息 + +524 +00:24:56,330 --> 00:24:58,832 +您收到的响应仅包含 + +525 +00:24:58,832 --> 00:25:00,200 +您请求的元素 + +526 +00:25:00,200 --> 00:25:02,503 +其他身份验证机制 + +527 +00:25:02,503 --> 00:25:04,938 +比如扫描实体身份证 + +528 +00:25:04,938 --> 00:25:07,274 +会共享身份证上的所有信息 + +529 +00:25:07,274 --> 00:25:09,710 +把共享信息限制在您需要的范围内 + +530 +00:25:09,710 --> 00:25:12,946 +钱包中的 ID +更能保护用户的隐私 + +531 +00:25:12,946 --> 00:25:15,148 +并减少您需要在服务器上储存的 + +532 +00:25:15,148 --> 00:25:18,752 +敏感信息数量 + +533 +00:25:18,752 --> 00:25:21,655 +响应由 ID 的颁发机构签名 + +534 +00:25:21,655 --> 00:25:23,557 +这样就可以直接验证 + +535 +00:25:23,557 --> 00:25:26,727 +响应中的信息是否真实 + +536 +00:25:26,727 --> 00:25:29,229 +请注意 ID 是由颁发机构创建 + +537 +00:25:29,229 --> 00:25:32,399 +但在调用 API 时 +颁发机构并不参与 + +538 +00:25:32,399 --> 00:25:34,935 +颁发机构不知道用户何时共享信息 + +539 +00:25:34,935 --> 00:25:39,206 +也不知道用户向谁共享了信息 + +540 +00:25:39,206 --> 00:25:42,009 +要使用 API 您需要通过 + +541 +00:25:42,009 --> 00:25:44,912 +开发者帐户请求授权 + +542 +00:25:44,912 --> 00:25:46,747 +然后 您需要设置商户 ID + +543 +00:25:46,747 --> 00:25:48,815 +和加密证书 + +544 +00:25:48,815 --> 00:25:51,852 +这个过程与使用 Apple Pay +设置应用内支付 + +545 +00:25:51,852 --> 00:25:53,253 +非常相似 + +546 +00:25:53,253 --> 00:25:58,125 +稍后我们将详细讨论 +如何使用 ID 和证书 + +547 +00:25:58,125 --> 00:26:01,428 +现在 我们来看看验证流程 + +548 +00:26:01,428 --> 00:26:04,298 +概括地说 包括四个步骤 + +549 +00:26:04,298 --> 00:26:07,968 +首先 您的应用将调用 +PassKit 框架中的 API + +550 +00:26:07,968 --> 00:26:11,772 +并指定您正在请求的信息 + +551 +00:26:11,772 --> 00:26:13,440 +然后 系统将显示一个表单 + +552 +00:26:13,440 --> 00:26:16,410 +提示用户批准请求 + +553 +00:26:16,410 --> 00:26:18,612 +用户通过请求后 您的 App + +554 +00:26:18,612 --> 00:26:21,114 +将收到一个加密的响应 + +555 +00:26:21,114 --> 00:26:23,817 +然后 应用会将该响应传递给服务器 + +556 +00:26:23,817 --> 00:26:27,187 +进行解密和验证 + +557 +00:26:27,187 --> 00:26:32,125 +首先 来看看如何使用 +PassKit 中的 API + +558 +00:26:32,125 --> 00:26:34,661 +如果您的应用使用 SwiftUI +您应该使用 + +559 +00:26:34,661 --> 00:26:37,965 +VerifyIdentityWithWalletButton +SwiftUI 视图 + +560 +00:26:37,965 --> 00:26:39,666 +这里会显示一个按钮 + +561 +00:26:39,666 --> 00:26:43,103 +按下时触发身份验证流程 + +562 +00:26:43,103 --> 00:26:46,840 +就像“使用 Apple Pay 支付” +和“添加航空通票到钱包”按钮一样 + +563 +00:26:46,840 --> 00:26:50,344 +“使用钱包验证身份”按钮 +提供了一个熟悉的 + +564 +00:26:50,344 --> 00:26:54,181 +一致的 +使用 API 的 App 体验 + +565 +00:26:54,181 --> 00:26:56,250 +有四种不同的标签供您选择 + +566 +00:26:56,250 --> 00:26:58,652 +以显示适合您的用例的按钮 + +567 +00:26:58,652 --> 00:27:00,854 +按钮会根据可用空间自动切换 + +568 +00:27:00,854 --> 00:27:05,926 +单行和多行的按钮 + +569 +00:27:05,926 --> 00:27:07,427 +创建按钮时 + +570 +00:27:07,427 --> 00:27:10,898 +您需要指定一个 +PKIdentityRequest 对象 + +571 +00:27:10,898 --> 00:27:13,667 +这个对象描述您希望请求的信息 + +572 +00:27:13,667 --> 00:27:15,536 +以及应该如何返回它 + +573 +00:27:15,536 --> 00:27:18,772 +让我们来看看如何创建按钮 + +574 +00:27:18,772 --> 00:27:19,907 +首先创建一个 + +575 +00:27:19,907 --> 00:27:22,843 +PKIdentityDriversLicenseDescriptor + +576 +00:27:22,843 --> 00:27:24,478 +它描述了您需要的 + +577 +00:27:24,478 --> 00:27:26,046 +数据元素 + +578 +00:27:26,046 --> 00:27:28,482 +使用 +addElements 方法 + +579 +00:27:28,482 --> 00:27:29,716 +指定您想请求的元素 + +580 +00:27:29,716 --> 00:27:32,419 +以及您是否打算存储元素 + +581 +00:27:32,419 --> 00:27:35,389 +您可以多次调用 +addElements 方法 + +582 +00:27:35,389 --> 00:27:37,191 +指定具有不同的存储意图的 + +583 +00:27:37,191 --> 00:27:39,226 +不同的元素集 + +584 +00:27:39,226 --> 00:27:42,429 +在这个例子中 我调用了两次 + +585 +00:27:42,429 --> 00:27:45,365 +首先 添加一个 +“年龄至少 18 岁”元素 + +586 +00:27:45,365 --> 00:27:48,368 +这个元素不会被存储 + +587 +00:27:48,368 --> 00:27:51,305 +然后 再次调用 +addElements 方法 + +588 +00:27:51,305 --> 00:27:54,641 +来请求用户的名字 姓氏和肖像 + +589 +00:27:54,641 --> 00:27:58,345 +所有元素都可以存储长达 30 天 + +590 +00:27:58,345 --> 00:28:03,317 +然后描述符进入 +PKIdentityRequest + +591 +00:28:03,317 --> 00:28:07,187 +下一步是指定要使用的商户标识符 + +592 +00:28:07,187 --> 00:28:08,755 +商户标识符表示 + +593 +00:28:08,755 --> 00:28:11,558 +API 响应将加密到的 + +594 +00:28:11,558 --> 00:28:13,427 +加密证书 + +595 +00:28:13,427 --> 00:28:15,629 +您将通过您的开发者帐户 + +596 +00:28:15,629 --> 00:28:19,766 +配置商家标识符及其加密证书 + +597 +00:28:19,766 --> 00:28:22,202 +最后 您需要指定一个随机数 + +598 +00:28:22,202 --> 00:28:23,937 +它将绑定到 + +599 +00:28:23,937 --> 00:28:25,439 +从 API 接收的响应 + +600 +00:28:25,439 --> 00:28:27,174 +这是一项重要的安全功能 + +601 +00:28:27,174 --> 00:28:29,376 +用于防止响应重放 + +602 +00:28:29,376 --> 00:28:32,613 +并将其绑定到特定的用户会话 + +603 +00:28:32,613 --> 00:28:35,349 +具体如何管理随机数 + +604 +00:28:35,349 --> 00:28:37,651 +取决于您自己的安全需求 + +605 +00:28:37,651 --> 00:28:40,654 +通常 它来自您的服务器 + +606 +00:28:40,654 --> 00:28:42,856 +因为稍后 您的服务器将负责执行 + +607 +00:28:42,856 --> 00:28:45,459 +随机数是有效的 + +608 +00:28:45,459 --> 00:28:47,060 +设置所有这些属性后 + +609 +00:28:47,060 --> 00:28:50,364 +PKIdentityRequest +就准备好了 + +610 +00:28:50,364 --> 00:28:52,733 +现在 我们再回到按钮部分 + +611 +00:28:52,733 --> 00:28:55,002 +如果身份​​验证可用 + +612 +00:28:55,002 --> 00:28:57,004 +这个按钮将显示在您的 App 中 + +613 +00:28:57,004 --> 00:28:59,673 +点击它将启动与您的请求的 + +614 +00:28:59,673 --> 00:29:02,075 +身份验证流程 + +615 +00:29:02,075 --> 00:29:04,745 +如果身份验证不可用 + +616 +00:29:04,745 --> 00:29:08,348 +则将显示您指定的回退视图 + +617 +00:29:08,348 --> 00:29:11,418 +例如 如果这款 iPhone 上的 +钱包中没有 ID + +618 +00:29:11,418 --> 00:29:12,953 +就会发生这种情况 + +619 +00:29:12,953 --> 00:29:14,254 +您可以使用回退视图 + +620 +00:29:14,254 --> 00:29:18,192 +提供其他方式来验证身份 + +621 +00:29:18,192 --> 00:29:20,994 +我们假设身份验证是可用的 + +622 +00:29:20,994 --> 00:29:22,930 +用户点击按钮 + +623 +00:29:22,930 --> 00:29:25,832 +系统会显示一张表单 +上面有您的请求 + +624 +00:29:25,832 --> 00:29:27,768 +其中包括您请求的元素 + +625 +00:29:27,768 --> 00:29:30,137 +以及您存储元素的意图 + +626 +00:29:30,137 --> 00:29:33,774 +用户可以通过 Face ID +或 Touch ID 批准请求 + +627 +00:29:33,774 --> 00:29:37,110 +或不批准并关闭表单 + +628 +00:29:37,110 --> 00:29:39,379 +然后您的代码将收到一个结果对象 + +629 +00:29:39,379 --> 00:29:42,950 +其中包含请求的结果 + +630 +00:29:42,950 --> 00:29:46,820 +如果请求受到批准 +您将收到成功结果 + +631 +00:29:46,820 --> 00:29:49,556 +结果带有一个包含加密响应的 + +632 +00:29:49,556 --> 00:29:51,558 +PKIdentityDocument 对象 + +633 +00:29:51,558 --> 00:29:53,193 +App 将发送给服务器 + +634 +00:29:53,193 --> 00:29:56,897 +进行解密和验证 + +635 +00:29:56,897 --> 00:29:58,899 +如果请求不成功 + +636 +00:29:58,899 --> 00:30:00,934 +您会收到一个失败的结果 + +637 +00:30:00,934 --> 00:30:02,302 +最常见的失败原因 + +638 +00:30:02,302 --> 00:30:04,271 +是请求未获批准 + +639 +00:30:04,271 --> 00:30:07,608 +在这种情况下 +您将收到“取消”的错误 + +640 +00:30:07,608 --> 00:30:10,277 +以上就是 VerifyIdentityWithWalletButton + +641 +00:30:10,277 --> 00:30:12,646 +SwiftUI 版本的 API + +642 +00:30:12,646 --> 00:30:14,248 +您可以用它来显示按钮 + +643 +00:30:14,248 --> 00:30:16,650 +用按钮启动身份验证流程 + +644 +00:30:16,650 --> 00:30:19,853 +并请求钱包中的 ID 信息 + +645 +00:30:19,853 --> 00:30:22,289 +如果您的应用中 +没有使用 SwiftUI + +646 +00:30:22,289 --> 00:30:24,791 +您还可以使用 +PKIdentityButton + +647 +00:30:24,791 --> 00:30:27,794 +和 PKIdentityAuthorizationController 类 + +648 +00:30:27,794 --> 00:30:31,098 +来完成相同的流程 + +649 +00:30:31,098 --> 00:30:34,535 +好了 现在您请求到了信息 + +650 +00:30:34,535 --> 00:30:36,803 +用户批准了请求 + +651 +00:30:36,803 --> 00:30:38,705 +App 向服务器发送了 + +652 +00:30:38,705 --> 00:30:40,240 +加密的响应 + +653 +00:30:40,240 --> 00:30:42,643 +现在 我们来看看服务器需要做什么 + +654 +00:30:42,643 --> 00:30:46,513 +来解密和验证响应 + +655 +00:30:46,513 --> 00:30:49,183 +我只会大致地略微聊聊这个话题 + +656 +00:30:49,183 --> 00:30:53,220 +那么 请查看开发人员文档 +以获取更多详细信息 + +657 +00:30:53,220 --> 00:30:56,190 +响应格式使用多个国际标准 + +658 +00:30:56,190 --> 00:30:58,592 +所以我强烈建议您 + +659 +00:30:58,592 --> 00:31:01,495 +也熟悉这些标准 + +660 +00:31:01,495 --> 00:31:03,096 +您将收到的响应数据 + +661 +00:31:03,096 --> 00:31:06,099 +位于 CBOR 编码的加密信封中 + +662 +00:31:06,099 --> 00:31:10,237 +CBOR +RFC 8949 中定义的数据格式 + +663 +00:31:10,237 --> 00:31:11,638 +类似于 JSON + +664 +00:31:11,638 --> 00:31:14,474 +但使用二进制数据对对象进行编码 + +665 +00:31:14,474 --> 00:31:16,677 +加密信封包含解密过程 + +666 +00:31:16,677 --> 00:31:18,612 +所需的元数据 + +667 +00:31:18,612 --> 00:31:21,715 +连同加密数据本身 + +668 +00:31:21,715 --> 00:31:24,318 +数据使用 HPKE 加密 + +669 +00:31:24,318 --> 00:31:28,021 +HPKE 是 RFC 9180 中 +定义的加密方案 + +670 +00:31:28,021 --> 00:31:32,025 +您的服务器将使用私钥解密数据 + +671 +00:31:32,025 --> 00:31:35,329 +解密后 您将获得 +一个 mdoc 响应对象 + +672 +00:31:35,329 --> 00:31:39,366 +mdoc 响应的定义 +在 ISO 18013 第 5 部分 + +673 +00:31:39,366 --> 00:31:44,004 +这是移动驾驶执照 +和州 ID 的 ISO 标准 + +674 +00:31:44,004 --> 00:31:46,640 +mdoc 响应对象包含 + +675 +00:31:46,640 --> 00:31:48,575 +您请求的数据元素 + +676 +00:31:48,575 --> 00:31:51,078 +还包括许多服务器需要验证的 + +677 +00:31:51,078 --> 00:31:52,713 +安全特性 + +678 +00:31:52,713 --> 00:31:55,415 +以确保响应是真实的 + +679 +00:31:55,415 --> 00:31:57,684 +请注意 您的服务器将执行解密 + +680 +00:31:57,684 --> 00:31:59,586 +和验证服务器本身 + +681 +00:31:59,586 --> 00:32:02,589 +Apple 服务器 +和发行机构的服务器 + +682 +00:32:02,589 --> 00:32:04,324 +都不会参与其中 + +683 +00:32:04,324 --> 00:32:06,059 +在讨论解密 + +684 +00:32:06,059 --> 00:32:07,528 +和响应验证之前 + +685 +00:32:07,528 --> 00:32:09,997 +我们需要讨论会话记录 + +686 +00:32:09,997 --> 00:32:13,133 +这是一个 CBOR 结构 +它将响应负载绑定到 + +687 +00:32:13,133 --> 00:32:16,170 +来自特定 App 的特定请求 + +688 +00:32:16,170 --> 00:32:18,772 +您的服务器将需要构建此结构 + +689 +00:32:18,772 --> 00:32:23,043 +并在解密和验证期间使用它 + +690 +00:32:23,043 --> 00:32:26,480 +会话记录包含您之前在 +PKIdentityRequest 中 + +691 +00:32:26,480 --> 00:32:29,683 +使用的同一个随机数和商户 ID + +692 +00:32:29,683 --> 00:32:32,186 +以及您的开发团队的团队 ID + +693 +00:32:32,186 --> 00:32:35,255 +以及您的加密证书的公钥的 + +694 +00:32:35,255 --> 00:32:37,758 +SHA256 散列 + +695 +00:32:37,758 --> 00:32:39,493 +在构建会话记录时 + +696 +00:32:39,493 --> 00:32:41,795 +服务器应该检查您正在使用的输入 + +697 +00:32:41,795 --> 00:32:43,063 +都是有效的 + +698 +00:32:43,063 --> 00:32:45,632 +这意味着随机数不应该已经被使用 + +699 +00:32:45,632 --> 00:32:47,968 +而应该被绑定到当前用户 + +700 +00:32:47,968 --> 00:32:50,070 +其他值应该与您的开发者帐户上 + +701 +00:32:50,070 --> 00:32:52,272 +所期望的值相匹配 + +702 +00:32:52,272 --> 00:32:55,576 +现在我们来聊聊解密加密数据 + +703 +00:32:55,576 --> 00:32:57,911 +您需要刚刚创建的会话记录 + +704 +00:32:57,911 --> 00:33:01,281 +以及来自加密信封的元数据 + +705 +00:33:01,281 --> 00:33:03,851 +您还需要个人密钥 + +706 +00:33:03,851 --> 00:33:04,952 +这是与您之前 + +707 +00:33:04,952 --> 00:33:07,788 +在开发者帐户中 + +708 +00:33:07,788 --> 00:33:09,456 +设置的证书相对应的个人密钥 + +709 +00:33:09,456 --> 00:33:12,292 +为保护用户信息的机密性 + +710 +00:33:12,292 --> 00:33:15,262 +您需要确保个人密钥保持私有 + +711 +00:33:15,262 --> 00:33:17,164 +安全存储在您的服务器上 + +712 +00:33:17,164 --> 00:33:19,333 +并且永远不要储存在 App 中 + +713 +00:33:19,333 --> 00:33:21,602 +如果您的个人密钥泄露 + +714 +00:33:21,602 --> 00:33:25,873 +请立即撤销开发者帐户中的证书 + +715 +00:33:25,873 --> 00:33:27,941 +解密加密数据后 + +716 +00:33:27,941 --> 00:33:30,110 +您将收到一个 mdoc 响应对象 + +717 +00:33:30,110 --> 00:33:32,279 +包含两个加密签名 + +718 +00:33:32,279 --> 00:33:34,481 +以及您要求的数据元素 + +719 +00:33:34,481 --> 00:33:37,351 +您需要检查 +mdoc 响应中的两个签名 + +720 +00:33:37,351 --> 00:33:39,853 +然后才能使用它的数据元素 + +721 +00:33:39,853 --> 00:33:42,923 +首先 您需要检查颁发者签名 + +722 +00:33:42,923 --> 00:33:45,092 +这是用户 ID 颁发机构的 + +723 +00:33:45,092 --> 00:33:46,960 +签名 + +724 +00:33:46,960 --> 00:33:48,462 +通过检查这个签名 + +725 +00:33:48,462 --> 00:33:50,664 +您正在验证响应中的数据 + +726 +00:33:50,664 --> 00:33:52,699 +来自真正的发证机关 + +727 +00:33:52,699 --> 00:33:54,601 +并且没有被篡改 + +728 +00:33:54,601 --> 00:33:57,538 +您应该检查签名不仅是有效的 + +729 +00:33:57,538 --> 00:34:01,275 +而且签名是由 +您信任的颁发者证书签署的 + +730 +00:34:01,275 --> 00:34:03,844 +查看文档 了解关于 +钱包中 ID 使用的 + +731 +00:34:03,844 --> 00:34:07,781 +颁发者证书的更多详细信息 + +732 +00:34:07,781 --> 00:34:11,018 +接下来 您需要验证设备签名 + +733 +00:34:11,018 --> 00:34:13,053 +这是由用户 iPhone 的 +Secure Element 中的 + +734 +00:34:13,053 --> 00:34:15,956 +密钥创建的签名 + +735 +00:34:15,956 --> 00:34:18,158 +这说明您收到的回复来自 + +736 +00:34:18,158 --> 00:34:20,627 +发卡机构最初发给您 ID 的 + +737 +00:34:20,627 --> 00:34:22,996 +那台 iPhone + +738 +00:34:22,996 --> 00:34:25,732 +在这里 您需要再次使用会话记录 + +739 +00:34:25,732 --> 00:34:29,970 +以及颁发者签名所涵盖的一些信息 + +740 +00:34:29,970 --> 00:34:32,406 +最后 可以使用请求的 + +741 +00:34:32,406 --> 00:34:33,907 +数据元素了 + +742 +00:34:33,907 --> 00:34:35,409 +在没有首先验证颁发者 +和设备签名之前 + +743 +00:34:35,409 --> 00:34:38,712 +永远不要使用这些元素 + +744 +00:34:38,712 --> 00:34:41,715 +否则您不知道您收到的数据 + +745 +00:34:41,715 --> 00:34:44,117 +是否真实 + +746 +00:34:44,117 --> 00:34:46,620 +完成所有这些步骤后 就完成了 + +747 +00:34:46,620 --> 00:34:48,755 +您的应用已经请求了信息 + +748 +00:34:48,755 --> 00:34:52,693 +并且您的服务器已经解密 +并验证了响应 + +749 +00:34:52,693 --> 00:34:55,262 +您可能想知道如果 +在钱包中没有 ID + +750 +00:34:55,262 --> 00:34:57,264 +如何测试您的设置 + +751 +00:34:57,264 --> 00:35:01,435 +我们提供了一些机制来帮助您 + +752 +00:35:01,435 --> 00:35:04,271 +首先 您可以在 +iOS 模拟器中测试 + +753 +00:35:04,271 --> 00:35:07,241 +模拟器中的 API +将返回一个模拟响应 + +754 +00:35:07,241 --> 00:35:09,643 +测试的响应类似于真实的响应 + +755 +00:35:09,643 --> 00:35:12,980 +但没有真正的签名 + +756 +00:35:12,980 --> 00:35:15,482 +同样 您可以使用测试配置文件 + +757 +00:35:15,482 --> 00:35:18,018 +在真正的 iPhone 上 +接收模拟响应 + +758 +00:35:18,018 --> 00:35:21,321 +哪怕 iPhone 上的钱包中 +没有 ID 也可以做到 + +759 +00:35:21,321 --> 00:35:24,958 +关于如何执行这项操作的 +更多详细信息 请参阅文档 + +760 +00:35:24,958 --> 00:35:26,693 +请注意 您的服务器不应该将 + +761 +00:35:26,693 --> 00:35:30,497 +像处理真实响应一样处理模拟响应 + +762 +00:35:30,497 --> 00:35:32,966 +要帮助您设置服务器 + +763 +00:35:32,966 --> 00:35:36,170 +文档中还有一个示例响应 + +764 +00:35:36,170 --> 00:35:41,441 +以及解密和验证所需要的一切 + +765 +00:35:41,441 --> 00:35:44,378 +这就是在 iOS 16 中 +使用钱包中 ID + +766 +00:35:44,378 --> 00:35:47,181 +进行身份验证的方式 + +767 +00:35:47,181 --> 00:35:49,950 +我们讨论了如何 +在您的应用中使用 API + +768 +00:35:49,950 --> 00:35:52,085 +如何处理服务器上的响应 + +769 +00:35:52,085 --> 00:35:54,888 +以及如何测试您的设置 + +770 +00:35:54,888 --> 00:35:57,624 +Lais:今年我们为 +钱包和 Apple Pay + +771 +00:35:57,624 --> 00:35:59,393 +推出了很多很棒的新功能 + +772 +00:35:59,393 --> 00:36:01,762 +新功能包括多商户支付 + +773 +00:36:01,762 --> 00:36:04,364 +改进了对自动支付的支持 + +774 +00:36:04,364 --> 00:36:07,568 +订单跟踪和身份验证 + +775 +00:36:07,568 --> 00:36:09,436 +请查看开发者文档 + +776 +00:36:09,436 --> 00:36:10,804 +以了解更多信息 + +777 +00:36:10,804 --> 00:36:14,975 +David:感谢您的收看 +希望您在 WWDC 体验愉快 + +778 +00:36:14,975 --> 00:36:19,079 +♪ + diff --git a/zho/2022 Session 10043 What's new in App Store Connect.srt b/zho/2022 Session 10043 What's new in App Store Connect.srt new file mode 100644 index 0000000..c9848a6 --- /dev/null +++ b/zho/2022 Session 10043 What's new in App Store Connect.srt @@ -0,0 +1,932 @@ +1 +00:00:00,267 --> 00:00:03,670 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,670 --> 00:00:09,710 +♪ + +3 +00:00:09,710 --> 00:00:12,746 +大家好 欢迎来到 +“App Store Connect 的新功能” + +4 +00:00:12,746 --> 00:00:14,815 +我是 +App Store Connect 的工程经理 + +5 +00:00:14,815 --> 00:00:17,150 +我叫 Will Averill + +6 +00:00:17,150 --> 00:00:20,053 +这些年来 +App Store Connect 发展迅速 + +7 +00:00:20,053 --> 00:00:22,489 +您可以在我们 +所有平台的 App Store + +8 +00:00:22,489 --> 00:00:25,425 +使用它来创建 +管理和发展您的 App + +9 +00:00:25,425 --> 00:00:27,895 +我们持续在网页上、iOS 和 iPadOS App +以及 App Store Connect API 上 + +10 +00:00:27,895 --> 00:00:33,500 +为 App Store Connect +带来新功能 + +11 +00:00:33,500 --> 00:00:36,637 +就在去年 我们推出了 +一系列很棒的新功能 + +12 +00:00:36,637 --> 00:00:39,273 +您可能了解过这些新功能 +如 in-app events + +13 +00:00:39,273 --> 00:00:41,942 +自定义产品页面 以及 +Mac 版 TestFlight + +14 +00:00:41,942 --> 00:00:43,744 +所以 我想快速着重介绍一些 + +15 +00:00:43,744 --> 00:00:46,547 +您可能错过的近期更新 + +16 +00:00:46,547 --> 00:00:48,916 +在 TestFlight 中 +管理您组建的 + +17 +00:00:48,916 --> 00:00:51,518 +相关测试者群组更容易 + +18 +00:00:51,518 --> 00:00:54,721 +只需单击一下 您现在就可以直接 + +19 +00:00:54,721 --> 00:00:56,290 +从 Versions 或 +Build Groups 选项卡中 + +20 +00:00:56,290 --> 00:00:59,493 +为一个 build 快速添加或删除 +一个测试者群组到 + +21 +00:00:59,493 --> 00:01:02,162 +我们也很在意您的反馈 + +22 +00:01:02,162 --> 00:01:04,798 +并做了很多改进 + +23 +00:01:04,798 --> 00:01:06,867 +您现在可以转让使用 +Apple 钱包 的 App 了 + +24 +00:01:06,867 --> 00:01:09,603 +最后 我们优化了 +App Store 审核体验 + +25 +00:01:09,603 --> 00:01:11,972 +简化了 in-app events + +26 +00:01:11,972 --> 00:01:13,841 +自定义产品页面 +和产品页面优化 + +27 +00:01:13,841 --> 00:01:17,044 +的审核流程 + +28 +00:01:17,044 --> 00:01:19,179 +这是我们对审核流程 + +29 +00:01:19,179 --> 00:01:20,714 +所做的最大优化之一 + +30 +00:01:20,714 --> 00:01:24,184 +所以让我们来一起 +更详细地探讨这一优化 + +31 +00:01:24,184 --> 00:01:27,054 +首先 您现在可以在一个审核申请中 + +32 +00:01:27,054 --> 00:01:29,323 +成组提交多个项目 + +33 +00:01:29,323 --> 00:01:31,225 +另外 在大多数情况下 + +34 +00:01:31,225 --> 00:01:34,862 +您可以选择在没有 +App 新版本的情况下提交 + +35 +00:01:34,862 --> 00:01:37,865 +我们还引入了 +专门的 App 审核页面 + +36 +00:01:37,865 --> 00:01:40,000 +在这里您可以管理正在审核的内容 + +37 +00:01:40,000 --> 00:01:41,535 +与 App Review 的对话 + +38 +00:01:41,535 --> 00:01:44,471 +甚至查看最近完成的提交内容 + +39 +00:01:44,471 --> 00:01:46,440 +让我们先聊聊在提交审核过程中 + +40 +00:01:46,440 --> 00:01:49,243 +将项目成组意味着什么 + +41 +00:01:49,243 --> 00:01:51,478 +假设我们有许多自定义产品页 + +42 +00:01:51,478 --> 00:01:54,781 +或者任何其他 +想要发布到商店的审核项目 + +43 +00:01:54,781 --> 00:01:56,650 +由于审核项目只能 +作为审核申请的一部分 + +44 +00:01:56,650 --> 00:01:58,519 +进行提交 + +45 +00:01:58,519 --> 00:02:01,154 +第一步是将审核项目都 +添加到一个申请中 + +46 +00:02:01,154 --> 00:02:03,290 +您可以将审核申请视为 + +47 +00:02:03,290 --> 00:02:06,894 +携带审核项目往返 +App review 的载体 + +48 +00:02:06,894 --> 00:02:10,397 +审核申请里只要有 +一个项目就可以提交 + +49 +00:02:10,397 --> 00:02:12,399 +但是将多个项目成组的好处是 + +50 +00:02:12,399 --> 00:02:14,868 +它们会在同一个上下文中一起被审核 + +51 +00:02:14,868 --> 00:02:17,871 +这有助于确保审核一致且有效 + +52 +00:02:17,871 --> 00:02:19,806 +事实上 无论审核项目的数量 +或类型如何 + +53 +00:02:19,806 --> 00:02:22,209 +所有的审核申请 + +54 +00:02:22,209 --> 00:02:26,113 +通常会在 24 小时内被审核 + +55 +00:02:26,113 --> 00:02:28,048 +审核后 申请中的每一项 + +56 +00:02:28,048 --> 00:02:30,784 +将被标记为批准或拒绝 + +57 +00:02:30,784 --> 00:02:32,052 +请注意 + +58 +00:02:32,052 --> 00:02:34,321 +在审核申请的所有项目都被批准之前 + +59 +00:02:34,321 --> 00:02:37,591 +不会有单个审核项目被批准 + +60 +00:02:37,591 --> 00:02:39,493 +所以 让我们来看看 + +61 +00:02:39,493 --> 00:02:42,529 +两种处理已拒绝项目的审核申请方法 + +62 +00:02:42,529 --> 00:02:45,832 +第一个方法是 +编辑所有这些被拒绝的审核项目 + +63 +00:02:45,832 --> 00:02:47,534 +然后重新提交 + +64 +00:02:47,534 --> 00:02:49,937 +如果这些项目现在被批准了 + +65 +00:02:49,937 --> 00:02:51,672 +则审核申请完成 + +66 +00:02:51,672 --> 00:02:52,840 +并且每个项目都被批准了 + +67 +00:02:52,840 --> 00:02:55,676 +能够发布到 App Store + +68 +00:02:55,676 --> 00:02:57,211 +另一种方法是简单地删除 + +69 +00:02:57,211 --> 00:02:59,913 +所有已提交的被拒绝项目 + +70 +00:02:59,913 --> 00:03:01,515 +这样审核申请里就 + +71 +00:03:01,515 --> 00:03:03,083 +只有已获批准的项目了 + +72 +00:03:03,083 --> 00:03:06,119 +然后再次继续完成审核流程 + +73 +00:03:06,119 --> 00:03:08,789 +但是 请记住 为了通过审核 + +74 +00:03:08,789 --> 00:03:11,992 +所有已删除的项目 + +75 +00:03:11,992 --> 00:03:14,228 +将需要列入新的审核申请中重新提交 + +76 +00:03:14,228 --> 00:03:15,495 +在我继续下一部分讲解之前 + +77 +00:03:15,495 --> 00:03:17,431 +我想提醒大家 + +78 +00:03:17,431 --> 00:03:20,133 +审核项目可以是 +App 版本,in-app events + +79 +00:03:20,133 --> 00:03:24,438 +自定义产品页面 +或产品页面优化测试 + +80 +00:03:24,438 --> 00:03:26,773 +现在 让我们看看 +如果没有新的 App 版本 + +81 +00:03:26,773 --> 00:03:28,742 +您该如何提交 + +82 +00:03:28,742 --> 00:03:30,944 +要了解这是如何工作的 + +83 +00:03:30,944 --> 00:03:32,379 +我们需要先来了解 + +84 +00:03:32,379 --> 00:03:34,715 +关于审核申请的更多详情 + +85 +00:03:34,715 --> 00:03:39,486 +首先 每个提交都有一个关联平台 + +86 +00:03:39,486 --> 00:03:41,455 +另外 每个平台都支持 + +87 +00:03:41,455 --> 00:03:44,024 +一套特定的审核项目 + +88 +00:03:44,024 --> 00:03:46,527 +尽管如您所见 +大多数项目都会打包 + +89 +00:03:46,527 --> 00:03:49,930 +成为iOS 提交的一部分 +进行审核 + +90 +00:03:49,930 --> 00:03:52,933 +最后 您在每个平台可以有一个 + +91 +00:03:52,933 --> 00:03:54,368 +正在进行的审核申请 + +92 +00:03:54,368 --> 00:03:56,503 +在这个示例中 您可以看到 + +93 +00:03:56,503 --> 00:03:59,273 +我们正在提交 App 的三个版本 + +94 +00:03:59,273 --> 00:04:01,341 +但是 让我们继续仔细看看 + +95 +00:04:01,341 --> 00:04:04,178 +这个 iOS 的审核申请 + +96 +00:04:04,178 --> 00:04:06,780 +App Review 会根据 +App 版本来审核申请中的所有项目 + +97 +00:04:06,780 --> 00:04:10,651 +以确保审核的一致性 + +98 +00:04:10,651 --> 00:04:12,753 +如果提交内容中包含 App 版本 + +99 +00:04:12,753 --> 00:04:15,088 +则该版本将用于审核 + +100 +00:04:15,088 --> 00:04:16,590 +但是 就像我之前提到的 + +101 +00:04:16,590 --> 00:04:20,427 +申请内容中没有添加新版本 +您也可以提交 + +102 +00:04:20,427 --> 00:04:22,930 +只需要在您的 App 中 + +103 +00:04:22,930 --> 00:04:24,031 +有之前已获批的版本 + +104 +00:04:24,031 --> 00:04:25,566 +当然 一旦提交 + +105 +00:04:25,566 --> 00:04:28,836 +项目将根据此版本进行审核 + +106 +00:04:28,836 --> 00:04:31,171 +这意味着您可以 +在您的第一个 iOS 版本 + +107 +00:04:31,171 --> 00:04:34,541 +获得批准之后的任意时间 +提交 in-app events + +108 +00:04:34,541 --> 00:04:37,511 +自定义产品页面和产品页面优化测试 + +109 +00:04:37,511 --> 00:04:40,447 +且无需新的 App 二进制文件 + +110 +00:04:40,447 --> 00:04:43,016 +现在我已经讲解了 +这种审核是如何运作的 + +111 +00:04:43,016 --> 00:04:44,318 +让我来展示一下 +App Store Connect 中 + +112 +00:04:44,318 --> 00:04:47,821 +专门的 App Review 提交页面 + +113 +00:04:47,821 --> 00:04:49,857 +登录并选择 App 后 + +114 +00:04:49,857 --> 00:04:53,327 +单击左侧导航菜单上的 +App Review + +115 +00:04:53,327 --> 00:04:55,629 +这就是 App Review 页面 + +116 +00:04:55,629 --> 00:04:58,532 +您可以在这里管理整个审核流程 + +117 +00:04:58,532 --> 00:05:00,734 +在这里 您可以查看您的申请概览 + +118 +00:05:00,734 --> 00:05:04,171 +单击其中任何一个 +都可以查看更多详情 + +119 +00:05:04,171 --> 00:05:06,874 +显然 网页界面使用感很棒 + +120 +00:05:06,874 --> 00:05:08,775 +但如果能随时提交 + +121 +00:05:08,775 --> 00:05:11,378 +并跟踪提交状态岂不是更好? + +122 +00:05:11,378 --> 00:05:12,746 +这就是为什么 +我们很高兴地与大家分享 + +123 +00:05:12,746 --> 00:05:14,915 +本周的更新 我们将加强版申请体验 + +124 +00:05:14,915 --> 00:05:20,521 +带到 iPadOS 和 iOS 的 +App Store Connect 上 + +125 +00:05:20,521 --> 00:05:21,889 +您现在只需轻轻一按 + +126 +00:05:21,889 --> 00:05:24,458 +就可以在任何地方 + +127 +00:05:24,458 --> 00:05:27,327 +将您已准备好的审核 +提交至 App Review + +128 +00:05:27,327 --> 00:05:28,629 +一经提交 + +129 +00:05:28,629 --> 00:05:31,965 +您可以跟踪您的审核申请进度 + +130 +00:05:31,965 --> 00:05:34,868 +您还可以选择接收 + +131 +00:05:34,868 --> 00:05:37,371 +状态更新相关的即时通知 + +132 +00:05:37,371 --> 00:05:41,608 +以及通过删除项目 查看拒绝原因 + +133 +00:05:41,608 --> 00:05:46,213 +回复 App Review +来管理您的申请 + +134 +00:05:46,213 --> 00:05:48,949 +这就是加强版 +App Store 申请体验 + +135 +00:05:48,949 --> 00:05:50,951 +现已在 iPadOS 和 iOS 的 + +136 +00:05:50,951 --> 00:05:53,854 +App Store Connect 上可用 + +137 +00:05:53,854 --> 00:05:55,389 +让我们换个角度 + +138 +00:05:55,389 --> 00:05:57,224 +来关注一下 +App Store Connect API + +139 +00:05:57,224 --> 00:05:59,560 +它是一个很棒的工具 + +140 +00:05:59,560 --> 00:06:01,929 +您可以用它来定制 +和自动化您的 App 工作流程 + +141 +00:06:01,929 --> 00:06:04,665 +最重要的是 我们一直致力于 + +142 +00:06:04,665 --> 00:06:06,633 +增加 API 的功能 + +143 +00:06:06,633 --> 00:06:10,370 +去年 我们支持了 轻 App +Xcode Cloud + +144 +00:06:10,370 --> 00:06:12,773 +in-app events +自定义产品页面 + +145 +00:06:12,773 --> 00:06:14,641 +产品页面优化 + +146 +00:06:14,641 --> 00:06:17,044 +以及加强版 App Store 申请体验 + +147 +00:06:17,044 --> 00:06:18,512 +就像我刚才说的 + +148 +00:06:18,512 --> 00:06:20,414 +今年也不例外 + +149 +00:06:20,414 --> 00:06:23,283 +随着今年夏天 +我们 2.0 版本的到来 + +150 +00:06:23,283 --> 00:06:25,686 +我们将把 API 中的资源数量 + +151 +00:06:25,686 --> 00:06:27,721 +扩大了 60% + +152 +00:06:27,721 --> 00:06:28,956 +在今年夏天的版本中 + +153 +00:06:28,956 --> 00:06:30,791 +我们添加了许多已被强烈要求的 + +154 +00:06:30,791 --> 00:06:32,860 +很棒的新功能 + +155 +00:06:32,860 --> 00:06:35,562 +首先 是一套全面的 API 让您可以 + +156 +00:06:35,562 --> 00:06:37,664 +管理您所有的应用内购买 + +157 +00:06:37,664 --> 00:06:39,933 +和订阅期限 + +158 +00:06:39,933 --> 00:06:41,935 +我们将订阅分成了 + +159 +00:06:41,935 --> 00:06:43,770 +各自的资源 + +160 +00:06:43,770 --> 00:06:47,608 +并让您有完全的控制来 +创建、编辑或删除 + +161 +00:06:47,608 --> 00:06:50,711 +您的 App 内购买项目 +或订阅项目 + +162 +00:06:50,711 --> 00:06:54,882 +您还可以管理定价、提交审核 + +163 +00:06:54,882 --> 00:06:57,851 +并创建特别优惠和促销码 + +164 +00:06:57,851 --> 00:06:59,653 +我们迫不及待想看看您如何利用 + +165 +00:06:59,653 --> 00:07:02,122 +这个新机会来自动化您的应用内购买 + +166 +00:07:02,122 --> 00:07:04,491 +和订阅工作流程 + +167 +00:07:04,491 --> 00:07:05,759 +我们还添加了获取和回复 + +168 +00:07:05,759 --> 00:07:08,862 +用户评论的功能 + +169 +00:07:08,862 --> 00:07:10,697 +目标是让您可以 +围绕用户使用体验 + +170 +00:07:10,697 --> 00:07:14,268 +去搭建一些很棒的 +自定义工作流程 + +171 +00:07:14,268 --> 00:07:16,537 +最后 针对 App 卡顿 + +172 +00:07:16,537 --> 00:07:19,439 +我们还增加了 +App 功耗和性能指标 + +173 +00:07:19,439 --> 00:07:21,141 +以及诊断 API 的补充报告 + +174 +00:07:21,141 --> 00:07:23,577 +识别和消除 App 中的卡顿 + +175 +00:07:23,577 --> 00:07:25,612 +有助于提高性能 + +176 +00:07:25,612 --> 00:07:28,015 +和改善用户体验 + +177 +00:07:28,015 --> 00:07:30,317 +但到目前为止 +您只能通过 API 查看指标 + +178 +00:07:30,317 --> 00:07:33,187 +比如您的 App 的卡顿率 + +179 +00:07:33,187 --> 00:07:34,988 +这种情况将在今年夏天得到改变 + +180 +00:07:34,988 --> 00:07:38,325 +因为我们会为 App 卡顿 +添加一个全新的诊断类型 + +181 +00:07:38,325 --> 00:07:39,626 +您将能够使用这个诊断类型 + +182 +00:07:39,626 --> 00:07:42,362 +和现有的诊断签名资源 + +183 +00:07:42,362 --> 00:07:43,864 +去查找 App 中 + +184 +00:07:43,864 --> 00:07:46,033 +最容易出现卡顿的地方 + +185 +00:07:46,033 --> 00:07:48,001 +不仅如此 您也可以通过 + +186 +00:07:48,001 --> 00:07:50,470 +诊断报告来查看 + +187 +00:07:50,470 --> 00:07:53,707 +卡顿签名的详细堆栈 trace + +188 +00:07:53,707 --> 00:07:55,843 +我在这里只讲了一些皮毛 + +189 +00:07:55,843 --> 00:07:58,178 +如果您想了解更多 +关于这些 API 的工作原理 + +190 +00:07:58,178 --> 00:08:00,914 +以及如何使用这些数据来洞悉 + +191 +00:08:00,914 --> 00:08:02,282 +更多 App 的行为 + +192 +00:08:02,282 --> 00:08:05,085 +一定要看看这两个相关讲座 + +193 +00:08:05,085 --> 00:08:08,722 +总体而言 +App Store Connect API 2.0 的发布 + +194 +00:08:08,722 --> 00:08:10,757 +是一个重要的里程碑 + +195 +00:08:10,757 --> 00:08:14,361 +经过四年的发展 +我们已经完全拥抱了 + +196 +00:08:14,361 --> 00:08:17,097 +REST API 作为 +App Store Connect 自动化的未来 + +197 +00:08:17,097 --> 00:08:19,433 +因此 我们将在今年秋季 + +198 +00:08:19,433 --> 00:08:21,735 +开始停用 XML feed + +199 +00:08:21,735 --> 00:08:25,172 +因此 我们强烈建议您将您的集成 + +200 +00:08:25,172 --> 00:08:28,008 +与 App Store Connect API 保持一致 + +201 +00:08:28,008 --> 00:08:30,444 +总之 为了简化您的审核流程 + +202 +00:08:30,444 --> 00:08:32,513 +我们建议您充分利用 + +203 +00:08:32,513 --> 00:08:35,616 +加强版 App Store 提交体验 + +204 +00:08:35,616 --> 00:08:38,185 +并下载适用于 +iOS 和 iPadOS 的 + +205 +00:08:38,185 --> 00:08:41,221 +最新版本 App Store Connect + +206 +00:08:41,221 --> 00:08:43,857 +最新版本增加了 +对加强版提交体验的支持 + +207 +00:08:43,857 --> 00:08:46,393 +和其他几个更新 + +208 +00:08:46,393 --> 00:08:49,162 +最后 在今年夏天发布的 2.0 中 + +209 +00:08:49,162 --> 00:08:50,731 +我们在 +App Store Connect API 里 + +210 +00:08:50,731 --> 00:08:53,400 +新增了一系列新功能 + +211 +00:08:53,400 --> 00:08:56,503 +强烈建议您集成我们的 API + +212 +00:08:56,503 --> 00:08:59,306 +特别是我们在今年秋天晚些时候 + +213 +00:08:59,306 --> 00:09:01,041 +就要开始 +停用 XML feed 了 + +214 +00:09:01,041 --> 00:09:03,210 +一如既往 我们期待听到您的反馈 + +215 +00:09:03,210 --> 00:09:06,380 +希望您在 WWDC 有愉快的体验 + +216 +00:09:06,380 --> 00:09:07,881 +感谢收看 + +217 +00:09:07,881 --> 00:09:12,052 +♪ + diff --git a/zho/2022 Session 10044 Discover Benchmarks in App Analytics.srt b/zho/2022 Session 10044 Discover Benchmarks in App Analytics.srt new file mode 100644 index 0000000..4b20e6b --- /dev/null +++ b/zho/2022 Session 10044 Discover Benchmarks in App Analytics.srt @@ -0,0 +1,855 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,643 --> 00:00:11,612 +Mahesh Molakalapalli: +我叫 Mahesh Molakalapalli + +3 +00:00:11,645 --> 00:00:16,083 +我是 App Store 和 +App 分析团队的工程师 + +4 +00:00:16,116 --> 00:00:20,020 +App 分析旨在帮助您 +获得关于您 App 的独到见解 + +5 +00:00:20,053 --> 00:00:24,024 +从而帮您拓展业务 + +6 +00:00:24,057 --> 00:00:28,629 +今天要给大家介绍 +一个令人兴奋的新功能 + +7 +00:00:28,662 --> 00:00:31,098 +名字叫 App 基准化 + +8 +00:00:31,131 --> 00:00:35,636 +通过这一功能 +您能获得前所未有的见解 + +9 +00:00:35,669 --> 00:00:39,706 +我们先从基准化的 +概述开始 + +10 +00:00:39,740 --> 00:00:45,779 +然后我们再讨论您所看到的 +基准化数据中的指标 + +11 +00:00:45,812 --> 00:00:50,684 +接下来 我们将展示如何在 +保护所有 App 隐私的同时 + +12 +00:00:50,717 --> 00:00:55,155 +创建相关的基准值 + +13 +00:00:55,189 --> 00:00:59,526 +最后 我们将向您展示 +如何利用基准化中 + +14 +00:00:59,560 --> 00:01:03,530 +获得的见解采取行动 + +15 +00:01:03,564 --> 00:01:05,132 +我们开始吧 + +16 +00:01:05,165 --> 00:01:07,868 +许多人可能 +已经在使用 App 分析 + +17 +00:01:07,901 --> 00:01:10,537 +在这个工具中 我们会向您显示 + +18 +00:01:10,571 --> 00:01:15,409 +您 App 的获客率 +使用率和收入情况的数据 + +19 +00:01:15,442 --> 00:01:19,546 +假设您是 Mountain Climber App 的 +开发者 + +20 +00:01:19,580 --> 00:01:23,650 +这是一个提供订阅的 +旅行 App + +21 +00:01:23,684 --> 00:01:28,655 +概述页面通过关键的表现指标 +显示了 Mountain Climber + +22 +00:01:28,689 --> 00:01:31,558 +表现的变化过程 + +23 +00:01:31,592 --> 00:01:36,864 +您可以根据这些指标 +监控客户生命周期每个阶段的表现 + +24 +00:01:36,897 --> 00:01:42,236 +从发现期到转换期 再到持续使用 + +25 +00:01:42,269 --> 00:01:44,771 +由于您关注的是增长 + +26 +00:01:44,805 --> 00:01:49,643 +假设您 App 业务的首要目标 + +27 +00:01:49,676 --> 00:01:52,479 +是提高转化率 + +28 +00:01:52,513 --> 00:01:56,483 +看数据会发现 您一直在稳步提高 + +29 +00:01:56,517 --> 00:02:00,888 +在过去的 90 天里 +增加了 5.5% + +30 +00:02:00,921 --> 00:02:04,758 +但不清楚的是 持续下去 + +31 +00:02:04,791 --> 00:02:08,262 +还有多少提升空间 + +32 +00:02:08,295 --> 00:02:10,664 +这个 App 还有更多的增长空间吗 + +33 +00:02:10,697 --> 00:02:14,535 +或者您是否应该 +把精力集中到别的地方 + +34 +00:02:14,568 --> 00:02:17,838 +这就需要 +引进对等组基准化 + +35 +00:02:17,871 --> 00:02:20,607 +在隐私保护的前提下 +您可以学习 + +36 +00:02:20,641 --> 00:02:24,144 +与您 App 类似的 App 的表现 + +37 +00:02:24,178 --> 00:02:28,415 +并他们和您 App 的表现作比较 + +38 +00:02:28,448 --> 00:02:30,584 +比如您的 +Mountain Climber App + +39 +00:02:30,617 --> 00:02:34,621 +右侧所有的 App 都是 + +40 +00:02:34,655 --> 00:02:37,724 +使用了订阅模式的旅行 App + +41 +00:02:37,758 --> 00:02:42,963 +看看您的 App +与这个群组相比如何 + +42 +00:02:44,064 --> 00:02:48,836 +您可以看到相同的 App +从左到右 + +43 +00:02:48,869 --> 00:02:52,673 +按从低到高的转化率排列 + +44 +00:02:52,706 --> 00:02:56,610 +您的 App 与其他 App 相比起来如何呢 + +45 +00:02:56,643 --> 00:03:00,347 +虽然您的转化率 +一直在持续改善 + +46 +00:03:00,380 --> 00:03:03,784 +但是在同类组群中 +仍处于后半部分 + +47 +00:03:03,817 --> 00:03:06,119 +还有很大的改进空间 + +48 +00:03:06,153 --> 00:03:08,989 +基准化提供了 +如上的见解 + +49 +00:03:09,022 --> 00:03:14,728 +而非公开对等组中的 +单个 App 的表现 + +50 +00:03:15,495 --> 00:03:20,501 +我们通过覆盖足够多的 App +从整体角度来 + +51 +00:03:20,534 --> 00:03:21,869 +提供对您有所助益的结果 + +52 +00:03:21,902 --> 00:03:26,373 +这样不会暴露 +单个 App 的表现 + +53 +00:03:26,406 --> 00:03:29,543 +为了显示您的相对位置 + +54 +00:03:29,576 --> 00:03:34,381 +我们向您展示了同类群组的水平 + +55 +00:03:34,414 --> 00:03:40,053 +如您所在群组的 25%、 +50% 和 75% 的位置 + +56 +00:03:41,455 --> 00:03:44,324 +您能借此看到相对同类群组来说 + +57 +00:03:44,358 --> 00:03:46,293 +您的 App 表现如何 + +58 +00:03:46,326 --> 00:03:49,363 +并了解其是否还有提升机会 + +59 +00:03:49,396 --> 00:03:52,900 +或者您是否 +已经从竞争中脱颖而出 + +60 +00:03:52,933 --> 00:03:57,437 +现在您已了解了 +对等组基准化的概念 + +61 +00:03:57,471 --> 00:03:59,640 +及其重要性 + +62 +00:03:59,673 --> 00:04:04,611 +我们来谈谈这个功能中包含的可用指标 + +63 +00:04:05,512 --> 00:04:09,449 +基准化的目标之一 +是针对您的 App 在整个 + +64 +00:04:09,483 --> 00:04:14,288 +客户生命周期的表现提供见解 + +65 +00:04:14,321 --> 00:04:20,160 +所以我们会提供获客率、 +使用率以及收入情况等 + +66 +00:04:20,194 --> 00:04:22,963 +相关的指标基准 + +67 +00:04:22,996 --> 00:04:25,699 +为了帮您衡量您在 +客户增长方面的付出 + +68 +00:04:25,732 --> 00:04:29,036 +我们为您提供了转化率基准 + +69 +00:04:29,069 --> 00:04:33,440 +转化率能帮助您了解 +人们在 App Store 上发现 + +70 +00:04:33,473 --> 00:04:37,978 +您的 App 后进行下载 +或重新下载的频率 + +71 +00:04:38,011 --> 00:04:39,847 +转化率越高 + +72 +00:04:39,880 --> 00:04:43,617 +您的获客效率就越高 + +73 +00:04:44,785 --> 00:04:49,089 +为了帮助您衡量使用率 +我们会提供第 1 日 + +74 +00:04:49,122 --> 00:04:52,359 +第 7 日和第 28 日的持续使用率 + +75 +00:04:52,392 --> 00:04:56,129 +持续使用率有助于让您了解 +用户在下载 1 天、 + +76 +00:04:56,163 --> 00:04:58,699 +7 天以及 + +77 +00:04:58,732 --> 00:05:00,133 +28 天后 + +78 +00:05:00,167 --> 00:05:02,369 +有多少比率的用户 +返回您的 App + +79 +00:05:02,402 --> 00:05:06,807 +这一指标可以很好地衡量 + +80 +00:05:06,840 --> 00:05:08,408 +您的 App 对用户的吸引力 + +81 +00:05:09,676 --> 00:05:13,747 +除此之外 您也能看到相对于同行 + +82 +00:05:13,780 --> 00:05:15,682 +您的崩溃率有多少 + +83 +00:05:15,716 --> 00:05:19,186 +如果您的 App 的崩溃率 +比平时更频繁 + +84 +00:05:19,219 --> 00:05:23,390 +可能会对其用户参与率 +和收入情况都产生负面影响 + +85 +00:05:23,423 --> 00:05:26,627 +所以这个比率要尽可能低一些 + +86 +00:05:27,928 --> 00:05:32,032 +最后 帮助您评估 +您的货币化策略 + +87 +00:05:32,065 --> 00:05:37,471 +您会看到关于每位付费用户 +带来的收入的基准 + +88 +00:05:37,504 --> 00:05:42,075 +这能让您看到同行 + +89 +00:05:42,109 --> 00:05:44,444 +每个付费客户能获取多少收益 + +90 +00:05:44,478 --> 00:05:47,314 +所以可以看到您是如何比较的 + +91 +00:05:47,347 --> 00:05:51,385 +现在知道了您将看到哪些指标 + +92 +00:05:51,418 --> 00:05:55,222 +我们谈谈相关性和隐私性 + +93 +00:05:55,255 --> 00:05:57,424 +通过这个功能的开发 + +94 +00:05:57,457 --> 00:06:00,260 +我们努力创建了 + +95 +00:06:00,294 --> 00:06:03,463 +与您和您业务高度相关的 +同行群体 + +96 +00:06:03,497 --> 00:06:08,802 +同时也保护该组中 +每个 App 的隐私 + +97 +00:06:08,836 --> 00:06:14,141 +有助于我们在不透露 +单一 App 表现情况下 + +98 +00:06:14,174 --> 00:06:18,478 +为您提供有用见解这一目标 + +99 +00:06:18,512 --> 00:06:20,881 +不管您在 +App Store 中有什么 App + +100 +00:06:20,914 --> 00:06:24,585 +先来让我们讨论两个 + +101 +00:06:24,618 --> 00:06:29,289 +我们如何让同类群组 +和您建立联系的例子 + +102 +00:06:29,323 --> 00:06:34,094 +首先 我们要使用一些 App Store +的属性 + +103 +00:06:34,127 --> 00:06:36,096 +创建您的同类群组 + +104 +00:06:36,129 --> 00:06:39,199 +包括 App 的 App Store 类别 + +105 +00:06:39,233 --> 00:06:43,003 +例如 如果您已将您的 App +归在旅游类别中 + +106 +00:06:43,036 --> 00:06:44,938 +我们会将您与其它同样在 + +107 +00:06:44,972 --> 00:06:48,509 +旅游类别 App 放在一起 + +108 +00:06:48,542 --> 00:06:53,547 +其次 我们还要看您的 App +在商店中的盈利方式 + +109 +00:06:53,580 --> 00:06:56,350 +例如 是否是一个免费的 App + +110 +00:06:56,383 --> 00:07:00,320 +免费增值 付费 付费增值或订阅 + +111 +00:07:00,354 --> 00:07:04,024 +由于不同商业模式的 App +对于用户行为 + +112 +00:07:04,057 --> 00:07:05,759 +有不同的期望 + +113 +00:07:05,792 --> 00:07:10,564 +所以这也是创建相关的对等组 +很重要的因素 + +114 +00:07:10,597 --> 00:07:14,468 +我们用于创建同类群组的每个属性 + +115 +00:07:14,501 --> 00:07:19,173 +已经过测试 以确保 +它允许 App + +116 +00:07:19,206 --> 00:07:23,143 +及其对等组之间 +按时间线进行有意义的比较 + +117 +00:07:23,177 --> 00:07:25,546 +接下来 我们谈谈隐私 + +118 +00:07:25,579 --> 00:07:30,217 +在 Apple 我们拥有丰富的经验 +打造强大的 + +119 +00:07:30,250 --> 00:07:32,286 +具有隐私性的产品 + +120 +00:07:32,319 --> 00:07:36,023 +这经验也能为我们所用 + +121 +00:07:36,056 --> 00:07:38,192 +为了实现我们的隐私目标 + +122 +00:07:38,225 --> 00:07:41,361 +我们使用一种 +Differential Privacy 技术 + +123 +00:07:41,395 --> 00:07:44,932 +这是确保汇数据的黄金标准 + +124 +00:07:44,965 --> 00:07:50,037 +可以确保两者都有帮助的同时 +保持隐私 + +125 +00:07:50,070 --> 00:07:54,074 +当我们计算您同类组群 +的整体转化率时 + +126 +00:07:54,107 --> 00:07:56,643 +您同类群组共享出来的 + +127 +00:07:56,677 --> 00:08:01,181 +每个数据点都增加了少量的干扰 + +128 +00:08:01,215 --> 00:08:05,485 +还确保了 +您的同类组群有足够多的 App + +129 +00:08:05,519 --> 00:08:08,522 +这样不可能知道 + +130 +00:08:08,555 --> 00:08:13,427 +特定 App 是在 +您的同类组群之中或之外 + +131 +00:08:13,460 --> 00:08:16,597 +因为添加到数据组的干扰信号 + +132 +00:08:16,630 --> 00:08:21,201 +大到足以掩盖对等组的确切构成 + +133 +00:08:21,235 --> 00:08:24,238 +同时从整体上说 +仍可提供关于同类组的 + +134 +00:08:24,271 --> 00:08:27,074 +有用的信息 + +135 +00:08:27,107 --> 00:08:30,043 +这样既可以保护您 App 的隐私 + +136 +00:08:30,077 --> 00:08:33,046 +也可以保护同类组中其它 App + +137 +00:08:33,080 --> 00:08:37,751 +最后 我们看一下 +您可以如何使用其它工具 + +138 +00:08:37,784 --> 00:08:40,153 +来操作这一信息 + +139 +00:08:41,288 --> 00:08:44,725 +App Store 提供了许多 +让您在整个客户生命周期 + +140 +00:08:44,758 --> 00:08:49,530 +能够优化并提高您的表现 + +141 +00:08:49,563 --> 00:08:52,332 +开发者功能 + +142 +00:08:52,366 --> 00:08:55,569 +例如 要拥有很高的转化率 + +143 +00:08:55,602 --> 00:08:58,639 +您需要有一个很棒的 +App Store 产品页面 + +144 +00:08:58,672 --> 00:09:02,409 +App Store 为您 +提供了对应的工具 + +145 +00:09:02,442 --> 00:09:04,611 +产品页面优化方面 + +146 +00:09:04,645 --> 00:09:07,314 +您可以测试不同的 App 图标 + +147 +00:09:07,347 --> 00:09:09,683 +屏幕截图和 App 预览 + +148 +00:09:09,716 --> 00:09:15,689 +找出哪些特征组合 +最适合您的客户 + +149 +00:09:15,722 --> 00:09:19,960 +并通过自定义产品页面 +针对不同的观众 + +150 +00:09:19,993 --> 00:09:21,562 +创建专注于特定兴趣 + +151 +00:09:21,595 --> 00:09:24,097 +独特的产品页面 + +152 +00:09:24,131 --> 00:09:28,235 +而不是为所有客户 +准备统一的产品页面 + +153 +00:09:28,268 --> 00:09:33,807 +这两个功能都可以帮助您 +提高您的转化率 + +154 +00:09:33,841 --> 00:09:36,410 +为了改善您的使用指标 + +155 +00:09:36,443 --> 00:09:39,947 +您可以借助 App 内活动 +和轻 App 功能 + +156 +00:09:39,980 --> 00:09:43,984 +App 内活动是 App 和游戏中 +具有时限的活动 + +157 +00:09:44,017 --> 00:09:46,019 +比如游戏比赛 + +158 +00:09:46,053 --> 00:09:49,456 +电影首映礼或直播体验 + +159 +00:09:49,489 --> 00:09:51,992 +您可以在 App Store 上展示 + +160 +00:09:52,025 --> 00:09:56,730 +吸引新顾客 并重新吸引现有顾客 + +161 +00:09:56,763 --> 00:09:59,933 +而轻 App 则是 +App 的一小部分 + +162 +00:09:59,967 --> 00:10:03,403 +方便人们在有关联的场景中发现 + +163 +00:10:03,437 --> 00:10:07,441 +并便捷地完成 +来自您 App 的快速任务 + +164 +00:10:07,474 --> 00:10:10,944 +比如 从餐厅点外卖、 + +165 +00:10:10,978 --> 00:10:14,214 +租一辆滑板车或 +第一次设置新的连接设备的时候 + +166 +00:10:14,248 --> 00:10:17,251 +人们就可以启动轻 App + +167 +00:10:17,284 --> 00:10:20,854 +轻松地开始和完成任务 + +168 +00:10:20,888 --> 00:10:23,891 +最后 为了提高您的收益 + +169 +00:10:23,924 --> 00:10:26,426 +您还可以尝试不同的价格等级 + +170 +00:10:26,460 --> 00:10:29,396 +以便用户可以根据他们的喜好 + +171 +00:10:29,429 --> 00:10:34,067 +以及他们想要支付的金额 +自定义用户体验 + +172 +00:10:34,101 --> 00:10:37,271 +或者您可以创建 App 内购买项目 +并进行推广 + +173 +00:10:37,304 --> 00:10:41,975 +允许用户直接在 App Store 上 +或甚至在他们下载 + +174 +00:10:42,009 --> 00:10:45,078 +您的 App 之前 就能发现 +您的待售 App 内购买项目 + +175 +00:10:45,112 --> 00:10:48,715 +总之 通过 +将对等组基准化 + +176 +00:10:48,749 --> 00:10:52,719 +和其它 App Store 工具相结合 +您就可以在您 App + +177 +00:10:52,753 --> 00:10:57,191 +需求量最大的地方 +取得重大进展 + +178 +00:10:57,224 --> 00:11:01,795 +请访问 +developer.apple.com/cn/app-store + +179 +00:11:01,828 --> 00:11:03,997 +了解更多相关信息 + +180 +00:11:04,031 --> 00:11:07,301 +对今天的内容 +我们来做一个快速的总结 + +181 +00:11:07,334 --> 00:11:10,437 +对等组基准化 +是一个令人兴奋的工具 + +182 +00:11:10,470 --> 00:11:13,874 +可以让您与 +商店中类似的 App 组对比 + +183 +00:11:13,907 --> 00:11:18,245 +各自在 App Store 中的表现 + +184 +00:11:18,278 --> 00:11:20,814 +我们设计了 +对等组基准化 + +185 +00:11:20,848 --> 00:11:25,052 +使用差分隐私技术 +在不透露信息的情况下 + +186 +00:11:25,085 --> 00:11:30,157 +提供针对单个 App 的相关见解 + +187 +00:11:30,190 --> 00:11:32,292 +使用对等组基准化 + +188 +00:11:32,326 --> 00:11:36,263 +与 App Store 中 +其它开发者功能相结合 + +189 +00:11:36,296 --> 00:11:42,369 +将能有效帮助您的 App 在 App Store 上 +进一步提升表现 + +190 +00:11:42,402 --> 00:11:47,007 +对等组基准化 +于明年初即将推出 + +191 +00:11:47,040 --> 00:11:48,942 +感谢收看 + diff --git a/zho/2022 Session 10045 What's new in managing Apple devices.srt b/zho/2022 Session 10045 What's new in managing Apple devices.srt new file mode 100644 index 0000000..427d416 --- /dev/null +++ b/zho/2022 Session 10045 What's new in managing Apple devices.srt @@ -0,0 +1,3430 @@ +1 +00:00:00,000 --> 00:00:03,770 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,770 --> 00:00:09,776 +♪ + +3 +00:00:09,776 --> 00:00:12,279 +Nadia Hussein: +欢迎来到 WWDC + +4 +00:00:12,279 --> 00:00:15,849 +我是 Nadia 我和我的 +同事 Graham 迫不及待 + +5 +00:00:15,849 --> 00:00:18,619 +想要和您分享 macOS Ventura +iOS 以及 iPadOS 16 上 + +6 +00:00:18,619 --> 00:00:25,993 +设备管理功能的相关新资讯 + +7 +00:00:25,993 --> 00:00:27,794 +在设备管理领域 + +8 +00:00:27,794 --> 00:00:30,731 +让员工蓬勃发展 + +9 +00:00:30,731 --> 00:00:32,533 +提高师生间的教学效率 + +10 +00:00:32,533 --> 00:00:35,068 +是我们共同的使命 + +11 +00:00:35,068 --> 00:00:37,905 +我们不断研发 + +12 +00:00:37,905 --> 00:00:41,842 +推动师生合作的工具和技术 + +13 +00:00:41,842 --> 00:00:45,746 +在 macOS Ventura +iOS 以及 iPadOS 16 中 + +14 +00:00:45,746 --> 00:00:48,615 +进行了许多优化升级 +并新增了不少功能 + +15 +00:00:48,615 --> 00:00:51,018 +本次讲座会提及部分上述内容 + +16 +00:00:51,018 --> 00:00:53,687 +但我首先想快速地强调一下 + +17 +00:00:53,687 --> 00:00:56,456 +您可以查看其他讲座 + +18 +00:00:56,456 --> 00:01:01,628 +来获取更多企业和 +教育空间的相关资讯 + +19 +00:01:01,628 --> 00:01:04,064 +在 WWDC 2021 上 + +20 +00:01:04,064 --> 00:01:06,767 +我们推出了声明式设备管理 + +21 +00:01:06,767 --> 00:01:08,769 +这一设备管理的新范式 + +22 +00:01:08,769 --> 00:01:11,572 +使设备变得更加自治和主动 + +23 +00:01:11,572 --> 00:01:14,775 +同时允许服务器 +更轻量化、反应更快 + +24 +00:01:14,775 --> 00:01:18,912 +今年我们继续增加 + +25 +00:01:18,912 --> 00:01:21,615 +声明式设备管理的平台支持和功能 + +26 +00:01:21,615 --> 00:01:23,417 +我们强烈推荐您观看 + +27 +00:01:23,417 --> 00:01:27,321 +《Adopt declarative +device management》讲座 + +28 +00:01:27,321 --> 00:01:30,891 +Apple Business Essentials +是一项一站式的订阅 + +29 +00:01:30,891 --> 00:01:34,027 +它可以无缝的整合设备管理 + +30 +00:01:34,027 --> 00:01:36,964 +提供 7*24 全天候 +支持和云存储 + +31 +00:01:36,964 --> 00:01:38,732 +有了 Apple Business Essentials + +32 +00:01:38,732 --> 00:01:42,636 +小型企业能够轻松管理 +每台 iPhone iPad + +33 +00:01:42,636 --> 00:01:45,939 +Mac 还有 Apple TV +面面俱到 + +34 +00:01:45,939 --> 00:01:49,076 +查看《探索 Apple Business Essentials》讲座 + +35 +00:01:49,076 --> 00:01:52,613 +了解更多信息 + +36 +00:01:52,613 --> 00:01:55,983 +托管设备证明是一项新的安全功能 + +37 +00:01:55,983 --> 00:01:57,484 +此功能使用 +Secure Enclave + +38 +00:01:57,484 --> 00:02:00,621 +为客户端设备提供强有力的保障 + +39 +00:02:00,621 --> 00:02:03,690 +比如身份识别和软件版本 + +40 +00:02:03,690 --> 00:02:07,060 +参与讲座《Discover +Managed Device Attestation》 + +41 +00:02:07,060 --> 00:02:09,963 +了解更多信息 + +42 +00:02:09,963 --> 00:02:12,566 +在本次讲座中 我们将探讨 + +43 +00:02:12,566 --> 00:02:16,203 +Apple Configurator +的新功能 + +44 +00:02:16,203 --> 00:02:20,140 +跨平台身份识别技术 + +45 +00:02:20,140 --> 00:02:23,977 +关于 macOS Ventura iOS +和 iPadOS 16 的协议变更 + +46 +00:02:23,977 --> 00:02:26,446 +iOS and iPadOS 16 + +47 +00:02:26,446 --> 00:02:31,451 +最后是激动人心的 +文档提供方式的变更 + +48 +00:02:31,451 --> 00:02:36,290 +我们先从 Apple +Configurator 讲起 + +49 +00:02:36,290 --> 00:02:41,228 +在 WWDC 2021 上 我们发布了 +iPhone 版本的 Apple Configurator + +50 +00:02:41,228 --> 00:02:43,430 +教育和企业用户 + +51 +00:02:43,430 --> 00:02:45,766 +都喜欢通过这个方案 + +52 +00:02:45,766 --> 00:02:50,904 +来进行所有 Mac 的 +自动设备注册 + +53 +00:02:50,904 --> 00:02:54,141 +有了 iPhone 版本的 Apple +Configurator + +54 +00:02:54,141 --> 00:02:56,376 +即便是常规购买渠道 +以外到手的 Mac + +55 +00:02:56,376 --> 00:02:58,712 +也能轻松添加到所属组织 +只要组织在 + +56 +00:02:58,712 --> 00:03:02,049 +Apple School Manager 或 +Apple Business Manager + +57 +00:03:02,049 --> 00:03:05,285 +在 Mac 上的设置助理中 + +58 +00:03:05,285 --> 00:03:07,487 +只需拿着您的 iPhone +用 Configurator + +59 +00:03:07,487 --> 00:03:10,224 +[铃声] 对准动态图片扫描 + +60 +00:03:10,224 --> 00:03:12,259 +Mac 将连接到网络 + +61 +00:03:12,259 --> 00:03:16,563 +并自动添加到您的组织当中 + +62 +00:03:16,563 --> 00:03:20,400 +1.0.1 版本带来了显著新支持 + +63 +00:03:20,400 --> 00:03:22,936 +只要在 Mac 上是可用的网络 + +64 +00:03:22,936 --> 00:03:24,638 +就能活用现有网络连接 + +65 +00:03:24,638 --> 00:03:31,111 +我们很高兴地宣布 +在 iOS 和 iPadOS 16 里 + +66 +00:03:31,111 --> 00:03:34,248 +iPhone 版本 Apple Configurator +现在也可以添加 + +67 +00:03:34,248 --> 00:03:38,919 +iPhone 和 iPad 设备 +到您的组织中去 + +68 +00:03:38,919 --> 00:03:43,290 +而且正如您预想那般 这俩种设备的添加 +跟 Mac 的添加操作无异 + +69 +00:03:43,290 --> 00:03:46,126 +这也是 Mac 版本 Configurator +的强势新功能 + +70 +00:03:46,126 --> 00:03:47,694 +运行着 Configurator 的 Mac + +71 +00:03:47,694 --> 00:03:50,364 +需要通过 USB + +72 +00:03:50,364 --> 00:03:53,767 +连接每个设备 + +73 +00:03:53,767 --> 00:03:56,537 +您扫描 iOS 和 iPadOS +Setup Assistant 面板时 + +74 +00:03:56,537 --> 00:03:59,406 +会发现跟 macOS 有所不同 + +75 +00:03:59,406 --> 00:04:02,342 +在 iOS 和 iPadOS 上 +显示的是“Wi-Fi”面板 + +76 +00:04:02,342 --> 00:04:05,078 +但在 macOS 上 +会显示“国家或地区”面板 + +77 +00:04:05,078 --> 00:04:09,449 +请留意 就跟 Mac 版的 +Configurator 使用一样 + +78 +00:04:09,449 --> 00:04:12,686 +在将任何设备添加到您的组织之前 + +79 +00:04:12,686 --> 00:04:14,154 +若该设备需要进行交互式激活操作 + +80 +00:04:14,154 --> 00:04:16,290 +例如 激活锁或蜂窝网络运营商激活 + +81 +00:04:16,290 --> 00:04:19,626 +都要手动处理 + +82 +00:04:19,626 --> 00:04:22,563 +运行 iOS 或 +iPadOS 16 的设备 + +83 +00:04:22,563 --> 00:04:25,832 +目前可在 +App Store 中下载 + +84 +00:04:25,832 --> 00:04:29,102 +iPhone 版本的 Apple +Configurator 加入组织 + +85 +00:04:29,102 --> 00:04:32,072 +我们接着介绍商业和教育版块的 + +86 +00:04:32,072 --> 00:04:34,842 +身份验证管理 + +87 +00:04:34,842 --> 00:04:38,512 +我们知道业界很注重身份验证管理 + +88 +00:04:38,512 --> 00:04:41,481 +Apple 也同样注重 + +89 +00:04:41,481 --> 00:04:44,952 +身份验证管理为用户提供连贯的体验 + +90 +00:04:44,952 --> 00:04:47,554 +同时保障用户数据安全 + +91 +00:04:49,456 --> 00:04:54,228 +我们的身份验证目标 +是让用户只用登录一次 + +92 +00:04:54,228 --> 00:04:55,429 +登录了一次后 + +93 +00:04:55,429 --> 00:04:59,299 +就能在操作系统中一直使用该身份 + +94 +00:04:59,299 --> 00:05:00,901 +我们在逐步实现这个目标 + +95 +00:05:00,901 --> 00:05:03,337 +研发了很多技术来支持这目标 + +96 +00:05:03,337 --> 00:05:06,206 +其中包括 macOS Ventura + +97 +00:05:06,206 --> 00:05:10,744 +iOS 和 +iPadOS 16 中的新功能 + +98 +00:05:10,744 --> 00:05:13,847 +Apple Business Manager 现与 +Google Workspace + +99 +00:05:13,847 --> 00:05:15,949 +共同成为 Identity Provider + +100 +00:05:15,949 --> 00:05:17,885 +进行联合身份验证 + +101 +00:05:17,885 --> 00:05:20,220 +这允许用户凭借自身工作凭证 + +102 +00:05:20,220 --> 00:05:23,190 +作为管理式 +Apple ID 去对 iOS + +103 +00:05:23,190 --> 00:05:27,594 +iPadOS 和 macOS +上的服务进行身份验证 + +104 +00:05:27,594 --> 00:05:29,863 +请别忘了打开 +Directory Sync + +105 +00:05:29,863 --> 00:05:31,798 +之前称之为 SCIM + +106 +00:05:31,798 --> 00:05:37,437 +来实现自动创建用户帐户 +为管理式 Apple ID + +107 +00:05:37,437 --> 00:05:40,841 +有了 Managed Apple ID +现通过 Apple 登录 + +108 +00:05:40,841 --> 00:05:42,676 +可以用在工作和学校中 + +109 +00:05:42,676 --> 00:05:44,745 +只要是支持 +通过 Apple 登录的 + +110 +00:05:44,745 --> 00:05:46,580 +App 就可以使用 + +111 +00:05:46,580 --> 00:05:49,183 +如果您想限制用户登录范围 + +112 +00:05:49,183 --> 00:05:50,717 +您可以选择允许在 +Apple 校园教务管理 + +113 +00:05:50,717 --> 00:05:53,153 +或 Apple Business Manager +中所有 App 中使用 + +114 +00:05:53,153 --> 00:05:56,456 +或允许部分添加到范围 +列表的 App 使用 + +115 +00:05:56,456 --> 00:05:57,791 +若想了解更多信息 请看 + +116 +00:05:57,791 --> 00:06:01,528 +《在工作和学校发现通过 Apple 登录》讲座 + +117 +00:06:01,528 --> 00:06:04,498 +另一值得留意的身份验证管理升级 + +118 +00:06:04,498 --> 00:06:06,333 +是 OAuth 支持 + +119 +00:06:06,333 --> 00:06:08,569 +在 iOS 和 +iPadOS 15 中 + +120 +00:06:08,569 --> 00:06:12,072 +我们运用了一个简单的 +准入令牌授权机制 + +121 +00:06:12,072 --> 00:06:15,909 +来允许 MDM 服务器 +验证用户身份 + +122 +00:06:15,909 --> 00:06:20,113 +而在 iOS 和 iPadOS 16 中 +我们将增加 OAuth 2 + +123 +00:06:20,113 --> 00:06:22,816 +作为另一种授权机制 + +124 +00:06:22,816 --> 00:06:25,452 +OAuth 给 MDM 服务器提供了 + +125 +00:06:25,452 --> 00:06:28,222 +各种已使用 +OAuth 的身份提供者 + +126 +00:06:28,222 --> 00:06:30,157 +作为选择 + +127 +00:06:30,157 --> 00:06:34,094 +它还依靠其令牌刷新 +机制提高了安全性 + +128 +00:06:34,094 --> 00:06:36,630 +该机制能够使用短期访问令牌 + +129 +00:06:36,630 --> 00:06:38,832 +加上无提示刷新 + +130 +00:06:38,832 --> 00:06:42,002 +这刷新方式不会主动 +提醒用户输入凭证 + +131 +00:06:42,002 --> 00:06:43,670 +OAuth 可与现有的 + +132 +00:06:43,670 --> 00:06:46,139 +帐户驱动的用户注册流程共用 + +133 +00:06:46,139 --> 00:06:49,910 +但当它跟下面提到的 +炫酷新功能结合使用时 + +134 +00:06:49,910 --> 00:06:52,346 +会提供更好的用户体验 + +135 +00:06:52,346 --> 00:06:56,049 +这个功能就是 +Enrollment Single Sign-on + +136 +00:06:56,049 --> 00:06:57,751 +简称 Enrollment SSO + +137 +00:06:57,751 --> 00:07:00,888 +这是一种通过对个人设备 + +138 +00:07:00,888 --> 00:07:02,723 +来进行单次身份验证的更快捷新的方法 + +139 +00:07:02,723 --> 00:07:05,726 +能够快速完成 MDM 注册 + +140 +00:07:05,726 --> 00:07:09,363 +并快速准入 +您组织的 App 和网站 + +141 +00:07:09,363 --> 00:07:12,466 +此新技术建立在一些 +现有技术的基础上 + +142 +00:07:12,466 --> 00:07:17,571 +iOS 13 为组织的 +App 和网站推出了 + +143 +00:07:17,571 --> 00:07:21,508 +可扩展 SSO +作为 SSO 的新配置 + +144 +00:07:21,508 --> 00:07:23,877 +而 iOS 和 iPadOS 15 + +145 +00:07:23,877 --> 00:07:25,746 +推出了帐户驱动的用户注册 + +146 +00:07:25,746 --> 00:07:27,714 +使得用户只需在设置 + +147 +00:07:27,714 --> 00:07:30,984 +中输入邮箱地址 就能注册 MDM + +148 +00:07:30,984 --> 00:07:33,086 +为了继续优化注册 + +149 +00:07:33,086 --> 00:07:35,689 +我们将这两种技术结合在一起 + +150 +00:07:35,689 --> 00:07:37,758 +因为我们知道 BYOD 设备 + +151 +00:07:37,758 --> 00:07:41,128 +是部署的重要组成部分 + +152 +00:07:41,128 --> 00:07:44,998 +首先 用户在设置中输入邮箱地址 + +153 +00:07:44,998 --> 00:07:47,000 +然后会有消息提示 +他们去 App Store + +154 +00:07:47,000 --> 00:07:48,669 +下载 App + +155 +00:07:48,669 --> 00:07:50,137 +这个 App 其中包含 + +156 +00:07:50,137 --> 00:07:52,606 +Enrollment Single Sign-on 扩展 + +157 +00:07:52,606 --> 00:07:56,643 +能够提供 +原生 UI 来完成身份验证步骤 + +158 +00:07:56,643 --> 00:07:58,712 +因为这是一个基于 App 的模型 + +159 +00:07:58,712 --> 00:08:02,416 +您可以使用 +您随意选择的身份验证技术 + +160 +00:08:02,416 --> 00:08:05,118 +作为用户 只需登录一次 + +161 +00:08:05,118 --> 00:08:08,222 +该 App 就无需再次登录并帮助 + +162 +00:08:08,222 --> 00:08:12,326 +您完成一系列注册流程 + +163 +00:08:12,326 --> 00:08:14,328 +激活 Enrollment Single Sign-on + +164 +00:08:14,328 --> 00:08:16,530 +主要需要四个组件 + +165 +00:08:16,530 --> 00:08:19,166 +首先 App 开发者 +需要更新 App + +166 +00:08:19,166 --> 00:08:22,769 +才能使用 +Enrollment SSO + +167 +00:08:22,769 --> 00:08:26,006 +接着 MDM 厂商联合 +MDM 协议客户端身份验证 + +168 +00:08:26,006 --> 00:08:30,644 +作为身份提供商 + +169 +00:08:30,644 --> 00:08:33,614 +然后管理员运用 +Apple 校园教务管理 + +170 +00:08:33,614 --> 00:08:37,217 +或 Apple Business Manager +设置管理式 Apple ID + +171 +00:08:37,217 --> 00:08:40,954 +最后 配置 MDM 服务器 +返回一个 URL + +172 +00:08:40,954 --> 00:08:42,523 +到身份验证响应标头 + +173 +00:08:42,523 --> 00:08:46,493 +中的 JSON 文档里 + +174 +00:08:46,493 --> 00:08:48,829 +既然我们讨论完这个功能的作用 + +175 +00:08:48,829 --> 00:08:54,568 +操作跟执行者 +下面我们继续深入了解细节 + +176 +00:08:54,568 --> 00:08:56,670 +接收到来自服务器的初始身份验证 + +177 +00:08:56,670 --> 00:09:00,040 +质询时 +会出现一个 HTTP 标头 + +178 +00:09:00,040 --> 00:09:02,609 +意味着能够使用 +Enrollment SSO + +179 +00:09:02,609 --> 00:09:04,311 +而且应该使用 + +180 +00:09:04,311 --> 00:09:08,215 +该标头的值将是客户端将用来 + +181 +00:09:08,215 --> 00:09:11,451 +下载 JSON 文档的 URL + +182 +00:09:11,451 --> 00:09:14,054 +此 JSON 文档包含所有 + +183 +00:09:14,054 --> 00:09:18,091 +客户端继续注册所需的详细信息 + +184 +00:09:18,091 --> 00:09:20,894 +“iTunesStoreID” +键的值 + +185 +00:09:20,894 --> 00:09:22,996 +必须参考注册时会用到的 + +186 +00:09:22,996 --> 00:09:26,466 +Enrollment Single Sign-on App + +187 +00:09:26,466 --> 00:09:29,803 +“AssociatedDomains”键与 + +188 +00:09:29,803 --> 00:09:35,876 +“ApplicationAttributes”可用的键相同 +都可以在这里配置 + +189 +00:09:35,876 --> 00:09:37,811 +最后“ConfigurationProfile” + +190 +00:09:37,811 --> 00:09:40,280 +应该是“Base64EncodedProfile” + +191 +00:09:40,280 --> 00:09:43,283 +里面包含至少一个 +可扩展 SSO 有效负载 + +192 +00:09:43,283 --> 00:09:48,622 +如果有需要 也可能 +包含证书有效负载 + +193 +00:09:48,622 --> 00:09:51,592 +我们会在即将推出的 +iOS 和 iPadOS 16 中 + +194 +00:09:51,592 --> 00:09:55,329 +为顾客提供此功能 + +195 +00:09:55,329 --> 00:09:57,564 +如果您有兴趣开发 + +196 +00:09:57,564 --> 00:09:59,266 +支持此功能的 App + +197 +00:09:59,266 --> 00:10:01,134 +您需要通过 Apple +Developer Program + +198 +00:10:01,134 --> 00:10:05,072 +申请新的Entitlement + +199 +00:10:05,072 --> 00:10:08,208 +不过 现在您可以在测试模式下 + +200 +00:10:08,208 --> 00:10:10,210 +就能进行开发 + +201 +00:10:10,210 --> 00:10:11,478 +这是 Enrollment +Single Sign-on + +202 +00:10:11,478 --> 00:10:13,547 +研发过程中的一个特殊的版本 + +203 +00:10:13,547 --> 00:10:14,815 +发放您测试您 App 的许可 + +204 +00:10:14,815 --> 00:10:19,286 +而且还是在 +上架 App Store 之前 + +205 +00:10:19,286 --> 00:10:20,754 +要想着手使用测试模式 + +206 +00:10:20,754 --> 00:10:22,823 +请前往设置的 Developer + +207 +00:10:22,823 --> 00:10:26,226 +启用 Enrollment +Single Sign-on 测试模式 + +208 +00:10:26,226 --> 00:10:28,929 +然后 您需要 +用新的 HTTP 标头 + +209 +00:10:28,929 --> 00:10:30,864 +跟相应的 JSON 文档 + +210 +00:10:30,864 --> 00:10:34,001 +配置您的身份验证响应 + +211 +00:10:34,001 --> 00:10:36,203 +接着在 VPN 和设备管理中 + +212 +00:10:36,203 --> 00:10:38,338 +开始注册 + +213 +00:10:38,338 --> 00:10:39,306 +在此期间 + +214 +00:10:39,306 --> 00:10:42,476 +系统将提示您 +安装 Single Sign-on + +215 +00:10:42,476 --> 00:10:45,546 +您可以使用任何可行 +渠道来安装此 App + +216 +00:10:45,546 --> 00:10:50,250 +例如 Xcode 或是 TestFlight 甚至 +Enterprise App Distribution + +217 +00:10:50,250 --> 00:10:55,556 +下载后 返回设置完成注册 + +218 +00:10:55,556 --> 00:10:58,292 +测试模式需要用到不同的标头来响应 + +219 +00:10:58,292 --> 00:11:02,729 +和修改过的 JSON 文档 + +220 +00:11:02,729 --> 00:11:06,934 +屏幕上是测试模式的 JSON 文档示例 + +221 +00:11:06,934 --> 00:11:08,969 +您可以看到“iTunesStoreID”键 + +222 +00:11:08,969 --> 00:11:11,238 +已被“AppIDs”键取代 + +223 +00:11:11,238 --> 00:11:13,540 +这个键的值是个字符串数组 + +224 +00:11:13,540 --> 00:11:16,510 +包含着能注册的 App ID + +225 +00:11:16,510 --> 00:11:21,081 +其余的都维持原样 + +226 +00:11:21,081 --> 00:11:24,952 +我们接着来探索 +Single Sign-on 扩展 + +227 +00:11:24,952 --> 00:11:27,788 +2019 年 iOS 13 和 +macOS Catalina 里有了 + +228 +00:11:27,788 --> 00:11:30,557 +Single Sign-On 插件 + +229 +00:11:30,557 --> 00:11:33,994 +身份提供商能够 +让其用户所使用的 App + +230 +00:11:33,994 --> 00:11:36,730 +和网站都用上 SSO 身份验证 + +231 +00:11:36,730 --> 00:11:39,166 +使用 SSO 扩展程序时 + +232 +00:11:39,166 --> 00:11:41,502 +设备解锁后 + +233 +00:11:41,502 --> 00:11:43,637 +会提示用户登录扩展程序 + +234 +00:11:43,637 --> 00:11:46,206 +这意味着要输入凭据两次 + +235 +00:11:46,206 --> 00:11:50,210 +如果一个组织同时使用 +内置的 Kerberos 扩展程序 + +236 +00:11:50,210 --> 00:11:52,379 +用户大概率都要重新登录 + +237 +00:11:52,379 --> 00:11:56,550 +很多情况下 身份凭证都是一样的 + +238 +00:11:56,550 --> 00:12:00,587 +因此 在 macOS Ventura 中 +我们准备推出 + +239 +00:12:00,587 --> 00:12:04,291 +Platform Single Sign-On +简称 Platform SSO + +240 +00:12:04,291 --> 00:12:07,728 +用户只需在登录窗口登录一次 + +241 +00:12:07,728 --> 00:12:12,599 +就能自动登录各 App 和网站了 + +242 +00:12:12,599 --> 00:12:15,102 +Platform SSO +在登录中生成令牌 + +243 +00:12:15,102 --> 00:12:17,838 +令牌可用于 +第三方 SSO 扩展程序 + +244 +00:12:17,838 --> 00:12:23,310 +也能与内置的 +Kerberos 扩展程序并行 + +245 +00:12:23,310 --> 00:12:26,580 +首次登录 +使用本地帐户密码进行身份验证 + +246 +00:12:26,580 --> 00:12:29,850 +同时也能解锁 +设备里的加密 FileVault + +247 +00:12:29,850 --> 00:12:32,419 +用户可以离线登录 + +248 +00:12:32,419 --> 00:12:35,422 +也可以连接 +Captive Network 登录 + +249 +00:12:35,422 --> 00:12:37,925 +这之后 身份提供商的密码 + +250 +00:12:37,925 --> 00:12:40,093 +也能用于解锁 + +251 +00:12:40,093 --> 00:12:43,430 +此外 Platform SSO +支持使用密码 + +252 +00:12:43,430 --> 00:12:45,299 +或 Secure Enclave +支持的密钥 + +253 +00:12:45,299 --> 00:12:47,835 +向身份提供商进行身份验证 + +254 +00:12:47,835 --> 00:12:50,270 +而且无论用了何种身份验证方法 + +255 +00:12:50,270 --> 00:12:53,373 +SSO 令牌能在身份提供者那检索 + +256 +00:12:53,373 --> 00:12:54,541 +存储在钥匙串中 + +257 +00:12:54,541 --> 00:12:57,678 +能用于 SSO 扩展程序 + +258 +00:12:57,678 --> 00:13:00,447 +也能检索 +Kerberos TGT + +259 +00:13:00,447 --> 00:13:02,015 +导入凭证缓存 + +260 +00:13:02,015 --> 00:13:05,319 +还能选择与 +Kerberos 扩展程序共享 + +261 +00:13:05,319 --> 00:13:08,055 +如果身份提供商密码变更了 + +262 +00:13:08,055 --> 00:13:10,290 +Platform SSO +将在解锁后 + +263 +00:13:10,290 --> 00:13:13,694 +向身份提供商验证新密码 + +264 +00:13:13,694 --> 00:13:16,496 +Platform SSO 是 +一个完整集成协议 + +265 +00:13:16,496 --> 00:13:18,999 +建立在使用 +OAuth 和 OpenID 之上 + +266 +00:13:18,999 --> 00:13:22,135 +且不需要打开网页进行身份验证 + +267 +00:13:22,135 --> 00:13:26,673 +Platform SSO +是 AD Binding + +268 +00:13:26,673 --> 00:13:28,408 +和移动帐户的新型替代品 + +269 +00:13:28,408 --> 00:13:31,411 +请注意 它不会直接使用目录服务 + +270 +00:13:31,411 --> 00:13:33,046 +或在每次解锁时 + +271 +00:13:33,046 --> 00:13:34,781 +与身份提供商验证身份 + +272 +00:13:34,781 --> 00:13:37,518 +反而只在用户尝试用新密码解锁 + +273 +00:13:37,518 --> 00:13:40,821 +或检索 SSO 令牌时 + +274 +00:13:40,821 --> 00:13:43,891 +身份提供商才会被调用 + +275 +00:13:43,891 --> 00:13:47,361 +Platform SSO 也不会 +基于身份提供商的响应 + +276 +00:13:47,361 --> 00:13:50,063 +而阻止登录 Mac + +277 +00:13:50,063 --> 00:13:52,299 +若想阻止登录 运用 MDM + +278 +00:13:52,299 --> 00:13:57,237 +或替代方案来禁用准入 + +279 +00:13:57,237 --> 00:13:58,906 +要想利用好 +Platform SSO + +280 +00:13:58,906 --> 00:14:02,009 +身份提供商需实现 SSO 协议 + +281 +00:14:02,009 --> 00:14:04,511 +更新他们的 SSO 扩展 + +282 +00:14:04,511 --> 00:14:07,447 +然后确保 +可扩展 SSO 评测已更新 + +283 +00:14:07,447 --> 00:14:11,952 +以支持托管设备上的新密钥 + +284 +00:14:11,952 --> 00:14:13,787 +更多实施详情 + +285 +00:14:13,787 --> 00:14:17,724 +请查看 +Apple Platform Deployment 指南 + +286 +00:14:17,724 --> 00:14:20,394 +总结一下 我们推出了 + +287 +00:14:20,394 --> 00:14:23,897 +跟 Google Workspace 的集成 +Enrollment SSO + +288 +00:14:23,897 --> 00:14:27,034 +OAuth 支持 +和 Platform SSO + +289 +00:14:27,034 --> 00:14:30,637 +以提供便捷的登录体验 + +290 +00:14:30,637 --> 00:14:34,408 +身份验证管理是一项日新月盛的技术 + +291 +00:14:34,408 --> 00:14:39,112 +我们仅仅是刚起步而已 +未来将更精彩 + +292 +00:14:39,112 --> 00:14:43,350 +macOS Ventura +进行了不少优化升级 + +293 +00:14:43,350 --> 00:14:45,419 +涵盖注册 安全方面和操作系统升级 + +294 +00:14:45,419 --> 00:14:49,723 +让我们从软件的更新说起 + +295 +00:14:49,723 --> 00:14:52,392 +macOS Monterey +对“托管软件更新” + +296 +00:14:52,392 --> 00:14:54,394 +进行了根本性的变革 + +297 +00:14:54,394 --> 00:14:57,497 +我的同事 Lucy 在 +《管理您组织中的软件更新》 + +298 +00:14:57,497 --> 00:15:00,300 +讲座中细讲了这点 + +299 +00:15:00,300 --> 00:15:05,339 +我们将操作系统更新分为三个方面 + +300 +00:15:05,339 --> 00:15:08,442 +测试 部署和执行 + +301 +00:15:08,442 --> 00:15:11,245 +今年 我们更多地专注于 + +302 +00:15:11,245 --> 00:15:15,148 +升级部署和执行这两方面 + +303 +00:15:15,148 --> 00:15:18,886 +回顾历史 命令在 +“电能小憩”模式下发送时 + +304 +00:15:18,886 --> 00:15:21,088 +每次操作系统更新命令后 +返回的都是“NotNow” + +305 +00:15:21,088 --> 00:15:23,390 +为了提供更加连贯和 + +306 +00:15:23,390 --> 00:15:27,094 +稳健的操作系统更新部署 +即使设备处于睡眠状态 + +307 +00:15:27,094 --> 00:15:31,598 +或“电能小憩”模式 +设备现将识别并响应 + +308 +00:15:31,598 --> 00:15:34,001 +“ScheduleOSUpdate” +“OSUpdateStatus” + +309 +00:15:34,001 --> 00:15:37,571 +以及“AvailableOSUpdate”命令 + +310 +00:15:37,571 --> 00:15:40,541 +另外因为我们也理解管理员有时 + +311 +00:15:40,541 --> 00:15:43,410 +想要尽快更新操作系统 + +312 +00:15:43,410 --> 00:15:46,480 +我们引入了一个新的名为“priority”的键 + +313 +00:15:46,480 --> 00:15:49,249 +通过“ScheduleOSUpdate”命令发送 + +314 +00:15:49,249 --> 00:15:51,852 +选择“High” +或“Low”字符串值 + +315 +00:15:51,852 --> 00:15:53,420 +该值控制调度下载 + +316 +00:15:53,420 --> 00:15:56,356 +和准备已请求更新的优先级 + +317 +00:15:56,356 --> 00:15:58,458 +发送“High”优先级 +命令将在系统设置中 + +318 +00:15:58,458 --> 00:16:01,428 +模仿成像用户 + +319 +00:16:01,428 --> 00:16:03,297 +自己请求更新的样子 + +320 +00:16:03,297 --> 00:16:08,535 +请留意 这个键仅支持 +小型的操作系统更新 + +321 +00:16:08,535 --> 00:16:13,140 +在 macOS 12.3 里 我们运用 +“OSUpdateStatus”命令 + +322 +00:16:13,140 --> 00:16:19,346 +提升了更多日志和报告的管理可见性 + +323 +00:16:19,346 --> 00:16:22,649 +“DeferralsRemaining”指的是提示 + +324 +00:16:22,649 --> 00:16:26,286 +用户更新的通知剩下多少次 + +325 +00:16:26,286 --> 00:16:28,789 +“MaxDeferrals”表示 + +326 +00:16:28,789 --> 00:16:34,528 +允许用户推迟操作系统 +更新通知的总次数 + +327 +00:16:34,528 --> 00:16:36,864 +“NextScheduledInstall” +是操作系统 + +328 +00:16:36,864 --> 00:16:40,601 +将尝试下次安装更新的日期 + +329 +00:16:40,601 --> 00:16:44,538 +最后是“PastNotifications” + +330 +00:16:44,538 --> 00:16:49,042 +代表通知推送给用户 +时的确切时间和日期 + +331 +00:16:49,042 --> 00:16:52,112 +所有这些 OSUpdateStatus 命令的更新 + +332 +00:16:52,112 --> 00:16:53,647 +对管理员进一步明确 + +333 +00:16:53,647 --> 00:16:58,919 +其用户的合规性都很有帮助 + +334 +00:16:58,919 --> 00:17:02,422 +macOS Ventura +iOS 和 iPadOS 16 + +335 +00:17:02,422 --> 00:17:03,924 +正在推出一种新机制 + +336 +00:17:03,924 --> 00:17:07,895 +能够更快地向用户发送 +重要的安全修复程序 + +337 +00:17:07,895 --> 00:17:10,030 +即 Rapid Security Response + +338 +00:17:10,030 --> 00:17:12,933 +它不会修改固件 + +339 +00:17:12,933 --> 00:17:14,735 +而且如有必要 用户也可以删除 + +340 +00:17:14,735 --> 00:17:18,238 +为此 我们推出了两个限制键 + +341 +00:17:18,238 --> 00:17:21,175 +用“allowRapidSecurityResponseInstallation” + +342 +00:17:21,175 --> 00:17:24,611 +能够让这新型安全响应机制失效 + +343 +00:17:24,611 --> 00:17:27,447 +而用“allowRapidSecurityResponseRemoval” + +344 +00:17:27,447 --> 00:17:28,882 +能阻止终端用户 + +345 +00:17:28,882 --> 00:17:34,354 +删除 Rapid Security Response + +346 +00:17:34,354 --> 00:17:39,393 +接下来 我们谈谈注册方面的变更 + +347 +00:17:39,393 --> 00:17:42,896 +设备自动注册流程简化 + +348 +00:17:42,896 --> 00:17:45,699 +从设备拆箱 激活到 + +349 +00:17:45,699 --> 00:17:50,237 +在该组织的 +MDM 解决方案下注册 + +350 +00:17:50,237 --> 00:17:51,905 +即将发布的版本里 + +351 +00:17:51,905 --> 00:17:54,007 +抹掉或恢复 Mac 后 + +352 +00:17:54,007 --> 00:17:56,009 +在“Apple 校园教务管理” + +353 +00:17:56,009 --> 00:17:57,644 +或“Apple Business Manager ” + +354 +00:17:57,644 --> 00:18:00,147 +中注册到您的组织的设备 + +355 +00:18:00,147 --> 00:18:03,750 +将需要连接网络来使用“设置助手” + +356 +00:18:03,750 --> 00:18:05,786 +Mac 首次设置好 + +357 +00:18:05,786 --> 00:18:07,621 +并连接到网络后 + +358 +00:18:07,621 --> 00:18:11,425 +这台 Mac 就确认好 +归组织所有了 + +359 +00:18:11,425 --> 00:18:14,094 +假如 MDM 后来发动 + +360 +00:18:14,094 --> 00:18:16,196 +“删除所有内容和设置”操作 + +361 +00:18:16,196 --> 00:18:18,866 +如果设备是通过 +Configurator 恢复的 + +362 +00:18:18,866 --> 00:18:20,534 +那么不论是网络 + +363 +00:18:20,534 --> 00:18:22,336 +还是设备注册 + +364 +00:18:22,336 --> 00:18:25,138 +都无法在“设置助手”中绕过 + +365 +00:18:25,138 --> 00:18:27,241 +请继续关注 +AppleSeed for IT + +366 +00:18:27,241 --> 00:18:31,645 +获取发布时间说明 + +367 +00:18:31,645 --> 00:18:34,381 +描述文件命令行工具已成为重要工具 + +368 +00:18:34,381 --> 00:18:37,251 +多年来作为管理工具 + +369 +00:18:37,251 --> 00:18:39,887 +用于 MDM 部署 迁移和报告 + +370 +00:18:39,887 --> 00:18:44,725 +我们现对其在 macOS Ventura +中的使用进行了更新 + +371 +00:18:44,725 --> 00:18:46,126 +描述文件工具 +在 macOS 上的使用 + +372 +00:18:46,126 --> 00:18:49,429 +将实施速率限制 + +373 +00:18:49,429 --> 00:18:50,764 +该工具将仅为 + +374 +00:18:50,764 --> 00:18:52,933 +组织注册类型开放 + +375 +00:18:52,933 --> 00:18:57,004 +拥有“show” “ renew”和 +“validate”三个命令 + +376 +00:18:57,004 --> 00:19:00,541 +每个命令每天最多接收 +来自服务器的 10 个请求 + +377 +00:19:00,541 --> 00:19:03,510 +如果超过该数量 + +378 +00:19:03,510 --> 00:19:06,580 +结果将以缓存信息返回 + +379 +00:19:06,580 --> 00:19:09,349 +如果您不想用掉 10 个 +请求中的一次机会 + +380 +00:19:09,349 --> 00:19:11,385 +“show”命令有一个可选新标记 + +381 +00:19:11,385 --> 00:19:14,054 +来返回缓存的信息 + +382 +00:19:14,054 --> 00:19:15,923 +详情请参阅“profile manual page” + +383 +00:19:15,923 --> 00:19:20,060 +了解更多 + +384 +00:19:20,060 --> 00:19:23,263 +每次 macOS 版本上新 +我们都在为我们的用户 + +385 +00:19:23,263 --> 00:19:26,600 +不断提升保护能力 + +386 +00:19:26,600 --> 00:19:32,506 +下面是一些即将上线且 +值得关注的安全变更 + +387 +00:19:32,506 --> 00:19:35,275 +在 iOS 10.3 中 +我们推出了一项 + +388 +00:19:35,275 --> 00:19:38,779 +证书有效负载的 +默认 TLS 信任策略变更 + +389 +00:19:38,779 --> 00:19:41,915 +以加强对用户的整体保护 + +390 +00:19:41,915 --> 00:19:45,319 +即将到来的上新环节 我们将把 +此变更带到 macOS 中去 + +391 +00:19:45,319 --> 00:19:48,522 +这意味着手动安装的证书有效负载 + +392 +00:19:48,522 --> 00:19:51,925 +将不再受 TLS 意图的信任 + +393 +00:19:51,925 --> 00:19:56,196 +除非用户信任授权其 +使用“钥匙串访问” + +394 +00:19:56,196 --> 00:19:59,666 +请注意 如果证书是嵌入 +在 MDM 描述文件中的 + +395 +00:19:59,666 --> 00:20:03,270 +那么我们仍将继续完全信任证书 + +396 +00:20:03,270 --> 00:20:05,672 +但在涉及交互式证书安装的情况下 + +397 +00:20:05,672 --> 00:20:11,044 +请务必更新相关工作流程 + +398 +00:20:11,044 --> 00:20:14,781 +接着是 macOS 上的 +“允许配件连接” + +399 +00:20:14,781 --> 00:20:18,385 +其旨在保护我们的客户 +免受近距离访问攻击 + +400 +00:20:18,385 --> 00:20:21,622 +在配备了“Apple 设计的芯片”的 +便携式 Mac 上受支持 + +401 +00:20:21,622 --> 00:20:24,191 +初始配置是即使在解锁状态下 + +402 +00:20:24,191 --> 00:20:27,461 +也要询问用户来允许 + +403 +00:20:27,461 --> 00:20:30,898 +新的“雷雳”或 USB 配件 + +404 +00:20:30,898 --> 00:20:33,133 +获批准的配件 +可连接上着锁的 Mac + +405 +00:20:33,133 --> 00:20:34,801 +长达三天时间 + +406 +00:20:34,801 --> 00:20:37,504 +如果您将未知配件 +连接到锁着的 Mac + +407 +00:20:37,504 --> 00:20:40,040 +系统将提示您解锁 Mac + +408 +00:20:40,040 --> 00:20:43,110 +从 MDM 的角度来看 +我们理解这可能 + +409 +00:20:43,110 --> 00:20:45,646 +影响企业和教育工作流程 + +410 +00:20:45,646 --> 00:20:48,148 +例如批量配置或测试 + +411 +00:20:48,148 --> 00:20:51,084 +为了解决这个问题 +我们准备给 macOS + +412 +00:20:51,084 --> 00:20:54,821 +使用在 iOS 和 iPadOS +上相同的限制条件 + +413 +00:20:54,821 --> 00:20:58,225 +现有的“allowUSBRestrictedMode”限制 + +414 +00:20:58,225 --> 00:20:59,660 +将允许有线配件 + +415 +00:20:59,660 --> 00:21:02,963 +没有任何限制一直保持连接 + +416 +00:21:02,963 --> 00:21:04,464 +该限制能忽略 + +417 +00:21:04,464 --> 00:21:07,568 +需用户同意的要求 提供授权 + +418 +00:21:07,568 --> 00:21:08,836 +还请知晓 + +419 +00:21:08,836 --> 00:21:12,873 +这操作本质上会降低 +用户系统的安全性 + +420 +00:21:12,873 --> 00:21:14,975 +所以请仅在您有 + +421 +00:21:14,975 --> 00:21:19,613 +合法的企业需求的情况下 +使用此限制 + +422 +00:21:19,613 --> 00:21:22,282 +至于其他限制和有效载荷修改 + +423 +00:21:22,282 --> 00:21:24,518 +比如新的“allowUniversalControl” + +424 +00:21:24,518 --> 00:21:27,221 +和“UIConfigurationProfileInstallation” + +425 +00:21:27,221 --> 00:21:29,990 +请务必查看文档 + +426 +00:21:29,990 --> 00:21:32,960 +感谢收听即将面世的 +macOS Ventura + +427 +00:21:32,960 --> 00:21:34,962 +一系列激动人心的变化 + +428 +00:21:34,962 --> 00:21:38,432 +现在我将把舞台交给 +Graham 来谈谈 iOS + +429 +00:21:38,432 --> 00:21:39,399 +Graham McLuhan:谢谢 Nadia + +430 +00:21:39,399 --> 00:21:41,134 +我很高兴今天能借此机会告诉您 + +431 +00:21:41,134 --> 00:21:43,403 +在 iOS +和 iPadOS 16 中 + +432 +00:21:43,403 --> 00:21:47,407 +上新的大量出众设备管理功能 + +433 +00:21:47,407 --> 00:21:49,676 +我们知道管理设备上的网络流量 + +434 +00:21:49,676 --> 00:21:53,146 +是提高数据安全性的重要方式 + +435 +00:21:53,146 --> 00:21:54,414 +您管理 Apple 设备上的 + +436 +00:21:54,414 --> 00:21:57,050 +流量主要有三种方式 + +437 +00:21:57,050 --> 00:22:01,188 +VPN 以及 DNS Proxy 和 +Web Content Filter + +438 +00:22:01,188 --> 00:22:04,458 +多年来 我们一直 +提供 Per-app VPN + +439 +00:22:04,458 --> 00:22:06,360 +实际上 对于用户注册的设备来说 + +440 +00:22:06,360 --> 00:22:10,597 +这款 VPN +是 MDM 唯一可用的类型 + +441 +00:22:10,597 --> 00:22:12,699 +在 iOS +和 iPadOS 16 中 + +442 +00:22:12,699 --> 00:22:14,635 +我们准备扩宽“Per-app” +线的产品类型 + +443 +00:22:14,635 --> 00:22:17,871 +将把 DNS Proxy 和 Web +Content Filter 也包括进去 + +444 +00:22:17,871 --> 00:22:20,674 +这类功能可用于所有注册类型 + +445 +00:22:20,674 --> 00:22:22,776 +但我们认为用在用户注册 + +446 +00:22:22,776 --> 00:22:23,911 +它们会特别好用 + +447 +00:22:23,911 --> 00:22:25,712 +因为这是组织第一次 + +448 +00:22:25,712 --> 00:22:29,583 +能够通过这种方式保护 BYOD +设备 App 流量 + +449 +00:22:29,583 --> 00:22:32,553 +配置这些新功能需要两步 + +450 +00:22:32,553 --> 00:22:35,355 +而且跟配置 +Per-App VPN 差不多 + +451 +00:22:35,355 --> 00:22:38,992 +我们快速了解一下操作步骤 + +452 +00:22:38,992 --> 00:22:41,595 +首先 您需要添加一个新的键值对 + +453 +00:22:41,595 --> 00:22:43,130 +到每个有效负载 + +454 +00:22:43,130 --> 00:22:45,098 +在 Web Content Filter +有效负载中 + +455 +00:22:45,098 --> 00:22:47,701 +用的键是“ContentFilterUUID” + +456 +00:22:47,701 --> 00:22:52,039 +对于 DNS Proxy 来说 +用的键是“DNSProxyUUID” + +457 +00:22:52,039 --> 00:22:55,008 +使用这些键需要注意一些事项 + +458 +00:22:55,008 --> 00:22:59,746 +首先 这些键的值可以是任意字符串 + +459 +00:22:59,746 --> 00:23:02,482 +其次 当这个键被添加到 Payload 时 + +460 +00:23:02,482 --> 00:23:05,452 +它只能通过 MDM 安装 + +461 +00:23:05,452 --> 00:23:09,356 +然后 我们需要配置 +App 来使用这些新功能 + +462 +00:23:09,356 --> 00:23:11,592 +使用“InstallApplication”命令 + +463 +00:23:11,592 --> 00:23:13,493 +或“Settings”命令 + +464 +00:23:13,493 --> 00:23:16,530 +把相同的 UUID +添加到 App 的属性中 + +465 +00:23:16,530 --> 00:23:18,699 +属性将运用“Per-app”的功能 + +466 +00:23:18,699 --> 00:23:21,301 +在这个示例中 我们把 +两个键都包含进去了 + +467 +00:23:21,301 --> 00:23:25,072 +但您可以只包含其中任意一个键 + +468 +00:23:25,072 --> 00:23:27,774 +另外 我还想指出一些细节的地方 + +469 +00:23:27,774 --> 00:23:31,845 +首先 App 开发者 +无需新做任何事物 + +470 +00:23:31,845 --> 00:23:34,781 +一切现有的 DNS Proxy 和 +Web Content Filter App + +471 +00:23:34,781 --> 00:23:36,650 +都能使用 + +472 +00:23:36,650 --> 00:23:39,586 +其次 您可以拥有 +多个 DNS Proxy + +473 +00:23:39,586 --> 00:23:43,490 +但您不能混用用于系统的 +和用于一个 App 的代理 + +474 +00:23:43,490 --> 00:23:46,260 +最后 对于 +Web Content Filter 类型来说 + +475 +00:23:46,260 --> 00:23:48,228 +Per-app 过滤器 +最多可有七个 + +476 +00:23:48,228 --> 00:23:51,965 +用于系统的过滤器能有一个 + +477 +00:23:51,965 --> 00:23:54,735 +接下来 我想谈谈管理 eSIM + +478 +00:23:54,735 --> 00:23:56,670 +eSIM 对于世界各地的运营商 + +479 +00:23:56,670 --> 00:23:59,706 +已成为新标准 在过去的几年里 + +480 +00:23:59,706 --> 00:24:01,742 +我们添加了些许 MDM 功能 + +481 +00:24:01,742 --> 00:24:04,878 +让管理 eSIM +变得前所未有的轻松 + +482 +00:24:04,878 --> 00:24:07,181 +我们想花点时间谈谈 +MDM 供应商如何 + +483 +00:24:07,181 --> 00:24:09,082 +把这些功能结合起来 + +484 +00:24:09,082 --> 00:24:11,919 +以提供更好的体验 + +485 +00:24:11,919 --> 00:24:14,421 +当我们与 +使用 eSIM 的组织交流时 + +486 +00:24:14,421 --> 00:24:16,256 +他们正在做的主要任务有 + +487 +00:24:16,256 --> 00:24:18,759 +配备新设备 + +488 +00:24:18,759 --> 00:24:20,727 +在运营商之间迁移设备 + +489 +00:24:20,727 --> 00:24:22,596 +还有帮助有需要的用户 + +490 +00:24:22,596 --> 00:24:27,067 +要解决的有多个运营商的问题 +或传送和漫游的相关问题 + +491 +00:24:27,067 --> 00:24:28,335 +为了完成这些任务 + +492 +00:24:28,335 --> 00:24:30,771 +他们要从已注册的设备中查询数据 + +493 +00:24:30,771 --> 00:24:33,140 +并将收集好的数据提供给运营商 + +494 +00:24:33,140 --> 00:24:34,808 +然后 他们得能 + +495 +00:24:34,808 --> 00:24:38,178 +在设备上安装 eSIM + +496 +00:24:38,178 --> 00:24:40,113 +让我们先从着手探讨 + +497 +00:24:40,113 --> 00:24:42,449 +设备查询和运营商数据要求 + +498 +00:24:42,449 --> 00:24:44,985 +“DeviceInformation” +查询是收集设备数据 + +499 +00:24:44,985 --> 00:24:46,954 +最简单的方法 + +500 +00:24:46,954 --> 00:24:49,656 +在 iOS 12 中 +“ServiceSubscriptions” + +501 +00:24:49,656 --> 00:24:52,726 +是一站式收集 +iPhone 和 iPad 上 + +502 +00:24:52,726 --> 00:24:57,397 +所有关于蜂窝网络数据的键 + +503 +00:24:57,397 --> 00:25:01,068 +查看这些响应时 说几个 +您可能会觉得有用的点 + +504 +00:25:01,068 --> 00:25:04,338 +在“ServiceSubscriptions” +中返回两个项的设备 + +505 +00:25:04,338 --> 00:25:07,541 +支持两个活跃的蜂窝网络计划 + +506 +00:25:07,541 --> 00:25:11,678 +如果响应包含 EID +那么设备用的是 eSIM + +507 +00:25:11,678 --> 00:25:15,916 +较新的设备 例如 iPhone 13 +和 iPhone SE (第 3 代) + +508 +00:25:15,916 --> 00:25:19,119 +支持双活跃运营商 +eSIM 描述文件 + +509 +00:25:19,119 --> 00:25:21,121 +因在“ServiceSubscriptions” +响应中 + +510 +00:25:21,121 --> 00:25:24,024 +可能有不止一个 eSIM 返回 + +511 +00:25:24,024 --> 00:25:28,128 +还请注意 每个设备的 EID +都是独一无二的 + +512 +00:25:28,128 --> 00:25:30,898 +从 iOS +和 iPadOS 16 开始 + +513 +00:25:30,898 --> 00:25:33,367 +返回数据的 +“otherDeviceInformation”查询 + +514 +00:25:33,367 --> 00:25:36,036 +不再会出现在 +“ServiceSubscriptions”响应 + +515 +00:25:36,036 --> 00:25:38,472 +一同响应的做法现已弃用 + +516 +00:25:38,472 --> 00:25:41,708 +且在以后的操作系统都不会返回 + +517 +00:25:41,708 --> 00:25:43,877 +既然我们知道了如何 +从设备中获取数据 + +518 +00:25:43,877 --> 00:25:47,014 +现在我们来看我们需要给运营商什么 + +519 +00:25:47,014 --> 00:25:49,483 +一般来说 运营商需要四类数据 + +520 +00:25:49,483 --> 00:25:51,919 +为设备设置 eSIM + +521 +00:25:51,919 --> 00:25:56,790 +IMEI 和 EID +序列号还有电话号码 + +522 +00:25:56,790 --> 00:25:59,159 +让您的管理员能够生成 + +523 +00:25:59,159 --> 00:26:01,895 +包含这些数据的报告 + +524 +00:26:01,895 --> 00:26:04,198 +会让其更容易启动并运行 eSIM + +525 +00:26:04,198 --> 00:26:06,400 +我们来总结回顾一下 + +526 +00:26:06,400 --> 00:26:08,635 +如何配备 eSIM + +527 +00:26:08,635 --> 00:26:12,272 +首先 MDM 服务器使用 +“ServiceSubscriptions”查询 + +528 +00:26:12,272 --> 00:26:15,542 +在设备中收集所需的数据 + +529 +00:26:15,542 --> 00:26:19,313 +然后 管理员将数据发送给运营商 + +530 +00:26:19,313 --> 00:26:22,282 +最后 运营商在其 +eSIM 服务器上 + +531 +00:26:22,282 --> 00:26:24,117 +为设备配备 eSIM + +532 +00:26:24,117 --> 00:26:25,619 +我们现在可以把注意力 + +533 +00:26:25,619 --> 00:26:28,755 +放到设备安装 eSIM 上 + +534 +00:26:28,755 --> 00:26:31,859 +运营商将向客户提供服务器 URL + +535 +00:26:31,859 --> 00:26:33,360 +设备可以通过 +“RefreshCellularPlans”命令 + +536 +00:26:33,360 --> 00:26:37,331 +在 URL 中获取 eSIM + +537 +00:26:37,331 --> 00:26:38,966 +MDM 服务器将发送 + +538 +00:26:38,966 --> 00:26:41,602 +“RefreshCellularPlans”命令至设备 + +539 +00:26:41,602 --> 00:26:44,505 +这会向运营商的 +eSIM 服务器发起请求 + +540 +00:26:44,505 --> 00:26:46,807 +并检查有没有可用的 eSIM + +541 +00:26:46,807 --> 00:26:49,543 +如果有 MDM 会自动 +下载并安装 eSIM + +542 +00:26:49,543 --> 00:26:52,880 +无需任何用户交互 + +543 +00:26:52,880 --> 00:26:56,049 +然后 MDM 服务器可以使用 +“ServiceSubscriptions”查询 + +544 +00:26:56,049 --> 00:26:59,152 +当查询返回的是非空号时 + +545 +00:26:59,152 --> 00:27:03,123 +就能确认 eSIM 已成功安装 + +546 +00:27:03,123 --> 00:27:04,992 +现在我们来谈谈几个 + +547 +00:27:04,992 --> 00:27:07,227 +您应该记住的关键点 + +548 +00:27:07,227 --> 00:27:09,963 +eSIM 安装是一次性操作 + +549 +00:27:09,963 --> 00:27:13,333 +以及未来在同一设备上 +安装 eSIM 的请求 + +550 +00:27:13,333 --> 00:27:16,670 +会要求运营商配备新的 eSIM + +551 +00:27:16,670 --> 00:27:18,205 +为防止用户意外 + +552 +00:27:18,205 --> 00:27:19,673 +移除自己的 eSIM + +553 +00:27:19,673 --> 00:27:22,910 +使用“allowESIMModification”限制 + +554 +00:27:22,910 --> 00:27:25,412 +还要注意“RefreshCellularPlans”命令 + +555 +00:27:25,412 --> 00:27:28,882 +在安装限制的情况下 +可以安装 eSIM + +556 +00:27:28,882 --> 00:27:31,952 +最后 MDM 清除设备时也可以 + +557 +00:27:31,952 --> 00:27:33,554 +把 eSIM 移除掉 + +558 +00:27:33,554 --> 00:27:37,591 +为避免这种情况 发送 +“EraseDevice”命令时请务必将 + +559 +00:27:37,591 --> 00:27:39,793 +“PreserveDataPlan”键 +设置为“True” + +560 +00:27:39,793 --> 00:27:42,496 +我们希望这些信息就如何管理 + +561 +00:27:42,496 --> 00:27:45,666 +和部署 eSIM +提供了更清晰的理解 + +562 +00:27:45,666 --> 00:27:49,570 +接下来 让我们来谈谈 +共享 iPad 的一些更新 + +563 +00:27:49,570 --> 00:27:53,106 +共享 iPad 是教育 +和商业客户的好伙伴 + +564 +00:27:53,106 --> 00:27:55,576 +能一对多环境中使用 iPad + +565 +00:27:55,576 --> 00:27:58,846 +同时还能为用户提供个性化体验 + +566 +00:27:58,846 --> 00:28:00,280 +我们今年做了些许变更 + +567 +00:28:00,280 --> 00:28:04,051 +能把共享 iPad 做得更好 + +568 +00:28:04,051 --> 00:28:07,654 +首先 我们把 +“ManagedAppleIDDefaultDomains”添加 + +569 +00:28:07,654 --> 00:28:10,557 +到了“SharedDeviceConfiguration”设置命令 + +570 +00:28:10,557 --> 00:28:12,993 +有了这命令 您将能够节省用户 + +571 +00:28:12,993 --> 00:28:18,065 +使用快速输入键盘输入 +管理式 Apple ID 的时间 + +572 +00:28:18,065 --> 00:28:20,701 +只要用户开始输入 +管理式 Apple ID + +573 +00:28:20,701 --> 00:28:22,469 +显示您域名的输入建议 + +574 +00:28:22,469 --> 00:28:25,105 +将自动出现供用户点击使用 + +575 +00:28:25,105 --> 00:28:27,975 +这个设置命令将接受任何大小的列表 + +576 +00:28:27,975 --> 00:28:32,513 +但只会向用户显示其中三个用户 + +577 +00:28:32,513 --> 00:28:33,747 +我们还对 + +578 +00:28:33,747 --> 00:28:36,350 +远程认证的要求进行了变更 + +579 +00:28:36,350 --> 00:28:39,386 +目前共享 iPad +大概每 7 天要求 + +580 +00:28:39,386 --> 00:28:41,722 +进行一次远程身份验证 + +581 +00:28:41,722 --> 00:28:46,059 +在 iPadOS 16 中 共享 iPad +将对于设备上的现有用户 + +582 +00:28:46,059 --> 00:28:48,996 +仅需要进行本地验证 + +583 +00:28:48,996 --> 00:28:51,532 +如果管理员想要强制 +执行远程身份验证 + +584 +00:28:51,532 --> 00:28:52,533 +管理员可以 + +585 +00:28:52,533 --> 00:28:54,935 +在“SharedDeviceConfiguration”设置命令中 + +586 +00:28:54,935 --> 00:28:57,771 +设置“OnlineAuthenticationGracePeriod”键 + +587 +00:28:57,771 --> 00:29:00,174 +该键将是一个整数值 表示 + +588 +00:29:00,174 --> 00:29:03,210 +两次远程身份验证相隔的天数 + +589 +00:29:03,210 --> 00:29:06,280 +零值则需要所有登录 + +590 +00:29:06,280 --> 00:29:08,315 +都进行远程身份验证 + +591 +00:29:08,315 --> 00:29:11,118 +“ManagedAppleIDDefaultDomains”值 + +592 +00:29:11,118 --> 00:29:13,820 +和“OnlineAuthenticationGracePeriod”值 + +593 +00:29:13,820 --> 00:29:18,025 +可以通过 +“DeviceInformation”查询检索到 + +594 +00:29:18,025 --> 00:29:20,260 +最后 我想围绕共享 iPad 配额 + +595 +00:29:20,260 --> 00:29:22,829 +如何明确提供一些帮助 + +596 +00:29:22,829 --> 00:29:24,331 +“SharedDeviceConfiguration”命令 + +597 +00:29:24,331 --> 00:29:27,768 +是在共享 iPad 上 +管理配额的最佳方式 + +598 +00:29:27,768 --> 00:29:31,138 +您可以使用两个相关键来设置配额 + +599 +00:29:31,138 --> 00:29:34,107 +“QuotaSize”和 +“ResidentUsers” + +600 +00:29:34,107 --> 00:29:36,543 +无论您选择设置哪个键 + +601 +00:29:36,543 --> 00:29:40,180 +最终操作系统都会计算存储配额 + +602 +00:29:40,180 --> 00:29:43,217 +我们来看一个例子 + +603 +00:29:43,217 --> 00:29:48,488 +这台 iPad 有 35 GB 的可用 +空间能用于存储用户数据 + +604 +00:29:48,488 --> 00:29:51,291 +如果我发送 +“SharedDeviceConfigurationSettings”命令 + +605 +00:29:51,291 --> 00:29:54,261 +要求设备将 +“ResidentUsers”设置为三个 + +606 +00:29:54,261 --> 00:29:59,166 +它将计算出 +每个用户的配额为 11.67 GB + +607 +00:29:59,166 --> 00:30:00,868 +或者 如果我要求设备 + +608 +00:30:00,868 --> 00:30:03,070 +配额大小为 10 GB + +609 +00:30:03,070 --> 00:30:06,840 +每个用户将有 10 GB 的配额 + +610 +00:30:06,840 --> 00:30:09,576 +假设设备上现有三个用户 + +611 +00:30:09,576 --> 00:30:11,712 +第四个用户想要登录 + +612 +00:30:11,712 --> 00:30:14,748 +现有用户中的某一用户 +数据将从设备中删除 + +613 +00:30:14,748 --> 00:30:17,351 +来为新用户创造足够的空间 + +614 +00:30:17,351 --> 00:30:19,686 +在“QuotaSize”的示例中 + +615 +00:30:19,686 --> 00:30:21,822 +即使有 5 GB 的空间仍然可用 + +616 +00:30:21,822 --> 00:30:23,090 +但这不满足 + +617 +00:30:23,090 --> 00:30:25,158 +第四个用户要登录的要求 + +618 +00:30:25,158 --> 00:30:28,595 +因此仍然需要删除一位用户 + +619 +00:30:28,595 --> 00:30:30,597 +我们再看一个场景 是关于 + +620 +00:30:30,597 --> 00:30:33,433 +在不改变配额的情况下 + +621 +00:30:33,433 --> 00:30:36,336 +如何在设备上调整用户数量 + +622 +00:30:36,336 --> 00:30:37,638 +还是原来的背景设定 + +623 +00:30:37,638 --> 00:30:40,340 +我们有 35 GB 的可用空间 + +624 +00:30:40,340 --> 00:30:42,109 +但其实是 iPad 上 +总空间的 25 GB + +625 +00:30:42,109 --> 00:30:46,180 +都被 App 和书籍文件占用了 + +626 +00:30:46,180 --> 00:30:47,748 +做了一点研究后 + +627 +00:30:47,748 --> 00:30:49,716 +我找到这台设备上有一些 App + +628 +00:30:49,716 --> 00:30:52,386 +没有人会继续用了 + +629 +00:30:52,386 --> 00:30:54,288 +然后我帮我的 App 库瘦身成功 + +630 +00:30:54,288 --> 00:30:57,457 +我的设备有额外的 +10 GB 可用空间 + +631 +00:30:57,457 --> 00:31:00,093 +意味着有第四个用户要登录 + +632 +00:31:00,093 --> 00:31:03,797 +也不需要删除另一个用户了 + +633 +00:31:03,797 --> 00:31:07,167 +另外 请记住 +自 iOS 13.4 起 + +634 +00:31:07,167 --> 00:31:09,703 +只要设备上没有缓存的用户 + +635 +00:31:09,703 --> 00:31:13,173 +配额大小可以随时调整 + +636 +00:31:13,173 --> 00:31:15,108 +记住这些要点应该可以让您享受到 + +637 +00:31:15,108 --> 00:31:19,780 +共享 iPad 部署的最佳体验 + +638 +00:31:19,780 --> 00:31:24,151 +让我们用 MDM 协议以及 +您应该留意的行为变化 + +639 +00:31:24,151 --> 00:31:28,021 +来结束我们的 iOS 和 +iPadOS 更新部分 + +640 +00:31:28,021 --> 00:31:31,391 +Apple 设备标配内置辅助功能 + +641 +00:31:31,391 --> 00:31:33,327 +使人们体验到设备 + +642 +00:31:33,327 --> 00:31:35,195 +应该提供的各种花样 + +643 +00:31:35,195 --> 00:31:37,598 +每个用户本来都需要 + +644 +00:31:37,598 --> 00:31:39,833 +自己启用辅助功能设置 + +645 +00:31:39,833 --> 00:31:44,104 +但在 iOS 和 iPadOS 16 中 +我们允许 MDM + +646 +00:31:44,104 --> 00:31:49,643 +管理许多热度高的辅助功能设置 + +647 +00:31:49,643 --> 00:31:53,514 +管理的功能中包括 +文字大小、旁白、缩放 + +648 +00:31:53,514 --> 00:31:56,183 +触控调节、粗体文本 + +649 +00:31:56,183 --> 00:31:58,685 +减弱动态效果、增强对比度 + +650 +00:31:58,685 --> 00:32:00,988 +和降低透明度 + +651 +00:32:00,988 --> 00:32:03,023 +有了这些选项 + +652 +00:32:03,023 --> 00:32:05,359 +我们相信管理员可以 +让所有用户体会到 + +653 +00:32:05,359 --> 00:32:10,197 +在学校、餐厅和医院都 +能更方便地访问设备 + +654 +00:32:10,197 --> 00:32:13,333 +请注意 这些设置在 +完成后不会被锁定 + +655 +00:32:13,333 --> 00:32:14,735 +用户可以自由修改设置 + +656 +00:32:14,735 --> 00:32:17,571 +来匹配自己各自的喜好 + +657 +00:32:17,571 --> 00:32:19,673 +MDM 服务器也可以 + +658 +00:32:19,673 --> 00:32:23,844 +使用“DeviceInformation” +查询这些设置 + +659 +00:32:23,844 --> 00:32:27,481 +还有 从 iOS +和 iPadOS 16 开始 + +660 +00:32:27,481 --> 00:32:29,216 +您现在可以 + +661 +00:32:29,216 --> 00:32:31,185 +在自动设备注册期间 + +662 +00:32:31,185 --> 00:32:33,587 +在“AwaitDeviceConfigured” +状态下安装 App + +663 +00:32:33,587 --> 00:32:35,556 +有几件事值得留意 + +664 +00:32:35,556 --> 00:32:37,357 +在这个阶段用户很有可能 + +665 +00:32:37,357 --> 00:32:39,893 +无法登录到 App Store + +666 +00:32:39,893 --> 00:32:43,330 +因此我们建议使用基于 +设备的 App 许可证 + +667 +00:32:43,330 --> 00:32:46,733 +设置中的未受监督设备 +仍将返回“NotNow” + +668 +00:32:46,733 --> 00:32:48,435 +直到用户见到主屏幕 + +669 +00:32:48,435 --> 00:32:49,970 +有了这个功能 您现在能够 + +670 +00:32:49,970 --> 00:32:52,806 +在退出设置助手之前 + +671 +00:32:52,806 --> 00:32:56,610 +就把设备需要用户 +入门的一切准备好了 + +672 +00:32:56,610 --> 00:32:59,446 +随着我们不断提高设备的安全性 + +673 +00:32:59,446 --> 00:33:01,348 +在第一次解锁之前 + +674 +00:33:01,348 --> 00:33:03,050 +某些数据类型变得不可访问 + +675 +00:33:03,050 --> 00:33:05,085 +因此“CertificateList”查询 + +676 +00:33:05,085 --> 00:33:08,755 +将在第一次解锁之前 +都会返回“NotNow” + +677 +00:33:08,755 --> 00:33:10,891 +一旦用户解锁设备 + +678 +00:33:10,891 --> 00:33:14,795 +查询将正常响应 直至设备重新启动 + +679 +00:33:14,795 --> 00:33:17,197 +请 MDM 开发者确保您的服务器 + +680 +00:33:17,197 --> 00:33:22,236 +能够处理此类查询 +的“NotNow”响应 + +681 +00:33:22,236 --> 00:33:25,539 +最后 Apple TV +也有激动人心的更新 + +682 +00:33:25,539 --> 00:33:29,176 +从 tvOS 16 开始 +在您通过设置或 MDM + +683 +00:33:29,176 --> 00:33:31,712 +抹除 Apple TV 时 + +684 +00:33:31,712 --> 00:33:34,248 +遥控器现将保持配对状态 + +685 +00:33:34,248 --> 00:33:37,684 +与 Auto Advance +相结合 + +686 +00:33:37,684 --> 00:33:41,855 +让您的 Apple TV +常在常新 蓄势待发 + +687 +00:33:41,855 --> 00:33:44,157 +除了我们今天涵盖的内容之外 + +688 +00:33:44,157 --> 00:33:46,059 +您还可以在 developer.apple.com/cn +上的文档里 + +689 +00:33:46,059 --> 00:33:51,865 +查看更多改变 + +690 +00:33:51,865 --> 00:33:55,202 +说到文档 在之前的 WWDC 上 + +691 +00:33:55,202 --> 00:33:58,438 +我们把 MDM 文档 +带到了它的新家 + +692 +00:33:58,438 --> 00:34:00,040 +这此变动提供了更准确 +与时俱进的文档 + +693 +00:34:00,040 --> 00:34:01,975 +但也能让您在 + +694 +00:34:01,975 --> 00:34:04,211 +特定的操作系统版本中 + +695 +00:34:04,211 --> 00:34:06,446 +突出显示变化 + +696 +00:34:06,446 --> 00:34:09,550 +这份文件的接受度令人惊叹 + +697 +00:34:09,550 --> 00:34:11,885 +今天 我很高兴地告诉您 + +698 +00:34:11,885 --> 00:34:14,755 +我们准备公开支持该文档的源代码 + +699 +00:34:14,755 --> 00:34:18,392 +在 MIT 开源许可证下公开可用 + +700 +00:34:18,392 --> 00:34:20,227 +我们放在 Apple 的 +GitHub 页面上 + +701 +00:34:20,227 --> 00:34:22,729 +新的设备管理项目中 + +702 +00:34:22,729 --> 00:34:25,632 +让我们来看看您打开后会发现什么 + +703 +00:34:25,632 --> 00:34:27,067 +两个文件夹 + +704 +00:34:27,067 --> 00:34:30,204 +一个包含所有的 MDM 文档 + +705 +00:34:30,204 --> 00:34:31,572 +另一个 + +706 +00:34:31,572 --> 00:34:33,907 +包含声明式设备管理新文档 + +707 +00:34:33,907 --> 00:34:38,879 +以及 README 文件 +和我们的许可信息 + +708 +00:34:38,879 --> 00:34:41,515 +在 MDM 文件夹中 您会找到 + +709 +00:34:41,515 --> 00:34:44,384 +签入 命令和描述文件的文件夹 + +710 +00:34:44,384 --> 00:34:45,853 +而声明式管理文件夹 + +711 +00:34:45,853 --> 00:34:49,389 +有声明 协议和状态文件夹 + +712 +00:34:49,389 --> 00:34:50,657 +如果您仔细查看这些文件夹 + +713 +00:34:50,657 --> 00:34:53,026 +您会发现 +每个命令的 YAML 文件 + +714 +00:34:53,026 --> 00:34:55,295 +描述文件或声明 + +715 +00:34:55,295 --> 00:34:56,830 +我想强调一些项目 + +716 +00:34:56,830 --> 00:35:00,033 +来让您熟悉这些文件 + +717 +00:35:00,033 --> 00:35:02,102 +首先是 Payload 键 + +718 +00:35:02,102 --> 00:35:05,172 +该键显示 MDM 命令的请求类型 + +719 +00:35:05,172 --> 00:35:07,608 +在这个例子中 +就是“ProfileList” + +720 +00:35:07,608 --> 00:35:09,510 +它返回一个安装在设备上 + +721 +00:35:09,510 --> 00:35:12,279 +的所有描述文件的列表 + +722 +00:35:12,279 --> 00:35:14,081 +接下来 +是“supportedOS”键 + +723 +00:35:14,081 --> 00:35:16,183 +这个键为您提供平台的信息 + +724 +00:35:16,183 --> 00:35:18,585 +比如操作系统 版本支持 + +725 +00:35:18,585 --> 00:35:21,154 +需要监督与否 + +726 +00:35:21,154 --> 00:35:23,457 +或者该键是否适用于用户注册 + +727 +00:35:23,457 --> 00:35:30,130 +我们能在这里发现 “ProfileList ”键 +是在 iOS 4 中推出的 + +728 +00:35:30,130 --> 00:35:31,732 +“payloadkeys” +为您提供 + +729 +00:35:31,732 --> 00:35:34,434 +关于查询提供的附加功能的相关信息 + +730 +00:35:34,434 --> 00:35:37,905 +每个子键可能包含一个 +额外的“supportedOS”键 + +731 +00:35:37,905 --> 00:35:41,041 +额外键将覆盖超过 Payload 的值 + +732 +00:35:41,041 --> 00:35:44,178 +“ProfileList”查询是 +在 iOS 4 中引入的 + +733 +00:35:44,178 --> 00:35:48,215 +但“ManagedOnly” +功能直到 iOS 13 才有 + +734 +00:35:48,215 --> 00:35:51,318 +“supportedOS” +的其余信息保持不变 + +735 +00:35:51,318 --> 00:35:53,153 +表示不需要监督 + +736 +00:35:53,153 --> 00:35:56,823 +并且查询适用于用户注册 + +737 +00:35:56,823 --> 00:35:58,625 +对于 +“ProfileList”查询 + +738 +00:35:58,625 --> 00:36:01,228 +它从 MDM 服务器返回响应 + +739 +00:36:01,228 --> 00:36:04,431 +响应键详细说明了此信息 + +740 +00:36:04,431 --> 00:36:07,301 +在我们的例子中 我们 +可以得知一个字典数组 + +741 +00:36:07,301 --> 00:36:10,571 +对应描述安装好的一个描述文件 + +742 +00:36:10,571 --> 00:36:13,974 +在该字典中 您将看到键值对 + +743 +00:36:13,974 --> 00:36:16,343 +包括“PayloadUUID” + +744 +00:36:16,343 --> 00:36:18,378 +和“PayloadIdentifier” + +745 +00:36:18,378 --> 00:36:19,947 +这只是一个简单的例子 + +746 +00:36:19,947 --> 00:36:21,915 +您会在 README 里发现 + +747 +00:36:21,915 --> 00:36:24,718 +关于存储库的架构 + +748 +00:36:24,718 --> 00:36:26,053 +和结构的全面的细节 + +749 +00:36:26,053 --> 00:36:29,857 +我们接着聊一些细节 + +750 +00:36:29,857 --> 00:36:30,991 +您会发现 + +751 +00:36:30,991 --> 00:36:35,362 +数据公布到 iOS 15 和 +macOS Monterey 的初始版本 + +752 +00:36:35,362 --> 00:36:38,498 +从那起 我们为每个版本发布新分支 + +753 +00:36:38,498 --> 00:36:41,869 +并根据需要播种 这意味着 + +754 +00:36:41,869 --> 00:36:43,670 +您现在就能查看 + +755 +00:36:43,670 --> 00:36:46,273 +iOS 16 和 +macOS Ventura 文档 + +756 +00:36:46,273 --> 00:36:48,709 +我们认为有很多对于这些 + +757 +00:36:48,709 --> 00:36:50,811 +新数据的有趣用例 + +758 +00:36:50,811 --> 00:36:54,548 +我们迫不及待地想看 +您想出了什么新工具或集成 + +759 +00:36:54,548 --> 00:36:56,517 +您开始处理这些数据时 + +760 +00:36:56,517 --> 00:37:00,687 +请使用反馈助理让我们知道进展情况 + +761 +00:37:00,687 --> 00:37:02,890 +我们今天涵盖了大量的信息 + +762 +00:37:02,890 --> 00:37:05,325 +所以我们来花点时间回顾一下 + +763 +00:37:05,325 --> 00:37:07,294 +iPhone 版本的 +Apple Configurator + +764 +00:37:07,294 --> 00:37:10,264 +现可以将 iPhone 和 +iPad 添加到您的组织中去 + +765 +00:37:10,264 --> 00:37:14,034 +让您更轻松地管理和部署设备 + +766 +00:37:14,034 --> 00:37:16,703 +然后来到身份验证 +Google Workspace 集成 + +767 +00:37:16,703 --> 00:37:19,206 +Enrollment SSO +和 Platform SSO + +768 +00:37:19,206 --> 00:37:22,376 +带来更具连贯的身份验证体验 + +769 +00:37:22,376 --> 00:37:25,512 +Nadia 接着向我们介绍了 +macOS Ventura 如何 + +770 +00:37:25,512 --> 00:37:27,014 +为您提供更多信息以帮助您 + +771 +00:37:27,014 --> 00:37:29,883 +管理您的队伍的软件更新 + +772 +00:37:29,883 --> 00:37:32,152 +在抹掉或恢复 Mac 之后 + +773 +00:37:32,152 --> 00:37:34,621 +设置助手期间需要网络连接 + +774 +00:37:34,621 --> 00:37:37,357 +自动设备注册更为智能 + +775 +00:37:37,357 --> 00:37:39,693 +然后我们谈及 + +776 +00:37:39,693 --> 00:37:42,362 +影响部署的重要的安全变更 + +777 +00:37:42,362 --> 00:37:44,631 +在 iOS +和 iPadOS 16 中 + +778 +00:37:44,631 --> 00:37:47,968 +您现在可以基于每个 App + +779 +00:37:47,968 --> 00:37:49,703 +管理 DNS Proxy 和 +Web Content Filter + +780 +00:37:49,703 --> 00:37:54,842 +我们探索了用在 iPhone 和 +iPad 上管理 eSIM 的工具 + +781 +00:37:54,842 --> 00:37:56,877 +我们讨论了共享 iPad +的优化升级 + +782 +00:37:56,877 --> 00:37:59,780 +最后 MDM 协议的更改 + +783 +00:37:59,780 --> 00:38:03,350 +包括在设置助手期间 +安装 App 的能力 + +784 +00:38:03,350 --> 00:38:06,753 +最后的最后 我们希望 +我们机器可读的新文档 + +785 +00:38:06,753 --> 00:38:10,824 +能使您构建激动 +人心的新工具和新集成 + +786 +00:38:10,824 --> 00:38:12,025 +感谢您参加我们的讲座 + +787 +00:38:12,025 --> 00:38:15,529 +希望您能过个难忘的 WWDC + +788 +00:38:15,529 --> 00:38:19,800 +♪ + diff --git a/zho/2022 Session 10046 Adopt declarative device management.srt b/zho/2022 Session 10046 Adopt declarative device management.srt new file mode 100644 index 0000000..708a3b3 --- /dev/null +++ b/zho/2022 Session 10046 Adopt declarative device management.srt @@ -0,0 +1,2670 @@ +1 +00:00:00,000 --> 00:00:03,837 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,837 --> 00:00:09,977 +♪ + +3 +00:00:09,977 --> 00:00:12,613 +欢迎收看本期视频 本期主题是 + +4 +00:00:12,613 --> 00:00:13,614 +采用声明式设备管理 + +5 +00:00:13,614 --> 00:00:15,249 +我叫 Cyrus Daboo + +6 +00:00:15,249 --> 00:00:18,352 +是设备管理团队的工程师 + +7 +00:00:18,352 --> 00:00:21,421 +本期视频 我将讲述声明式设备管理 + +8 +00:00:21,421 --> 00:00:24,458 +加入了哪些激动人心的新功能 + +9 +00:00:24,458 --> 00:00:26,760 +在 WWDC 21 大会上 + +10 +00:00:26,760 --> 00:00:30,531 +我的同事 Melissa 简要介绍 +声明式设备管理 + +11 +00:00:30,531 --> 00:00:33,400 +通过这一管理 +Apple 设备的新模式 + +12 +00:00:33,400 --> 00:00:37,337 +Melissa 表达了 +对 MDM 协议本身的全新展望 + +13 +00:00:37,337 --> 00:00:39,239 +从其介绍 我们知道了 + +14 +00:00:39,239 --> 00:00:41,508 +声明式设备管理功能的强大之处 + +15 +00:00:41,508 --> 00:00:45,412 +声明式管理能够 +使设备自治 并获得主动 + +16 +00:00:45,412 --> 00:00:47,147 +设备自治指的是 + +17 +00:00:47,147 --> 00:00:49,716 +设备能够对自身状态变化做出反应 + +18 +00:00:49,716 --> 00:00:52,452 +随即无需服务器提示 + +19 +00:00:52,452 --> 00:00:54,788 +就能将管理逻辑应用于自己 + +20 +00:00:54,788 --> 00:00:56,290 +而设备获得主动意味着 + +21 +00:00:56,290 --> 00:00:58,859 +发生重要的状态更改时 + +22 +00:00:58,859 --> 00:01:01,862 +服务器可通过状态通道收到异步报告 + +23 +00:01:01,862 --> 00:01:06,166 +避免服务器轮询设备 + +24 +00:01:06,166 --> 00:01:07,901 +声明式设备管理数据模型 + +25 +00:01:07,901 --> 00:01:10,704 +包含两个关键要素 + +26 +00:01:10,704 --> 00:01:13,173 +即 声明和状态 + +27 +00:01:13,173 --> 00:01:16,510 +声明包括激活函数与谓词 + +28 +00:01:16,510 --> 00:01:20,113 +配置 资产 和管理类型 + +29 +00:01:20,113 --> 00:01:24,518 +状态包括状态项和状态报告 + +30 +00:01:24,518 --> 00:01:26,987 +让我们花点时间说说其重要之处 + +31 +00:01:26,987 --> 00:01:28,856 +以及 这对您和您产品的用户组织 + +32 +00:01:28,856 --> 00:01:32,092 +都意味着什么 + +33 +00:01:32,092 --> 00:01:34,061 +我们创造这项技术的目的是 + +34 +00:01:34,061 --> 00:01:36,897 +为了支持新的复杂管理策略 + +35 +00:01:36,897 --> 00:01:40,567 +改善设备托管用户的整体体验 + +36 +00:01:40,567 --> 00:01:44,771 +为 IT 管理员 +减少重复和繁琐的任务 + +37 +00:01:44,771 --> 00:01:47,307 +让设备自我驱动 + +38 +00:01:47,307 --> 00:01:50,043 +自主管理 + +39 +00:01:50,043 --> 00:01:53,647 +如果您是 +设备管理解决方案的开发人员 + +40 +00:01:53,647 --> 00:01:56,083 +采用声明式 可以让您的服务器 + +41 +00:01:56,083 --> 00:01:58,719 +减轻体量 增强反应性 + +42 +00:01:58,719 --> 00:02:00,721 +而且 声明式数据模型 + +43 +00:02:00,721 --> 00:02:03,957 +能够更紧密地映射到组织结构 + +44 +00:02:03,957 --> 00:02:08,495 +也就是说 设备更改会更加简明直观 + +45 +00:02:08,495 --> 00:02:11,265 +状态报告包含多样的反馈渠道 + +46 +00:02:11,265 --> 00:02:14,935 +使服务器能够更密切地监控设备 + +47 +00:02:14,935 --> 00:02:17,204 +并提供相关信息 + +48 +00:02:17,204 --> 00:02:19,740 +这种报告方式 更及时 更可靠 + +49 +00:02:19,740 --> 00:02:22,242 +不必像轮询设备那样 + +50 +00:02:22,242 --> 00:02:24,478 +采用各种复杂策略 + +51 +00:02:24,478 --> 00:02:27,080 +综上 声明式管理能够简化开发工作 + +52 +00:02:27,080 --> 00:02:30,417 +使您能够专注于设备管理功能 + +53 +00:02:30,417 --> 00:02:33,053 +将价值增加在刀刃上 + +54 +00:02:33,053 --> 00:02:37,391 +并为客户创建符合喜好的解决方案 + +55 +00:02:37,391 --> 00:02:39,293 +如果您是 IT 管理员 + +56 +00:02:39,293 --> 00:02:41,762 +如果采用声明式管理 + +57 +00:02:41,762 --> 00:02:44,498 +您会对设备是否 +处于预期状态更有信心 + +58 +00:02:44,498 --> 00:02:47,234 +如果设备并非处于预期状态 + +59 +00:02:47,234 --> 00:02:48,936 +所有敏感的组织数据 + +60 +00:02:48,936 --> 00:02:51,972 +也会处于被保护的安全状态 + +61 +00:02:51,972 --> 00:02:55,943 +即使丢失与服务器的连接也不必担心 + +62 +00:02:55,943 --> 00:03:00,113 +声明式管理中的状态报告 + +63 +00:03:00,113 --> 00:03:02,850 +提供了来自设备的关键反馈 + +64 +00:03:02,850 --> 00:03:04,918 +能够减少网络带宽等资源的占用 + +65 +00:03:04,918 --> 00:03:07,187 +进而提高管理员的效率 + +66 +00:03:07,187 --> 00:03:09,223 +如果您是组织用户 + +67 +00:03:09,223 --> 00:03:11,592 +声明式管理 +可以提升设备管理的响应性 + +68 +00:03:11,592 --> 00:03:14,862 +增强可靠性 使数据打通更加高效 + +69 +00:03:14,862 --> 00:03:16,430 +缩短恢复时间 + +70 +00:03:16,430 --> 00:03:20,167 +并更好地获得组织支持 + +71 +00:03:20,167 --> 00:03:22,135 +考虑到所有这些好处 + +72 +00:03:22,135 --> 00:03:25,205 +再加上我们都知道 + +73 +00:03:25,205 --> 00:03:28,909 +未来协议特征必将侧重于 +声明式设备管理 + +74 +00:03:28,909 --> 00:03:30,677 +对您来说 + +75 +00:03:30,677 --> 00:03:33,013 +在现有产品中采用声明式设备管理 + +76 +00:03:33,013 --> 00:03:36,383 +显得愈发重要 + +77 +00:03:36,383 --> 00:03:39,386 +如果您希望 +进一步了解声明式设备管理 + +78 +00:03:39,386 --> 00:03:41,455 +以及采用步骤 + +79 +00:03:41,455 --> 00:03:46,326 +请务必观看 +WWDC 21 讲座视频 + +80 +00:03:46,326 --> 00:03:49,363 +在此版本中 +我们将重点放在了三个领域上 + +81 +00:03:49,363 --> 00:03:52,633 +扩大声明式设备管理的范围 + +82 +00:03:52,633 --> 00:03:57,304 +增强状态报告 以及增强谓词 + +83 +00:03:57,304 --> 00:03:59,439 +让我们先来说说 + +84 +00:03:59,439 --> 00:04:02,543 +扩大声明式设备管理的范围 + +85 +00:04:02,543 --> 00:04:05,078 +声明式设备管理在刚推出时 + +86 +00:04:05,078 --> 00:04:08,749 +只有用户注册模式的 iOS +可以支持 + +87 +00:04:08,749 --> 00:04:11,485 +现在 声明式设备管理可用于 + +88 +00:04:11,485 --> 00:04:15,355 +所有 MDM 支持的注册类型 + +89 +00:04:15,355 --> 00:04:17,024 +例如 包括受监督设备在内的 + +90 +00:04:17,024 --> 00:04:19,893 +自动设备注册 + +91 +00:04:19,893 --> 00:04:21,795 +基于个人资料的注册 + +92 +00:04:21,795 --> 00:04:25,465 +以及基于个人资料和帐户的用户注册 + +93 +00:04:25,465 --> 00:04:28,402 +现在 共享 iPad 也同样适用 + +94 +00:04:28,402 --> 00:04:30,938 +声明式设备管理 + +95 +00:04:30,938 --> 00:04:34,474 +iOS 16 的用户 +可以通过“设置” + +96 +00:04:34,474 --> 00:04:38,545 +在 MDM 配置文件 +详细信息视图中找到配置 + +97 +00:04:38,545 --> 00:04:41,748 +点击配置行可查看 + +98 +00:04:41,748 --> 00:04:44,852 +活动配置相关的详细信息 + +99 +00:04:44,852 --> 00:04:47,354 +还有 我很高兴能在此宣布 + +100 +00:04:47,354 --> 00:04:49,656 +现在 MDM 支持的每个平台 + +101 +00:04:49,656 --> 00:04:53,227 +都能够使用声明式设备管理 + +102 +00:04:53,227 --> 00:04:56,997 +macOS Ventura +支持声明式管理 + +103 +00:04:56,997 --> 00:05:01,435 +macOS 支持的 +所有 MDM 注册类型皆适用 + +104 +00:05:01,435 --> 00:05:04,938 +tvOS 16 也支持声明式管理 + +105 +00:05:04,938 --> 00:05:08,509 +所有 MDM 设备注册 +类型也都适用 + +106 +00:05:08,509 --> 00:05:10,310 +在操作系统支持的情况下 + +107 +00:05:10,310 --> 00:05:12,446 +凡是在 iOS 上可用的 + +108 +00:05:12,446 --> 00:05:14,248 +声明和状态集 + +109 +00:05:14,248 --> 00:05:18,852 +在 macOS +和 tvOS 也同样适用 + +110 +00:05:18,852 --> 00:05:21,889 +macOS 的配置部分显示在 + +111 +00:05:21,889 --> 00:05:24,191 +MDM 配置文件详细信息视图中 + +112 +00:05:24,191 --> 00:05:26,894 +可以查看活动配置 + +113 +00:05:26,894 --> 00:05:30,430 +tvOS 也是如此 其配置部分 + +114 +00:05:30,430 --> 00:05:34,635 +显示在 MDM 配置文件 +详细信息视图中 + +115 +00:05:34,635 --> 00:05:36,336 +最后需要注意的是 + +116 +00:05:36,336 --> 00:05:39,006 +macOS 和 +共享 iPad 设备 + +117 +00:05:39,006 --> 00:05:41,375 +都有两个 MDM 通道 + +118 +00:05:41,375 --> 00:05:44,745 +即 设备通道和用户通道 + +119 +00:05:44,745 --> 00:05:46,446 +设备通道允许管理 + +120 +00:05:46,446 --> 00:05:47,981 +设备级状态 + +121 +00:05:47,981 --> 00:05:50,217 +用户通道则针对管理 + +122 +00:05:50,217 --> 00:05:52,419 +特定用户的状态 + +123 +00:05:52,419 --> 00:05:55,322 +要在任何通道上使用声明式设备管理 + +124 +00:05:55,322 --> 00:05:58,392 +都必须为该通道单独启用 + +125 +00:05:58,392 --> 00:06:01,228 +也就是必须在相应的频道上 + +126 +00:06:01,228 --> 00:06:03,664 +分别发送声明式管理命令 + +127 +00:06:03,664 --> 00:06:07,100 +此外 声明性设备管理的状态报告 + +128 +00:06:07,100 --> 00:06:09,870 +也会单独为各通道生成 + +129 +00:06:09,870 --> 00:06:14,374 +同样需要分别监控 + +130 +00:06:14,374 --> 00:06:19,847 +接下来是第二个重点领域:状态报告 + +131 +00:06:19,847 --> 00:06:23,116 +让我们快速回顾一下状态报告 + +132 +00:06:23,116 --> 00:06:26,486 +这指的是 +设备可以逐步向服务器报告状态 + +133 +00:06:26,486 --> 00:06:29,022 +订阅状态项 + +134 +00:06:29,022 --> 00:06:32,092 +设备通过跟踪来自服务器的成功响应 + +135 +00:06:32,092 --> 00:06:34,461 +来确保状态更新无误 + +136 +00:06:34,461 --> 00:06:36,730 +而遇到网络或其他问题时 + +137 +00:06:36,730 --> 00:06:39,233 +也不会错过更新 + +138 +00:06:39,233 --> 00:06:42,503 +设备通过状态报告获得了主动 + +139 +00:06:42,503 --> 00:06:45,606 +服务器不必再为了观察状态变化 + +140 +00:06:45,606 --> 00:06:47,741 +而不断轮询设备 + +141 +00:06:47,741 --> 00:06:51,645 +在 iOS 15 中 +我们引入了一组状态项 + +142 +00:06:51,645 --> 00:06:54,348 +以适应各种设备属性 例如模型类型 + +143 +00:06:54,348 --> 00:06:56,917 +和各操作系统版本 + +144 +00:06:56,917 --> 00:07:01,054 +本次我们将在三个方面扩展状态 + +145 +00:07:01,054 --> 00:07:02,923 +密码状态 + +146 +00:07:02,923 --> 00:07:05,359 +通过配置安装的帐户 + +147 +00:07:05,359 --> 00:07:08,896 +和 MDM 安装 App + +148 +00:07:08,896 --> 00:07:12,232 +我们从密码状态开始说起 + +149 +00:07:12,232 --> 00:07:16,803 +在 iOS 15 中 +我们引入了密码策略配置 + +150 +00:07:16,803 --> 00:07:20,474 +当用户更改密码时 + +151 +00:07:20,474 --> 00:07:22,643 +策略的应用和密码合规 + +152 +00:07:22,643 --> 00:07:24,478 +可能存在一定时间差 + +153 +00:07:24,478 --> 00:07:28,148 +MDM 密码策略配置文件也是如此 + +154 +00:07:28,148 --> 00:07:31,652 +因此 MDM 服务器必须轮询设备 + +155 +00:07:31,652 --> 00:07:34,021 +才能确定密码什么时候合规 + +156 +00:07:34,021 --> 00:07:36,089 +但如果应用了新的 +声明式设备管理密码状态项 + +157 +00:07:36,089 --> 00:07:40,794 +就没有必要这样做了 + +158 +00:07:40,794 --> 00:07:43,897 +我们添加了两个状态项 + +159 +00:07:43,897 --> 00:07:48,836 +passcode.is-compliant +和 passcode.is-present + +160 +00:07:48,836 --> 00:07:51,338 +合规性用于指示密码是否符合 + +161 +00:07:51,338 --> 00:07:54,741 +通过 MDM 文件或配置应用的 + +162 +00:07:54,741 --> 00:07:57,211 +所有密码策略 + +163 +00:07:57,211 --> 00:07:59,546 +这些状态项具有布尔值 + +164 +00:07:59,546 --> 00:08:01,481 +能够反映那些可通过 MDM 查询 + +165 +00:08:01,481 --> 00:08:05,452 +检索到的等价属性 + +166 +00:08:05,452 --> 00:08:08,856 +让我们探索一个典型的服务器行为 + +167 +00:08:08,856 --> 00:08:12,359 +一般来说 组织都会在设备上 + +168 +00:08:12,359 --> 00:08:14,061 +应用安全敏感状态 + +169 +00:08:14,061 --> 00:08:17,364 +例如 只允许 VPN +或 Wi-Fi 配置文件 + +170 +00:08:17,364 --> 00:08:21,001 +访问受保护的网络 + +171 +00:08:21,001 --> 00:08:23,837 +而在设备启用该状态必须有个前提 + +172 +00:08:23,837 --> 00:08:26,907 +那就是存在强密码策略 + +173 +00:08:26,907 --> 00:08:31,078 +且密码符合该策略 + +174 +00:08:31,078 --> 00:08:33,780 +在传统的 MDM 中 +当用户更改密码时 + +175 +00:08:33,780 --> 00:08:37,184 +服务器必须先发送密码策略配置文件 + +176 +00:08:37,184 --> 00:08:39,586 +然后轮询设备 + +177 +00:08:39,586 --> 00:08:41,455 +等待密码合规 + +178 +00:08:41,455 --> 00:08:44,558 +最初密码可能不合规 + +179 +00:08:44,558 --> 00:08:48,195 +导致无法发送 +Wi-Fi 配置文件 + +180 +00:08:48,195 --> 00:08:50,764 +最后 用户更改密码 + +181 +00:08:50,764 --> 00:08:52,599 +才能使其合规 + +182 +00:08:52,599 --> 00:08:54,134 +接着 服务器在下一次轮询中 + +183 +00:08:54,134 --> 00:08:57,337 +检测到更改后的合规状态 + +184 +00:08:57,337 --> 00:09:01,108 +确定可以发送 +Wi-Fi 配置文件 + +185 +00:09:01,108 --> 00:09:04,444 +然后才能将其安装在设备上 + +186 +00:09:04,444 --> 00:09:06,947 +声明式设备管理的激活函数谓词 + +187 +00:09:06,947 --> 00:09:10,350 +能够被密码的合规状态触发 + +188 +00:09:10,350 --> 00:09:13,520 +因此免去了服务器轮询 + +189 +00:09:13,520 --> 00:09:15,622 +服务器将密码策略 +和 Wi-Fi 配置文件 + +190 +00:09:15,622 --> 00:09:18,859 +作为配置同时发送 + +191 +00:09:18,859 --> 00:09:21,962 +且 Wi-Fi 配置绑定于 + +192 +00:09:21,962 --> 00:09:25,199 +基于密码合规性的激活函数 + +193 +00:09:25,199 --> 00:09:27,835 +可以立即激活密码配置 + +194 +00:09:27,835 --> 00:09:31,205 +并应用强大的密码策略 + +195 +00:09:31,205 --> 00:09:34,007 +密码可能在最开始显示不合规 + +196 +00:09:34,007 --> 00:09:36,910 +导致激活谓词求值为假 + +197 +00:09:36,910 --> 00:09:40,347 +Wi-Fi 配置保持未激活状态 + +198 +00:09:40,347 --> 00:09:44,551 +等到用户更新密码 使其合规后 + +199 +00:09:44,551 --> 00:09:47,821 +会触发对激活函数的重新求值 + +200 +00:09:47,821 --> 00:09:50,591 +这时候 谓词求值就会为真 + +201 +00:09:50,591 --> 00:09:54,628 +并激活 Wi-Fi 配置 + +202 +00:09:54,628 --> 00:09:58,365 +以上过程完全不需要服务器的干预 + +203 +00:09:58,365 --> 00:10:01,034 +甚至也不需要 + +204 +00:10:01,034 --> 00:10:03,670 +和现存服务器进行连接 + +205 +00:10:03,670 --> 00:10:06,273 +而当配置激活时 + +206 +00:10:06,273 --> 00:10:09,176 +服务器会自动从设备获取状态报告 + +207 +00:10:09,176 --> 00:10:11,845 +因此 服务器知道何时发生变化 + +208 +00:10:11,845 --> 00:10:14,748 +以上过程说明了我们成功地 + +209 +00:10:14,748 --> 00:10:17,751 +将业务逻辑从服务器移动到设备 + +210 +00:10:17,751 --> 00:10:19,319 +并避免轮询的过程 + +211 +00:10:19,319 --> 00:10:24,291 +设备行为也能够因此 +变得更灵敏 更可靠 + +212 +00:10:24,291 --> 00:10:27,895 +现在 让我们转向帐户状态 + +213 +00:10:27,895 --> 00:10:31,398 +在 iOS 15 中 +我们引入了账户配置 + +214 +00:10:31,398 --> 00:10:34,968 +以在设备上安装各种类型的帐户 + +215 +00:10:34,968 --> 00:10:37,538 +通常都是组织帐户 + +216 +00:10:37,538 --> 00:10:41,008 +用来授予用户访问组织数据的权限 + +217 +00:10:41,008 --> 00:10:44,044 +能够知道账户合适成功安装 + +218 +00:10:44,044 --> 00:10:45,812 +以及账户处于什么状态 + +219 +00:10:45,812 --> 00:10:47,548 +对管理员来说是很有用的功能 + +220 +00:10:47,548 --> 00:10:51,451 +方便管理员支持可能遇到问题的用户 + +221 +00:10:51,451 --> 00:10:55,722 +此版本为邮件 日历和其他帐户类型 + +222 +00:10:55,722 --> 00:10:58,325 +添加了八个帐户状态项 + +223 +00:10:58,325 --> 00:11:01,261 +请注意 该状态仅会报告 + +224 +00:11:01,261 --> 00:11:03,063 +通过配置安装的帐户 + +225 +00:11:03,063 --> 00:11:05,666 +且手动创建的帐户 + +226 +00:11:05,666 --> 00:11:08,969 +或通过 MDM 配置文件 +安装的账户也不适用 + +227 +00:11:08,969 --> 00:11:11,104 +每个新的状态项 + +228 +00:11:11,104 --> 00:11:13,073 +都和帐户配置类型对应 + +229 +00:11:13,073 --> 00:11:16,043 +对于接收和发送邮件的帐户 + +230 +00:11:16,043 --> 00:11:18,345 +其状态会被分别报告 + +231 +00:11:18,345 --> 00:11:22,249 +每个新的状态项 +使用不同类型的 JSON 对象 + +232 +00:11:22,249 --> 00:11:26,253 +来表示对应账户类型的状态 + +233 +00:11:26,253 --> 00:11:29,556 +以下是接收邮件状态项 + +234 +00:11:29,556 --> 00:11:32,993 +和订阅日历状态项的示例 + +235 +00:11:32,993 --> 00:11:36,063 +对于状态项对象数组中的对象 + +236 +00:11:36,063 --> 00:11:39,600 +标识符键的值是唯一标识符 + +237 +00:11:39,600 --> 00:11:42,002 +稍后会详细介绍 + +238 +00:11:42,002 --> 00:11:44,872 +声明标识符键的值 + +239 +00:11:44,872 --> 00:11:46,773 +匹配安装帐户的配置文件的 + +240 +00:11:46,773 --> 00:11:49,343 +标识符属性值 + +241 +00:11:49,343 --> 00:11:51,211 +更易于交叉引用 + +242 +00:11:51,211 --> 00:11:55,415 +状态项对象及其相关配置 + +243 +00:11:55,415 --> 00:11:57,851 +这两个键始终存在于 + +244 +00:11:57,851 --> 00:12:01,188 +所有类型的帐户状态项对象中 + +245 +00:12:01,188 --> 00:12:03,790 +其余键则针对特定帐户类型 + +246 +00:12:03,790 --> 00:12:06,960 +例如 邮件服务器的主机名和端口 + +247 +00:12:06,960 --> 00:12:11,164 +或已订阅日历的日历链接 + +248 +00:12:11,164 --> 00:12:15,469 +此版本引入了值为数组的状态项 + +249 +00:12:15,469 --> 00:12:17,704 +支持报告一个或多个 + +250 +00:12:17,704 --> 00:12:19,473 +同类型帐户 + +251 +00:12:19,473 --> 00:12:22,809 +这样的数组值具有特殊行为 + +252 +00:12:22,809 --> 00:12:25,712 +数组中的每一项 +都是一个 JSON 对象 + +253 +00:12:25,712 --> 00:12:30,083 +其模式和用于单个数组中 +所有对象的相同 + +254 +00:12:30,083 --> 00:12:32,986 +每个对象类型都有一个标识符键 + +255 +00:12:32,986 --> 00:12:35,822 +作为在数组内定位对象 + +256 +00:12:35,822 --> 00:12:37,424 +的主键 + +257 +00:12:37,424 --> 00:12:38,859 +还有其他键 + +258 +00:12:38,859 --> 00:12:42,196 +与所报告的基本状态类型相关联 + +259 +00:12:42,196 --> 00:12:44,498 +为了能够前向兼容 + +260 +00:12:44,498 --> 00:12:47,467 +未来操作系统版本中可能添加的键 + +261 +00:12:47,467 --> 00:12:52,506 +您的服务器必须能够接受 +数组对象中的未知键 + +262 +00:12:52,506 --> 00:12:55,075 +为了性能考虑 + +263 +00:12:55,075 --> 00:12:57,211 +凡是数组值的更改 + +264 +00:12:57,211 --> 00:13:01,181 +都会基于单个对象逐步报告到服务器 + +265 +00:13:01,181 --> 00:13:02,716 +让我们来看个例子 + +266 +00:13:02,716 --> 00:13:05,886 +看看这个新功能是如何工作的 + +267 +00:13:05,886 --> 00:13:07,187 +在这个例子中 + +268 +00:13:07,187 --> 00:13:09,756 +服务器向设备发送了 + +269 +00:13:09,756 --> 00:13:10,991 +两个邮件账户配置 + +270 +00:13:10,991 --> 00:13:14,228 +由于两个账户都处于活动状态 + +271 +00:13:14,228 --> 00:13:16,330 +因此设备上存在着两个邮件帐户 + +272 +00:13:16,330 --> 00:13:18,465 +服务器现在发送信号 + +273 +00:13:18,465 --> 00:13:21,001 +订阅邮件帐户状态项 + +274 +00:13:21,001 --> 00:13:23,203 +订阅激活后 + +275 +00:13:23,203 --> 00:13:25,239 +会收集帐户状态 + +276 +00:13:25,239 --> 00:13:29,209 +且设备会向服务器发送状态报告 + +277 +00:13:29,209 --> 00:13:32,546 +状态报告将包括在状态数组中的 + +278 +00:13:32,546 --> 00:13:34,214 +两个帐户状态对象 + +279 +00:13:34,214 --> 00:13:35,849 +使服务器能对设备当前内容 + +280 +00:13:35,849 --> 00:13:38,852 +有全面的了解 + +281 +00:13:38,852 --> 00:13:42,089 +每个数组对象都有不同的标识符 + +282 +00:13:42,089 --> 00:13:44,124 +处理完这份报告后 + +283 +00:13:44,124 --> 00:13:46,660 +服务器储存着两个邮件帐户的状态 + +284 +00:13:46,660 --> 00:13:49,530 +和设备上的内容一致 + +285 +00:13:49,530 --> 00:13:52,132 +当服务器通过发送新配置 + +286 +00:13:52,132 --> 00:13:55,802 +以在设备上添加邮件帐户时 +设备上的状态项 + +287 +00:13:55,802 --> 00:13:58,906 +在其数组值中添加了一个新对象 + +288 +00:13:58,906 --> 00:14:03,143 +又向服务器发送了一份状态报告 + +289 +00:14:03,143 --> 00:14:05,712 +该报告仅反映了新项目 + +290 +00:14:05,712 --> 00:14:08,615 +由于标识符键的值 + +291 +00:14:08,615 --> 00:14:10,350 +与服务器已知的都不匹配 + +292 +00:14:10,350 --> 00:14:15,155 +服务器因此可以推断出 +该标识符来自新帐户 + +293 +00:14:15,155 --> 00:14:16,623 +处理完这份报告后 + +294 +00:14:16,623 --> 00:14:19,359 +服务器储存着三个邮件帐户的状态 + +295 +00:14:19,359 --> 00:14:21,929 +两个初始账户和一个新账户 + +296 +00:14:21,929 --> 00:14:25,933 +依旧与设备内容完全一致 + +297 +00:14:25,933 --> 00:14:27,901 +当账户状态发生变化时 + +298 +00:14:27,901 --> 00:14:31,705 +例如当用户切换邮件 +或便笺启用状态时 + +299 +00:14:31,705 --> 00:14:33,440 +设备上的状态项 + +300 +00:14:33,440 --> 00:14:36,643 +将在其数组值中增加一个更新对象 + +301 +00:14:36,643 --> 00:14:41,014 +于是状态报告再次被发送到服务器 + +302 +00:14:41,014 --> 00:14:43,517 +且仅报告更改的项目 + +303 +00:14:43,517 --> 00:14:46,320 +在这个例子中 用户关闭了账户中的 + +304 +00:14:46,320 --> 00:14:47,921 +便笺功能 + +305 +00:14:47,921 --> 00:14:49,923 +标识符键的值 + +306 +00:14:49,923 --> 00:14:52,159 +和服务器储存的其中之一相匹配 + +307 +00:14:52,159 --> 00:14:54,962 +所以 服务器可以推断出这是 + +308 +00:14:54,962 --> 00:14:56,330 +一次现有帐户的更新 + +309 +00:14:56,330 --> 00:14:57,531 +然后 + +310 +00:14:57,531 --> 00:15:00,434 +服务器用新对象替换了 + +311 +00:15:00,434 --> 00:15:02,769 +现有的状态项数组对象 + +312 +00:15:02,769 --> 00:15:04,438 +处理完这份报告后 + +313 +00:15:04,438 --> 00:15:07,074 +服务器储存着三个邮件帐户的状态 + +314 +00:15:07,074 --> 00:15:09,943 +其中之一经历了更改 + +315 +00:15:09,943 --> 00:15:13,080 +从设备中删除帐户配置时 + +316 +00:15:13,080 --> 00:15:14,615 +设备上的状态项 + +317 +00:15:14,615 --> 00:15:17,684 +会被打上相应的对象标记 以示删除 + +318 +00:15:17,684 --> 00:15:21,788 +又一份状态报告被发送到服务器 + +319 +00:15:21,788 --> 00:15:24,258 +仅报告已删除的项目 + +320 +00:15:24,258 --> 00:15:25,859 +为了表示删除 + +321 +00:15:25,859 --> 00:15:29,429 +数组项对象仅包含两个键 + +322 +00:15:29,429 --> 00:15:30,998 +首先是 标识符键 + +323 +00:15:30,998 --> 00:15:33,767 +其值与服务器已有的值相匹配 + +324 +00:15:33,767 --> 00:15:37,471 +其次是删除键 其值被设置为真 + +325 +00:15:37,471 --> 00:15:40,374 +有了这两个键 服务器就能够 + +326 +00:15:40,374 --> 00:15:44,511 +通过删除现有项目来更新设备状态 + +327 +00:15:44,511 --> 00:15:46,380 +处理完这份报告后 + +328 +00:15:46,380 --> 00:15:49,216 +服务器只储存着两个邮件帐户的状态 + +329 +00:15:49,216 --> 00:15:52,953 +和设备现状完全一致 + +330 +00:15:52,953 --> 00:15:55,923 +关于状态报告 我还有最后一点要说 + +331 +00:15:55,923 --> 00:15:59,226 +设备会限制状态报告的发送速率 + +332 +00:15:59,226 --> 00:16:01,528 +以避免性能出现问题 + +333 +00:16:01,528 --> 00:16:04,565 +在最长为 1 分钟的时间间隔内 + +334 +00:16:04,565 --> 00:16:07,334 +设备会整合状态项的更改 + +335 +00:16:07,334 --> 00:16:10,571 +再向服务器发送状态报告 + +336 +00:16:10,571 --> 00:16:13,006 +也就是说 设备状态的报告速度虽快 + +337 +00:16:13,006 --> 00:16:15,676 +却不是即时的 + +338 +00:16:15,676 --> 00:16:17,544 +接下来 让我们换个方向 + +339 +00:16:17,544 --> 00:16:20,514 +看看该如何解决 +长期存在的 MDM 瓶颈 + +340 +00:16:20,514 --> 00:16:24,051 +即 监控 App 安装状态 + +341 +00:16:24,051 --> 00:16:28,822 +MDM 服务器通常需要 +在设备上安装 App + +342 +00:16:28,822 --> 00:16:32,659 +才能授权用户访问其 +工作或教育所需的工具 + +343 +00:16:32,659 --> 00:16:34,862 +通常来说 App 是否安装成功 + +344 +00:16:34,862 --> 00:16:37,998 +决定了服务器端的逻辑 + +345 +00:16:37,998 --> 00:16:42,102 +所以 MDM 服务器 +需要监控 App 安装进度 + +346 +00:16:42,102 --> 00:16:46,106 +还要注意用户是否会删除 + +347 +00:16:46,106 --> 00:16:48,876 +设备上的托管 App + +348 +00:16:48,876 --> 00:16:53,146 +目前 MDM 服务器可以使用 +InstalledApplicationList + +349 +00:16:53,146 --> 00:16:56,350 +或 ManagedApplicationList +命令来轮询设备 + +350 +00:16:56,350 --> 00:16:59,586 +以观察 App 安装进度 + +351 +00:16:59,586 --> 00:17:02,089 +而我们可以通过让设备主动 +向服务器反映应用安装进度 + +352 +00:17:02,089 --> 00:17:06,059 +来避免轮询 + +353 +00:17:06,059 --> 00:17:07,327 +所需要用到的工具就是 + +354 +00:17:07,327 --> 00:17:12,199 +声明式设备管理状态报告 + +355 +00:17:12,199 --> 00:17:15,469 +此版本添加了一个 +mdm.app 状态项 + +356 +00:17:15,469 --> 00:17:19,139 +其值是一个对象数组 +每个对象代表一个 + +357 +00:17:19,139 --> 00:17:22,142 +已由 MDM 服务器 +安装的 App + +358 +00:17:22,142 --> 00:17:25,612 +由于值是数组 所以 +其采用的是增量式报告 + +359 +00:17:25,612 --> 00:17:28,115 +这一过程我们之前已经描述过了 + +360 +00:17:28,115 --> 00:17:31,985 +请注意 即使在受监督的设备上此 + +361 +00:17:31,985 --> 00:17:35,189 +也只有 MDM 安装的 App +会被报告 + +362 +00:17:35,189 --> 00:17:38,358 +此状态报告包含 + +363 +00:17:38,358 --> 00:17:40,494 +已安装完成应用的状态项 + +364 +00:17:40,494 --> 00:17:43,163 +对于数组项对象 + +365 +00:17:43,163 --> 00:17:45,599 +标识符键是唯一标识符 +在这种情况下 + +366 +00:17:45,599 --> 00:17:48,168 +标识符键 +也是 App 的捆绑标识符 + +367 +00:17:48,168 --> 00:17:51,171 +name 键表示 App 的名称 + +368 +00:17:51,171 --> 00:17:54,007 +三个 version 键 +分别是普通 简要 + +369 +00:17:54,007 --> 00:17:57,044 +和外部版本标识符 + +370 +00:17:57,044 --> 00:17:58,912 +而 state 键则用于指明 + +371 +00:17:58,912 --> 00:18:02,850 +App 当前的安装阶段 + +372 +00:18:02,850 --> 00:18:04,852 +这些键的值和 + +373 +00:18:04,852 --> 00:18:07,054 +MDM 托管 App 列表 +命令响应中的等价项 + +374 +00:18:07,054 --> 00:18:10,190 +相互对应 + +375 +00:18:10,190 --> 00:18:13,927 +有了这些信息 +服务器可以立即识别出 + +376 +00:18:13,927 --> 00:18:18,765 +正在报告哪个 App +以及该 App 正处于什么状态 + +377 +00:18:18,765 --> 00:18:22,903 +以某个 App 安装时的 +数据流为示例 + +378 +00:18:22,903 --> 00:18:25,739 +右侧是一台 iOS 16 设备 + +379 +00:18:25,739 --> 00:18:28,575 +由 MDM 服务器管理 + +380 +00:18:28,575 --> 00:18:31,979 +其服务器已启用了声明式设备管理 + +381 +00:18:31,979 --> 00:18:33,647 +并发送了对于 +MDM 安装 App 状态项 + +382 +00:18:33,647 --> 00:18:37,050 +的状态订阅 + +383 +00:18:37,050 --> 00:18:39,720 +服务器下一步要做的是 + +384 +00:18:39,720 --> 00:18:43,223 +通过 MDM 命令安装 App + +385 +00:18:43,223 --> 00:18:46,627 +由于是用户注册 +安装 App 需要用户批准 + +386 +00:18:46,627 --> 00:18:49,296 +所以当设备处理 +App 安装命令时 + +387 +00:18:49,296 --> 00:18:52,699 +会出现弹窗提示 + +388 +00:18:52,699 --> 00:18:55,869 +此时 安装进度暂停 + +389 +00:18:55,869 --> 00:18:58,605 +等待用户输入 + +390 +00:18:58,605 --> 00:19:01,542 +设备将向服务器发送状态报告 + +391 +00:19:01,542 --> 00:19:05,646 +报告内容包括单个 +MDM 安装 App 的状态对象 + +392 +00:19:05,646 --> 00:19:10,284 +以及 App 的捆绑 ID +和弹窗提示状态 + +393 +00:19:10,284 --> 00:19:13,086 +有时候 当用户点击安装按钮 + +394 +00:19:13,086 --> 00:19:16,857 +设备随即开始安装 App + +395 +00:19:16,857 --> 00:19:20,694 +随着安装的进行 +将发送另一个状态报告 + +396 +00:19:20,694 --> 00:19:23,830 +这次将应用状态设置为正在安装 + +397 +00:19:23,830 --> 00:19:28,302 +表示正在下载和安装该 App + +398 +00:19:28,302 --> 00:19:30,537 +知道最后 App 完成安装 + +399 +00:19:30,537 --> 00:19:32,706 +可以投入使用 + +400 +00:19:32,706 --> 00:19:35,242 +此时 将发送另一个状态报告 + +401 +00:19:35,242 --> 00:19:37,444 +将应用状态设置为托管 + +402 +00:19:37,444 --> 00:19:41,381 +表明 App 已正确安装和管理 + +403 +00:19:41,381 --> 00:19:46,086 +现在假设用户 +手动删除了设备上的 App + +404 +00:19:46,086 --> 00:19:48,555 +同样 设备将发送状态报告 + +405 +00:19:48,555 --> 00:19:53,260 +这次 App 状态将被设置为 +托管但已卸载 + +406 +00:19:53,260 --> 00:19:55,896 +表明该 App 不再处于安装状态 + +407 +00:19:55,896 --> 00:19:58,498 +但仍在设备上 + +408 +00:19:58,498 --> 00:20:00,701 +跟踪其管理状态 + +409 +00:20:00,701 --> 00:20:02,836 +假设服务器要删除 + +410 +00:20:02,836 --> 00:20:04,771 +应用管理状态 + +411 +00:20:04,771 --> 00:20:07,808 +为了实现这一点 服务器会向设备 + +412 +00:20:07,808 --> 00:20:09,343 +发送 App 删除命令 + +413 +00:20:09,343 --> 00:20:12,312 +这样就删除了原本的管理状态 + +414 +00:20:12,312 --> 00:20:14,648 +且如果 App 仍然存在 + +415 +00:20:14,648 --> 00:20:17,284 +这时也会被删除 + +416 +00:20:17,284 --> 00:20:19,753 +接下来 被标记为已从 +应用状态数组中移除的 App 对象 + +417 +00:20:19,753 --> 00:20:22,823 +将与另一份状态报告一起发送 + +418 +00:20:22,823 --> 00:20:26,727 +通过以上说明 我们了解了 +新 MDM 状态项的强大功能 + +419 +00:20:26,727 --> 00:20:28,595 +它能够帮助提高响应能力 + +420 +00:20:28,595 --> 00:20:30,964 +也能增强 App 安装的可靠性 + +421 +00:20:30,964 --> 00:20:35,002 +而且简单便捷 +只需几个步骤即可实施 + +422 +00:20:35,002 --> 00:20:40,374 +接下来 让我们看看 +第三个重点领域 谓词 + +423 +00:20:40,374 --> 00:20:43,343 +先快速回顾一下激活谓词 + +424 +00:20:43,343 --> 00:20:45,913 +激活函数包括一个可选谓词 + +425 +00:20:45,913 --> 00:20:47,981 +以确定激活中引用的配置 + +426 +00:20:47,981 --> 00:20:52,119 +是否将应用于设备 + +427 +00:20:52,119 --> 00:20:53,854 +谓词可以引用状态项 + +428 +00:20:53,854 --> 00:20:57,824 +以便测试状态项的值 + +429 +00:20:57,824 --> 00:21:00,594 +当谓词中引用的状态项发生更改时 + +430 +00:21:00,594 --> 00:21:03,664 +设备将重新处理所有激活函数 + +431 +00:21:03,664 --> 00:21:06,567 +重新对所有谓词求值 + +432 +00:21:06,567 --> 00:21:08,402 +NSPredicate +即谓词语法 + +433 +00:21:08,402 --> 00:21:10,404 +谓词被指定为字符串 + +434 +00:21:10,404 --> 00:21:13,574 +记录在 Apple Developer 网站上 + +435 +00:21:13,574 --> 00:21:16,677 +为了支持更复杂的谓词表达式 + +436 +00:21:16,677 --> 00:21:19,813 +我们扩展了谓词语法 + +437 +00:21:19,813 --> 00:21:23,684 +使其更容易检测出表达式中的状态项 + +438 +00:21:23,684 --> 00:21:26,320 +在新语法中 状态项名称被放置于 + +439 +00:21:26,320 --> 00:21:30,457 +谓词字符串中的 +@status 项内 + +440 +00:21:30,457 --> 00:21:33,493 +在示例中 序列号状态项 + +441 +00:21:33,493 --> 00:21:35,329 +运用使用新语法 + +442 +00:21:35,329 --> 00:21:38,332 +出现在谓词表达式中 + +443 +00:21:38,332 --> 00:21:40,267 +以前的语法依然有效 + +444 +00:21:40,267 --> 00:21:44,538 +但是为了向后兼容 +旧语法已被弃用了 + +445 +00:21:44,538 --> 00:21:47,641 +所以 请您采用新语法 + +446 +00:21:47,641 --> 00:21:49,576 +让我们看看面对状态项数组值时 + +447 +00:21:49,576 --> 00:21:52,012 +谓词是如何运作的 + +448 +00:21:52,012 --> 00:21:55,048 +正如之前的流程 现在有了状态项值 + +449 +00:21:55,048 --> 00:21:56,884 +其指的是帐户的数组 + +450 +00:21:56,884 --> 00:21:59,786 +和 MDM +安装 App 的状态项 + +451 +00:21:59,786 --> 00:22:02,523 +能够在数组的某个项目上触发激活 + +452 +00:22:02,523 --> 00:22:05,158 +会很有帮助 + +453 +00:22:05,158 --> 00:22:08,562 +比如说 在设备上安装和管理 + +454 +00:22:08,562 --> 00:22:10,964 +具有特定捆绑标识符的 App 时 + +455 +00:22:10,964 --> 00:22:14,568 +我们可能需要触发激活 + +456 +00:22:14,568 --> 00:22:16,870 +NSPredicate +有一个子查询词条 + +457 +00:22:16,870 --> 00:22:20,240 +可用于对数组进行操作 + +458 +00:22:20,240 --> 00:22:23,143 +此 NSPredicate +表达式使用的子查询 + +459 +00:22:23,143 --> 00:22:26,813 +正针对着 MDM +安装 App 状态项 + +460 +00:22:26,813 --> 00:22:30,984 +状态项被用作子查询的第一个参数 + +461 +00:22:30,984 --> 00:22:33,086 +第二个参数定义了一个变量 + +462 +00:22:33,086 --> 00:22:35,756 +该变量将引用数组的每个元素 + +463 +00:22:35,756 --> 00:22:38,025 +第三个参数是谓词表达式 + +464 +00:22:38,025 --> 00:22:42,496 +用于测试由该变量标识的每个元素 + +465 +00:22:42,496 --> 00:22:45,399 +子查询表达式返回一个 +与第三参数中的谓词 + +466 +00:22:45,399 --> 00:22:48,702 +相匹配的元素数组 + +467 +00:22:48,702 --> 00:22:51,638 +接着 @count 运算符 +返回该数组的长度 + +468 +00:22:51,638 --> 00:22:53,774 +并且对其长度进行检查 + +469 +00:22:53,774 --> 00:22:57,477 +以确定是否存在结果匹配 + +470 +00:22:57,477 --> 00:23:00,447 +安装和管理指定的 App 时 + +471 +00:23:00,447 --> 00:23:02,749 +该子查询表达式将用一个元素 + +472 +00:23:02,749 --> 00:23:04,451 +返回一个数组 + +473 +00:23:04,451 --> 00:23:07,454 +此时谓词求值将为真 + +474 +00:23:07,454 --> 00:23:10,357 +未安装应用时 子查询表达式 + +475 +00:23:10,357 --> 00:23:12,092 +将返回一个空数组 + +476 +00:23:12,092 --> 00:23:15,696 +且谓词求值将为假 + +477 +00:23:15,696 --> 00:23:18,232 +请注意 为了 +在状态项数组对象中引用键 + +478 +00:23:18,232 --> 00:23:21,802 +必须使用 @key 扩展项 + +479 +00:23:21,802 --> 00:23:25,839 +来确保关键路径被正确处理 + +480 +00:23:25,839 --> 00:23:28,542 +新的谓词语法是可扩展的 + +481 +00:23:28,542 --> 00:23:30,978 +我们现在说说该怎么使用新语法 + +482 +00:23:30,978 --> 00:23:35,782 +来为一种新型数据添加谓词 + +483 +00:23:35,782 --> 00:23:38,418 +服务器需要的是 +能够更直接地控制谓词求值 + +484 +00:23:38,418 --> 00:23:42,222 +以便将复杂的服务器端逻辑 + +485 +00:23:42,222 --> 00:23:45,592 +转化为设备上的简单状态变化 + +486 +00:23:45,592 --> 00:23:48,896 +并且无需为了实现这些变化 + +487 +00:23:48,896 --> 00:23:51,131 +而大量同步配置 + +488 +00:23:51,131 --> 00:23:54,401 +举个例子 有这个需求的组织 + +489 +00:23:54,401 --> 00:23:57,237 +可能希望在将设备分发给用户时 + +490 +00:23:57,237 --> 00:23:59,072 +能够高效 即时地 +将设备分配给多个角色 + +491 +00:23:59,072 --> 00:24:03,010 +也有可能 该组织需要的是 + +492 +00:24:03,010 --> 00:24:05,646 +能够快速分发替换设备 + +493 +00:24:05,646 --> 00:24:07,814 +或快速开启设备的安全模式 + +494 +00:24:07,814 --> 00:24:10,517 +来保护组织数据 + +495 +00:24:10,517 --> 00:24:13,187 +我很高兴能告诉开发者 +为了满足以上需求 + +496 +00:24:13,187 --> 00:24:16,356 +我们正在添加一个新的声明 + +497 +00:24:16,356 --> 00:24:19,059 +以允许服务器在设备上设置任意属性 + +498 +00:24:19,059 --> 00:24:22,329 +用于直接激活谓词 + +499 +00:24:22,329 --> 00:24:26,867 +这就是新的管理属性声明 + +500 +00:24:26,867 --> 00:24:29,503 +该声明由一个 JSON 对象组成 + +501 +00:24:29,503 --> 00:24:33,006 +其键名由服务器定义 + +502 +00:24:33,006 --> 00:24:36,643 +JSON 对象值可以 +是任何 JSON 值类型 + +503 +00:24:36,643 --> 00:24:39,646 +包括数组或对象 + +504 +00:24:39,646 --> 00:24:41,582 +屏幕上的管理属性声明 + +505 +00:24:41,582 --> 00:24:44,952 +包括三个属性 其中姓名和年龄 + +506 +00:24:44,952 --> 00:24:47,254 +具有字符串和整数值 + +507 +00:24:47,254 --> 00:24:51,725 +而角色属性则是字符串数组 + +508 +00:24:51,725 --> 00:24:54,094 +这是一个带有谓词的激活函数 + +509 +00:24:54,094 --> 00:24:56,930 +引用了一些管理属性 + +510 +00:24:56,930 --> 00:24:59,967 +该函数首先会测试年龄属性 + +511 +00:24:59,967 --> 00:25:03,704 +判断其整数值是否 +大于 18 或等于 18 + +512 +00:25:03,704 --> 00:25:06,473 +接着 该函数会测试角色属性 + +513 +00:25:06,473 --> 00:25:11,578 +判断属性数组值中 +是否出现字符串“12 年级” + +514 +00:25:11,578 --> 00:25:12,846 +每个属性的引用都使用了 + +515 +00:25:12,846 --> 00:25:15,449 +@property 扩展术语 + +516 +00:25:15,449 --> 00:25:19,653 +且属性键名称就属于该类术语 + +517 +00:25:19,653 --> 00:25:21,688 +虽然可以向设备发送 + +518 +00:25:21,688 --> 00:25:23,290 +多个管理属性声明 + +519 +00:25:23,290 --> 00:25:26,693 +但所有键名都应该互不重复 + +520 +00:25:26,693 --> 00:25:29,463 +如果键名重复 则引用属性时 + +521 +00:25:29,463 --> 00:25:32,466 +其值会随机被谓语引用 + +522 +00:25:32,466 --> 00:25:35,836 +导致难以预料的结果 + +523 +00:25:35,836 --> 00:25:39,473 +所以 请避免使用重复的键名 + +524 +00:25:39,473 --> 00:25:43,076 +让我们来看一个使用案例 + +525 +00:25:43,076 --> 00:25:45,412 +该系统由一所学校采用 + +526 +00:25:45,412 --> 00:25:48,649 +学校里有很多教师 这点不用多说 + +527 +00:25:48,649 --> 00:25:52,886 +这所学校分为两个学部 +高年部和低年部 + +528 +00:25:52,886 --> 00:25:57,324 +每个学部都有自己的校区 +和独立 Wi-Fi 网络 + +529 +00:25:57,324 --> 00:25:59,860 +部分教师是 IT 管理员 + +530 +00:25:59,860 --> 00:26:02,896 +需要访问共享邮件帐户 + +531 +00:26:02,896 --> 00:26:05,632 +其中部分教师兼任体育教练 + +532 +00:26:05,632 --> 00:26:07,501 +需要为体育比赛制定时间表 + +533 +00:26:07,501 --> 00:26:10,370 +订阅日历 + +534 +00:26:10,370 --> 00:26:13,841 +因此 一名教师可能 +可以扮演四种不同的角色 + +535 +00:26:13,841 --> 00:26:16,844 +有时甚至需要身兼多职 + +536 +00:26:16,844 --> 00:26:19,079 +而每个角色都有一组配置 + +537 +00:26:19,079 --> 00:26:22,015 +添加到设备时 + +538 +00:26:22,015 --> 00:26:25,419 +必须按设备分配的角色区分 + +539 +00:26:25,419 --> 00:26:28,889 +让我们以两位教师为例 + +540 +00:26:28,889 --> 00:26:30,891 +一号教师在低年部任教 + +541 +00:26:30,891 --> 00:26:33,427 +兼任体育教练 + +542 +00:26:33,427 --> 00:26:39,299 +二号教师在高年部任教 +同时是一名 IT 管理员 + +543 +00:26:39,299 --> 00:26:41,068 +传统的 MDM 服务器 + +544 +00:26:41,068 --> 00:26:44,171 +该如何处理这样的用例呢? + +545 +00:26:44,171 --> 00:26:46,640 +一般来说 在完成设备配置之前 + +546 +00:26:46,640 --> 00:26:48,342 +传统服务器必须先 + +547 +00:26:48,342 --> 00:26:51,578 +等待设备被分配给教师 + +548 +00:26:51,578 --> 00:26:55,249 +服务器必须先确定教师的角色 + +549 +00:26:55,249 --> 00:26:59,586 +才能确定该如何链接配置文件 + +550 +00:26:59,586 --> 00:27:02,489 +接着 服务器必须轮流地在设备上 + +551 +00:27:02,489 --> 00:27:05,158 +分别安装配置文件 + +552 +00:27:05,158 --> 00:27:07,995 +如果教师改变角色 服务器必须 + +553 +00:27:07,995 --> 00:27:11,331 +添加或删除配置文件来匹配新角色 + +554 +00:27:11,331 --> 00:27:14,101 +这一过程不仅耗时 + +555 +00:27:14,101 --> 00:27:17,337 +还可能导致设备管理系统的重大卡顿 + +556 +00:27:17,337 --> 00:27:19,473 +高峰期尤其如此 + +557 +00:27:19,473 --> 00:27:21,875 +我们以角色分配完成后的 + +558 +00:27:21,875 --> 00:27:24,411 +开学第一天作为案例背景 + +559 +00:27:24,411 --> 00:27:26,747 +新的管理属性声明 + +560 +00:27:26,747 --> 00:27:30,017 +提供了一个更有效的替代方案 + +561 +00:27:30,017 --> 00:27:32,953 +该方案可以在设备上 + +562 +00:27:32,953 --> 00:27:35,956 +预加载一整套声明 + +563 +00:27:35,956 --> 00:27:38,325 +通过管理属性 + +564 +00:27:38,325 --> 00:27:41,261 +可以根据角色触发谓词 + +565 +00:27:41,261 --> 00:27:44,364 +来将配置分配给激活函数 + +566 +00:27:44,364 --> 00:27:47,801 +设备分配给教师后 +服务器只需要发送 + +567 +00:27:47,801 --> 00:27:49,937 +一份管理属性声明 + +568 +00:27:49,937 --> 00:27:52,873 +以及该教师的角色 + +569 +00:27:52,873 --> 00:27:56,376 +来触发激活其角色的配置 + +570 +00:27:56,376 --> 00:27:58,846 +这种方法不仅可以将整个服务器 + +571 +00:27:58,846 --> 00:28:01,849 +和网络的流量消耗降至最低 + +572 +00:28:01,849 --> 00:28:05,619 +还能够使快速更改设备状态更加简便 + +573 +00:28:05,619 --> 00:28:07,955 +回到学校的例子 + +574 +00:28:07,955 --> 00:28:11,592 +服务器将预加载以下声明集 + +575 +00:28:11,592 --> 00:28:13,994 +两个用于为各学部 + +576 +00:28:13,994 --> 00:28:17,364 +设置 Wi-Fi 网络的 +激活/配置对 + +577 +00:28:17,364 --> 00:28:19,867 +一个为 IT 管理员 + +578 +00:28:19,867 --> 00:28:23,003 +安装邮件帐户的激活/配置对 + +579 +00:28:23,003 --> 00:28:26,073 +最后是一个安装订阅日历的 + +580 +00:28:26,073 --> 00:28:29,343 +激活/配置对 + +581 +00:28:29,343 --> 00:28:32,446 +每个激活函数都备有一个谓词 + +582 +00:28:32,446 --> 00:28:36,517 +用于检测学部或 +角色管理属性的函数名称 + +583 +00:28:36,517 --> 00:28:39,386 +最初在未分配的设备上加载时 + +584 +00:28:39,386 --> 00:28:44,191 +所有谓词都为假 +因此不会应用任何内容 + +585 +00:28:44,191 --> 00:28:48,428 +接下来 让我们看看 +分配当天会发生什么 + +586 +00:28:48,428 --> 00:28:50,697 +服务器只需要给每位教师 + +587 +00:28:50,697 --> 00:28:52,599 +分别创建 + +588 +00:28:52,599 --> 00:28:55,469 +管理属性声明 + +589 +00:28:55,469 --> 00:28:59,940 +一号教师的角色属性 +列出了低学部和体育 + +590 +00:28:59,940 --> 00:29:05,212 +二号教师的角色属性 +列出了高学部和 IT 管理员 + +591 +00:29:05,212 --> 00:29:07,481 +单独向每个分配的设备 + +592 +00:29:07,481 --> 00:29:09,283 +发送这些声明时 + +593 +00:29:09,283 --> 00:29:13,420 +预加载的激活函数将全部重新求值 + +594 +00:29:13,420 --> 00:29:16,557 +在一号教师的设备中 + +595 +00:29:16,557 --> 00:29:20,327 +激活了低学部和体育教练的配置 + +596 +00:29:20,327 --> 00:29:23,197 +而二号教师的设备 + +597 +00:29:23,197 --> 00:29:27,201 +激活了高学部和 IT 管理员配置 + +598 +00:29:27,201 --> 00:29:29,870 +只需一个声明即可触发 + +599 +00:29:29,870 --> 00:29:33,440 +应用多种配置 + +600 +00:29:33,440 --> 00:29:34,775 +最后 让我们再来看看 + +601 +00:29:34,775 --> 00:29:37,644 +当教师改变角色时会发生什么 + +602 +00:29:37,644 --> 00:29:40,514 +目前为止 +在当前已分配角色的基础上 + +603 +00:29:40,514 --> 00:29:43,450 +二号教师增加了体育教练的角色 + +604 +00:29:43,450 --> 00:29:45,285 +分配给教师的设备中 + +605 +00:29:45,285 --> 00:29:47,921 +管理属性声明现已更新 + +606 +00:29:47,921 --> 00:29:50,958 +加入了新增角色的名称 + +607 +00:29:50,958 --> 00:29:53,460 +当该声明在设备上更新时 + +608 +00:29:53,460 --> 00:29:56,330 +所有激活函数都被重新求值 + +609 +00:29:56,330 --> 00:29:58,999 +于是 适用于体育教练角色的 + +610 +00:29:58,999 --> 00:30:01,735 +订阅日历配置将被启用 + +611 +00:30:01,735 --> 00:30:06,840 +同样 只需要一个声明更改就能触发 + +612 +00:30:06,840 --> 00:30:07,975 +以上过程说明了 + +613 +00:30:07,975 --> 00:30:10,110 +管理属性声明 + +614 +00:30:10,110 --> 00:30:13,514 +提供了一种强大的解决方案 + +615 +00:30:13,514 --> 00:30:16,683 +能够快捷切换设备配置集 + +616 +00:30:16,683 --> 00:30:18,819 +使复杂的服务器端逻辑 + +617 +00:30:18,819 --> 00:30:23,557 +能够转化为设备上的简单状态变化 + +618 +00:30:23,557 --> 00:30:25,826 +最后 让我们总结一下 + +619 +00:30:25,826 --> 00:30:29,029 +我们在 iOS 16 机型 tvOS 16 机型 +和 macOS Ventura 上 + +620 +00:30:29,029 --> 00:30:34,501 +扩展了声明式设备管理的范围 + +621 +00:30:34,501 --> 00:30:37,404 +并且使其适用于所有 +MDM 注册用户的适用类型 + +622 +00:30:37,404 --> 00:30:41,175 +共享 iPad 也包括在内 + +623 +00:30:41,175 --> 00:30:45,078 +因此 所有支持 MDM 的 +Apple 设备 + +624 +00:30:45,078 --> 00:30:49,950 +都能够支持声明式设备管理 + +625 +00:30:49,950 --> 00:30:53,921 +我们为密码 帐户 +和 MDM 安装 App + +626 +00:30:53,921 --> 00:30:56,323 +都添加了新的状态项 + +627 +00:30:56,323 --> 00:31:00,360 +MDM 安装的 App 状态 +为解决 MDM 的关键瓶颈之一 + +628 +00:31:00,360 --> 00:31:03,897 +提供了一个很好的解决方案 + +629 +00:31:03,897 --> 00:31:06,800 +最后 我们增强了谓词语法 + +630 +00:31:06,800 --> 00:31:10,103 +使其更具可扩展性和易于使用 + +631 +00:31:10,103 --> 00:31:13,307 +并添加了新的管理属性声明 + +632 +00:31:13,307 --> 00:31:16,009 +使得服务器能够更便捷地 + +633 +00:31:16,009 --> 00:31:19,813 +将复杂的业务逻辑转移到设备上 + +634 +00:31:19,813 --> 00:31:22,416 +是时候让您的产品 + +635 +00:31:22,416 --> 00:31:24,051 +采用声明式设备管理了 + +636 +00:31:24,051 --> 00:31:26,286 +您将如何运用声明式设备管理 + +637 +00:31:26,286 --> 00:31:28,589 +来重新构想设备管理解决方案 + +638 +00:31:28,589 --> 00:31:32,359 +我们期待见到您的答案 + +639 +00:31:32,359 --> 00:31:35,629 +一如往常 我们期待着您的反馈 + +640 +00:31:35,629 --> 00:31:38,465 +感谢收看 +请继续享受 WWDC 之旅 + +641 +00:31:38,465 --> 00:31:43,570 +♪ + diff --git a/zho/2022 Session 10048 What's new in Safari and WebKit.srt b/zho/2022 Session 10048 What's new in Safari and WebKit.srt new file mode 100644 index 0000000..3df78a4 --- /dev/null +++ b/zho/2022 Session 10048 What's new in Safari and WebKit.srt @@ -0,0 +1,2566 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,710 +♪ + +3 +00:00:09,710 --> 00:00:12,145 +您好!我是 +Kendall Bagley + +4 +00:00:12,145 --> 00:00:14,982 +Safari 浏览器 +团队的软件工程师 + +5 +00:00:14,982 --> 00:00:19,486 +自从上次我们 +在 WWDC 相遇已经过去一年了 + +6 +00:00:19,486 --> 00:00:21,488 +今天 我们会来聊聊 + +7 +00:00:21,488 --> 00:00:23,957 +Safari 浏览器 +和 WebKit 上的所有绝妙的 + +8 +00:00:23,957 --> 00:00:25,425 +新功能和改进 + +9 +00:00:25,425 --> 00:00:28,629 +包括今年 WWDC 的最新更新 + +10 +00:00:28,629 --> 00:00:32,032 +以及过去一整年间的积累 + +11 +00:00:32,032 --> 00:00:35,335 +说实话 这一年可真够忙的! + +12 +00:00:35,335 --> 00:00:38,372 +从去年秋天起 +每次 Safari 的版本更新 + +13 +00:00:38,372 --> 00:00:42,209 +都带来了各位网页开发者一直想要的 + +14 +00:00:42,209 --> 00:00:44,211 +令人激动的全新功能 + +15 +00:00:44,211 --> 00:00:47,014 +一年来 我们做出的所有改进 + +16 +00:00:47,014 --> 00:00:49,349 +都是在响应开发者分享给我们的 + +17 +00:00:49,349 --> 00:00:51,451 +反馈中的重点 + +18 +00:00:51,451 --> 00:00:55,022 +比如用 :has() +伪类添加了父选择器 + +19 +00:00:55,022 --> 00:00:59,059 +新的 flexbox inspector +还有容器查询功能 + +20 +00:00:59,059 --> 00:01:02,362 +我们想要在优化和简化 +您的日常工作的同时 + +21 +00:01:02,362 --> 00:01:05,032 +构建出最强大的 + +22 +00:01:05,032 --> 00:01:06,400 +Web 开发软件 + +23 +00:01:06,400 --> 00:01:09,670 +实际上 画面上的 +就是我们今天要介绍的 + +24 +00:01:09,670 --> 00:01:11,872 +一部分新内容 + +25 +00:01:11,872 --> 00:01:15,242 +但我们不可能在短短的一个讲座里 + +26 +00:01:15,242 --> 00:01:18,378 +面面俱到的讲清楚一切 + +27 +00:01:18,378 --> 00:01:23,150 +过去一年间 Safari 浏览器 + +28 +00:01:23,150 --> 00:01:26,019 +经历了七次版本更新 +带来了总计 162 个 + +29 +00:01:26,019 --> 00:01:27,721 +新网页平台功能 + +30 +00:01:27,721 --> 00:01:31,692 +我们很荣幸能为您提供那么多新工具 + +31 +00:01:31,692 --> 00:01:34,361 +来帮助您建设网站和网页 App + +32 +00:01:34,361 --> 00:01:38,932 +对 macOS 来说 +尽快查看更新内容的最佳方法 + +33 +00:01:38,932 --> 00:01:42,836 +就是使用 +Safari Technology Preview + +34 +00:01:42,836 --> 00:01:45,339 +在那里 您可以试用最新最棒的 + +35 +00:01:45,339 --> 00:01:48,308 +Safari 和 WebKit 功能 + +36 +00:01:48,308 --> 00:01:51,011 +并帮助我们了解还需改进之处 + +37 +00:01:51,011 --> 00:01:55,148 +但如您所见 新功能可真是有一大堆 + +38 +00:01:55,148 --> 00:01:56,250 +让我们来看看 + +39 +00:01:56,250 --> 00:01:59,086 +接下来要讲解的内容吧 + +40 +00:01:59,086 --> 00:02:03,557 +今天我们要了解一下 +新的 HTML 功能 + +41 +00:02:03,557 --> 00:02:05,192 +CSS 改进 + +42 +00:02:05,192 --> 00:02:09,463 +有一大堆改进 帮您改善代码架构 + +43 +00:02:09,463 --> 00:02:15,435 +新的 Web Inspector 工具 +多种新 web API + +44 +00:02:15,435 --> 00:02:19,206 +出色的 JavaScript +和 WebAssembly 功能 + +45 +00:02:19,206 --> 00:02:23,210 +以及安全和隐私方面的改进 + +46 +00:02:23,210 --> 00:02:27,281 +首先 让我们来看看 +HTML 有哪些更新 + +47 +00:02:27,281 --> 00:02:29,750 +我创建了一个网页供我和同事使用 + +48 +00:02:29,750 --> 00:02:32,753 +让我们拿它当作示例 + +49 +00:02:32,753 --> 00:02:36,223 +我这个人比较节俭 喜欢再利用衣服 + +50 +00:02:36,223 --> 00:02:39,226 +好让我的衣橱更加持久 + +51 +00:02:39,226 --> 00:02:41,461 +所以我觉得一个衣物交换网站 + +52 +00:02:41,461 --> 00:02:46,233 +应该是一个好主意 +可以让我们的团队也参与进来 + +53 +00:02:46,233 --> 00:02:49,670 +我设计的网站有一个请求物品按键 + +54 +00:02:49,670 --> 00:02:51,338 +能让您在发现一件中意的衣服时 + +55 +00:02:51,338 --> 00:02:54,174 +展示一个供您填写的表单 + +56 +00:02:54,174 --> 00:02:56,577 +我想在整个 +网页的上方 一个覆盖层上 + +57 +00:02:56,577 --> 00:02:58,812 +展示这个表单 + +58 +00:02:58,812 --> 00:03:01,882 +新的对话框元素 +提供了一个非常简单的方法 + +59 +00:03:01,882 --> 00:03:06,253 +可以稳定而方便的创建覆盖层 + +60 +00:03:06,253 --> 00:03:08,789 +好创建我们的申请表 + +61 +00:03:08,789 --> 00:03:11,959 +CSS 中新的背景伪元素 + +62 +00:03:11,959 --> 00:03:14,461 +让我们可以设置模态后面 + +63 +00:03:14,461 --> 00:03:16,330 +背景的样式 + +64 +00:03:16,330 --> 00:03:19,867 +让我们请求一个物品 调出对话框 + +65 +00:03:19,867 --> 00:03:22,369 +看到这阴影和动画了吗? + +66 +00:03:22,369 --> 00:03:24,471 +看起来真棒! + +67 +00:03:24,471 --> 00:03:27,374 +有人在网站上申请了物品之后 + +68 +00:03:27,374 --> 00:03:28,575 +发布它的人 + +69 +00:03:28,575 --> 00:03:32,980 +要能够接受这个请求 + +70 +00:03:32,980 --> 00:03:35,415 +在页面底部 有一个轮播 + +71 +00:03:35,415 --> 00:03:38,452 +可以让您翻阅所有收到的请求 + +72 +00:03:38,452 --> 00:03:41,788 +但我不希望有人因为 + +73 +00:03:41,788 --> 00:03:44,591 +鼠标或键盘的误点按 + +74 +00:03:44,591 --> 00:03:46,360 +与这些不是在最前面的 + +75 +00:03:46,360 --> 00:03:49,463 +按钮或文本框互动 + +76 +00:03:49,463 --> 00:03:52,766 +我可以使用 +inert 属性来解决这个问题 + +77 +00:03:52,766 --> 00:03:55,202 +在 JavaScript 的这里 + +78 +00:03:55,202 --> 00:03:56,937 +动态应用 inert 属性 + +79 +00:03:56,937 --> 00:04:00,541 +我就可以在用户切换轮播时 + +80 +00:04:00,541 --> 00:04:02,843 +禁用与非当前轮播卡片上 + +81 +00:04:02,843 --> 00:04:04,945 +元素的互动 + +82 +00:04:04,945 --> 00:04:08,782 +Inert 还能关闭 + +83 +00:04:08,782 --> 00:04:11,885 +辅助技术的互动 防止屏幕阅读器 + +84 +00:04:11,885 --> 00:04:14,688 +读出那些禁用的项目 + +85 +00:04:14,688 --> 00:04:16,523 +这能更清晰的引导系统 + +86 +00:04:16,523 --> 00:04:20,661 +知道应该与哪些元素交互 + +87 +00:04:20,661 --> 00:04:25,399 +最后 对 HTML 来说 +还有新的图像延迟加载功能 + +88 +00:04:25,399 --> 00:04:27,534 +在我的网站上 那些头部的图标 + +89 +00:04:27,534 --> 00:04:32,339 +需要立刻加载 但那些初次加载时 + +90 +00:04:32,339 --> 00:04:34,875 +处在屏幕外的衣物图片 + +91 +00:04:34,875 --> 00:04:37,511 +可以对它们使用延迟加载 + +92 +00:04:37,511 --> 00:04:40,881 +这样 只有在用户 +滚动到它们时 图片才会加载 + +93 +00:04:40,881 --> 00:04:44,685 +这会使网页的 +加载和响应看起来都变得更快 + +94 +00:04:44,685 --> 00:04:47,254 +我很喜欢这个网站现在的样子 + +95 +00:04:47,254 --> 00:04:48,989 +对于那些使用 + +96 +00:04:48,989 --> 00:04:52,392 +辅助技术的人来说 它也会十分好用 + +97 +00:04:52,392 --> 00:04:56,697 +这些 HTML 特性只是一个开始 + +98 +00:04:56,697 --> 00:04:58,966 +因为今年 CSS 也有许多 + +99 +00:04:58,966 --> 00:05:02,269 +值得关注之处 + +100 +00:05:02,269 --> 00:05:04,838 +我们对 CSS 的关注重点 + +101 +00:05:04,838 --> 00:05:07,975 +主要是通过更强大的架构 让您可以 + +102 +00:05:07,975 --> 00:05:10,410 +更轻松的复用您的 CSS + +103 +00:05:10,410 --> 00:05:13,280 +鉴于此 我们知道 +对于新 web 技术 + +104 +00:05:13,280 --> 00:05:16,650 +开发者的头号需求就是容器查询 + +105 +00:05:16,650 --> 00:05:19,419 +我们很高兴地宣布 + +106 +00:05:19,419 --> 00:05:22,589 +容器查询会在 +Safari 16 中实装! + +107 +00:05:22,589 --> 00:05:24,758 +您将可以同时使用尺寸查询 + +108 +00:05:24,758 --> 00:05:27,261 +和容器查询单元 + +109 +00:05:27,261 --> 00:05:30,197 +在这里 +我在尝试为这个衣物交换网站 + +110 +00:05:30,197 --> 00:05:32,499 +设计另一种布局 + +111 +00:05:32,499 --> 00:05:35,235 +我要把这个代表一件衣服的卡片 + +112 +00:05:35,235 --> 00:05:38,672 +变成一个可复用的组件 +并把这个组件 + +113 +00:05:38,672 --> 00:05:42,176 +放到页面布局的几个不同位置 + +114 +00:05:42,176 --> 00:05:43,610 +在侧边栏中 + +115 +00:05:43,610 --> 00:05:46,580 +这里的空间有点狭窄 + +116 +00:05:46,580 --> 00:05:49,149 +所以我希望组件中的内容 + +117 +00:05:49,149 --> 00:05:51,451 +垂直堆叠 + +118 +00:05:51,451 --> 00:05:53,086 +在物品的主网格中 + +119 +00:05:53,086 --> 00:05:56,190 +我想把第一个变成主页横幅 + +120 +00:05:56,190 --> 00:05:59,660 +让它占满所有横向空间 + +121 +00:05:59,660 --> 00:06:02,896 +并把其中的内容调整成适合 + +122 +00:06:02,896 --> 00:06:05,232 +宽布局的样式 + +123 +00:06:05,232 --> 00:06:07,968 +主内容区域中的其他物品 + +124 +00:06:07,968 --> 00:06:10,871 +应被分成较小的列 + +125 +00:06:10,871 --> 00:06:12,873 +所以我又创建了一种布局 + +126 +00:06:12,873 --> 00:06:17,110 +适用于中等横向空间的情况 + +127 +00:06:17,110 --> 00:06:20,747 +用容器查询 而不是媒体查询的方式 + +128 +00:06:20,747 --> 00:06:22,416 +处理这种布局的变化 + +129 +00:06:22,416 --> 00:06:26,420 +我只需为这个组件写一次布局代码 + +130 +00:06:26,420 --> 00:06:29,523 +就可以在网站的任何地方 +任何大小的容器中 + +131 +00:06:29,523 --> 00:06:31,859 +使用这个组件 + +132 +00:06:31,859 --> 00:06:35,395 +且始终会应用正确的布局 + +133 +00:06:35,395 --> 00:06:38,799 +我指定了容器应该使用哪些元素 + +134 +00:06:38,799 --> 00:06:41,935 +以及它应该只衡量行内大小 + +135 +00:06:41,935 --> 00:06:45,806 +还是要同时衡量行内和块级大小 + +136 +00:06:45,806 --> 00:06:48,909 +这是通过 +container-type 属性实现的 + +137 +00:06:48,909 --> 00:06:51,445 +为容器命名是一个可选项 + +138 +00:06:51,445 --> 00:06:53,614 +用 container-name 属性即可 + +139 +00:06:53,614 --> 00:06:58,519 +它能让我更加灵活的构建 HTML + +140 +00:06:58,519 --> 00:07:03,090 +然后我使用 @container 规则 +基于容器的尺寸 + +141 +00:07:03,090 --> 00:07:05,359 +规定了应用样式的条件 + +142 +00:07:05,359 --> 00:07:08,095 +这里 如果一个衣物卡片组件 + +143 +00:07:08,095 --> 00:07:10,898 +处于一个宽度超过 +250 像素的组件中 + +144 +00:07:10,898 --> 00:07:14,968 +网格就会有两列 而不是一列 + +145 +00:07:14,968 --> 00:07:18,739 +CSS 架构的另一个更新:级联层 + +146 +00:07:18,739 --> 00:07:22,809 +这是 CSS 级联的一个重大升级 + +147 +00:07:22,809 --> 00:07:24,912 +自 CSS 诞生之日起 + +148 +00:07:24,912 --> 00:07:28,348 +级联就一直是由这些不同的层组成的 + +149 +00:07:28,348 --> 00:07:32,052 +但无论各层中给定选择器的 + +150 +00:07:32,052 --> 00:07:34,621 +优先级如何 作者样式 + +151 +00:07:34,621 --> 00:07:37,024 +也就是您作为 +web 开发者所写的样式 + +152 +00:07:37,024 --> 00:07:39,860 +总是会覆盖浏览器默认样式 + +153 +00:07:39,860 --> 00:07:43,597 +而行内样式则总是高于作者样式 + +154 +00:07:43,597 --> 00:07:46,600 +以此类推 剩下的层级也如此 + +155 +00:07:46,600 --> 00:07:49,369 +级联层采用了这种概念 + +156 +00:07:49,369 --> 00:07:52,339 +还允许您创建自己的自定义层 + +157 +00:07:52,339 --> 00:07:57,277 +每层中的优先级都是独立计算得出的 + +158 +00:07:57,277 --> 00:08:00,380 +一整层的优先级会高于另一整层 + +159 +00:08:00,380 --> 00:08:04,985 +无论使用中的选择器优先级如何 + +160 +00:08:04,985 --> 00:08:08,388 +而哪些层高于哪些层是由您 + +161 +00:08:08,388 --> 00:08:13,293 +通过在 CSS 中 +定义层顺序决定的 + +162 +00:08:13,293 --> 00:08:15,395 +在为大型项目构建 CSS + +163 +00:08:15,395 --> 00:08:18,298 +以及长期维护其代码时 + +164 +00:08:18,298 --> 00:08:20,767 +级联层会成为一种好用的工具 + +165 +00:08:20,767 --> 00:08:22,202 +也许您的团队会用它 + +166 +00:08:22,202 --> 00:08:24,938 +防止一个设计系统被覆盖 + +167 +00:08:24,938 --> 00:08:28,775 +或者把它与您为项目中的 +自定义样式使用的框架分开 + +168 +00:08:28,775 --> 00:08:30,911 +一切都取决于您! + +169 +00:08:30,911 --> 00:08:33,780 +对您的 CSS 架构来说 +所有这些精彩的 + +170 +00:08:33,780 --> 00:08:36,917 +新改进之上的 +画龙点睛一笔就是 :has() + +171 +00:08:36,917 --> 00:08:40,921 +这是一个伪类 +用作大家期待已久的父选择器 + +172 +00:08:40,921 --> 00:08:42,689 +它还有许多其他功能 + +173 +00:08:42,689 --> 00:08:45,626 +与 CSS 中的 +任何其他选择器结合 + +174 +00:08:45,626 --> 00:08:48,629 +:has() 可以用于 +寻找兄弟元素 属性 + +175 +00:08:48,629 --> 00:08:51,131 +表单文本框状态等等 + +176 +00:08:51,131 --> 00:08:54,034 +它真的很强大 + +177 +00:08:54,034 --> 00:08:56,970 +在这里 我想在 +每当有人为一条消息 + +178 +00:08:56,970 --> 00:08:59,706 +选中了“Urgent?”(紧急?) 复选框时 + +179 +00:08:59,706 --> 00:09:01,608 +就高亮显示整个消息框 + +180 +00:09:01,608 --> 00:09:05,145 +我可以用 :has 伪类来规定 + +181 +00:09:05,145 --> 00:09:08,715 +只要表单元素有一个复选框被选中的 + +182 +00:09:08,715 --> 00:09:12,719 +复选框类型输入 +就应用这个 CSS + +183 +00:09:12,719 --> 00:09:16,890 +我甚至都不需要 +用 JavaScript + +184 +00:09:16,890 --> 00:09:19,359 +我们希望这些为处理 + +185 +00:09:19,359 --> 00:09:21,995 +CSS 架构所进行的改进 + +186 +00:09:21,995 --> 00:09:25,999 +包括 :has() 级联层 +以及容器查询 + +187 +00:09:25,999 --> 00:09:28,135 +能大大改善 +您作为一名 web 开发者的 + +188 +00:09:28,135 --> 00:09:30,470 +工作效率 + +189 +00:09:30,470 --> 00:09:33,240 +但让我们如此兴奋的 CSS 改进 + +190 +00:09:33,240 --> 00:09:35,976 +可不止这些 + +191 +00:09:35,976 --> 00:09:39,179 +开发者一直想要一个 +类似现有的视口单元的工具 + +192 +00:09:39,179 --> 00:09:41,915 +但要更好的适配那些在滚动时 + +193 +00:09:41,915 --> 00:09:44,618 +视口尺寸会变化的设备 + +194 +00:09:44,618 --> 00:09:48,589 +为此我们给大家 +带来了新的视口单元 + +195 +00:09:48,589 --> 00:09:50,457 +如果您想知道视口在最小状态时 + +196 +00:09:50,457 --> 00:09:53,527 +它的高度 用 svh 即可 + +197 +00:09:53,527 --> 00:09:54,828 +要是想知道视口 + +198 +00:09:54,828 --> 00:09:57,431 +在最大状态时的高度 请用 lvh + +199 +00:09:57,431 --> 00:10:00,868 +只要记住:s 代表小 l 代表大 + +200 +00:10:00,868 --> 00:10:03,637 +对于那些始终匹配视口 + +201 +00:10:03,637 --> 00:10:07,741 +当前实际高度的动态数字 +用 dvh 即可 + +202 +00:10:07,741 --> 00:10:10,210 +不只是高度 + +203 +00:10:10,210 --> 00:10:14,581 +我们还为您准备了更多视口单元 + +204 +00:10:14,581 --> 00:10:17,618 +有宽度单元 与常用的高度单元配合 + +205 +00:10:17,618 --> 00:10:20,687 +可以改善完整性 + +206 +00:10:20,687 --> 00:10:24,091 +还有块和行内元素 + +207 +00:10:24,091 --> 00:10:25,792 +它们在多语言情况下 + +208 +00:10:25,792 --> 00:10:28,729 +不同语言的文本 +溢出情况不同时 会很有用 + +209 +00:10:28,729 --> 00:10:32,332 +当然我们也没忘了最小和最大值 + +210 +00:10:32,332 --> 00:10:35,736 +但要是您想在网页上创造一些运动 + +211 +00:10:35,736 --> 00:10:39,039 +而不只是做出被动反应呢? + +212 +00:10:39,039 --> 00:10:42,509 +以前 动画一直都是高度声明性的 + +213 +00:10:42,509 --> 00:10:46,079 +您要指定一个 +开始 结束 和持续时间 + +214 +00:10:46,079 --> 00:10:48,015 +让物体动起来 + +215 +00:10:48,015 --> 00:10:51,785 +但让网页元素动起来 +一直都是一个挑战 + +216 +00:10:51,785 --> 00:10:54,655 +无论是在您试图 +让它沿着弧形轨迹移动时 + +217 +00:10:54,655 --> 00:10:59,426 +还是只是让它根据一个偏移量移动 + +218 +00:10:59,426 --> 00:11:02,162 +而我想在您点按头部横幅时 + +219 +00:11:02,162 --> 00:11:04,531 +添加一个秘密动画效果 + +220 +00:11:04,531 --> 00:11:07,801 +因为这样会很有趣 + +221 +00:11:07,801 --> 00:11:10,637 +有了新的 offset-path + +222 +00:11:10,637 --> 00:11:13,574 +您可以定义对象运动的轨迹 + +223 +00:11:13,574 --> 00:11:17,678 +用 offset-path +来设置运动轨迹 + +224 +00:11:17,678 --> 00:11:19,947 +用 offset-distance +来设置关键帧效果 + +225 +00:11:19,947 --> 00:11:24,218 +然后用 animation 属性 +来应用关键帧效果 + +226 +00:11:24,218 --> 00:11:27,855 +这样您就可以全权控制 + +227 +00:11:27,855 --> 00:11:30,190 +CSS 中的动画 + +228 +00:11:30,190 --> 00:11:33,660 +我们还想把更多的网页控制权交给您 + +229 +00:11:33,660 --> 00:11:36,430 +即使是那些通常都是被 + +230 +00:11:36,430 --> 00:11:39,132 +浏览器引擎定义的那一部分 + +231 +00:11:39,132 --> 00:11:43,470 +而 over scroll-behavior +就是这类实践的第一个例子 + +232 +00:11:43,470 --> 00:11:46,473 +自网络诞生以来 如果您点按了一个 + +233 +00:11:46,473 --> 00:11:49,109 +把您转至网页某处的链接 + +234 +00:11:49,109 --> 00:11:51,812 +它会在视觉上表现为一次跳跃 + +235 +00:11:51,812 --> 00:11:54,982 +有时候这会使用户迷失方向 + +236 +00:11:54,982 --> 00:11:58,085 +CSS 中的 +scroll-behavior 属性 + +237 +00:11:58,085 --> 00:12:01,788 +允许您指定是否想要这种行为 + +238 +00:12:01,788 --> 00:12:06,760 +它的默认值是自动 +也就是显示为那种跳跃 + +239 +00:12:06,760 --> 00:12:09,630 +如果把 scroll-behavior +指定为平滑 + +240 +00:12:09,630 --> 00:12:12,699 +浏览器就会平滑的滚动到 + +241 +00:12:12,699 --> 00:12:14,902 +页面上的指定位置 + +242 +00:12:14,902 --> 00:12:17,604 +您还可以用 JavaScript +方法来实现这个效果 + +243 +00:12:17,604 --> 00:12:21,942 +用 Window.scroll() +scrollTo() 或 scrollBy() 即可 + +244 +00:12:21,942 --> 00:12:24,044 +最了解您的客户的人就是您自己 + +245 +00:12:24,044 --> 00:12:27,247 +您应该能定义自己的网页体验 + +246 +00:12:27,247 --> 00:12:30,417 +而不必拘束于浏览器引擎默认值 + +247 +00:12:30,417 --> 00:12:33,654 +在这方面 :focus-visible + +248 +00:12:33,654 --> 00:12:37,157 +和 accent-color +同样可以大放异彩 + +249 +00:12:37,157 --> 00:12:39,860 +如果您曾经想要对焦点选择器 + +250 +00:12:39,860 --> 00:12:42,496 +应用某种样式 以使其更符合 + +251 +00:12:42,496 --> 00:12:44,364 +您的整体设计 + +252 +00:12:44,364 --> 00:12:47,935 +那您可能已经很熟悉焦点选择器了 + +253 +00:12:47,935 --> 00:12:50,571 +但这么做可能会导致 + +254 +00:12:50,571 --> 00:12:55,576 +损失一些 +基于浏览器的无障碍辅助功能 + +255 +00:12:55,576 --> 00:12:59,046 +而在我的网站上 +我喜欢用自定义表单颜色 + +256 +00:12:59,046 --> 00:13:02,349 +而不是内置的颜色 + +257 +00:13:02,349 --> 00:13:05,285 +让我们把头部横幅的蓝绿色 + +258 +00:13:05,285 --> 00:13:09,156 +用在这里的焦点高亮和复选框上吧 + +259 +00:13:09,156 --> 00:13:11,458 +用 :focus-visible 伪类 + +260 +00:13:11,458 --> 00:13:14,528 +您可以自定义焦点选择器的样式 + +261 +00:13:14,528 --> 00:13:18,098 +同时使其只在浏览器原生支持时 + +262 +00:13:18,098 --> 00:13:21,802 +才显示出来 + +263 +00:13:21,802 --> 00:13:25,172 +而且 +要为您的表单增加另一层自定义 + +264 +00:13:25,172 --> 00:13:27,708 +您还可以用 +accent-color 来改变 + +265 +00:13:27,708 --> 00:13:30,844 +表单控件 UI 不同部分的颜色 + +266 +00:13:30,844 --> 00:13:32,913 +它可以用来调整复选框 + +267 +00:13:32,913 --> 00:13:35,983 +以及单选按钮 等等 + +268 +00:13:35,983 --> 00:13:38,018 +另外 对于 CSS + +269 +00:13:38,018 --> 00:13:42,256 +我们一直在越来越多的 +替换掉 WebKit 前缀 + +270 +00:13:42,256 --> 00:13:44,124 +它们曾经是进行 + +271 +00:13:44,124 --> 00:13:47,194 +特性实验的完美方法 但现在 + +272 +00:13:47,194 --> 00:13:50,297 +我们可以逐步接近 +它们的标准定义属性了 + +273 +00:13:50,297 --> 00:13:55,202 +这样可以使您的 CSS +更易于编写 提高互操作性 + +274 +00:13:55,202 --> 00:13:59,940 +但别担心 您已有的带有 +WebKit 前缀的 CSS + +275 +00:13:59,940 --> 00:14:02,009 +将在您把它们过渡至 + +276 +00:14:02,009 --> 00:14:04,578 +相应的 web 标准期间正常工作 + +277 +00:14:04,578 --> 00:14:08,682 +Backface-visibility +print-color-adjust + +278 +00:14:08,682 --> 00:14:11,919 +以及 text-align: match-parent +都与它们的对应前缀版本 + +279 +00:14:11,919 --> 00:14:14,521 +完全相同 + +280 +00:14:14,521 --> 00:14:17,558 +Mask 和 text-combine-upright + +281 +00:14:17,558 --> 00:14:20,827 +都从前缀版本更新了语法 + +282 +00:14:20,827 --> 00:14:23,163 +以符合标准 + +283 +00:14:23,163 --> 00:14:26,633 +而且不带前缀的 +appearance 属性还增加了 + +284 +00:14:26,633 --> 00:14:29,303 +对新的 auto 值的支持 +但 Safari 16 中移除了 + +285 +00:14:29,303 --> 00:14:32,306 +WebKit 特定的值 + +286 +00:14:32,306 --> 00:14:34,541 +比如 caret 和 listitem + +287 +00:14:34,541 --> 00:14:38,345 +以符合标准规范 + +288 +00:14:38,345 --> 00:14:39,613 +我们新增的排版选项 + +289 +00:14:39,613 --> 00:14:42,249 +也颇值得关注 + +290 +00:14:42,249 --> 00:14:45,419 +特别是 +font-palette 属性的加入 + +291 +00:14:45,419 --> 00:14:48,155 +使为彩色字体选择调色板 + +292 +00:14:48,155 --> 00:14:50,257 +变得更加简单 + +293 +00:14:50,257 --> 00:14:52,192 +尝试为我的网站添加 logo + +294 +00:14:52,192 --> 00:14:55,796 +想必会很酷 + +295 +00:14:55,796 --> 00:14:57,264 +我们可以用内置的深色 + +296 +00:14:57,264 --> 00:15:00,133 +或浅色调色板来试试看怎么样 + +297 +00:15:00,133 --> 00:15:02,369 +甚至还可以用色彩覆盖 + +298 +00:15:02,369 --> 00:15:05,405 +自定义加入一点明亮的黄色 + +299 +00:15:05,405 --> 00:15:08,909 +使其完全符合我想要的样子 + +300 +00:15:08,909 --> 00:15:11,778 +在排版方面 还增加了 + +301 +00:15:11,778 --> 00:15:15,282 +text-decoration-skip-ink +它允许您控制 + +302 +00:15:15,282 --> 00:15:18,051 +一条下划线或上划线 + +303 +00:15:18,051 --> 00:15:21,221 +与字母或字符相交时会发生什么 + +304 +00:15:21,221 --> 00:15:25,492 +还有 ic 单元 可以让您在块方向 + +305 +00:15:25,492 --> 00:15:28,829 +精确排列 CJK 字符 + +306 +00:15:28,829 --> 00:15:31,765 +对于中文 日文和韩文等语言 + +307 +00:15:31,765 --> 00:15:36,570 +它可以助您创建一个整洁的排版网格 + +308 +00:15:36,570 --> 00:15:40,741 +最后在这些 +优秀的 CSS 特性中 + +309 +00:15:40,741 --> 00:15:43,777 +我们当然还得说说 subgrid + +310 +00:15:43,777 --> 00:15:47,414 +多年来 网页布局一直都是一个难题 + +311 +00:15:47,414 --> 00:15:50,217 +CSS Grid 是革命性的功能 + +312 +00:15:50,217 --> 00:15:55,455 +但它只对网格容器的直接子级有用 + +313 +00:15:55,455 --> 00:15:59,526 +在这里我使用了 +CSS Grid 来布局这些卡片 + +314 +00:15:59,526 --> 00:16:01,528 +使其根据视口宽度 + +315 +00:16:01,528 --> 00:16:04,965 +通过增加或移除列来调整布局 + +316 +00:16:04,965 --> 00:16:08,068 +这里没有进行任何媒体查询 + +317 +00:16:08,068 --> 00:16:12,439 +但每张卡片的内容的尺寸都是不同的 + +318 +00:16:12,439 --> 00:16:14,541 +有些标题会更长 + +319 +00:16:14,541 --> 00:16:17,244 +照片的宽高比也不同 + +320 +00:16:17,244 --> 00:16:21,048 +这使一切看起来很乱 + +321 +00:16:21,048 --> 00:16:23,684 +我想要让页面上所有的 + +322 +00:16:23,684 --> 00:16:27,454 +请求物品按键和消息框都对齐 + +323 +00:16:27,454 --> 00:16:31,425 +我想要在出现标题很长的卡片时 + +324 +00:16:31,425 --> 00:16:35,696 +其他卡片能随其调整 +使它们维持相同的间距 + +325 +00:16:35,696 --> 00:16:39,132 +现在 我们可以用 +subgrid 来实现此功能 + +326 +00:16:39,132 --> 00:16:41,401 +我在每张卡片上都放了一个网格 + +327 +00:16:41,401 --> 00:16:44,905 +并把这些网格 +都绑定到了它们的父网格 + +328 +00:16:44,905 --> 00:16:49,843 +只需写入 +“grid-template-rows: subgrid”即可 + +329 +00:16:49,843 --> 00:16:53,380 +您可以在 Web Inspector +的 Grid Inspector 中看到 + +330 +00:16:53,380 --> 00:16:57,184 +所有衣物卡片的内容都完美对齐了 + +331 +00:16:57,184 --> 00:17:01,622 +在这里我还可以 +启用所有我需要的网格 + +332 +00:17:01,622 --> 00:17:06,727 +使用 Web Inspector +能让许多 CSS 作业都变得轻松 + +333 +00:17:06,727 --> 00:17:10,163 +事实上 +Web Inspector 获得了许多 + +334 +00:17:10,163 --> 00:17:11,498 +很棒的新功能 + +335 +00:17:11,498 --> 00:17:14,968 +我觉得您一定会跃跃欲试的 + +336 +00:17:14,968 --> 00:17:17,271 +首先 布局变的更容易写了 + +337 +00:17:17,271 --> 00:17:19,406 +因为您可以实时看到它们的情况 + +338 +00:17:19,406 --> 00:17:23,744 +这正是 +Web Inspector 如此重要的原因 + +339 +00:17:23,744 --> 00:17:26,146 +另外 有了新的 +Flexbox Inspector + +340 +00:17:26,146 --> 00:17:30,317 +您可以直接看到各元素之间的间距 + +341 +00:17:30,317 --> 00:17:32,819 +在我的网站上 +我在为头部横幅添加图标时 + +342 +00:17:32,819 --> 00:17:35,589 +遇到了一些麻烦 + +343 +00:17:35,589 --> 00:17:39,626 +我只需点按检查元素 + +344 +00:17:39,626 --> 00:17:42,162 +选择布局选项卡 + +345 +00:17:42,162 --> 00:17:44,932 +因为我现在要看的不是网格 + +346 +00:17:44,932 --> 00:17:47,534 +我可以折叠这一部分 + +347 +00:17:47,534 --> 00:17:51,205 +直接进入新的 +Flexbox Inspector + +348 +00:17:51,205 --> 00:17:53,240 +甚至只需点按一下 + +349 +00:17:53,240 --> 00:17:57,911 +我就能打开所有的视图 +而且并不影响流畅性 + +350 +00:17:57,911 --> 00:18:00,147 +打开所有视图后 + +351 +00:18:00,147 --> 00:18:01,915 +我可以清楚的看到那些井号 + +352 +00:18:01,915 --> 00:18:05,419 +和容器框标识着 +这些元素是如何排列的的 + +353 +00:18:05,419 --> 00:18:09,590 +以及空白空间为什么占据了视图 + +354 +00:18:09,590 --> 00:18:13,393 +现在我可以使用新的对齐编辑器 + +355 +00:18:13,393 --> 00:18:16,163 +来好好对齐这些内容了 + +356 +00:18:16,163 --> 00:18:18,065 +转到样式选项卡 + +357 +00:18:18,065 --> 00:18:21,134 +找到 align-items +旁的一个新按钮 + +358 +00:18:21,134 --> 00:18:24,137 +在这里 我可以切换不同的选项 + +359 +00:18:24,137 --> 00:18:26,907 +来找到哪种样式最适合我的头部横幅 + +360 +00:18:26,907 --> 00:18:30,677 +justify-content +也可以应用同样的方法 + +361 +00:18:30,677 --> 00:18:33,881 +同样的 只需在不同选项间切换 + +362 +00:18:33,881 --> 00:18:39,253 +找到适合您的那一款 + +363 +00:18:39,253 --> 00:18:43,090 +我还觉得这些黄色图标有点太小了 + +364 +00:18:43,090 --> 00:18:47,060 +我想让它们变得与红色图标一样大 + +365 +00:18:47,060 --> 00:18:49,396 +这些红色图标应该在名称中 + +366 +00:18:49,396 --> 00:18:50,931 +使用了“medium”这个变量 + +367 +00:18:50,931 --> 00:18:54,768 +但我实在想不起来它们的全名了 + +368 +00:18:54,768 --> 00:18:56,803 +我可以检查这些黄色图标 + +369 +00:18:56,803 --> 00:18:58,805 +在 inspector 中更改它们的高度 + +370 +00:18:58,805 --> 00:19:02,009 +这样就可以调整它们的尺寸 + +371 +00:19:02,009 --> 00:19:05,312 +而且 有了新的 +CSS 模糊自动补全功能 + +372 +00:19:05,312 --> 00:19:10,851 +我可以直接输入“medium” +我想要的变量就直接出现了 + +373 +00:19:10,851 --> 00:19:14,354 +尽管“medium” +是在其名称的末尾 + +374 +00:19:14,354 --> 00:19:16,256 +这样一来那些黄色图标 + +375 +00:19:16,256 --> 00:19:20,093 +终于不会显得太小了 + +376 +00:19:20,093 --> 00:19:23,030 +而且 对于我要检查的元素中 + +377 +00:19:23,030 --> 00:19:26,233 +不需要的各图标中的其他变量 + +378 +00:19:26,233 --> 00:19:29,369 +新的 CSS 工具 +会将它们隐藏起来 + +379 +00:19:29,369 --> 00:19:32,339 +但别担心 +如果您需要 也有一个按键 + +380 +00:19:32,339 --> 00:19:34,308 +可以显示它们 + +381 +00:19:34,308 --> 00:19:38,145 +接下来的这个 可能是今年 +Web Inspector 最为激动人心的更新 + +382 +00:19:38,145 --> 00:19:40,514 +我们很高兴的宣布 + +383 +00:19:40,514 --> 00:19:44,518 +Safari Web Inspector +支持开发者工具扩展了 + +384 +00:19:44,518 --> 00:19:47,688 +创作了您最喜欢的 +开发者工具扩展的人 + +385 +00:19:47,688 --> 00:19:50,390 +现在可以把它们 +移植到 Safari 浏览器上了 + +386 +00:19:50,390 --> 00:19:55,329 +可以使用它们在其他浏览器中 +使用的相同底层 API 来完成移植 + +387 +00:19:55,329 --> 00:19:58,532 +如果您想学习如何为 + +388 +00:19:58,532 --> 00:20:00,367 +Web Inspector +开发扩展 + +389 +00:20:00,367 --> 00:20:03,637 +探索新 API 并开始自己 + +390 +00:20:03,637 --> 00:20:06,707 +设置与使用它们 请务必查看 + +391 +00:20:06,707 --> 00:20:12,412 +今年 WWDC 的“创建 +Safari Web Inspector 扩展”讲座 + +392 +00:20:12,412 --> 00:20:15,082 +现在我们已经了解了相当多的 + +393 +00:20:15,082 --> 00:20:18,485 +我们的前端技术 是时候换个方向 + +394 +00:20:18,485 --> 00:20:22,256 +了解一下我们的 +web API 有什么新内容了 + +395 +00:20:22,256 --> 00:20:26,827 +我们很高兴的宣布 +对 web push 的支持 + +396 +00:20:26,827 --> 00:20:31,365 +该功能会在 Safari 16 +和 macOS Ventura 中更新 + +397 +00:20:31,365 --> 00:20:35,769 +它将在明年登陆 +iOS 和 iPadOS + +398 +00:20:35,769 --> 00:20:39,406 +Web push 让您可以从 +网站或 web App 向用户 + +399 +00:20:39,406 --> 00:20:41,775 +远程发送通知 + +400 +00:20:41,775 --> 00:20:46,513 +这是一个完全可互操作的 +基于标准的功能 + +401 +00:20:46,513 --> 00:20:48,882 +如果您已经在其他浏览器中 + +402 +00:20:48,882 --> 00:20:50,918 +部署实现了 web push + +403 +00:20:50,918 --> 00:20:55,255 +那您应该无需任何修改 +就可使其在 Safari 浏览器上工作 + +404 +00:20:55,255 --> 00:20:58,825 +而且您也不需要 +Apple Developer 账户 + +405 +00:20:58,825 --> 00:21:00,794 +要了解所有详情 + +406 +00:21:00,794 --> 00:21:06,433 +请查看 WWDC 22 的“了解 +Safari 浏览器的 Web Push”讲座 + +407 +00:21:06,433 --> 00:21:08,569 +如果您为 +web push 感到兴奋 + +408 +00:21:08,569 --> 00:21:10,204 +那想必新的 +web App 清单改进 + +409 +00:21:10,204 --> 00:21:13,273 +也会令您兴奋 + +410 +00:21:13,273 --> 00:21:16,810 +现在 您可以在 +manifest 文件中 + +411 +00:21:16,810 --> 00:21:20,247 +自定义用户保存在主屏幕上的图标 + +412 +00:21:20,247 --> 00:21:23,317 +要优先显示清单中的图标 + +413 +00:21:23,317 --> 00:21:24,918 +您要确保在 HTML head 中 + +414 +00:21:24,918 --> 00:21:28,922 +没有定义 apple-touch-icon + +415 +00:21:28,922 --> 00:21:32,826 +如果您想在 iOS 和 +iPadOS 中显示一种图标 + +416 +00:21:32,826 --> 00:21:36,463 +而在其他移动平台上显示另一种 + +417 +00:21:36,463 --> 00:21:39,967 +您仍然可以使用 +HTML head 中的 + +418 +00:21:39,967 --> 00:21:44,037 +apple-touch-icon +来定义 Apple 设备的图标 + +419 +00:21:44,037 --> 00:21:47,174 +如果您没有在这两个地方设置图标 + +420 +00:21:47,174 --> 00:21:50,043 +用户把您的网站保存到主屏幕时 + +421 +00:21:50,043 --> 00:21:52,546 +就只会看到您的网站的屏幕截图 + +422 +00:21:52,546 --> 00:21:56,283 +激动人心的是 我们在 +载入 manifest 文件时 + +423 +00:21:56,283 --> 00:21:58,685 +不再等待用户在共享菜单中选择 + +424 +00:21:58,685 --> 00:22:01,889 +“添加到主屏幕”了 +也就是说 您可以 + +425 +00:22:01,889 --> 00:22:05,325 +在您的整个网站上 +用 manifest 文件来定义网页特征 + +426 +00:22:05,325 --> 00:22:08,428 +进一步降低 + +427 +00:22:08,428 --> 00:22:11,632 +使用 meta 标签的需求 + +428 +00:22:11,632 --> 00:22:15,235 +此外 我们的 API 还改进了 + +429 +00:22:15,235 --> 00:22:18,172 +相同来源情况下 多种浏览上下文的 + +430 +00:22:18,172 --> 00:22:20,007 +网页使用情况 + +431 +00:22:20,007 --> 00:22:22,843 +广播频道允许您在那些 + +432 +00:22:22,843 --> 00:22:25,812 +不同浏览上下文间发送通知 + +433 +00:22:25,812 --> 00:22:29,249 +假设有人正在使用这个衣物交换网站 + +434 +00:22:29,249 --> 00:22:32,619 +并同时在两个窗口中打开了它 + +435 +00:22:32,619 --> 00:22:35,923 +然后用户 +在其中一个窗口请求了一件衣服 + +436 +00:22:35,923 --> 00:22:39,626 +我们能够发布一条消息 +在其他打开的 + +437 +00:22:39,626 --> 00:22:43,397 +选项卡或窗口中同步这个不可用状态 + +438 +00:22:43,397 --> 00:22:47,134 +但也许您不只需要更新后台选项卡 + +439 +00:22:47,134 --> 00:22:49,803 +还需要更新网站保存的文件 + +440 +00:22:49,803 --> 00:22:51,605 +为此 我们还更新了 + +441 +00:22:51,605 --> 00:22:54,675 +文件系统访问 API + +442 +00:22:54,675 --> 00:22:57,177 +我们在这一年间的几个版本中 + +443 +00:22:57,177 --> 00:22:59,780 +对这个 API 进行了增量更新 + +444 +00:22:59,780 --> 00:23:02,983 +从访问域私有文件系统开始 + +445 +00:23:02,983 --> 00:23:05,786 +它是基于访问域的私有存储 + +446 +00:23:05,786 --> 00:23:06,854 +比如 + +447 +00:23:06,854 --> 00:23:09,857 +我的衣物交换网站上的文件 + +448 +00:23:09,857 --> 00:23:13,694 +不会被其他网站 +比如 apple.com 读取 + +449 +00:23:13,694 --> 00:23:17,164 +然后我们给 API 添加了 + +450 +00:23:17,164 --> 00:23:21,068 +FileSystemFileHandle +的 getFile() 方法 + +451 +00:23:21,068 --> 00:23:24,071 +它会从您的网站的 +根目录读取检索得出的已存在的文件 + +452 +00:23:24,071 --> 00:23:26,540 +就像我们对这个 + +453 +00:23:26,540 --> 00:23:29,910 +我们刚刚创建的草稿文件所做的一样 + +454 +00:23:29,910 --> 00:23:33,146 +现在让我们看看我们今年 + +455 +00:23:33,146 --> 00:23:37,718 +最有活力的 API 新内容 色彩 + +456 +00:23:37,718 --> 00:23:40,854 +Display P3 色域使我们可以 + +457 +00:23:40,854 --> 00:23:45,158 +呈现 RGB 色域中不存在的颜色 + +458 +00:23:45,158 --> 00:23:48,295 +这是色彩选择器的一些示例 + +459 +00:23:48,295 --> 00:23:50,464 +弯曲的白线的左侧 + +460 +00:23:50,464 --> 00:23:53,267 +是 RGB 色域中存在的颜色 + +461 +00:23:53,267 --> 00:23:58,238 +而线的右侧则 +是只在 P3 色域中才有的颜色 + +462 +00:23:58,238 --> 00:24:03,443 +2016 年 我们为 +视频和照片添加了 P3 色域支持 + +463 +00:24:03,443 --> 00:24:06,947 +去年 我们很高兴成为了第一个 + +464 +00:24:06,947 --> 00:24:12,352 +实装了 CSS Color Level 4 +定义的新色值语法的浏览器 + +465 +00:24:12,352 --> 00:24:15,489 +今年 我们为画布元素内的内容 + +466 +00:24:15,489 --> 00:24:18,258 +添加了 P3 色域的支持 + +467 +00:24:18,258 --> 00:24:21,461 +我们终于不必再受限于 + +468 +00:24:21,461 --> 00:24:24,565 +90 年代设备的色域了 +您可以开始利用 + +469 +00:24:24,565 --> 00:24:28,168 +今天的优秀设备所支持的全部 + +470 +00:24:28,168 --> 00:24:29,870 +色彩再现能力 + +471 +00:24:29,870 --> 00:24:33,740 +过去一年间 +我们的 Web API 的新功能 + +472 +00:24:33,740 --> 00:24:38,879 +甚至还不止这些 +包括 shadow realms web locks + +473 +00:24:38,879 --> 00:24:42,916 +以及更新了对 +ResizeObserver API 的支持 + +474 +00:24:42,916 --> 00:24:45,953 +用于 ResizeObserverSize 界面 + +475 +00:24:45,953 --> 00:24:47,287 +它能助您监控 + +476 +00:24:47,287 --> 00:24:50,357 +元素的 box-sizing 属性变化 + +477 +00:24:50,357 --> 00:24:52,559 +在我们 API 更新中 + +478 +00:24:52,559 --> 00:24:55,262 +有太多值得一试的部分 + +479 +00:24:55,262 --> 00:24:58,699 +当然了 那些新功能也是 + +480 +00:24:58,699 --> 00:25:02,002 +事实上 我们还有更多内容 + +481 +00:25:02,002 --> 00:25:05,038 +接下来 让我们来看看 + +482 +00:25:05,038 --> 00:25:08,141 +JavaScript +和 WebAssembly 的新特性 + +483 +00:25:08,141 --> 00:25:11,144 +如果您的网站使用 worker +而您想让这些 worker 的 + +484 +00:25:11,144 --> 00:25:14,681 +实例在选项卡和窗口间共享 + +485 +00:25:14,681 --> 00:25:17,684 +那么新的共享 worker 界面 +一定会有所帮助 + +486 +00:25:17,684 --> 00:25:20,888 +它还可能减少内存使用量 + +487 +00:25:20,888 --> 00:25:24,491 +不需要为每项您希望发生在后台的 + +488 +00:25:24,491 --> 00:25:27,561 +任务产生新的 worker + +489 +00:25:27,561 --> 00:25:31,498 +每个同访问域的浏览上下文 +只需要一个 worker + +490 +00:25:31,498 --> 00:25:35,202 +每个脚本都会用同样方式 +创建一个共享 worker + +491 +00:25:35,202 --> 00:25:37,604 +然后它们就可以用相同的端口 + +492 +00:25:37,604 --> 00:25:40,140 +来接收和发送消息 + +493 +00:25:40,140 --> 00:25:42,442 +共享 worker 将可以 + +494 +00:25:42,442 --> 00:25:44,378 +接收和回复来自所有 + +495 +00:25:44,378 --> 00:25:47,648 +不同脚本的消息 + +496 +00:25:47,648 --> 00:25:50,751 +这会降低您的服务器的载荷 + +497 +00:25:50,751 --> 00:25:52,286 +同时使客户的 + +498 +00:25:52,286 --> 00:25:56,223 +网页浏览体验顺滑快速 + +499 +00:25:56,223 --> 00:26:00,360 +我们还有一系列的 +数组功能要展示给您 + +500 +00:26:00,360 --> 00:26:03,764 +当您想要从末尾搜索时 + +501 +00:26:03,764 --> 00:26:05,899 +不必使用 +reverse() 来改变数组 + +502 +00:26:05,899 --> 00:26:10,370 +现在您只需要使用 findLast() +和 findLastIndex() 方法 + +503 +00:26:10,370 --> 00:26:13,273 +就像我现在这样 查询最后一个项目 + +504 +00:26:13,273 --> 00:26:17,344 +包含“鞋带”的项目和索引 + +505 +00:26:17,344 --> 00:26:19,880 +新的 at() 方法还能使 + +506 +00:26:19,880 --> 00:26:22,783 +从末尾搜索数组更加简单 + +507 +00:26:22,783 --> 00:26:26,386 +当索引为正时 使用大括号效果很好 + +508 +00:26:26,386 --> 00:26:28,922 +但 at() 给了我们额外的功能 + +509 +00:26:28,922 --> 00:26:31,258 +可以用负值索引 + +510 +00:26:31,258 --> 00:26:35,262 +使您的代码更简洁易读 + +511 +00:26:35,262 --> 00:26:39,499 +但即使有这么多的新数组功能 + +512 +00:26:39,499 --> 00:26:41,969 +也没有什么能比得上 + +513 +00:26:41,969 --> 00:26:46,540 +我们新增的国际化功能的数量 + +514 +00:26:46,540 --> 00:26:49,676 +在过去一年间 +WebKit 持续不断的 + +515 +00:26:49,676 --> 00:26:54,147 +得到了我们的 +Intl 功能方面的更新 + +516 +00:26:54,147 --> 00:26:57,618 +我们增加了支持不同数字系统的 + +517 +00:26:57,618 --> 00:27:00,187 +新方法:NumberFormat + +518 +00:27:00,187 --> 00:27:03,557 +更新了 Locale 和 DisplayNames +以支持更多日历 + +519 +00:27:03,557 --> 00:27:09,630 +还有通过 Intl Enumeration API +支持了更多货币种类 + +520 +00:27:09,630 --> 00:27:13,100 +正如我所说 这一年来我们 + +521 +00:27:13,100 --> 00:27:15,836 +新增了许多 Intl 功能 + +522 +00:27:15,836 --> 00:27:20,040 +可供您尝试和探索 以满足您的 + +523 +00:27:20,040 --> 00:27:24,111 +世界各地用户的功能 + +524 +00:27:24,111 --> 00:27:27,681 +绝不会少对于那些已经有 +各种不同编程语言的项目 + +525 +00:27:27,681 --> 00:27:32,886 +比如 C Objective C 或 Swift + +526 +00:27:32,886 --> 00:27:34,988 +要把它们带到 web 上来 + +527 +00:27:34,988 --> 00:27:38,959 +只需使用 WebAssembly +无需重写 即可运行 + +528 +00:27:38,959 --> 00:27:40,627 +有了今年的这些改进 + +529 +00:27:40,627 --> 00:27:45,365 +您的使用 WebAssembly 的 +web App 只会变得更强大 + +530 +00:27:45,365 --> 00:27:49,203 +其可寻址内存扩展到了 4GB + +531 +00:27:49,203 --> 00:27:51,505 +新的零成本异常处理 + +532 +00:27:51,505 --> 00:27:54,575 +也会进一步提升性能 + +533 +00:27:54,575 --> 00:27:58,011 +总的来说 +JavaScript 和 WebAssembly + +534 +00:27:58,011 --> 00:28:01,582 +毫无疑问都得到了一些 +激动人心的特性供您尝试 + +535 +00:28:01,582 --> 00:28:05,519 +说到 WebAssembly +我们还有一些安全 + +536 +00:28:05,519 --> 00:28:08,155 +和隐私增强 它们不仅 + +537 +00:28:08,155 --> 00:28:11,258 +保护我们开发的网页所面向的用户 + +538 +00:28:11,258 --> 00:28:16,396 +还会为您 +作为开发者带来许多新的潜能 + +539 +00:28:16,396 --> 00:28:19,833 +有了新的 +Cross Origin Opener Policy + +540 +00:28:19,833 --> 00:28:25,305 +和 Cross Origin Embedder Policy +HTTP 响应标头 + +541 +00:28:25,305 --> 00:28:28,542 +您的网站可以选择加入进程隔离 + +542 +00:28:28,542 --> 00:28:30,110 +使您的网站运行在 + +543 +00:28:30,110 --> 00:28:33,680 +它自己的专用 +webContent 进程中 + +544 +00:28:33,680 --> 00:28:36,850 +我们知道 使用 +WebAssembly 多线程 + +545 +00:28:36,850 --> 00:28:40,888 +许多 App 可以受益于 +在多个线程上平行运行 + +546 +00:28:40,888 --> 00:28:46,026 +有了这些新的标头 +您可以安全的使用这一功能 + +547 +00:28:46,026 --> 00:28:51,031 +我们的第二个安全性增强 +同样涉及 HTTP 标头 + +548 +00:28:51,031 --> 00:28:55,502 +我们支持了 +内容安全策略 level 3 + +549 +00:28:55,502 --> 00:28:58,272 +CSP 增强了对您的加载内容的 + +550 +00:28:58,272 --> 00:29:01,308 +安全控制 还降低了 + +551 +00:29:01,308 --> 00:29:04,745 +跨站点脚本以及其他漏洞的风险 + +552 +00:29:04,745 --> 00:29:08,015 +Level 3 更新 +带来的最令人激动的新功能 + +553 +00:29:08,015 --> 00:29:11,485 +就是新的 +strict-dynamic 源表达式 + +554 +00:29:11,485 --> 00:29:15,389 +Strict-dynamic 的设计者 +意识到您可以用随机数 + +555 +00:29:15,389 --> 00:29:18,125 +来允许某些脚本 然后把这种信任 + +556 +00:29:18,125 --> 00:29:21,061 +扩展到已受信任脚本加载的脚本中 + +557 +00:29:21,061 --> 00:29:24,331 +而不再需要明确的允许列表 + +558 +00:29:24,331 --> 00:29:26,767 +看看这能让标头变的多简洁 + +559 +00:29:26,767 --> 00:29:29,303 +原来的那种一长串域名的形式 + +560 +00:29:29,303 --> 00:29:32,539 +可能会导致允许值过多 + +561 +00:29:32,539 --> 00:29:37,010 +这就是我们的安全和隐私特性更新 + +562 +00:29:37,010 --> 00:29:39,346 +今天我们的讲座 + +563 +00:29:39,346 --> 00:29:41,748 +也就到此为止了 + +564 +00:29:41,748 --> 00:29:45,018 +但还有许多东西 等待您自己去探索 + +565 +00:29:45,018 --> 00:29:47,588 +比如 我们还带来了一些媒体更新 + +566 +00:29:47,588 --> 00:29:51,558 +包括使用 +getUserDisplay() API + +567 +00:29:51,558 --> 00:29:57,564 +支持截屏特定 Safari 窗口 +WebRTC 完美协商 + +568 +00:29:57,564 --> 00:30:03,003 +带内章节轨道 +和 requestVideoFrameCallback() + +569 +00:30:03,003 --> 00:30:06,173 +以及许多 +web 扩展的酷炫新特性 + +570 +00:30:06,173 --> 00:30:08,642 +支持了 manifest version 3 + +571 +00:30:08,642 --> 00:30:12,613 +以及一堆新的 +web 扩展 API + +572 +00:30:12,613 --> 00:30:16,350 +要更深入了解今天介绍的这些特性 + +573 +00:30:16,350 --> 00:30:20,220 +探索 Safari +和 WebKit 在过去一年间的 + +574 +00:30:20,220 --> 00:30:23,757 +所有 162 项特性和改进 + +575 +00:30:23,757 --> 00:30:26,460 +请务必下载 +Safari Technology Preview + +576 +00:30:26,460 --> 00:30:29,930 +来跟上未来的更新 + +577 +00:30:29,930 --> 00:30:33,300 +为探索 web 技术 +请查看我们的版本更新日志 + +578 +00:30:33,300 --> 00:30:37,070 +博客文章以及 +webkit.org 上所有的精彩内容 + +579 +00:30:37,070 --> 00:30:41,642 +包括关于 +Web Inspector 的详细文档 + +580 +00:30:41,642 --> 00:30:44,178 +和往常一样 通过提交错误报告 + +581 +00:30:44,178 --> 00:30:47,881 +告诉我们您的想法 +和您接下来想要的东西 + +582 +00:30:47,881 --> 00:30:50,284 +如果您在 +WebKit 中遇到了错误 + +583 +00:30:50,284 --> 00:30:55,889 +无论是 HTML CSS +JavaScript DOM API + +584 +00:30:55,889 --> 00:30:58,592 +还是 Web Inspector +都请务必提交您的反馈 + +585 +00:30:58,592 --> 00:31:03,830 +使用 bugs.webkit.org 上的 +WebKit 的错误跟踪系统即可 + +586 +00:31:03,830 --> 00:31:07,367 +有关 Safari 浏览器界面 +的建议或错误报告 + +587 +00:31:07,367 --> 00:31:11,171 +请通过 Apple +反馈助理提交问题 + +588 +00:31:11,171 --> 00:31:14,775 +在接下来的一年 我们期待着 + +589 +00:31:14,775 --> 00:31:17,044 +带来更多优秀的特性 + +590 +00:31:17,044 --> 00:31:19,680 +持续更新 Safari 浏览器 + +591 +00:31:19,680 --> 00:31:22,349 +和 Safari Technology Preview + +592 +00:31:22,349 --> 00:31:24,451 +来改善 web 开发者的工作效率 + +593 +00:31:24,451 --> 00:31:26,687 +感谢参加我的讲座 + +594 +00:31:26,687 --> 00:31:30,190 +祝您在 WWDC 过的愉快 + +595 +00:31:30,190 --> 00:31:32,259 +再见! + +596 +00:31:32,259 --> 00:31:35,562 +♪ + diff --git a/zho/2022 Session 10049 What's new in WKWebView.srt b/zho/2022 Session 10049 What's new in WKWebView.srt new file mode 100644 index 0000000..1906284 --- /dev/null +++ b/zho/2022 Session 10049 What's new in WKWebView.srt @@ -0,0 +1,701 @@ +1 +00:00:00,300 --> 00:00:05,339 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:05,339 --> 00:00:09,476 +♪ + +3 +00:00:09,476 --> 00:00:12,980 +大家好 欢迎来到 +“WKWebView 的新功能” + +4 +00:00:12,980 --> 00:00:16,450 +我是 WebKit 组的工程师 +Alex Christensen + +5 +00:00:16,450 --> 00:00:19,653 +今年我们增加了很多新的网络技术 + +6 +00:00:19,653 --> 00:00:23,223 +供您在 App 中使用 + +7 +00:00:23,223 --> 00:00:25,158 +不过 在我们开始之前 + +8 +00:00:25,158 --> 00:00:27,494 +我们要确保 + +9 +00:00:27,494 --> 00:00:29,830 +您的 App 使用了正确的技术 + +10 +00:00:29,830 --> 00:00:33,467 +如果您希望无需深度定制就能在 + +11 +00:00:33,467 --> 00:00:36,003 +App 中浏览 Web 内容 + +12 +00:00:36,003 --> 00:00:40,974 +那么一定要试试 +SFSafariViewController + +13 +00:00:40,974 --> 00:00:45,712 +如果您的 App 仍在使用 +已弃用的 UIWebView + +14 +00:00:45,712 --> 00:00:48,248 +现在是时候迁移到更快且 + +15 +00:00:48,248 --> 00:00:51,051 +更具响应性的 WKWebView + +16 +00:00:51,051 --> 00:00:56,190 +未来的版本中 +将删除 UIWebView + +17 +00:00:56,190 --> 00:00:58,759 +WKWebView 提供 API + +18 +00:00:58,759 --> 00:01:02,663 +用于 Web 内容和 +App 之间交互 + +19 +00:01:02,663 --> 00:01:05,532 +您可以将它用于 +基于 CSS 的用户界面 + +20 +00:01:05,532 --> 00:01:09,102 +或调用 JavaScript 编写 App + +21 +00:01:09,102 --> 00:01:11,705 +您可能在使用 App 绑定域 + +22 +00:01:11,705 --> 00:01:14,274 +与自己的 Web 内容交互 + +23 +00:01:14,274 --> 00:01:17,978 +您也可能正在开发自己的浏览器 + +24 +00:01:17,978 --> 00:01:20,214 +无论您的 App 是什么 + +25 +00:01:20,214 --> 00:01:22,216 +我们不断添加新功能以便您制作 + +26 +00:01:22,216 --> 00:01:25,786 +更丰富的 Web App + +27 +00:01:25,786 --> 00:01:28,622 +WKWebView +今年可用的新功能 + +28 +00:01:28,622 --> 00:01:30,624 +分为四类 + +29 +00:01:30,624 --> 00:01:33,160 +与 Web 内容交互的新方式 + +30 +00:01:33,160 --> 00:01:35,762 +内容拦截器的新功能 + +31 +00:01:35,762 --> 00:01:41,602 +加密媒体 以及 +允许三方浏览器远程调试 Web + +32 +00:01:41,602 --> 00:01:44,371 +首先 我们将介绍 + +33 +00:01:44,371 --> 00:01:47,708 +用于 Web 内容交互的 API + +34 +00:01:47,708 --> 00:01:50,444 +iOS16 中 您的 App +可以通过以下三种新方式 + +35 +00:01:50,444 --> 00:01:55,616 +与 Web 内容轻松交互: +使用全屏 API + +36 +00:01:55,616 --> 00:02:01,154 +使用新的 CSS 视口单元 +以及使用查找交互 + +37 +00:02:01,154 --> 00:02:03,490 +让我们先来看看全屏 API + +38 +00:02:03,490 --> 00:02:04,791 +一直以来 在浏览器中展示的视频 + +39 +00:02:04,791 --> 00:02:07,628 +游戏等都可以通过 HTML 元素 + +40 +00:02:07,628 --> 00:02:11,698 +使其实现全屏 + +41 +00:02:11,698 --> 00:02:15,469 +现在 App 内嵌的 +H5 页面中也可以做到这一点了 + +42 +00:02:15,469 --> 00:02:19,173 +这是手机上的一个简单示例 + +43 +00:02:19,173 --> 00:02:21,708 +JavaScript 可以 +请求全屏 + +44 +00:02:21,708 --> 00:02:26,113 +然后用户或 JavaScript +也可以退出全屏 + +45 +00:02:26,113 --> 00:02:27,748 +您仅需要在您的 App 中 +将 WKPreferences + +46 +00:02:27,748 --> 00:02:32,519 +的 .isElementFullscreenEnabled 属性 + +47 +00:02:32,519 --> 00:02:37,024 +设置为 true 来加载网页内容 +这些内容可以使用全屏 API + +48 +00:02:37,024 --> 00:02:39,893 +比如 webkitRequestFullscreen + +49 +00:02:39,893 --> 00:02:41,595 +这是开箱即用的API 效果也很好 + +50 +00:02:41,595 --> 00:02:44,798 +如果您想要自定义过渡动画 +可以通过监听 + +51 +00:02:44,798 --> 00:02:49,036 +WKWebView 的 +fullscreenState 来实现 + +52 +00:02:49,036 --> 00:02:52,105 +该属性让 App 可以准确知道 + +53 +00:02:52,105 --> 00:02:55,275 +网页内容何时全屏或返回 + +54 +00:02:55,275 --> 00:02:58,412 +以上就是在 App 中使用 + +55 +00:02:58,412 --> 00:02:59,913 +WebKit 全屏 API +的全部内容 + +56 +00:03:01,248 --> 00:03:04,251 +我们也新增了 CSS 单位 + +57 +00:03:04,251 --> 00:03:08,222 +可根据视口(Viewport)大小布局 Web 内容 + +58 +00:03:08,222 --> 00:03:14,862 +这些新的 CSS 单位包括 +svh lvh dvh 等 + +59 +00:03:14,862 --> 00:03:17,064 +它们允许 Web 开发者根据 + +60 +00:03:17,064 --> 00:03:22,102 +最小 最大和动态的视口大小 +来修改 Web 布局 + +61 +00:03:22,102 --> 00:03:24,004 +让我们看一下 +Safari 浏览器的作用 + +62 +00:03:24,004 --> 00:03:28,742 +以了解如何在您的 App 中使用 + +63 +00:03:28,742 --> 00:03:31,311 +当首次在 Safari 浏览器中 +打开 H5 页面时 + +64 +00:03:31,311 --> 00:03:35,349 +能看到 H5 页面和一些底部按钮 + +65 +00:03:35,349 --> 00:03:38,452 +滚动时 视口会随着 + +66 +00:03:38,452 --> 00:03:41,622 +按钮的滚动而增大 + +67 +00:03:41,622 --> 00:03:45,659 +Svh、lvh 和 dvh +提供有用的单位 + +68 +00:03:45,659 --> 00:03:49,897 +来测量这些不同大小的视口 + +69 +00:03:49,897 --> 00:03:53,901 +当 App 需要更改 + +70 +00:03:53,901 --> 00:03:56,537 +WKWebView 视口大小 + +71 +00:03:56,537 --> 00:03:59,640 +以便在 App 中 + +72 +00:03:59,640 --> 00:04:02,643 +正确布局 Web 内容时 + +73 +00:04:02,643 --> 00:04:05,913 +需要提前通过 +WebKit 的函数 + +74 +00:04:05,913 --> 00:04:08,715 +setMinimumViewportInset + +75 +00:04:08,715 --> 00:04:10,717 +方法来告知视口的大小范围 + +76 +00:04:10,717 --> 00:04:13,754 +在 iOS 16 的 +WKWebView 中 + +77 +00:04:13,754 --> 00:04:17,824 +我们还引入了对查找交互的支持 + +78 +00:04:17,824 --> 00:04:21,428 +许多使用了 WKWebView +的 App 加载了大量文本内容 + +79 +00:04:21,428 --> 00:04:24,331 +并且用户想要搜索相应文本 + +80 +00:04:24,331 --> 00:04:27,668 +如果将 WKWebView 的 + +81 +00:04:27,668 --> 00:04:28,969 +.findInteractionEnabled + +82 +00:04:28,969 --> 00:04:32,139 +属性设置为 true 用户就可以 + +83 +00:04:32,139 --> 00:04:36,410 +在页面上使用 CMD-F 等 + +84 +00:04:36,410 --> 00:04:38,846 +快捷键来搜索文本 + +85 +00:04:38,846 --> 00:04:40,948 +打开该功能 + +86 +00:04:40,948 --> 00:04:42,883 +只需要一行代码 + +87 +00:04:42,883 --> 00:04:46,286 +除此之外 还可以通过 +WKWebView 的 findInteraction 属性 + +88 +00:04:46,286 --> 00:04:48,889 +来访问 UIFindInteraction 对象 + +89 +00:04:48,889 --> 00:04:52,059 +通过这个对象 +来执行查找和关闭查找等操作 + +90 +00:04:52,059 --> 00:04:55,929 +或者通过编码的方式 +移动到上一个或者下一个查找结果 + +91 +00:04:55,929 --> 00:04:59,132 +试试吧 +看它可以在您的 App 中做什么 + +92 +00:04:59,132 --> 00:05:00,634 +对于内容拦截器 + +93 +00:05:00,634 --> 00:05:04,738 +我们在 WKContentRuleList +添加了一项新功能 + +94 +00:05:04,738 --> 00:05:08,976 +用于在 Safari 浏览器中 +实现内容拦截的 API + +95 +00:05:08,976 --> 00:05:14,147 +在这里 我们将维基百科 +嵌入 H5 的 iframe 中 + +96 +00:05:14,147 --> 00:05:17,651 +以前 您可以在被请求的 URL + +97 +00:05:17,651 --> 00:05:20,754 +和顶部框架 URL 上运行正则表达式 + +98 +00:05:20,754 --> 00:05:24,758 +以决定是拦截加载还是执行其他操作 + +99 +00:05:24,758 --> 00:05:26,193 +但是 有时候 + +100 +00:05:26,193 --> 00:05:29,029 +您真正想要的是某个规则 仅适用于 + +101 +00:05:29,029 --> 00:05:33,934 +某些 iframe 内的加载 + +102 +00:05:33,934 --> 00:05:36,470 +现在您可以在当前框架的 + +103 +00:05:36,470 --> 00:05:39,339 +URL 上运行正则表达式 + +104 +00:05:39,339 --> 00:05:41,909 +我们将编写一条规则 + +105 +00:05:41,909 --> 00:05:47,147 +来拦截维基百科中的图像呈现 + +106 +00:05:47,147 --> 00:05:48,215 +首先 + +107 +00:05:48,215 --> 00:05:52,686 +在 JSON 规则的 trigger 中 + +108 +00:05:52,686 --> 00:05:55,455 +添加新增的 +if-frame-url 键 + +109 +00:05:55,455 --> 00:05:58,959 +并将其应用于 +WKWebViewConfiguration + +110 +00:05:58,959 --> 00:06:01,028 +然后在发出请求的 URL 上 + +111 +00:06:01,028 --> 00:06:06,200 +运行正则表达式 + +112 +00:06:06,200 --> 00:06:10,204 +此拦截规则现在仅适用于来自匹配 + +113 +00:06:10,204 --> 00:06:14,541 +if-frame-url 正则 +表达式的框架的请求 + +114 +00:06:14,541 --> 00:06:16,910 +在这里我们看到它 + +115 +00:06:16,910 --> 00:06:20,347 +成功的拦截了维基百科的图像 + +116 +00:06:20,347 --> 00:06:23,450 +如果您想要了解更多 +实施内容拦截器的内容 + +117 +00:06:23,450 --> 00:06:28,188 +建议查看有关 Safari 浏览器 +扩展的 WWDC 讲座 + +118 +00:06:28,188 --> 00:06:30,324 +该讲座包含了有关 +declarativeNetRequest + +119 +00:06:30,324 --> 00:06:33,060 +的一些新可能性 + +120 +00:06:33,060 --> 00:06:36,797 +iPadOS 16 中的 +WKWebView 中 + +121 +00:06:36,797 --> 00:06:38,899 +还新增了一个功能 即加密媒体 + +122 +00:06:38,899 --> 00:06:42,202 +如果您有相关使用加密媒体扩展 + +123 +00:06:42,202 --> 00:06:45,305 +和媒体源扩展 API 的经验 + +124 +00:06:45,305 --> 00:06:49,276 +现在可以在 iPadOS 上的 +App 中使用 + +125 +00:06:49,276 --> 00:06:53,480 +这意味着 如果您拥有 +AppleTV+ 等优质内容 + +126 +00:06:53,480 --> 00:06:57,684 +它将像 macOS 中一样 +在 iPadOS 上工作 + +127 +00:06:57,684 --> 00:07:00,888 +如果您的 App +有 Web 浏览器权限 + +128 +00:07:00,888 --> 00:07:03,223 +允许三方浏览器远程调试 Web + +129 +00:07:03,223 --> 00:07:07,261 +将会像在 iOS 上的 +Safari 一样正常工作 + +130 +00:07:07,261 --> 00:07:11,932 +无需添加任何代码或更改任何代码 + +131 +00:07:11,932 --> 00:07:15,002 +就可调试 Web 页面 + +132 +00:07:15,002 --> 00:07:17,671 +调试流程与 Safari 浏览器一样 + +133 +00:07:17,671 --> 00:07:20,007 +首先在 iOS 设备中 + +134 +00:07:20,007 --> 00:07:23,277 +开启 Web Inspector + +135 +00:07:23,277 --> 00:07:26,847 +然后在 macOS 上的 +Safari 浏览器的高级设置中 + +136 +00:07:26,847 --> 00:07:29,416 +启用开发菜单 + +137 +00:07:29,416 --> 00:07:33,020 +将手机连接到 Mac +并在 macOS 上的 + +138 +00:07:33,020 --> 00:07:36,490 +Safari 浏览器浏览器的 +开发菜单中查找您的设备 + +139 +00:07:36,490 --> 00:07:40,060 +Web 检查器有许多 +用于调试 Web 内容的工具 + +140 +00:07:40,060 --> 00:07:42,062 +您可以探索 DOM + +141 +00:07:42,062 --> 00:07:45,199 +运行和调试 JavaScript 的执行 + +142 +00:07:45,199 --> 00:07:48,702 +查看页面加载的时间线等 + +143 +00:07:48,702 --> 00:07:50,370 +如果您有网站 + +144 +00:07:50,370 --> 00:07:53,106 +您现在可以试着开启 +Web 检查器 + +145 +00:07:53,106 --> 00:07:55,242 +实现在第三方浏览器中 + +146 +00:07:55,242 --> 00:07:57,845 +调试 App 内嵌的 +Web 页面 + +147 +00:07:57,845 --> 00:08:00,147 +以上就是今年 WKWebView + +148 +00:08:00,147 --> 00:08:02,583 +的新增 API + +149 +00:08:02,583 --> 00:08:06,253 +试用一下 看看 +它们能在您的 App 中做什么 + +150 +00:08:06,253 --> 00:08:10,057 +请为您的 App +使用最好的 API + +151 +00:08:10,057 --> 00:08:13,360 +如果您认为 WKWebView +仍有还需完善的功能 + +152 +00:08:13,360 --> 00:08:17,364 +请使用反馈助理提交功能请求 + +153 +00:08:17,364 --> 00:08:19,399 +我们会查看收到的功能请求 + +154 +00:08:19,399 --> 00:08:23,770 +并根据您的建议确定开发的优先次序 + +155 +00:08:23,770 --> 00:08:24,938 +别忘了观看 + +156 +00:08:24,938 --> 00:08:27,441 +“Safari Web 扩展的新功能” + +157 +00:08:27,441 --> 00:08:30,344 +如果想要了解 Web 平台的 +更多内容 + +158 +00:08:30,344 --> 00:08:31,712 +请查看 + +159 +00:08:31,712 --> 00:08:34,448 +“Safari 和 WebKit 的新功能” + +160 +00:08:34,448 --> 00:08:37,684 +感谢观看 祝您 WWDC 愉快 + +161 +00:08:37,684 --> 00:08:41,922 +♪ + diff --git a/zho/2022 Session 10056 Compose custom layouts with SwiftUI.srt b/zho/2022 Session 10056 Compose custom layouts with SwiftUI.srt new file mode 100644 index 0000000..e500c2c --- /dev/null +++ b/zho/2022 Session 10056 Compose custom layouts with SwiftUI.srt @@ -0,0 +1,2130 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,843 --> 00:00:13,514 +Paul: 大家好 欢迎收看 +使用 SwiftUI 编写自定义布局 + +3 +00:00:13,547 --> 00:00:16,183 +我是 Paul 负责开发者文档 + +4 +00:00:16,216 --> 00:00:18,919 +SwiftUI 提供了一组丰富的构建模块 + +5 +00:00:18,952 --> 00:00:22,489 +你可以使用它们来搭建 +你的 App 界面 + +6 +00:00:22,523 --> 00:00:27,761 +你们可以组合显示文本 图像 +和图形等元素的 + +7 +00:00:27,794 --> 00:00:31,932 +内置视图 +以创建自定义的复合视图 + +8 +00:00:31,965 --> 00:00:35,769 +SwiftUI 提供了布局工具 +来将所有元素 + +9 +00:00:35,802 --> 00:00:37,804 +进行更复杂的分组 + +10 +00:00:39,139 --> 00:00:42,709 +像水平和垂直叠放之类的容器 + +11 +00:00:42,743 --> 00:00:45,112 +让你告诉 SwiftUI 放置视图的 +相对位置 + +12 +00:00:45,145 --> 00:00:47,581 +而视图修饰器可以让你们 +对间距和对齐 + +13 +00:00:47,614 --> 00:00:50,484 +等内容进行额外的控制 + +14 +00:00:51,218 --> 00:00:53,487 +在本次讲座中 +我将介绍一些新工具 + +15 +00:00:53,520 --> 00:00:56,590 +它们会使一些常见的布局 +更容易构建 + +16 +00:00:56,623 --> 00:00:59,560 +并且复杂的布局也能实现 + +17 +00:00:59,593 --> 00:01:04,364 +在此过程中 我会介绍一些在 +SwiftUI 中使用布局的技巧 + +18 +00:01:04,398 --> 00:01:06,967 +首先 我将向你们展示 +网格家族中的一个新成员 + +19 +00:01:07,000 --> 00:01:09,269 +当你们需要展示一组静态视图时 + +20 +00:01:09,303 --> 00:01:12,372 +它就非常适合二维布局 + +21 +00:01:12,406 --> 00:01:16,176 +接下来我将讨论如何使用 +新的布局协议 + +22 +00:01:16,210 --> 00:01:18,979 +创建自定义视图容器类型 + +23 +00:01:19,012 --> 00:01:21,949 +直接与布局引擎交互 + +24 +00:01:21,982 --> 00:01:24,318 +然后我会讲到 ViewThatFits + +25 +00:01:24,351 --> 00:01:27,621 +这是一种容器类型 +它自动从视图集合中 + +26 +00:01:27,654 --> 00:01:31,792 +选择适合可用空间的视图 + +27 +00:01:31,825 --> 00:01:34,862 +最后 我将向你展示 +如何使用 AnyLayout + +28 +00:01:34,895 --> 00:01:38,232 +在布局类型之间添加无缝过渡 + +29 +00:01:38,265 --> 00:01:40,334 +要查看所有这些新功能的实际效果 + +30 +00:01:40,367 --> 00:01:42,703 +我们来看看 +我一直在开发的一款 App + +31 +00:01:44,204 --> 00:01:45,906 +近年来 我的一些同事 + +32 +00:01:45,939 --> 00:01:50,410 +总是在争论什么是最好的宠物伙伴 + +33 +00:01:50,444 --> 00:01:54,781 +我有自己的看法 +但我很好奇大家能否达成共识 + +34 +00:01:54,815 --> 00:01:58,452 +所以我决定做一个 App 来进行投票 + +35 +00:01:58,485 --> 00:02:00,754 +我还想让对皮毛过敏的人也加入 + +36 +00:02:00,787 --> 00:02:03,357 +所以我额外加了一个选项 + +37 +00:02:03,390 --> 00:02:07,160 +现在 我喜欢用 SwiftUI +做大部分的界面设计 + +38 +00:02:07,194 --> 00:02:09,997 +因为使用预览制作原型非常容易 + +39 +00:02:10,030 --> 00:02:14,334 +但作为起点 我画了一个 +目标设计界面的速写 + +40 +00:02:14,368 --> 00:02:16,737 +我预计投票会持续一段时间 + +41 +00:02:16,770 --> 00:02:20,774 +所以我想要一个 +显示当前排名的排行榜 + +42 +00:02:20,807 --> 00:02:22,676 +我会把投票按钮放在底部 + +43 +00:02:22,709 --> 00:02:26,647 +而在顶部 我将展示一些 +大家投票的图片 + +44 +00:02:28,482 --> 00:02:30,751 +好 我要做的第一件事是 +搭建排行榜 + +45 +00:02:30,784 --> 00:02:33,554 +我们来仔细看看 + +46 +00:02:33,587 --> 00:02:38,559 +排行榜是一个二维元素网格 +每个参选者都有 + +47 +00:02:38,592 --> 00:02:43,197 +列显示名称 百分比和选票计数 + +48 +00:02:43,230 --> 00:02:47,367 +在这里 我想实现几个具体的目标 + +49 +00:02:47,401 --> 00:02:51,104 +首先 我希望两个文本的列宽 +尽可能的压缩 + +50 +00:02:51,138 --> 00:02:54,074 +仅需在各种情况下 +容纳最宽单元格即可 + +51 +00:02:54,107 --> 00:02:56,610 +因为我希望表示百分比的进度视图 + +52 +00:02:56,643 --> 00:02:58,812 +获得尽可能多的空间 + +53 +00:02:58,846 --> 00:03:02,349 +这个规则同样也会应用在 +当数量变大的时候 + +54 +00:03:02,382 --> 00:03:05,018 +以及对于说其它语言的朋友 + +55 +00:03:05,052 --> 00:03:09,022 +或者是在设备上使用 +不同字体大小的用户 + +56 +00:03:09,056 --> 00:03:11,792 +其次 我希望名称是向前对齐 + +57 +00:03:11,825 --> 00:03:14,728 +但数量是向后对齐的 + +58 +00:03:14,761 --> 00:03:20,167 +现在 SwiftUI 已经有了 lazy grids +非常适合滚动内容 + +59 +00:03:20,200 --> 00:03:23,704 +当你们有很多视图时 +这些容器非常有效 + +60 +00:03:23,737 --> 00:03:27,774 +因为它们只加载 +可见或即将可见的视图 + +61 +00:03:27,808 --> 00:03:29,776 +另一方面 这意味着容器 + +62 +00:03:29,810 --> 00:03:33,080 +不能在两个维度上 +自动调整单元格的大小 + +63 +00:03:34,515 --> 00:03:38,118 +例如 LazyHGrid 可以计算出 +每一列的宽度 + +64 +00:03:38,151 --> 00:03:42,823 +因为它可以在绘制列之前 +测量列中的所有视图 + +65 +00:03:42,856 --> 00:03:46,827 +但它不能测量一行中的 +每个视图来计算行高 + +66 +00:03:46,860 --> 00:03:48,795 +为了实现这一点 lazy grids 需要你们 + +67 +00:03:48,829 --> 00:03:52,366 +在初始化时提供其中一个维度的信息 + +68 +00:03:53,867 --> 00:03:58,305 +如需详细了解 lazy grids 和 +其他现有 SwiftUI 布局容器类型 + +69 +00:03:58,338 --> 00:04:02,176 +请参阅 2020 年的 +Stacks Grids 和 Outlines 讲座 + +70 +00:04:02,209 --> 00:04:06,079 +但就我而言 我不需要滚动 +我想让 SwiftUI + +71 +00:04:06,113 --> 00:04:09,616 +计算出每个单元格的高度和宽度 + +72 +00:04:09,650 --> 00:04:14,421 +对于这种布局 SwiftUI +现在提供了一个网格视图 + +73 +00:04:14,454 --> 00:04:17,891 +与 lazy grid 不同的是 +网格一次性加载其所有视图 + +74 +00:04:17,925 --> 00:04:21,161 +因此它可以 +自动调整其单元格的大小 + +75 +00:04:21,195 --> 00:04:25,265 +并在其列和行之间对齐 + +76 +00:04:25,299 --> 00:04:27,201 +我们来看看它的代码 + +77 +00:04:28,135 --> 00:04:31,438 +这是我以 Grid 形式编写的 +排行榜的基本版本 + +78 +00:04:31,471 --> 00:04:35,142 +这个特定的网格视图包含 +三个 GridRow 实例 + +79 +00:04:35,175 --> 00:04:38,512 +在一行中 每个视图对应一列 + +80 +00:04:38,545 --> 00:04:41,815 +所以在这个示例中 每一行中的 + +81 +00:04:41,849 --> 00:04:43,684 +第一个文本视图对应于第一列 + +82 +00:04:43,717 --> 00:04:45,919 +进度视图在第二列 + +83 +00:04:45,953 --> 00:04:49,623 +最后一个文本视图对应第三列 + +84 +00:04:49,656 --> 00:04:53,393 +请注意 网格为每行和每列 +分配了所需的空间 + +85 +00:04:53,427 --> 00:04:55,696 +以容纳其最大的视图 + +86 +00:04:55,729 --> 00:05:00,234 +因此 第一列文本的列宽足以容纳 +最长的名称 但不能更宽 + +87 +00:05:00,267 --> 00:05:04,104 +进度指示器等灵活视图 +会占用网格提供的尽可能多的空间 + +88 +00:05:04,137 --> 00:05:06,139 +在本例中 是为文本列 + +89 +00:05:06,173 --> 00:05:09,343 +分配空间后剩余的内容 + +90 +00:05:09,376 --> 00:05:13,247 +我想稍微调整一下 但首先 +我来创建一个基本的数据模型 + +91 +00:05:13,280 --> 00:05:15,382 +以存储投票数 + +92 +00:05:16,683 --> 00:05:20,354 +我需要更多的逻辑来管理 +以及在网络中共享这个数据 + +93 +00:05:20,387 --> 00:05:24,892 +但当我创建接口原型时 +只需要这样一个简单的结构 + +94 +00:05:24,925 --> 00:05:28,195 +我会遵循 Identifiable 协议 +这样我们可以更容易的 + +95 +00:05:28,228 --> 00:05:30,497 +在 ForEach 中使用这种类型 + +96 +00:05:30,531 --> 00:05:34,368 +遵循 Equatable 协议 +可以实现动画过渡 + +97 +00:05:35,869 --> 00:05:41,475 +我将创建一组示例数据 +以便在我制作原型时在预览中使用 + +98 +00:05:41,508 --> 00:05:44,578 +回到网格 我可以创建一个状态变量 + +99 +00:05:44,611 --> 00:05:46,947 +并用示例数据进行初始化 + +100 +00:05:46,980 --> 00:05:51,218 +使用这些数据 +我现在可以使用 ForEach 创建行 + +101 +00:05:51,251 --> 00:05:53,453 +请注意 渲染输出没有更改 + +102 +00:05:53,487 --> 00:05:56,757 +因为它仍然显示相同的数据 + +103 +00:05:56,790 --> 00:06:00,460 +已经很接近了 +但我需要调整单元格对齐 + +104 +00:06:00,494 --> 00:06:02,529 +现在 所有单元格都是居中对齐的 + +105 +00:06:02,563 --> 00:06:05,399 +这是网格的默认设置 +但如果你还记得 + +106 +00:06:05,432 --> 00:06:07,568 +我希望名称是向前对齐的 + +107 +00:06:07,601 --> 00:06:09,970 +数值是向后对齐的 + +108 +00:06:10,804 --> 00:06:14,808 +为此 我将使用前沿对齐 +来初始化网格 + +109 +00:06:14,842 --> 00:06:18,512 +我在这里使用的值 +适用于网格中的所有单元格 + +110 +00:06:18,545 --> 00:06:23,183 +对前两列很有效 但最后一列呢 + +111 +00:06:23,217 --> 00:06:25,385 +要影响单个列的对齐 + +112 +00:06:25,419 --> 00:06:31,091 +我可以对该列中的任何一个单元格 +应用 gridColumnAlignment 视图修饰器 + +113 +00:06:31,124 --> 00:06:34,862 +我将在最后一列的文本视图中 +执行此操作 + +114 +00:06:34,895 --> 00:06:37,764 +好了 已经成功了 但现在我看一下 + +115 +00:06:37,798 --> 00:06:41,835 +我觉得每行之间有个分隔符会更好 + +116 +00:06:41,869 --> 00:06:45,272 +如果我只是使用分隔符 +向 for-each 添加一个新行 + +117 +00:06:45,305 --> 00:06:47,407 +这并不是我想要的 + +118 +00:06:47,441 --> 00:06:50,677 +但请注意 这显示了一些有趣的东西 + +119 +00:06:50,711 --> 00:06:53,814 +首先 因为分隔符是一个灵活的视图 + +120 +00:06:53,847 --> 00:06:56,550 +会导致第一列占用更多的空间 + +121 +00:06:56,583 --> 00:06:59,586 +基本上 网格现在为最后一列 +提供所需的宽度 + +122 +00:06:59,620 --> 00:07:03,824 +并在前两列之间划分剩余空间 + +123 +00:07:03,857 --> 00:07:08,028 +其次 对于没有像其他网格行 +一样多的视图的网格行 + +124 +00:07:08,061 --> 00:07:11,965 +缺少的视图只会在后面的列中 +创建空单元格 + +125 +00:07:11,999 --> 00:07:16,670 +但我真正想要的是让分隔符 +跨越网格的所有列 + +126 +00:07:16,703 --> 00:07:20,440 +而 SwiftUI 有一个新的视图修饰器 +可以让我做到这一点 + +127 +00:07:23,744 --> 00:07:27,014 +通过在视图中 +添加 gridCellColumns 修饰器 + +128 +00:07:27,047 --> 00:07:30,017 +我可以设置单个视图跨越若干列 + +129 +00:07:30,050 --> 00:07:32,719 +在这种情况下 一共3列 + +130 +00:07:32,753 --> 00:07:35,923 +实际上 对于视图应该 +跨越整个网格的情况 + +131 +00:07:35,956 --> 00:07:40,994 +我可以通过在网格行之外 +单独编写视图来简化这一点 + +132 +00:07:41,028 --> 00:07:44,264 +好吧 我的排行榜状态很不错 + +133 +00:07:44,298 --> 00:07:47,668 +接下来让我看看用于投票的按钮 + +134 +00:07:48,836 --> 00:07:51,338 +乍一看 这里没有什么特别的东西 + +135 +00:07:51,371 --> 00:07:54,641 +不过 我有一个特殊的要求 + +136 +00:07:54,675 --> 00:07:57,077 +一方面 我不想为参与者 +带来倾向性选择 + +137 +00:07:57,110 --> 00:08:00,013 +由于某些选项的按钮更小 + +138 +00:08:00,047 --> 00:08:03,050 +但我也不希望 +按钮们和它们的容器一样大 + +139 +00:08:03,083 --> 00:08:06,386 +在 iPad 或 Mac 上可能会非常大 + +140 +00:08:06,420 --> 00:08:11,825 +相反 所有按钮的宽度 +都应该等于最宽的按钮文字宽度 + +141 +00:08:11,859 --> 00:08:15,462 +那么 如果我尝试用 Hstack创建它 +会发生什么呢 + +142 +00:08:15,495 --> 00:08:19,666 +我发现每个按钮的大小 +都是为了适应它的文本标签 + +143 +00:08:19,700 --> 00:08:23,203 +而 HStack 将这些水平地打包在一起 + +144 +00:08:23,237 --> 00:08:27,508 +这种默认叠放行为正是你们 +在很多情况下想要的 + +145 +00:08:27,541 --> 00:08:30,177 +但它并不完全符合 +我对这个项目的规范 + +146 +00:08:31,778 --> 00:08:34,781 +如需重新了解 SwiftUI 中的 +布局基础知识 + +147 +00:08:34,815 --> 00:08:39,019 +请参阅 2019 年的讲座 +Building Custom Views with SwiftUI + +148 +00:08:39,052 --> 00:08:42,789 +利用那个讲座中的概念 +我们来看看这个视图层次结构 + +149 +00:08:42,823 --> 00:08:45,659 +看看我可以改变什么 +来达到我想要的行为 + +150 +00:08:47,694 --> 00:08:52,132 +首先 叠放的容器 +会为叠放视图建议一个尺寸 + +151 +00:08:52,165 --> 00:08:56,069 +基于此 叠放视图为其三个按钮 +建议一个尺寸 + +152 +00:08:56,103 --> 00:09:00,674 +然后每个按钮将该尺寸 +传递给它的文本标签 + +153 +00:09:00,707 --> 00:09:03,377 +文本视图计算它们实际需要的大小 + +154 +00:09:03,410 --> 00:09:05,746 +这取决于它们包含的字符串 + +155 +00:09:05,779 --> 00:09:08,115 +并将此报告给按钮 + +156 +00:09:08,148 --> 00:09:10,884 +该按钮将信息传递回去 + +157 +00:09:10,918 --> 00:09:13,387 +叠放视图使用此信息调整自己的尺寸 + +158 +00:09:13,420 --> 00:09:18,425 +将按钮放在其空间中 +然后向容器报告自己的大小 + +159 +00:09:18,458 --> 00:09:21,028 +好了 如果按钮取其文本的大小 + +160 +00:09:21,061 --> 00:09:26,133 +如果我将每个文本视图包装在 +一个灵活框架中并允许其扩大呢 + +161 +00:09:26,166 --> 00:09:29,770 +文本没有改变 +但按钮看到一个灵活的子视图 + +162 +00:09:29,803 --> 00:09:33,607 +它尽可能多的占用了 +HStack 提供的空间 + +163 +00:09:33,640 --> 00:09:38,178 +然后叠放视图在它包含的视图之间 +平均分配其空间 + +164 +00:09:38,212 --> 00:09:40,714 +所以现在按钮都具有相同的大小了 +这一点很棒 + +165 +00:09:40,747 --> 00:09:44,117 +但它们的实际大小取决于 +叠放的容器 + +166 +00:09:44,151 --> 00:09:47,921 +叠放视图将会扩展 +以填充容器提供的任何空间 + +167 +00:09:47,955 --> 00:09:49,590 +这不是我想要的 + +168 +00:09:49,623 --> 00:09:52,793 +我真正想要的是一种 +自定义叠放类型 + +169 +00:09:52,826 --> 00:09:55,562 +它要求每个按钮的理想大小 + +170 +00:09:55,596 --> 00:09:59,800 +找到最宽的 +然后为每个按钮提供相应的空间 + +171 +00:09:59,833 --> 00:10:04,471 +幸运的是 SwiftUI 有一个新工具 +可以让我做到这一点 + +172 +00:10:04,505 --> 00:10:07,841 +使用布局协议 +我可以设定一个自定义布局容器 + +173 +00:10:07,875 --> 00:10:10,777 +它直接参与布局过程 + +174 +00:10:10,811 --> 00:10:13,981 +其行为根据我的用例量身定制 + +175 +00:10:14,014 --> 00:10:15,682 +我们看看它是怎么运行的 + +176 +00:10:16,583 --> 00:10:21,788 +再看一下 HStack +我把它改成 EqualWidthHStack + +177 +00:10:21,822 --> 00:10:26,093 +我要对它进行设定 +以解决我的特定问题 + +178 +00:10:26,126 --> 00:10:29,129 +这种类型将平均分配按钮的宽度 + +179 +00:10:29,162 --> 00:10:33,500 +其宽度就是最宽按钮的理想宽度 + +180 +00:10:33,534 --> 00:10:36,970 +我将保留灵活的框架 +以便文本较窄的按钮 + +181 +00:10:37,004 --> 00:10:40,174 +可以扩展以填充叠放提供的空间 + +182 +00:10:40,207 --> 00:10:43,310 +但是按钮仍然有一个 +我可以测量的理想尺寸 + +183 +00:10:43,343 --> 00:10:45,779 +即它们的文本宽度 + +184 +00:10:45,812 --> 00:10:49,316 +让我们看看如何实现 +MyEqualWidthHStack + +185 +00:10:52,052 --> 00:10:56,290 +我先创建一个遵循 Layout 协议的类型 + +186 +00:10:56,323 --> 00:10:59,693 +对于一个基本的布局 +我只需要两个必需的方法 + +187 +00:10:59,726 --> 00:11:02,462 +让我们为其添加存根 + +188 +00:11:02,496 --> 00:11:04,831 +第一个方法是 sizeThatFits + +189 +00:11:04,865 --> 00:11:08,669 +我将在其中计算并报告 +我的布局容器有多大 + +190 +00:11:10,571 --> 00:11:12,739 +我得到一个建议的视图大小输入 + +191 +00:11:12,773 --> 00:11:16,677 +这是一个布局自身容器视图的 +大小建议 + +192 +00:11:16,710 --> 00:11:21,648 +我可以用 subviews 参数 +建议布局的子视图大小 + +193 +00:11:22,883 --> 00:11:25,953 +注意 我不能直接访问子视图 + +194 +00:11:25,986 --> 00:11:28,789 +相反 子视图输入是一个代理的集合 + +195 +00:11:28,822 --> 00:11:32,059 +让我以特定的方式与子视图交互 + +196 +00:11:32,092 --> 00:11:34,761 +例如建议大小 + +197 +00:11:34,795 --> 00:11:39,132 +每个代理都会根据我提出的建议 +返回一个具体的大小 + +198 +00:11:39,166 --> 00:11:43,437 +我将收集所有这些响应 +并使用它们进行一些计算 + +199 +00:11:43,470 --> 00:11:48,041 +然后将等宽 HStack 的具体大小 +返回到其容器 + +200 +00:11:49,209 --> 00:11:52,846 +我要实现的第二个函数 +是 placeSubviews + +201 +00:11:52,880 --> 00:11:56,850 +我将使用这个来告诉我的布局 +子视图出现在哪里 + +202 +00:11:56,884 --> 00:12:01,054 +此方法采用相同的大小建议 +和子视图输入 + +203 +00:12:01,088 --> 00:12:04,157 +并且还接受边界输入 + +204 +00:12:04,191 --> 00:12:07,060 +它表示我需要放置子视图的区域 + +205 +00:12:07,094 --> 00:12:10,097 +边界是一个矩形 它的大小 + +206 +00:12:10,130 --> 00:12:12,666 +与我在 sizeThatFits 里要求的大小相符 + +207 +00:12:12,699 --> 00:12:15,202 +请记住 视图在 SwiftUI 中 +选择自己的大小 + +208 +00:12:15,235 --> 00:12:19,673 +因此我的布局容器将获取 +它要求的大小 + +209 +00:12:19,706 --> 00:12:22,309 +这个区域的原点在左上角 + +210 +00:12:22,342 --> 00:12:25,812 +positive X 在右边 +positive Y 在下面 + +211 +00:12:25,846 --> 00:12:28,515 +即使是在从右到左的语言环境中 + +212 +00:12:28,549 --> 00:12:30,851 +你也可以假设 +所有的布局计算都是如此 + +213 +00:12:30,884 --> 00:12:34,655 +因为框架在沿该方向布置视图时 + +214 +00:12:34,688 --> 00:12:37,457 +会自动翻转每个视图的 x 位置 + +215 +00:12:37,491 --> 00:12:42,596 +但是 不要假设 +矩形的原点值为(0,0) + +216 +00:12:42,629 --> 00:12:45,299 +除此之外 允许非零原点 + +217 +00:12:45,332 --> 00:12:47,334 +可以启用布局组合 + +218 +00:12:47,367 --> 00:12:49,536 +其中一个布局的 placeSubviews 方法 + +219 +00:12:49,570 --> 00:12:52,206 +调用另一个布局的相同方法 + +220 +00:12:52,239 --> 00:12:55,442 +为了使其更容易操作 矩形提供了 + +221 +00:12:55,475 --> 00:12:57,945 +访问区域重要部分的属性 + +222 +00:12:57,978 --> 00:12:59,980 +如每个维度中的最小点 + +223 +00:13:00,013 --> 00:13:03,884 +中心点和最大值点 + +224 +00:13:05,152 --> 00:13:07,421 +现在 在我继续讲之前 +请注意这两个方法都具有的 + +225 +00:13:07,454 --> 00:13:09,356 +另一个参数 + +226 +00:13:09,389 --> 00:13:11,458 +双向缓存 我可以使用它 + +227 +00:13:11,491 --> 00:13:16,363 +来跨方法调用共享中间计算的结果 + +228 +00:13:16,396 --> 00:13:18,899 +对于许多简单的布局 你不需要这个 + +229 +00:13:18,932 --> 00:13:22,035 +我会暂时忽略缓存 + +230 +00:13:22,069 --> 00:13:25,772 +但如果使用 Instruments +分析你的应用 + +231 +00:13:25,806 --> 00:13:27,908 +表明需要提高布局代码的效率 + +232 +00:13:27,941 --> 00:13:29,877 +可以考虑添加一个 + +233 +00:13:29,910 --> 00:13:32,513 +关于这方面的更多信息 +请查阅文档 + +234 +00:13:34,715 --> 00:13:37,084 +好 我们来实现 sizeThatFits + +235 +00:13:37,117 --> 00:13:39,419 +记住 我想为我的容器返回一个大小 + +236 +00:13:39,453 --> 00:13:44,825 +该大小适合所有水平排列 +宽度都相同的按钮 + +237 +00:13:44,858 --> 00:13:47,761 +首先 我会询问每个按钮的大小 + +238 +00:13:47,794 --> 00:13:51,565 +提出一个大小并查看返回的内容 + +239 +00:13:51,598 --> 00:13:53,567 +为了衡量子视图的灵活性 + +240 +00:13:53,600 --> 00:13:57,137 +我可以使用最小 最大 +和理想尺寸的特殊建议 + +241 +00:13:57,171 --> 00:13:59,406 +进行多次测量 + +242 +00:13:59,439 --> 00:14:01,875 +或者我可以提出一个特定的大小 + +243 +00:14:01,909 --> 00:14:07,347 +在本例中 我使用未指定的大小建议 +来要求理想大小 + +244 +00:14:08,582 --> 00:14:11,318 +然后我将找到所有尺寸中 + +245 +00:14:11,351 --> 00:14:13,487 +每个维度上的最大值 + +246 +00:14:13,520 --> 00:14:15,789 +在本例中 金鱼按钮设置宽度 + +247 +00:14:15,822 --> 00:14:18,625 +而且高度都相同 + +248 +00:14:18,659 --> 00:14:20,360 +现在我把它重构成一个方法 + +249 +00:14:20,394 --> 00:14:23,964 +因为放置子视图时还需要它 + +250 +00:14:23,997 --> 00:14:27,401 +接下来 我需要考虑视图之间的间距 + +251 +00:14:27,434 --> 00:14:30,604 +我可以使用固定间距 比如10点 + +252 +00:14:30,637 --> 00:14:33,440 +但布局协议让我做得更好 + +253 +00:14:33,473 --> 00:14:37,377 +在 SwiftUI 中 所有视图都有间距偏好 + +254 +00:14:37,411 --> 00:14:42,015 +这表明视图希望其自身 +和下一个视图之间拥有多少空间 + +255 +00:14:42,049 --> 00:14:45,219 +这些首选项存储在可用于 + +256 +00:14:45,252 --> 00:14:48,488 +布局容器的 ViewSpacing 实例中 + +257 +00:14:48,522 --> 00:14:51,024 +视图可能喜欢在不同的边上 +使用不同的值 + +258 +00:14:51,058 --> 00:14:54,928 +甚至对不同类型的相邻视图 +使用不同的值 + +259 +00:14:54,962 --> 00:14:57,497 +例如 一个视图 +与文本视图之间的空间 + +260 +00:14:57,531 --> 00:15:02,803 +可能比它与图像之间的空间 +要大或小 + +261 +00:15:02,836 --> 00:15:06,206 +并且值也可能因平台而异 + +262 +00:15:06,240 --> 00:15:09,743 +如果对你的布局有意义 +你可以忽略这些参考值 + +263 +00:15:09,776 --> 00:15:13,380 +这基本上是你们使用 +自定义间距初始化内置叠放时 + +264 +00:15:13,413 --> 00:15:15,415 +发生的情况 + +265 +00:15:15,449 --> 00:15:17,584 +但在你自己的布局中尊重这些偏好 + +266 +00:15:17,618 --> 00:15:20,487 +是获得自动遵循 +Apple 界面指南结果的 + +267 +00:15:20,521 --> 00:15:22,489 +好方法 + +268 +00:15:22,523 --> 00:15:26,527 +从而与系统其他部分的外观相匹配 + +269 +00:15:26,560 --> 00:15:29,796 +现在 每个视图对所有边都有偏好 + +270 +00:15:29,830 --> 00:15:31,532 +当我把两个视图放在一起时 + +271 +00:15:31,565 --> 00:15:35,068 +同一条边的偏好可能不匹配 + +272 +00:15:35,102 --> 00:15:37,204 +为了解决这个问题 内置布局容器 + +273 +00:15:37,237 --> 00:15:39,740 +使用两个首选项中较大的一个 + +274 +00:15:39,773 --> 00:15:41,942 +我可以在自己的布局中 +做同样的事情 + +275 +00:15:43,443 --> 00:15:47,314 +子视图代理给出了一种方法 +可以沿给定轴设定每个按钮 + +276 +00:15:47,347 --> 00:15:50,651 +与其他按钮的首选间距 + +277 +00:15:50,684 --> 00:15:54,688 +所以我通过扫描子视图 +来创建一个数组的值 + +278 +00:15:54,721 --> 00:15:59,493 +并在每个代理的间距实例上 +调用距离方法 + +279 +00:15:59,526 --> 00:16:02,930 +来获取下一个视图的间距实例 + +280 +00:16:02,963 --> 00:16:05,599 +沿水平轴的间距 + +281 +00:16:05,632 --> 00:16:07,601 +这个调用考虑了两个视图 + +282 +00:16:07,634 --> 00:16:11,004 +在它们的共同边上的偏好 + +283 +00:16:11,038 --> 00:16:13,407 +这个数组中的第一个元素告诉我 + +284 +00:16:13,440 --> 00:16:17,611 +猫按钮相对于金鱼按钮水平 +需要多少空间 + +285 +00:16:17,644 --> 00:16:22,216 +下一个元素告诉我金鱼按钮 +相对于狗按钮需要多少空间 + +286 +00:16:22,249 --> 00:16:24,952 +我将强制数组中的 +最后一个元素为零 + +287 +00:16:24,985 --> 00:16:28,622 +因为没有任何按钮可进行比较 + +288 +00:16:28,655 --> 00:16:32,626 +好 让我把它重构成一个方法 +稍后再用 + +289 +00:16:32,659 --> 00:16:36,597 +现在我可以结合间距值来找到总间距 + +290 +00:16:36,630 --> 00:16:39,132 +并将其与宽度和高度测量值 +一起使用 + +291 +00:16:39,166 --> 00:16:41,168 +以返回大小值 + +292 +00:16:41,201 --> 00:16:43,070 +这是我的布局需要的大小 + +293 +00:16:43,103 --> 00:16:45,439 +给定它的子视图的理想大小 + +294 +00:16:45,472 --> 00:16:49,376 +和每个子视图的首选间距 + +295 +00:16:49,409 --> 00:16:52,946 +我需要实现的另一个函数 +是 placeSubview + +296 +00:16:52,980 --> 00:16:55,983 +正如我前面提到的 +我得到了容器的边界 + +297 +00:16:56,016 --> 00:17:01,021 +以及可以用来引导按钮的 +子视图代理的集合 + +298 +00:17:01,054 --> 00:17:04,291 +首先 +我像在 sizeThatFits 方法中那样 + +299 +00:17:04,324 --> 00:17:06,593 +计算 maxSize 和间距数组 + +300 +00:17:06,627 --> 00:17:10,030 +因为这里也需要这些值 + +301 +00:17:10,063 --> 00:17:13,967 +然后我将创建一个 +可用于每个子视图的尺寸建议 + +302 +00:17:14,001 --> 00:17:16,537 +这一次基于我希望它们具有的尺寸 + +303 +00:17:16,570 --> 00:17:18,639 +而不是它们的理想尺寸 + +304 +00:17:18,672 --> 00:17:23,443 +我只需要一个建议 +因为我希望所有按钮的大小相同 + +305 +00:17:23,477 --> 00:17:26,313 +我会在我的第一个子视图的 +水平维度上 + +306 +00:17:26,346 --> 00:17:30,250 +找到一个起始位置 作为边界的前缘 + +307 +00:17:30,284 --> 00:17:32,553 +加上按钮宽度的一半 + +308 +00:17:32,586 --> 00:17:34,955 +请注意 我不依赖原点为零 + +309 +00:17:34,988 --> 00:17:39,159 +而是从 minX 值开始 + +310 +00:17:39,193 --> 00:17:42,296 +最后 我可以浏览每个子视图代理 + +311 +00:17:42,329 --> 00:17:45,532 +并用一个点调用它的放置方法 + +312 +00:17:45,566 --> 00:17:49,036 +声明该点在按钮方面代表什么 + +313 +00:17:49,069 --> 00:17:52,105 +以及尺寸建议 + +314 +00:17:52,139 --> 00:17:55,075 +每次通过循环 我都将水平位置 + +315 +00:17:55,108 --> 00:17:58,545 +更新为视图的宽度 +加上下一个视图对的间距 + +316 +00:17:58,579 --> 00:18:01,114 +以便为下一次迭代做好准备 + +317 +00:18:01,148 --> 00:18:02,549 +就是这样 + +318 +00:18:02,583 --> 00:18:06,053 +现在让我们看看使用 +新的视图布局类型会发生什么 + +319 +00:18:07,454 --> 00:18:08,655 +就是这个 + +320 +00:18:08,689 --> 00:18:11,058 +我将自己的自定义布局容器实例化 + +321 +00:18:11,091 --> 00:18:13,527 +就像我使用内置 HStack 一样 + +322 +00:18:13,560 --> 00:18:18,532 +按钮水平排列 宽度相同 + +323 +00:18:18,565 --> 00:18:20,467 +现在 我想在这里暂停片刻 + +324 +00:18:20,501 --> 00:18:22,970 +谈谈布局协议如何解决过去你们 + +325 +00:18:23,003 --> 00:18:27,040 +可能尝试使用 Geometry reader +解决的问题 + +326 +00:18:27,074 --> 00:18:31,378 +毕竟 Geometry reader +是测量视图大小的工具 + +327 +00:18:31,411 --> 00:18:35,015 +但是在这种情况下 这不是最佳选择 + +328 +00:18:35,048 --> 00:18:38,919 +这是因为 geometry reader +旨在测量其容器视图 + +329 +00:18:38,952 --> 00:18:41,288 +并将该大小报告给其子视图 + +330 +00:18:41,321 --> 00:18:45,792 +然后子视图使用这些信息 +来绘制它自己的内容 + +331 +00:18:45,826 --> 00:18:48,428 +注意 对于 geometry reader 来说 + +332 +00:18:48,462 --> 00:18:50,330 +信息是向下传递的 + +333 +00:18:50,364 --> 00:18:52,432 +reader所做的测量对其自身容器的 + +334 +00:18:52,466 --> 00:18:54,701 +布局没有影响 + +335 +00:18:55,836 --> 00:18:59,439 +这对于绘制随容器缩放的路径 +非常有用 + +336 +00:18:59,473 --> 00:19:03,143 +geometry reader 告诉路径逻辑 +它必须使用多少空间 + +337 +00:19:03,177 --> 00:19:07,714 +子视图中的路径逻辑相应地调整 + +338 +00:19:07,748 --> 00:19:10,984 +如果容器改变了大小 路径也会改变 + +339 +00:19:11,018 --> 00:19:14,755 +因为 geometry reader +会沿着新的大小传递 + +340 +00:19:14,788 --> 00:19:17,591 +但是 对于我的按钮来说 +我将在这里只关注一个 + +341 +00:19:17,624 --> 00:19:21,528 +以便更容易看到 +我需要测量文本视图 + +342 +00:19:21,562 --> 00:19:26,967 +然后使用它来决定如何设置 +以作为文本视图容器的框架 + +343 +00:19:27,000 --> 00:19:30,938 +因此 我可以在文本视图的叠加中 +添加一个 geometry reader + +344 +00:19:30,971 --> 00:19:33,173 +记住 测量其容器 + +345 +00:19:33,207 --> 00:19:36,343 +然后以某种方式将测量数据 +发送回框架 + +346 +00:19:36,376 --> 00:19:38,645 +在正常的流程之外 + +347 +00:19:38,679 --> 00:19:41,548 +但请注意 如果我这样做 +就会绕过布局引擎 + +348 +00:19:41,582 --> 00:19:43,784 +这可能会导致循环 + +349 +00:19:43,817 --> 00:19:46,887 +读取器测量布局并改变框架 + +350 +00:19:46,920 --> 00:19:51,925 +可能会改变布局 +可能需要再次测量等等 + +351 +00:19:51,959 --> 00:19:54,394 +现在要实现这个是有可能的 + +352 +00:19:54,428 --> 00:19:57,931 +但如果我不小心 +最终可能会导致我的 App 崩溃 + +353 +00:19:57,965 --> 00:20:00,868 +因此 不建议使用这个策略 + +354 +00:20:00,901 --> 00:20:04,238 +幸运的是 布局协议提供了一种 +更好的方法来解决这个问题 + +355 +00:20:04,271 --> 00:20:07,140 +允许你们在布局引擎中操作 + +356 +00:20:08,108 --> 00:20:10,711 +好 让我们再看看按钮 + +357 +00:20:10,744 --> 00:20:13,013 +这里我还想做点别的事 + +358 +00:20:13,046 --> 00:20:14,882 +首先 为了更易于观看 + +359 +00:20:14,915 --> 00:20:18,519 +我将把按钮重构为 +它们自身的子视图 + +360 +00:20:18,552 --> 00:20:21,321 +现在 我碰巧知道我的一位同事 +在他们的设备上使用 + +361 +00:20:21,355 --> 00:20:22,990 +更大的字体 + +362 +00:20:23,023 --> 00:20:27,461 +我的 App 自动支持 Dynamic Type +因为我使用了默认字体 + +363 +00:20:27,494 --> 00:20:30,898 +所以基本上可以 +免费获得正确的行为 + +364 +00:20:30,931 --> 00:20:35,235 +让我们看看如果增加字体大小 +会发生什么 + +365 +00:20:35,269 --> 00:20:37,437 +啊哦 按钮不适合了 + +366 +00:20:37,471 --> 00:20:41,041 +请记住 我的自定义叠放 +没有限制按钮的宽度 + +367 +00:20:41,074 --> 00:20:43,644 +而只是让它们拥有理想的大小 + +368 +00:20:43,677 --> 00:20:47,080 +在这种情况下 超过了显示的宽度 + +369 +00:20:47,114 --> 00:20:48,582 +那么我能做什么呢 + +370 +00:20:48,615 --> 00:20:51,318 +好吧 当视图不适合时 +我可以修改布局 + +371 +00:20:51,351 --> 00:20:54,421 +以做一些更复杂的事情 + +372 +00:20:54,454 --> 00:20:56,323 +同时考虑到布局容器的大小建议 + +373 +00:20:56,356 --> 00:20:59,626 +但是对于这种情况 +我可以使用新的 ViewThatFits 容器 + +374 +00:20:59,660 --> 00:21:01,828 +来为我完成大部分工作 + +375 +00:21:01,862 --> 00:21:05,499 +这个新类型从我提供的视图列表中 +选择第一个 + +376 +00:21:05,532 --> 00:21:07,901 +适合可用空间的视图 + +377 +00:21:09,336 --> 00:21:13,006 +通过将我的自定义叠放 +包装在一个适合视图的结构中 + +378 +00:21:13,040 --> 00:21:16,076 +然后添加相同内容的垂直叠放版本 + +379 +00:21:16,109 --> 00:21:20,747 +我可以让 SwiftUI 知道按钮 +什么时候需要以不同的方式排列 + +380 +00:21:20,781 --> 00:21:24,284 +当然 内置的 VStack +没有我自定义水平叠放 + +381 +00:21:24,318 --> 00:21:27,521 +所具有的等宽属性 + +382 +00:21:27,554 --> 00:21:31,725 +所以我也实现了自定义叠放的 +垂直版本 + +383 +00:21:31,758 --> 00:21:34,061 +它与我之前说的非常相似 + +384 +00:21:34,094 --> 00:21:37,564 +不同的是它将等宽的项目 + +385 +00:21:37,598 --> 00:21:40,067 +放置在垂直轴而不是水平轴上 + +386 +00:21:41,668 --> 00:21:44,771 +当然 当我删除动态类型大小覆盖时 + +387 +00:21:44,805 --> 00:21:47,574 +它又回到了水平布局 + +388 +00:21:47,608 --> 00:21:50,010 +现在 我还需要构建 +App 的最后一个部分 + +389 +00:21:50,043 --> 00:21:52,846 +那就是顶部的图像 + +390 +00:21:52,880 --> 00:21:56,483 +我可以做一些简单的事情 +比如只显示一组个人资料图片 + +391 +00:21:56,517 --> 00:21:59,186 +但我想可以从中获得一些乐趣 + +392 +00:21:59,219 --> 00:22:01,321 +所以我做了另一个自定义布局类型 + +393 +00:22:01,355 --> 00:22:04,458 +以圆形排列方式绘制视图 + +394 +00:22:04,491 --> 00:22:08,028 +然后根据排名旋转排列 + +395 +00:22:08,061 --> 00:22:11,031 +所以这个配置显示金鱼排名第一 + +396 +00:22:11,064 --> 00:22:13,500 +其他两个并列第二 + +397 +00:22:13,534 --> 00:22:17,070 +然后如果狗放到猫前面 +我可以旋转一下来展示 + +398 +00:22:17,104 --> 00:22:19,740 +或者我可以通过旋转径向布局 + +399 +00:22:19,773 --> 00:22:23,110 +展示一个更真实的结果 + +400 +00:22:23,143 --> 00:22:27,014 +使用布局协议创建此布局 +实际上非常简单 + +401 +00:22:27,047 --> 00:22:30,317 +和之前一样 我只需要两种方法 + +402 +00:22:30,350 --> 00:22:33,687 +对于适合的大小 +我希望视图填充可用空间 + +403 +00:22:33,720 --> 00:22:37,724 +所以我将返回容器视图建议的大小 + +404 +00:22:37,758 --> 00:22:40,360 +我将使用 +replace-unspecified-dimensions 方法 + +405 +00:22:40,394 --> 00:22:44,031 +将建议转换为具体尺寸 + +406 +00:22:44,064 --> 00:22:47,234 +如果容器要求理想的大小 + +407 +00:22:47,267 --> 00:22:50,737 +该方法会自动处理可能出现的 nil 值 + +408 +00:22:50,771 --> 00:22:53,340 +然后在放置子视图方法中 + +409 +00:22:53,373 --> 00:22:55,609 +我将根据布局区域的大小 + +410 +00:22:55,642 --> 00:22:59,213 +将每个子视图从中间偏移一些半径 + +411 +00:22:59,246 --> 00:23:03,350 +并应用取决于视图索引的旋转 + +412 +00:23:03,383 --> 00:23:07,588 +作为基线 会将视图 + +413 +00:23:07,621 --> 00:23:12,459 +放置在圆周的 0 1 和 三分之二处 + +414 +00:23:12,492 --> 00:23:14,161 +为了反映当前的排名 + +415 +00:23:14,194 --> 00:23:18,365 +我还将应用一个对所有视图 +产生同等影响的偏移量 + +416 +00:23:18,398 --> 00:23:20,033 +但是我从哪里获得排名呢 + +417 +00:23:20,067 --> 00:23:23,537 +记住 我的布局只能访问子视图代理 + +418 +00:23:23,570 --> 00:23:27,107 +而不能访问视图 +更不用说数据模型了 + +419 +00:23:27,140 --> 00:23:31,044 +原来布局协议还有另一个妙招 + +420 +00:23:31,078 --> 00:23:33,380 +它允许我们在每个子视图上存储值 + +421 +00:23:33,413 --> 00:23:37,384 +并从布局协议方法中读取值 + +422 +00:23:37,417 --> 00:23:41,822 +让我们看看我如何使用它 +来传达排名信息 + +423 +00:23:41,855 --> 00:23:46,593 +首先 我声明了一个新的类型 +遵循 LayoutValueKey 协议 + +424 +00:23:46,627 --> 00:23:48,829 +并给它一个默认值 + +425 +00:23:48,862 --> 00:23:53,166 +除了在未显式设置视图时 +为视图提供值外 + +426 +00:23:53,200 --> 00:23:56,303 +默认值还建立关联值的类型 + +427 +00:23:56,336 --> 00:23:59,339 +在本例中为整数 + +428 +00:23:59,373 --> 00:24:03,410 +然后 我在 View 上 +创建了一个方便的方法 + +429 +00:24:03,443 --> 00:24:07,114 +使用 layoutValue 视图修饰器 +来设置值 + +430 +00:24:07,147 --> 00:24:08,882 +现在 在我的视图层次结构中 + +431 +00:24:08,916 --> 00:24:13,187 +可以将便利排名修饰器 +应用到布局中的视图 + +432 +00:24:13,220 --> 00:24:15,322 +在这里 我计算每个宠物的排名 + +433 +00:24:15,355 --> 00:24:20,894 +并将其添加到我的径向布局中 +对应的宠物头像视图中 + +434 +00:24:20,928 --> 00:24:23,597 +最后 回到我的放置子视图方法 + +435 +00:24:23,630 --> 00:24:27,167 +我可以添加一些代码 +通过使用布局值键作为索引 + +436 +00:24:27,201 --> 00:24:31,371 +从每个子视图读取值 + +437 +00:24:31,405 --> 00:24:34,675 +我可以使用排名来计算偏移量 + +438 +00:24:34,708 --> 00:24:37,511 +我在这里就不赘述这种逻辑了 +但它基本上 + +439 +00:24:37,544 --> 00:24:40,914 +为任何可能的排名 +产生了一个合适的角度 + +440 +00:24:40,948 --> 00:24:43,283 +好吧 除了这个 + +441 +00:24:43,317 --> 00:24:45,752 +如果三个并列会怎么样呢 + +442 +00:24:45,786 --> 00:24:48,856 +无法通过旋转布局 +来使所有视图排成一行 + +443 +00:24:48,889 --> 00:24:53,393 +所以我必须替换 +完全不同的布局逻辑 + +444 +00:24:53,427 --> 00:24:56,330 +但是 已经有一种布局类型 +可以做到这一点 + +445 +00:24:56,363 --> 00:24:58,498 +那就是内置的 HStack + +446 +00:24:58,532 --> 00:25:01,168 +所以我真正想做的是 +当检测到三个并列时 + +447 +00:25:01,201 --> 00:25:03,604 +转换到 HStack + +448 +00:25:03,637 --> 00:25:07,107 +事实证明 +也有一个新工具可以做到这一点 + +449 +00:25:07,140 --> 00:25:09,476 +AnyLayout 类型允许你们 +将不同的布局 + +450 +00:25:09,510 --> 00:25:12,513 +应用于单个视图层次结构 +这样 当你从一个布局类型 + +451 +00:25:12,546 --> 00:25:16,517 +转换到另一个布局类型时 +可以保持视图的标识 + +452 +00:25:17,451 --> 00:25:20,988 +所以这里有 +我们之前看到的径向布局 + +453 +00:25:21,021 --> 00:25:24,057 +我所要做的就是用一个 +新的布局类型替换它 + +454 +00:25:24,091 --> 00:25:27,528 +取决于是否是三个并列 + +455 +00:25:27,561 --> 00:25:31,465 +因为 isThreeWayTie 属性是 +从状态派生的 + +456 +00:25:31,498 --> 00:25:33,333 +所以 SwiftUI 会注意到它的变化 + +457 +00:25:33,367 --> 00:25:36,370 +并识别出它需要重新绘制这个视图 + +458 +00:25:36,403 --> 00:25:39,540 +但是由于视图层次结构的结构标识 +始终保持不变 + +459 +00:25:39,573 --> 00:25:43,844 +SwiftUI 将其视为一个变化的视图 + +460 +00:25:43,877 --> 00:25:46,213 +而不是一个新的视图 + +461 +00:25:46,246 --> 00:25:48,949 +因此 只需要多一行 + +462 +00:25:48,982 --> 00:25:52,553 +我就可以在布局类型之间 +创建平滑的过渡 + +463 +00:25:52,586 --> 00:25:55,155 +而事实上 通过添加动画视图修饰器 + +464 +00:25:55,189 --> 00:25:59,726 +我还可以获得径向布局的 +所有不同状态之间的动画 + +465 +00:25:59,760 --> 00:26:03,931 +因为径向布局的配置 +依赖于相同的数据 + +466 +00:26:03,964 --> 00:26:06,733 +这是它实际运行的样子 + +467 +00:26:06,767 --> 00:26:09,403 +当我点击不同的按钮来更改 +投票计数时 + +468 +00:26:09,436 --> 00:26:13,540 +你可以看到头像如何平滑地移动 +来反映当前的排名 + +469 +00:26:17,845 --> 00:26:20,447 +这些是 SwiftUI 用于组合 + +470 +00:26:20,480 --> 00:26:23,083 +你的 App 的视图布局的一些新工具 + +471 +00:26:23,116 --> 00:26:25,719 +你可以使用 Grid 类型 +构建静态信息的 + +472 +00:26:25,752 --> 00:26:28,589 +高度可定制的二维布局 + +473 +00:26:28,622 --> 00:26:31,859 +你们可以使用布局协议 +来定义自己的通用布局 + +474 +00:26:31,892 --> 00:26:36,730 +可重用布局 +或高度针对特定用例的布局 + +475 +00:26:36,763 --> 00:26:40,734 +当你想让 SwiftUI 从一组视图中 +选择最适合可用空间的视图时 + +476 +00:26:40,767 --> 00:26:43,303 +可以使用 ViewThatFits + +477 +00:26:43,337 --> 00:26:48,442 +你可以使用 AnyLayout +在布局类型之间无缝切换 + +478 +00:26:48,475 --> 00:26:51,411 +感谢你今天加入我的行列 +希望你能像我一样 + +479 +00:26:51,445 --> 00:26:54,214 +从这些新的布局工具中获得乐趣 + diff --git a/zho/2022 Session 10058 SwiftUI on iPad - Organize your interface.srt b/zho/2022 Session 10058 SwiftUI on iPad - Organize your interface.srt new file mode 100644 index 0000000..deb32f6 --- /dev/null +++ b/zho/2022 Session 10058 SwiftUI on iPad - Organize your interface.srt @@ -0,0 +1,1477 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,676 --> 00:00:12,546 +大家好 欢迎收看 + +3 +00:00:12,579 --> 00:00:14,147 +“SwiftUI on iPad: +Organize your interface” + +4 +00:00:14,181 --> 00:00:17,751 +我是 Raj 从事 SwiftUI 工作 + +5 +00:00:17,784 --> 00:00:22,055 +iPadOS 16 有许多更新 +可以构建更高效 + +6 +00:00:22,089 --> 00:00:25,592 +更专业 功能更丰富的 App + +7 +00:00:25,626 --> 00:00:28,562 +在本次讲座中 +我将讨论其中的部分更新 + +8 +00:00:28,595 --> 00:00:34,268 +并讨论如何组织 SwiftUI app的界面 +使其在 iPad 上大放异彩 + +9 +00:00:34,301 --> 00:00:38,305 +首先 我将带你浏览列表和表格 + +10 +00:00:38,338 --> 00:00:41,041 +然后 我将讨论 SwiftUI 选择模型 + +11 +00:00:41,074 --> 00:00:44,378 +以及如何将选择与菜单集成 + +12 +00:00:44,411 --> 00:00:47,581 +最后 我将讨论如何使用分屏浏览 + +13 +00:00:47,614 --> 00:00:49,983 +来构建 iPad app 的导航 + +14 +00:00:50,017 --> 00:00:52,352 +但请等等 还有更多 + +15 +00:00:52,386 --> 00:00:55,689 +这实际上是两部分系列的第一部分 + +16 +00:00:55,722 --> 00:00:58,492 +在第二部分 我的同事 Harry + +17 +00:00:58,525 --> 00:01:01,762 +将带你浏览工具栏 标题等 + +18 +00:01:01,795 --> 00:01:03,797 +Harry 介绍了一些 +非常重要的新增功能 + +19 +00:01:03,830 --> 00:01:06,733 +这些功能将 SwiftUI iPad app +提升到了一个新的水平 + +20 +00:01:06,767 --> 00:01:09,970 +因此请务必观看这两个讲座 + +21 +00:01:10,003 --> 00:01:14,041 +我们先从列表和表格开始 + +22 +00:01:14,074 --> 00:01:18,011 +我最近加入了几个读书俱乐部 +但我的进展很慢 + +23 +00:01:18,045 --> 00:01:20,848 +很难找到一个安静的地方看书 + +24 +00:01:20,881 --> 00:01:24,051 +因此 为了帮助我专注于阅读 +我开始开发一个 App + +25 +00:01:24,084 --> 00:01:26,620 +来寻找这些神秘的安静之地 + +26 +00:01:26,653 --> 00:01:30,858 +安静的地方就像阅读的绿洲 +只有沙沙的翻书声 + +27 +00:01:30,891 --> 00:01:35,062 +这个 App 可以帮助我跟踪 +所有安静的地方 + +28 +00:01:35,095 --> 00:01:38,131 +我已经为 iPhone 构建了这款 App +但我认为为 iPad 更新这款 App + +29 +00:01:38,165 --> 00:01:42,035 +会是一个有趣的练习 +因为这样可以充分利用更大的屏幕 + +30 +00:01:42,069 --> 00:01:45,305 +通过让这款 App 更好地 +适用于 iPad + +31 +00:01:45,339 --> 00:01:48,175 +当我最终将其安装到 Mac 上时 +还会做进一步的改进 + +32 +00:01:48,208 --> 00:01:50,811 +我不会在本讲座中明确介绍 Mac + +33 +00:01:50,844 --> 00:01:54,815 +但所示的许多 API 也适用于 macOS + +34 +00:01:54,848 --> 00:01:58,318 +这是到目前为止我发现的 +所有安静地方的清单 + +35 +00:01:58,352 --> 00:02:01,989 +这份列表是更新 App 的 +一个很好的起点 + +36 +00:02:02,022 --> 00:02:04,424 +我已经开始研究 iPad 版本了 + +37 +00:02:04,458 --> 00:02:08,395 +这并不可怕 +但这并没有利用较大的屏幕 + +38 +00:02:08,428 --> 00:02:12,833 +这有点浪费空间 信息密度也很低 + +39 +00:02:12,866 --> 00:02:16,336 +幸运的是 在 iPadOS 16 中 +有一个很好的解决方案 + +40 +00:02:16,370 --> 00:02:19,072 +适用于这些信息密集场景类型 + +41 +00:02:19,106 --> 00:02:21,441 +多列表 + +42 +00:02:21,475 --> 00:02:24,178 +我来让你们看看它是什么样子的 + +43 +00:02:24,211 --> 00:02:27,915 +这是为多列表采用 SwiftUI API 后 + +44 +00:02:27,948 --> 00:02:29,816 +“All Places”界面的视图效果 + +45 +00:02:29,850 --> 00:02:33,420 +在接下来的几分钟内 +我将逐步完成这个截图 + +46 +00:02:33,453 --> 00:02:37,291 +SwiftUI 中的多列表格 +最早是在 macOS Monterey 中引入的 + +47 +00:02:37,324 --> 00:02:42,663 +从 iPadOS 16 开始 +同样的表 API 现在也可以用于 iPad + +48 +00:02:42,696 --> 00:02:47,968 +像在 Mac 上一样 iPad 上的表格 +支持多列和排序 + +49 +00:02:48,001 --> 00:02:50,337 +伴随着 iPad 上表格的引入 + +50 +00:02:50,370 --> 00:02:54,374 +SwiftUI 现在在 iPad 和 Mac 上 +支持表格分段 + +51 +00:02:55,976 --> 00:02:58,879 +上一个讲座 “SwiftUI on the Mac: +Build the fundamentals”中 + +52 +00:02:58,912 --> 00:03:03,016 +关于表格的一般指导 +仍然适用于 iPad + +53 +00:03:03,050 --> 00:03:06,320 +所以如果你还没有看过该讲座 +我建议你去看看 + +54 +00:03:07,354 --> 00:03:10,924 +我们从 iPhone 列表开始 +建立之前显示的表格 + +55 +00:03:10,958 --> 00:03:13,794 +这是前面的位置列表的代码 + +56 +00:03:15,495 --> 00:03:18,665 +首先 我将从列表切换到表格 + +57 +00:03:18,699 --> 00:03:21,502 +表格和列表的构造函数是不同的 + +58 +00:03:21,535 --> 00:03:24,872 +表格接受列生成器 而不是视图生成器 + +59 +00:03:26,406 --> 00:03:29,443 +我添加的第一列是地名 + +60 +00:03:29,476 --> 00:03:32,546 +该列需要一个标题名称 +和一个视图生成器 + +61 +00:03:32,579 --> 00:03:35,616 +来为集合中的每个元素生成视图 + +62 +00:03:35,649 --> 00:03:39,119 +我还指定了一个关键路径 +这在以后 + +63 +00:03:39,152 --> 00:03:41,889 +向表中添加排序时很重要 + +64 +00:03:41,922 --> 00:03:45,559 +请注意 视图生成器 +与基于列表的构造非常相似 + +65 +00:03:45,592 --> 00:03:49,229 +事实上 我甚至可以重复使用 +之前的 PlaceCell 类型 + +66 +00:03:50,797 --> 00:03:55,068 +在紧凑尺寸类中 +表格只显示它们的第一列 + +67 +00:03:55,102 --> 00:03:58,939 +这意味着我的列表在 iPhone 上和 +在 iPad 上侧拉时看起来仍然很棒 + +68 +00:04:00,340 --> 00:04:03,610 +你可能会注意到 +它在外观上与列表有些相似 + +69 +00:04:03,644 --> 00:04:05,979 +但我并没有仅仅用列表替换表格 + +70 +00:04:06,013 --> 00:04:09,416 +因为重用表格允许 +在尺寸类型之间转换时 + +71 +00:04:09,449 --> 00:04:12,920 +保留滚动位置和选择 + +72 +00:04:12,953 --> 00:04:15,322 +一般而言 确保使用第一栏 + +73 +00:04:15,355 --> 00:04:18,592 +以获得紧凑型外观 +并始终确保在各种环境中 + +74 +00:04:18,625 --> 00:04:21,862 +测试 iPad app 比如 侧拉 + +75 +00:04:23,163 --> 00:04:25,165 +好的 我们继续 + +76 +00:04:25,199 --> 00:04:28,135 +我将为舒适度和噪声级别添加列 + +77 +00:04:28,168 --> 00:04:32,506 +对于只包含文本内容的列 +TableColumn 提供了一个方便的 API + +78 +00:04:32,539 --> 00:04:36,376 +允许我在值指向字符串时 +省略视图生成器 + +79 +00:04:36,410 --> 00:04:38,645 +在这种情况下 +我知道舒适度不需要 + +80 +00:04:38,679 --> 00:04:41,515 +很大的空间 所以我采用了固定宽度 + +81 +00:04:42,683 --> 00:04:45,686 +我还可以使用比较器 +将排序添加到表格中 + +82 +00:04:45,719 --> 00:04:48,689 +我将创建一些状态来存储比较器 + +83 +00:04:48,722 --> 00:04:51,225 +这里的状态是一个数组 +因为它代表 + +84 +00:04:51,258 --> 00:04:53,460 +表格的所​​有比较器 + +85 +00:04:53,493 --> 00:04:56,096 +并且将初始值设置为名称比较器 + +86 +00:04:56,129 --> 00:04:59,333 +可以让表格在第一次显示时 +显示排序的结果 + +87 +00:05:00,534 --> 00:05:04,872 +接下来 将状态绑定传递到表格中 +以便将所有内容连接起来 + +88 +00:05:06,073 --> 00:05:09,176 +因为每个列都将其值指定为 +可比较字段的 + +89 +00:05:09,209 --> 00:05:12,613 +关键路径 +所以默认情况下它们是可排序的 + +90 +00:05:12,646 --> 00:05:18,051 +现在 这个表格完全可以 +按名称 舒适度和噪声进行排序 + +91 +00:05:18,085 --> 00:05:20,587 +请注意 表格本身并不处理排序 + +92 +00:05:20,621 --> 00:05:21,989 +这取决于我 + +93 +00:05:22,022 --> 00:05:26,059 +当排序顺序改变时 我可以使用 +onChange 修饰器对数据进行排序 + +94 +00:05:27,361 --> 00:05:29,796 +好的 我们来试一试吧 + +95 +00:05:30,797 --> 00:05:33,600 +这个表格看起来很棒 +显示了所有位置数据 + +96 +00:05:33,634 --> 00:05:37,137 +真正利用了大屏幕的优势 + +97 +00:05:37,171 --> 00:05:40,607 +与 Mac 不同 +iPad 上的表格不会水平滚动 + +98 +00:05:40,641 --> 00:05:43,310 +所以限制列数很重要 + +99 +00:05:43,343 --> 00:05:47,181 +这确保了所有列 都可以同时显示 + +100 +00:05:47,214 --> 00:05:49,816 +每列在头部显示标签 + +101 +00:05:49,850 --> 00:05:52,286 +点击标签对该列进行排序 + +102 +00:05:52,319 --> 00:05:54,154 +我甚至可以按噪声等级分类 + +103 +00:05:57,090 --> 00:06:00,127 +在侧拉功能中 表格折叠成一列 + +104 +00:06:00,160 --> 00:06:03,897 +以更简洁的格式表示所有信息 + +105 +00:06:03,931 --> 00:06:07,868 +现在我已经将列表更新为一个表格 +我们开始选择吧 + +106 +00:06:07,901 --> 00:06:11,071 +在本节中 我将回顾 SwiftUI 选择模型 + +107 +00:06:11,104 --> 00:06:14,041 +并讨论如何将选择与菜单集成 + +108 +00:06:14,074 --> 00:06:18,612 +在此过程中 +我将为位置表格增加丰富的功能 + +109 +00:06:18,645 --> 00:06:22,149 +但首先 我要谈谈 SwiftUI 中的 +选择是如何工作的 + +110 +00:06:22,182 --> 00:06:27,287 +SwiftUI 包括一个强大的 API +用于管理列表和表格选择 + +111 +00:06:27,321 --> 00:06:30,624 +这是一个图解 +里面的列表有多行 + +112 +00:06:30,657 --> 00:06:32,426 +每一行都有一个标签 + +113 +00:06:32,459 --> 00:06:37,331 +这些标签是每一行的唯一值 +用于帮助列表管理所选内容 + +114 +00:06:37,364 --> 00:06:40,234 +在这张图表中 标签以绿色圆圈显示 + +115 +00:06:41,602 --> 00:06:45,706 +除了标签 还有一些状态保留的选择 + +116 +00:06:45,739 --> 00:06:48,242 +这是保存标签值的类型 + +117 +00:06:48,275 --> 00:06:50,344 +例如 对于多个选择 + +118 +00:06:50,377 --> 00:06:54,448 +这是一个集合 +用于保存每个选定行的标签 + +119 +00:06:54,481 --> 00:06:57,518 +列表的任务是协调每行中的标签 + +120 +00:06:57,551 --> 00:06:58,886 +和选择状态 + +121 +00:06:58,919 --> 00:07:02,289 +它通过选择绑定来完成这一步 + +122 +00:07:02,322 --> 00:07:05,926 +所以当一行被选中时 +比如这里的第二行 + +123 +00:07:05,959 --> 00:07:09,763 +列表通过选择绑定将它添加到集合中 + +124 +00:07:09,796 --> 00:07:12,032 +同样 如果 App 的其他部分 + +125 +00:07:12,065 --> 00:07:17,437 +以编程方式更改了集合 +例如添加三个 + +126 +00:07:17,471 --> 00:07:20,941 +如图所示 则列表会选择它 +因为选择绑定会更改 + +127 +00:07:20,974 --> 00:07:24,611 +这个通用模型在 iOS 和 macOS 上 +都是一样的 + +128 +00:07:24,645 --> 00:07:29,383 +所以有两部分需要选择 标签和状态 + +129 +00:07:29,416 --> 00:07:32,719 +接下来我想说一下标签从何而来 + +130 +00:07:32,753 --> 00:07:36,957 +标签只是可选容器中视图的一个值 + +131 +00:07:36,990 --> 00:07:40,260 +用于跟踪该视图是否被选中 + +132 +00:07:40,294 --> 00:07:44,998 +在很多情况下 SwiftUI 可以为你 +自动合成标签 + +133 +00:07:45,032 --> 00:07:49,203 +标签类似于标识符 但不完全相同 + +134 +00:07:49,236 --> 00:07:52,673 +使用 ForEach 时 SwiftUI 将自动 + +135 +00:07:52,706 --> 00:07:55,242 +从视图的显式标识符 +派生出该视图的标签 + +136 +00:07:55,275 --> 00:08:00,013 +而且表格会使用其行值的标识符 +作为选择标签 + +137 +00:08:00,047 --> 00:08:04,885 +在位置 App 中 这意味着将使用 +位置结构的标识符类型 + +138 +00:08:04,918 --> 00:08:07,120 +有关显示标识的更多信息 + +139 +00:08:07,154 --> 00:08:09,323 +请查看 “Demystify SwiftUI” + +140 +00:08:11,325 --> 00:08:14,595 +要手动为视图做标签 +请使用 tag 修饰器 + +141 +00:08:14,628 --> 00:08:16,763 +这就是 ForEach 在内部所做的工作 + +142 +00:08:16,797 --> 00:08:19,099 +tag 修饰器采用哈希值 + +143 +00:08:19,132 --> 00:08:22,336 +但在使用标签修改器时 一定要注意 + +144 +00:08:22,369 --> 00:08:25,405 +可选择容器中的所有视图 +都共享相同的标签类型 + +145 +00:08:25,439 --> 00:08:27,708 +这一点很重要 + +146 +00:08:27,741 --> 00:08:31,612 +否则 SwiftUI 可能不知道 +如何选择视图 + +147 +00:08:31,645 --> 00:08:35,582 +请注意 如果使用 ID 修饰器 +它不会设置标签 + +148 +00:08:35,616 --> 00:08:39,219 +以上就是标签的介绍 +让我们再来回顾一下之前的图解 + +149 +00:08:40,487 --> 00:08:42,789 +现在我已经解释了这张图解的标签部分 + +150 +00:08:42,823 --> 00:08:45,893 +我想重点介绍选择等式的另一边 + +151 +00:08:45,926 --> 00:08:47,561 +选择状态 + +152 +00:08:47,594 --> 00:08:51,498 +在上一个示例中我使用了一个集合 +但也有其他选项 + +153 +00:08:52,900 --> 00:08:56,370 +你可以使用这些数据结构代表选择 + +154 +00:08:56,403 --> 00:08:59,806 +SwiftUI 支持单选 +macOS Ventura 中新增的 + +155 +00:08:59,840 --> 00:09:03,810 +macOS 侧边栏的必选项 +以及多选项 + +156 +00:09:06,680 --> 00:09:10,984 +iPadOS 16 还引入了轻量级多选 + +157 +00:09:11,018 --> 00:09:14,221 +现在 有了键盘连接 +你不需要进入编辑模式 + +158 +00:09:14,254 --> 00:09:18,025 +选择多行 +这有助于避免模态视图 + +159 +00:09:18,058 --> 00:09:20,527 +使用键盘时 你可以使用 shift + +160 +00:09:20,561 --> 00:09:24,164 +和 command 等常用快捷键 +来扩展和修改选择 + +161 +00:09:24,198 --> 00:09:26,633 +这与指针配合使用时效果很好 + +162 +00:09:26,667 --> 00:09:29,803 +这是采用选择后位置表格的样子 + +163 +00:09:29,837 --> 00:09:32,639 +在本例中 +我连接了一个键盘和触摸板 + +164 +00:09:32,673 --> 00:09:35,976 +因此行不会缩进 +但它们仍处于选中状态 + +165 +00:09:36,009 --> 00:09:39,413 +然而 当使用触摸功能时 +我仍然需要进入编辑模式 + +166 +00:09:39,446 --> 00:09:42,850 +使用双指平移可以加快编辑速度 + +167 +00:09:42,883 --> 00:09:45,619 +SwiftUI 自动支持这种手势 + +168 +00:09:45,652 --> 00:09:47,454 +说到编辑模式 也有一些 + +169 +00:09:47,487 --> 00:09:50,257 +单选和编辑模式的更新 + +170 +00:09:50,290 --> 00:09:53,327 +当选择单行时 + +171 +00:09:53,360 --> 00:09:56,563 +iPhone 和 iPad 上的列表选择 +不再需要编辑模式 + +172 +00:09:56,597 --> 00:10:00,334 +这对于协调更新的导航 API +非常有用 + +173 +00:10:01,502 --> 00:10:04,238 +通过所有这些更新 +我们会得到这个表格 + +174 +00:10:04,271 --> 00:10:08,242 +它是在前一个表的基础上 +增加了一个编辑模式的新列 + +175 +00:10:08,275 --> 00:10:12,446 +只有在没有键盘的情况下 +使用多重选择时 才需要编辑模式 + +176 +00:10:12,479 --> 00:10:16,416 +因此 我将更新位置表格以支持选择 + +177 +00:10:16,450 --> 00:10:19,019 +我可以通过添加一些状态 +来存储所选内容 + +178 +00:10:19,052 --> 00:10:22,589 +从而轻松地将所选内容 +添加到位置表格中 + +179 +00:10:22,623 --> 00:10:24,992 +创建状态后 +我会向表格的初始值设定项 + +180 +00:10:25,025 --> 00:10:27,628 +传递一个绑定 + +181 +00:10:27,661 --> 00:10:31,365 +表格强制其选择类型 +与其行标识符匹配 + +182 +00:10:31,398 --> 00:10:34,668 +因此我使用了位置 ID 类型 +作为选择类型 + +183 +00:10:34,701 --> 00:10:38,872 +因为我想要多个选择 +所以我使用了一个集合作为选择状态 + +184 +00:10:38,906 --> 00:10:42,943 +表格会自动为每行做标签 +所以我不需要自己做任何标签 + +185 +00:10:44,144 --> 00:10:46,346 +现在我可以选择表格中的行了 + +186 +00:10:46,380 --> 00:10:49,216 +但我还没有对选中的行做任何事情 + +187 +00:10:49,249 --> 00:10:53,120 +我想最好能添加一个按钮 +让我可以将选定的地点 + +188 +00:10:53,153 --> 00:10:56,523 +添加到指南中 以便与 +读书俱乐部中的其他人共享 + +189 +00:10:56,557 --> 00:10:58,992 +这是添加工具栏按钮的代码 + +190 +00:10:59,026 --> 00:11:03,096 +如果有非空选择 +按钮现在就会显示 + +191 +00:11:03,130 --> 00:11:04,765 +我还添加了一个编辑按钮 + +192 +00:11:04,798 --> 00:11:07,634 +它补充了现有的轻量级选择支持 + +193 +00:11:07,668 --> 00:11:10,704 +但在没有键盘的时候 它提供了一种 + +194 +00:11:10,737 --> 00:11:12,606 +进入和退出编辑模式的功能 + +195 +00:11:12,639 --> 00:11:15,976 +一款出色的 iPad app +无论有无键盘都会大放异彩 + +196 +00:11:16,009 --> 00:11:19,780 +因此提供进入和退出编辑模式的控件 +非常重要 + +197 +00:11:21,348 --> 00:11:22,416 +我们来看看 + +198 +00:11:22,449 --> 00:11:24,852 +现在 当我们选择行时 +会显示一个按钮 + +199 +00:11:24,885 --> 00:11:28,021 +以及一个进入和退出编辑模式的按钮 + +200 +00:11:28,055 --> 00:11:30,390 +有关工具栏的更多信息 +请务必观看 + +201 +00:11:30,424 --> 00:11:33,460 +本讲座的第二部分 + +202 +00:11:33,493 --> 00:11:35,162 +我对这里的工具栏按钮很满意 + +203 +00:11:35,195 --> 00:11:36,663 +但我们可以做得更多 + +204 +00:11:36,697 --> 00:11:39,333 +对于选择操作 +尽可能让它们容易访问 + +205 +00:11:39,366 --> 00:11:41,702 +是个很好的做法 + +206 +00:11:41,735 --> 00:11:46,240 +这就是为什么在 iOS16 +iPadOS16 和 macOSVentura 中 + +207 +00:11:46,273 --> 00:11:50,544 +SwiftUI 增加了对多选快捷菜单的支持 + +208 +00:11:50,577 --> 00:11:53,981 +多选快捷菜单允许 +在一组选定的标识符上 + +209 +00:11:54,014 --> 00:11:57,417 +显示一个快捷菜单 + +210 +00:11:57,451 --> 00:12:00,621 +让我们研究一下这张表格的结构 +以了解更多 + +211 +00:12:02,122 --> 00:12:05,325 +基于项目的快捷菜单有三种变体 + +212 +00:12:05,359 --> 00:12:07,728 +首先 你可以在多个项目上显示菜单 + +213 +00:12:07,761 --> 00:12:09,596 +例如顶部的选择 + +214 +00:12:10,764 --> 00:12:13,667 +你还可以在单个项目上显示快捷菜单 + +215 +00:12:15,102 --> 00:12:18,372 +最后 你可以在 +没有内容的空白区域 + +216 +00:12:18,405 --> 00:12:19,840 +显示快捷菜单 + +217 +00:12:21,108 --> 00:12:24,077 +让我们将这种支持 +添加到我们的位置表格中 + +218 +00:12:25,712 --> 00:12:28,282 +我省略了前面代码示例中的一些细节 + +219 +00:12:28,315 --> 00:12:30,784 +这样我们就可以专注于快捷菜单 + +220 +00:12:30,817 --> 00:12:34,888 +我添加了新的 contextMenu 修饰器 +该修饰器采用选择类型 + +221 +00:12:34,922 --> 00:12:38,292 +这需要匹配列表或表格的选择类型 + +222 +00:12:38,325 --> 00:12:41,328 +由于我使用的是表格 +我将使用位置 ID 类型 + +223 +00:12:43,030 --> 00:12:45,699 +闭包被传递给一组要操作的项 + +224 +00:12:45,732 --> 00:12:49,136 +所以若它是空的 +我就知道菜单是针对空区域的 + +225 +00:12:49,169 --> 00:12:52,806 +我认为一个添加新位置的按钮 +对于空白区域来说非常有用 + +226 +00:12:52,840 --> 00:12:56,109 +这样 当我在旅途中找到一个 +新的安静的地方阅读时 + +227 +00:12:56,143 --> 00:12:58,145 +我可以快速添加它 + +228 +00:12:58,178 --> 00:13:00,848 +请注意 如果空项目集的视图生成器 + +229 +00:13:00,881 --> 00:13:02,549 +无法解析为视图 + +230 +00:13:02,583 --> 00:13:05,586 +SwiftUI 将不会在空白区域显示菜单 + +231 +00:13:05,619 --> 00:13:08,188 +接下来 我们来处理单个选择 + +232 +00:13:08,222 --> 00:13:09,923 +如果该集合只有一个单项 + +233 +00:13:09,957 --> 00:13:13,694 +我就知道菜单显示的是单个位置 + +234 +00:13:13,727 --> 00:13:16,063 +对于单选和多选 + +235 +00:13:16,096 --> 00:13:18,732 +我希望能够将这些位置添加到指南中 + +236 +00:13:18,765 --> 00:13:21,068 +因此我将向菜单中添加另一个视图 + +237 +00:13:21,101 --> 00:13:23,203 +我们来看看进展 + +238 +00:13:23,237 --> 00:13:25,873 +下面是新的快捷菜单支持 + +239 +00:13:25,906 --> 00:13:29,476 +点击空白区域会显示一个 +添加新位置的菜单项 + +240 +00:13:29,510 --> 00:13:33,881 +选择一行仅显示该行的快捷菜单 + +241 +00:13:33,914 --> 00:13:36,183 +我可以用键盘扩展选择 + +242 +00:13:36,216 --> 00:13:38,085 +创建这个蓝色高亮区域 + +243 +00:13:38,118 --> 00:13:41,388 +然后我可以在多行上激活快捷菜单 + +244 +00:13:41,421 --> 00:13:44,091 +轻松地将位置添加到指南中 + +245 +00:13:45,459 --> 00:13:47,494 +这个表格现在看起来很时髦 + +246 +00:13:47,528 --> 00:13:49,997 +是时候在它周围添加一些结构了 + +247 +00:13:50,030 --> 00:13:52,833 +为此 我需要一个分屏浏览 + +248 +00:13:52,866 --> 00:13:55,702 +导航是 iPad 体验的基础部分 + +249 +00:13:55,736 --> 00:14:00,174 +分屏浏览是一个避免在 iPad 更大的 +显示屏上出现模态的好方法 + +250 +00:14:00,207 --> 00:14:04,111 +它可以一次显示更多信息 无需反复 + +251 +00:14:04,144 --> 00:14:06,847 +在本节中 我将介绍 SwiftUI 在 + +252 +00:14:06,880 --> 00:14:08,982 +导航和分屏浏览方面的一些更新 + +253 +00:14:09,016 --> 00:14:12,386 +在前面的部分中 我创建了位置表格 + +254 +00:14:12,419 --> 00:14:16,089 +并增加了丰富的功能 +比如选择和编辑模式 + +255 +00:14:16,123 --> 00:14:18,959 +但我认为位置 App 缺乏一些结构 + +256 +00:14:18,992 --> 00:14:22,062 +所以在本讲座中 +我将利用导航分屏浏览 + +257 +00:14:22,095 --> 00:14:25,098 +来构建我们 App 结构的基础 + +258 +00:14:25,132 --> 00:14:27,868 +SwiftUI 是 iPadOS 16 +和 macOS Ventura 中的新功能 + +259 +00:14:27,901 --> 00:14:30,370 +它改进了对 +NavigationSplitView 类型的 + +260 +00:14:30,404 --> 00:14:32,906 +分屏浏览的支持 + +261 +00:14:32,940 --> 00:14:35,909 +SwiftUI 支持两列或三列分屏浏览 + +262 +00:14:35,943 --> 00:14:38,545 +并具有多种样式 +可对各列的显示方式 + +263 +00:14:38,579 --> 00:14:41,215 +进行复杂控制 + +264 +00:14:41,248 --> 00:14:42,416 +我不会在本期讲座中 + +265 +00:14:42,449 --> 00:14:44,985 +全面讲述如何呈现导航内容 + +266 +00:14:45,018 --> 00:14:48,889 +为此 我邀请你查看 +SwiftUI 导航指南 + +267 +00:14:48,922 --> 00:14:50,657 +Curt 有很多秘诀 + +268 +00:14:50,691 --> 00:14:53,827 +可以拼凑出超棒的导航体验 + +269 +00:14:53,861 --> 00:14:56,897 +而我将更加专注分屏浏览 + +270 +00:14:56,930 --> 00:15:00,534 +这张图标显示了 iPad 上的 +两列分屏浏览 + +271 +00:15:00,567 --> 00:15:03,737 +在 SwiftUI 前导列被称为侧边列 + +272 +00:15:03,770 --> 00:15:07,207 +后尾列被称为详细信息列 + +273 +00:15:07,241 --> 00:15:10,177 +注意这里的列是如何相互平衡的 + +274 +00:15:10,210 --> 00:15:13,413 +在横向 SwiftUI 默认提供此功能 + +275 +00:15:13,447 --> 00:15:16,650 +然而 在纵向中 侧边列会隐藏起来 + +276 +00:15:16,683 --> 00:15:19,186 +仅显示详细信息列 + +277 +00:15:19,219 --> 00:15:20,654 +轻触侧栏按钮 + +278 +00:15:20,687 --> 00:15:22,656 +将显示侧边列 + +279 +00:15:22,689 --> 00:15:25,926 +该侧边列显示在详细信息列的上方 +并使其下方变暗 + +280 +00:15:27,294 --> 00:15:30,230 +通常 当空间受限时 + +281 +00:15:30,264 --> 00:15:32,833 +两列分频浏览 +更倾向于仅展示详细信息列 + +282 +00:15:32,866 --> 00:15:35,002 +因为详细信息列经常比侧边列 + +283 +00:15:35,035 --> 00:15:37,871 +显示更重要的信息 + +284 +00:15:37,905 --> 00:15:39,806 +如果你想自定义此行为 + +285 +00:15:39,840 --> 00:15:42,042 +你可以始终优先选择 + +286 +00:15:42,075 --> 00:15:44,578 +带有 prominentDetail 导航 +分屏浏览样式的 + +287 +00:15:44,611 --> 00:15:46,113 +详细信息列或用平衡的 + +288 +00:15:46,146 --> 00:15:48,649 +NavigationSplitView 样式 +来平衡权重 + +289 +00:15:48,682 --> 00:15:53,020 +NavigationSplitView 还支持三列布局 + +290 +00:15:53,053 --> 00:15:55,422 +有三列时 在侧边列 + +291 +00:15:55,455 --> 00:15:59,059 +和详细信息列中间还有一列 +称为 内容列 + +292 +00:15:59,092 --> 00:16:02,829 +如果你使用过 UIKit +你或许知道这是补充列 + +293 +00:16:02,863 --> 00:16:06,133 +在横向 显示内容和详细信息列 + +294 +00:16:06,166 --> 00:16:09,269 +并且可以切换侧边列 + +295 +00:16:09,303 --> 00:16:13,307 +点击工具栏按钮后 +详细信息列会滑出 + +296 +00:16:13,340 --> 00:16:16,810 +为侧边列和内容列腾出空间 + +297 +00:16:16,844 --> 00:16:19,813 +纵向仅显示详细信息列 + +298 +00:16:19,847 --> 00:16:23,083 +并点击工具栏按钮 显示内容列 + +299 +00:16:23,116 --> 00:16:26,520 +从那里 再次点击会显示侧边列 + +300 +00:16:26,553 --> 00:16:29,556 +侧边和内容两列都覆盖了详细信息列 + +301 +00:16:31,124 --> 00:16:33,861 +一般来说 我推荐 +对三列分屏浏览坚持使用 + +302 +00:16:33,894 --> 00:16:36,663 +自动样式 +因为它可以充分利用可用空间 + +303 +00:16:36,697 --> 00:16:40,467 +并且专门用于更大的显示器 + +304 +00:16:40,501 --> 00:16:43,804 +就像两列分屏浏览一样 +三列分屏浏览可以折叠成 + +305 +00:16:43,837 --> 00:16:46,540 +尺寸紧凑类型的 stack + +306 +00:16:46,573 --> 00:16:48,575 +现在我已经讲述了 +分屏浏览的基础知识 + +307 +00:16:48,609 --> 00:16:51,411 +现在是时候 +在位置 App 中添加一个了 + +308 +00:16:51,445 --> 00:16:52,980 +这是内容视图 + +309 +00:16:53,013 --> 00:16:56,116 +我创建了一个 NavigationSplitView +这里有两列 + +310 +00:16:56,149 --> 00:16:57,951 +第一列是侧边列 + +311 +00:16:57,985 --> 00:17:00,354 +第二列是详细信息列 + +312 +00:17:00,387 --> 00:17:03,657 +详细信息列由侧边列的链接填充 + +313 +00:17:03,690 --> 00:17:04,958 +但如果没有显示任何内容 + +314 +00:17:04,992 --> 00:17:08,629 +则会显示 select a place 的占位符 + +315 +00:17:10,597 --> 00:17:13,700 +这是占位符的屏幕截图 非常棒 + +316 +00:17:13,734 --> 00:17:17,204 +这里使用的是自动样式 +横向显示侧边列 + +317 +00:17:17,237 --> 00:17:20,174 +纵向隐藏 + +318 +00:17:20,207 --> 00:17:24,678 +点击侧边列中的某一行 +在详细信息列中就会显示该行详情 + +319 +00:17:24,711 --> 00:17:28,182 +当使用侧拉时 列会自动折叠 + +320 +00:17:28,215 --> 00:17:30,217 +这只是冰山一角 + +321 +00:17:30,250 --> 00:17:32,753 +这里还有很多 +令人兴奋的导航添加功能 + +322 +00:17:32,786 --> 00:17:35,455 +包括对状态恢复的更好的支持 + +323 +00:17:35,489 --> 00:17:38,859 +深度链接 甚至更丰富的程式控制 + +324 +00:17:38,892 --> 00:17:42,896 +我再次建议你检看导航指南讲座 + +325 +00:17:44,364 --> 00:17:47,034 +我已在 App 中构建了 +很棒的 iPad 功能 + +326 +00:17:47,067 --> 00:17:50,671 +很高兴能找到一些安静的阅读场所 + +327 +00:17:50,704 --> 00:17:53,640 +希望我能很快 +赶上读书俱乐部的进度 + +328 +00:17:53,674 --> 00:17:56,410 +在本期讲座中 +我已经介绍了如何利用表格进行 + +329 +00:17:56,443 --> 00:17:58,345 +丰富的数据展示 + +330 +00:17:58,378 --> 00:18:01,281 +如何管理复杂的选择交互 + +331 +00:18:01,315 --> 00:18:03,984 +以及如何利用分屏浏览避免模态 + +332 +00:18:05,485 --> 00:18:07,221 +请记得查看相关讲座 + +333 +00:18:07,254 --> 00:18:10,724 +并优化你的 SwiftUI app +充分利用 iPad 的强大功能 + +334 +00:18:11,992 --> 00:18:13,727 +谢谢大家 + +335 +00:18:13,760 --> 00:18:17,764 +♪ ♪ + diff --git a/zho/2022 Session 10059 The craft of SwiftUI API design - Progressive disclosure.srt b/zho/2022 Session 10059 The craft of SwiftUI API design - Progressive disclosure.srt new file mode 100644 index 0000000..86ae83c --- /dev/null +++ b/zho/2022 Session 10059 The craft of SwiftUI API design - Progressive disclosure.srt @@ -0,0 +1,1057 @@ +1 +00:00:09,309 --> 00:00:15,082 +Sam Lazarus: 大家好 我叫 Sam +是 SwiftUI 团队的一名工程师 + +2 +00:00:15,115 --> 00:00:18,852 +在设计 SwiftUI 时 +我们一直致力于 + +3 +00:00:18,886 --> 00:00:21,421 +依照明确定义的原则 +和渐进式呈现做决策 + +4 +00:00:21,455 --> 00:00:26,260 +今天我们将着重强调其中一点 +渐进式呈现 + +5 +00:00:26,293 --> 00:00:30,430 +在 SwiftUI 团队中 +我们花了很多时间 + +6 +00:00:30,464 --> 00:00:34,501 +思考并构建新的 API +但你可能没有意识到 + +7 +00:00:34,535 --> 00:00:37,037 +当你在构建一个可复用构件 + +8 +00:00:37,070 --> 00:00:38,572 +或抽象时 + +9 +00:00:38,605 --> 00:00:41,808 +你也是一名 API 设计师 + +10 +00:00:41,842 --> 00:00:46,413 +在这次谈话中 我们想揭开 +我们设计过程的帷幔 + +11 +00:00:46,446 --> 00:00:49,683 +分享我们对 +渐进式呈现的了解 + +12 +00:00:49,716 --> 00:00:54,021 +这样 下一次你在构建可复用构件 +或抽象时 + +13 +00:00:54,054 --> 00:00:56,056 +就可以使用一样新的工具 + +14 +00:00:57,457 --> 00:01:00,661 +让我们先来聊一聊 + +15 +00:01:00,694 --> 00:01:02,462 +渐进式呈现到底是什么吧 + +16 +00:01:02,496 --> 00:01:06,934 +其实这并不是 API 设计 +所独有的 + +17 +00:01:06,967 --> 00:01:12,406 +事实上 你可以在最常见的 +macOS UI 保存对话框中 + +18 +00:01:12,439 --> 00:01:13,974 +看到它的使用 + +19 +00:01:14,875 --> 00:01:16,810 +当你第一次看见保存对话框时 + +20 +00:01:16,844 --> 00:01:20,647 +它已经为你增添了一个默认位置 + +21 +00:01:20,681 --> 00:01:25,786 +此外 对话框里还有一个下拉列表 + +22 +00:01:25,819 --> 00:01:29,957 +其中包含一些常见的位置以便选择 + +23 +00:01:29,990 --> 00:01:34,728 +最后 如果你需要浏览文件系统 +以找到正确的路径 + +24 +00:01:34,761 --> 00:01:40,667 +可以展开对话框 +以显示更复杂但功能更强大的 UI + +25 +00:01:40,701 --> 00:01:45,572 +这包含了不同层次的复杂性 +可以在需要时显示 + +26 +00:01:45,606 --> 00:01:51,345 +这与我们希望通过 API +提供的体验是相同的 + +27 +00:01:51,378 --> 00:01:55,349 +这些代码相当于提供了 +良好的UI体验 + +28 +00:01:55,382 --> 00:01:58,418 +使你的 API 使用感变好 + +29 +00:02:00,053 --> 00:02:03,090 +作为开发者 我们习惯于 + +30 +00:02:03,123 --> 00:02:07,160 +从编写代码的角度来查看代码: +也就是代码声明的位置 + +31 +00:02:07,194 --> 00:02:09,997 +但为了让代码更好使用 + +32 +00:02:10,030 --> 00:02:13,033 +我们必须从一个不同的角度来看 + +33 +00:02:13,066 --> 00:02:15,068 +也就是代码实际使用的地方 + +34 +00:02:15,102 --> 00:02:17,337 +我们称其为调用端 + +35 +00:02:19,173 --> 00:02:22,509 +而渐进式呈现 +就是通过 API 的设计 + +36 +00:02:22,543 --> 00:02:27,314 +使调用端的复杂性 +随着用例的复杂性而增长 + +37 +00:02:28,515 --> 00:02:32,486 +一个理想的 API 应当 +既简洁 易操作 + +38 +00:02:32,519 --> 00:02:35,923 +又足够适应强大的用例 + +39 +00:02:37,257 --> 00:02:40,961 +这对开发者很有利 + +40 +00:02:40,994 --> 00:02:45,799 +首先 这最大程度上缩减了 +首次构建和运行所需的时间 + +41 +00:02:45,832 --> 00:02:49,336 +使你能够更快使用 API + +42 +00:02:49,369 --> 00:02:53,907 +这也降低了代码的学习曲线 + +43 +00:02:53,941 --> 00:02:58,145 +防止 API 因与所有用例无关的概念 +陷入停滞 + +44 +00:02:59,479 --> 00:03:02,950 +最后 它创造了一个紧密的反馈循环 + +45 +00:03:02,983 --> 00:03:05,853 +通过渐进式呈现的 API + +46 +00:03:05,886 --> 00:03:10,357 +你可以一点一点地添加内容 +查看每一步创建的东西 + +47 +00:03:11,391 --> 00:03:16,263 +所有这些因素使 App 开发 +成为了一个快速优化循环 + +48 +00:03:16,296 --> 00:03:19,066 +而不是单一的大规模前期投入 + +49 +00:03:20,634 --> 00:03:24,104 +因此渐进式呈现 +是一盏有用的指路明灯 + +50 +00:03:24,137 --> 00:03:28,809 +但我们该如何设计特定的 API +使它们采用这一原则呢 + +51 +00:03:28,842 --> 00:03:34,481 +在 SwiftUI 团队 +我们首先考虑了常见用例 + +52 +00:03:34,515 --> 00:03:37,184 +为了逐步展开功能 + +53 +00:03:37,217 --> 00:03:40,087 +我们需要确定什么是简单用例 + +54 +00:03:41,088 --> 00:03:44,291 +我们还致力于提供智能默认值 + +55 +00:03:44,324 --> 00:03:49,096 +以便常见用例 +能只列出所需的内容 + +56 +00:03:49,129 --> 00:03:52,199 +接下来 我们的目标是 +优化调用端 + +57 +00:03:52,232 --> 00:03:56,537 +确保调用端的每个字符 +都有目的 + +58 +00:03:56,570 --> 00:03:59,540 +最后 我们要设计 API + +59 +00:03:59,573 --> 00:04:03,477 +确保它们能整合各个部分 +而不是枚举可能性 + +60 +00:04:04,344 --> 00:04:08,982 +让我们来看看 +SwiftUI 上的一些例子 + +61 +00:04:09,016 --> 00:04:12,920 +从我们如何考虑常见用例开始 + +62 +00:04:12,953 --> 00:04:17,291 +在这方面 SwiftUI +做得特别好的一处是标签 + +63 +00:04:18,492 --> 00:04:22,162 +例如 当创建按钮时 我们要求你 + +64 +00:04:22,196 --> 00:04:24,131 +为按钮提供一个标签 + +65 +00:04:24,164 --> 00:04:27,768 +大多数情况下 这个标签只是文本 + +66 +00:04:27,801 --> 00:04:31,238 +用来描述按钮的作用 +而 SwiftUI 为你提供了 + +67 +00:04:31,271 --> 00:04:33,540 +一个简洁的拼写方法 + +68 +00:04:33,574 --> 00:04:35,876 +但如果你想进一步自定义按钮 + +69 +00:04:35,909 --> 00:04:38,145 +SwiftUI 也 +提供另一个重载函数 + +70 +00:04:38,178 --> 00:04:40,614 +即将任意视图作为标签 + +71 +00:04:41,815 --> 00:04:44,618 +这使你能通过这个简单的控件 + +72 +00:04:44,651 --> 00:04:47,221 +构建复杂的功能 + +73 +00:04:47,254 --> 00:04:51,225 +但是由于这个 API 仔细 +考虑了它的常见用例 + +74 +00:04:51,258 --> 00:04:55,262 +99% 的情况下 你只需要简单版本 + +75 +00:04:56,930 --> 00:05:00,767 +这个标签模式 +在 SwiftUI 中随处可见 + +76 +00:05:00,801 --> 00:05:03,704 +我说随处可见是认真的 + +77 +00:05:04,671 --> 00:05:07,708 +我们在整个框架中 + +78 +00:05:07,741 --> 00:05:10,010 +都考虑了常见用例 + +79 +00:05:10,043 --> 00:05:14,081 +接下来 我们看看提供智能默认值 + +80 +00:05:14,114 --> 00:05:16,850 +为了简化常见用例 + +81 +00:05:16,884 --> 00:05:19,052 +我们要为所有 +没有明确指定的东西 + +82 +00:05:19,086 --> 00:05:22,189 +提供智能默认值 + +83 +00:05:22,222 --> 00:05:26,627 +这里最好的例子就是 +SwiftUI 中最常用的 + +84 +00:05:26,660 --> 00:05:28,595 +API 之一 + +85 +00:05:28,629 --> 00:05:29,730 +Text + +86 +00:05:30,464 --> 00:05:34,034 +Text 是智能默认值一个很好的例子 + +87 +00:05:34,067 --> 00:05:37,804 +你可能已经编写了 +数百次这样的代码 + +88 +00:05:37,838 --> 00:05:41,308 +在编写时你没有考虑 +所有不必指定的内容 + +89 +00:05:42,309 --> 00:05:45,913 +有了这段代码 +SwiftUI 将通过在应用包中 + +90 +00:05:45,946 --> 00:05:48,849 +查找带有环境语言的本地化字符串 + +91 +00:05:48,882 --> 00:05:50,784 +来本地化文本 + +92 +00:05:50,817 --> 00:05:53,720 +它会自动适应当前的配色方案 + +93 +00:05:53,754 --> 00:05:56,857 +直接支持深色模式 + +94 +00:05:56,890 --> 00:06:00,761 +它会根据当前的 +辅助功能动态类型大小 + +95 +00:06:00,794 --> 00:06:03,964 +自动缩放文本 + +96 +00:06:04,831 --> 00:06:07,100 +我们之前也提到过这些行为 + +97 +00:06:07,134 --> 00:06:10,337 +但文本在幕后做了更多的事情 + +98 +00:06:11,905 --> 00:06:14,308 +例如 两个文本并排放入栈中 + +99 +00:06:14,341 --> 00:06:19,179 +文本之间的距离将按当前上下文 + +100 +00:06:19,213 --> 00:06:22,583 +自动调整为正确行间距 + +101 +00:06:23,383 --> 00:06:26,787 +所有这些行为都可以人为指定 + +102 +00:06:26,820 --> 00:06:30,424 +但 SwiftUI 的智能默认设置 +意味着当它们与你的用例无关时 + +103 +00:06:30,457 --> 00:06:33,427 +它们不会出现在调用端 + +104 +00:06:34,695 --> 00:06:39,533 +Text 是这样一个例子 +它的最简案例是极其简化的 + +105 +00:06:39,566 --> 00:06:43,337 +但智能默认值适用于 +所有类型的调用端 + +106 +00:06:43,370 --> 00:06:45,305 +以工具栏为例 + +107 +00:06:45,339 --> 00:06:49,643 +这是一个工具栏 上面有一堆按钮 + +108 +00:06:49,676 --> 00:06:52,846 +如果不明确指定它们的位置 + +109 +00:06:52,880 --> 00:06:57,184 +工具栏按钮会根据平台惯例放置 + +110 +00:06:57,217 --> 00:07:01,388 +在 macOS 上 +它们会出现在工具栏的前缘 + +111 +00:07:01,421 --> 00:07:04,958 +但在 iOS 上 +它们会出现在 + +112 +00:07:04,992 --> 00:07:07,261 +导航栏的后缘 + +113 +00:07:07,294 --> 00:07:11,565 +最后 在 watchOS 上 +只出现第一个项目 + +114 +00:07:11,598 --> 00:07:14,201 +固定在导航栏下面 + +115 +00:07:14,234 --> 00:07:17,704 +这种方法在大多数情况下都很有效 + +116 +00:07:17,738 --> 00:07:20,040 +但如果你确实需要更多的控件 + +117 +00:07:20,073 --> 00:07:23,744 +我们也提供了额外的 API +明确指定 + +118 +00:07:23,777 --> 00:07:25,712 +项目的放置位置 + +119 +00:07:25,746 --> 00:07:28,749 +同样 如果需要 你可以进行自定义 + +120 +00:07:28,782 --> 00:07:32,085 +但是智能默认值可以处理大多数情况 + +121 +00:07:33,420 --> 00:07:37,357 +参照常见用例并提供智能默认值 + +122 +00:07:37,391 --> 00:07:42,529 +可以创造一些非常棒的体验 +但如果这些 API 使用感较差 + +123 +00:07:42,563 --> 00:07:46,200 +或不完善 它可能会破坏整体效果 + +124 +00:07:46,233 --> 00:07:50,604 +这就引出了我们的最后一条策略 +优化调用端 + +125 +00:07:50,637 --> 00:07:54,808 +说到这一点 我们看看 +另一个 API 即 Table + +126 +00:07:55,909 --> 00:08:00,013 +多列表格是功能非常丰富的控件 + +127 +00:08:00,047 --> 00:08:03,684 +需要配置的东西很多 功能也很多 + +128 +00:08:03,717 --> 00:08:06,920 +但是大多数表格要简单得多 + +129 +00:08:06,954 --> 00:08:09,056 +也不需要所有这些功能 + +130 +00:08:09,089 --> 00:08:13,594 +我们希望表格能够处理 +这种更复杂的行为 + +131 +00:08:13,627 --> 00:08:16,897 +而它最详细的格式 +已经做到了这点 + +132 +00:08:16,930 --> 00:08:19,099 +它支持排序 + +133 +00:08:19,132 --> 00:08:24,838 +包含丰富单元格内容的 +多列 分段行等等 + +134 +00:08:25,906 --> 00:08:28,342 +但我们也希望在更常见的情况下 + +135 +00:08:28,375 --> 00:08:30,777 +提供出色的体验感 + +136 +00:08:30,811 --> 00:08:33,614 +所以 我们看看这个简单表格的 + +137 +00:08:33,647 --> 00:08:35,382 +完整代码 + +138 +00:08:35,415 --> 00:08:38,819 +并看看我们 +如何优化它的调用端 + +139 +00:08:38,852 --> 00:08:42,389 +首先 我们拆分一下这个例子 + +140 +00:08:42,422 --> 00:08:46,527 +表格首先指定 +如何为每一行生成数据 + +141 +00:08:48,128 --> 00:08:52,099 +在这里 我将枚举当前正在读的 +每一本书 + +142 +00:08:52,132 --> 00:08:56,136 +并为每一本书创建一个表行 + +143 +00:08:56,170 --> 00:09:01,775 +接下来 它会指定如何 +用每一行的数据填充列 + +144 +00:09:01,808 --> 00:09:06,180 +在这里 我创建了 +一个标题列和一个作者列 + +145 +00:09:08,448 --> 00:09:13,587 +它还会用绑定来排序次序 + +146 +00:09:13,620 --> 00:09:16,323 +以允许用户单击 +表列 header 时更改排序 + +147 +00:09:18,158 --> 00:09:22,529 +最后 我添加了一些代码 + +148 +00:09:22,563 --> 00:09:24,998 +以在排序次序发生变化时 +重新对表数据排序 + +149 +00:09:25,032 --> 00:09:27,734 +这有很多的信息 我们看看 + +150 +00:09:27,768 --> 00:09:32,072 +该如何优化这个调用端 +以真正实现渐进式呈现 + +151 +00:09:33,240 --> 00:09:38,145 +最常见的一个用例与行有关 + +152 +00:09:38,178 --> 00:09:43,083 +大多数时候 +行字段就像这个例子中一样 + +153 +00:09:43,116 --> 00:09:47,120 +一个集合上有一个 ForEach +为每项提供一个表行 + +154 +00:09:48,655 --> 00:09:51,859 +开发人员不需要 +自己循环所有这些内容 + +155 +00:09:51,892 --> 00:09:56,964 +SwiftUI 提供了一个方便的功能 +在底层处理这些内容 + +156 +00:09:56,997 --> 00:09:59,900 +通过将集合直接传递到表格 + +157 +00:09:59,933 --> 00:10:03,504 +可以在幕后完成 ForEach 行为 + +158 +00:10:03,537 --> 00:10:10,010 +极大地简化了我们的调用端 +但这还可以进一步简化 + +159 +00:10:10,043 --> 00:10:12,279 +其它常见用例有什么呢 + +160 +00:10:12,312 --> 00:10:13,947 +大多数时候 + +161 +00:10:13,981 --> 00:10:15,582 +当我想在表格中显示的一个值 +是字符串时 + +162 +00:10:15,616 --> 00:10:19,753 +我会直接使用文本在列中显示它 + +163 +00:10:20,721 --> 00:10:23,156 +这种情况下 我们也会优化调用端 + +164 +00:10:25,058 --> 00:10:27,961 +只要值路径指向一个字符串 + +165 +00:10:27,995 --> 00:10:31,832 +我们就允许省略 +与 TableColumn 关联的视图 + +166 +00:10:32,933 --> 00:10:38,172 +这是另一个重要的简化 +但仍有更多需要优化的部分 + +167 +00:10:38,205 --> 00:10:41,875 +调用端中有一些信息 +并不是所有表格 + +168 +00:10:41,909 --> 00:10:46,079 +都需要关注的 那就是排序次序 + +169 +00:10:46,113 --> 00:10:50,350 +表格最简单的用例和排序完全无关 + +170 +00:10:50,384 --> 00:10:53,320 +因此 我们也提供了一个 +本身不涉及 + +171 +00:10:53,353 --> 00:10:55,355 +排序的表格版本 + +172 +00:10:55,389 --> 00:10:59,660 +这就引出了我们的最后一次迭代 +简洁多了 + +173 +00:10:59,693 --> 00:11:03,764 +这个 call site 的每个字符 +都有一个明确的目的 + +174 +00:11:03,797 --> 00:11:08,702 +为了做到这点 我们每一步 +都问了自己两个关键问题 + +175 +00:11:08,735 --> 00:11:14,074 +“我们应该为哪些 +最常见的用例提供便利” + +176 +00:11:14,107 --> 00:11:19,680 +以及“什么信息总是必要的” + +177 +00:11:19,713 --> 00:11:22,916 +这些指导性的问题 +可以很好地帮助你 + +178 +00:11:22,950 --> 00:11:26,587 +优化 call sites +但要谨慎应用 + +179 +00:11:26,620 --> 00:11:29,857 +如果不仔细考虑它们 +对 API 的影响 + +180 +00:11:29,890 --> 00:11:31,758 +可能会把你引入歧途 + +181 +00:11:31,792 --> 00:11:37,464 +这就引出了我们的最终策略 +组合 而非枚举 + +182 +00:11:37,497 --> 00:11:40,501 +进一步说明这一点 +我们来谈谈 SwiftUI + +183 +00:11:40,534 --> 00:11:44,471 +布局系统一个部分的设计:Stack + +184 +00:11:44,505 --> 00:11:46,907 +特别是 HStack + +185 +00:11:46,940 --> 00:11:51,144 +首先 我们想想 HStack 的 + +186 +00:11:51,178 --> 00:11:52,746 +关键信息是什么 + +187 +00:11:52,779 --> 00:11:57,451 +它需要知道栈中应该有什么内容 + +188 +00:11:57,484 --> 00:12:01,788 +以及这些内容 +应该如何在栈中排列 + +189 +00:12:01,822 --> 00:12:05,692 +我们已经有视图生成器 +来指定 HStack 的内容 + +190 +00:12:05,726 --> 00:12:08,529 +所以我们要专注于排列 + +191 +00:12:08,562 --> 00:12:10,964 +回到我们强调的指导性问题 + +192 +00:12:10,998 --> 00:12:15,402 +在 HStack 中排列元素时 +最常见的用例是什么 + +193 +00:12:15,435 --> 00:12:19,606 +我有时想显示一个像这样的栈 + +194 +00:12:19,640 --> 00:12:23,944 +它会从前端开始 +一个接一个地显示盒子 + +195 +00:12:25,045 --> 00:12:28,715 +另一种常见的情况是希望元素居中 + +196 +00:12:28,749 --> 00:12:31,451 +最后 我可能想把元素 + +197 +00:12:31,485 --> 00:12:32,886 +向尾部对齐 + +198 +00:12:34,388 --> 00:12:39,526 +VStack 已经有了一个 +与此类似的 API 即对齐 + +199 +00:12:39,560 --> 00:12:42,396 +所以创建一个类似的 enum + +200 +00:12:42,429 --> 00:12:45,532 +来排列栈中的元素似乎很吸引人 + +201 +00:12:45,566 --> 00:12:48,135 +这支持我们提到的所有使用情况 + +202 +00:12:48,168 --> 00:12:52,706 +通过指定 HStack 的排列 +我可以选择前对齐 + +203 +00:12:52,739 --> 00:12:57,277 +尾对齐 或居中排列 +这取决于我想要什么 + +204 +00:12:57,311 --> 00:13:01,114 +但如果我现在想均匀地间隔元素 + +205 +00:13:01,148 --> 00:13:04,284 +或者只在元素之间 + +206 +00:13:04,318 --> 00:13:08,322 +或最后一个元素之前设置间隔呢 + +207 +00:13:08,355 --> 00:13:10,190 +这开始变得格外混乱 + +208 +00:13:10,224 --> 00:13:13,293 +但更重要的是 这是不可持续的 + +209 +00:13:13,327 --> 00:13:16,997 +我必须为我们想要的每个行为 +添加一个 enum 案例 + +210 +00:13:17,030 --> 00:13:20,534 +而我们可能无法把 +所有有用的案例考虑周全 + +211 +00:13:20,567 --> 00:13:23,203 +当你发现自己在列举常见情况 + +212 +00:13:23,237 --> 00:13:25,973 +而不是为它们提供方便时 + +213 +00:13:26,006 --> 00:13:29,843 +试着把你的 API 分解成 +可以构建解决方案的 + +214 +00:13:29,877 --> 00:13:34,014 +可组合块 +组合 而非枚举 + +215 +00:13:35,449 --> 00:13:41,154 +在栈的例子中 +SwiftUI 提供了 Spacer + +216 +00:13:41,188 --> 00:13:45,626 +让你将它与栈的元素组合 +以构建我们列举的所有间距方案 + +217 +00:13:45,659 --> 00:13:50,397 +诸如此类 +这也是今天这一 API 的起源 + +218 +00:13:51,798 --> 00:13:55,068 +为渐进式呈现设计最佳体验 + +219 +00:13:55,102 --> 00:13:57,604 +不仅仅在于最小化调用端 + +220 +00:13:57,638 --> 00:14:02,109 +还在于仔细思考 +该如何缩放调用端 + +221 +00:14:02,142 --> 00:14:05,946 +以处理所有用例 +在这种情况下是通过组合 + +222 +00:14:07,614 --> 00:14:11,451 +当你编写代码时 +同样仔细考虑自己创建的组件 + +223 +00:14:11,485 --> 00:14:15,789 +可能会非常有帮助 + +224 +00:14:15,822 --> 00:14:20,627 +回顾一下 首先是考虑常见用例 + +225 +00:14:20,661 --> 00:14:23,997 +通过应用渐进式呈现 +你编写的代码 + +226 +00:14:24,031 --> 00:14:27,601 +会在最常见的用例中 +节省你的时间 + +227 +00:14:27,634 --> 00:14:31,371 +智能默认值将意味着 +你不必考虑这些 + +228 +00:14:31,405 --> 00:14:33,740 +常见用例的细节 + +229 +00:14:33,774 --> 00:14:36,410 +努力优化你构建的调用端 + +230 +00:14:36,443 --> 00:14:37,945 +会允许你快速迭代 + +231 +00:14:38,645 --> 00:14:41,415 +最后 利用组合 + +232 +00:14:41,448 --> 00:14:46,386 +可以让你构建足够灵活的 API +以适应它们的所有用例 + +233 +00:14:47,521 --> 00:14:51,558 +因为你是一名 API 设计师 +你可以将这些经验 + +234 +00:14:51,592 --> 00:14:53,694 +应用到你每天编写的代码中 + +235 +00:14:53,727 --> 00:14:56,063 +无论它是为别人设计的 + +236 +00:14:56,096 --> 00:14:57,664 +还是只是自己使用的 + +237 +00:14:58,465 --> 00:14:59,967 +谢谢观看 + +238 +00:15:00,000 --> 00:15:02,102 +[古怪的音乐] + diff --git a/zho/2022 Session 10061 Bring multiple windows to your SwiftUI app .srt b/zho/2022 Session 10061 Bring multiple windows to your SwiftUI app .srt new file mode 100644 index 0000000..17083fa --- /dev/null +++ b/zho/2022 Session 10061 Bring multiple windows to your SwiftUI app .srt @@ -0,0 +1,1295 @@ +1 +00:00:00,267 --> 00:00:03,270 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,270 --> 00:00:09,843 +♪ + +3 +00:00:09,843 --> 00:00:10,944 +大家好 + +4 +00:00:10,944 --> 00:00:14,414 +我是 SwiftUI 团队的 +工程师 Jeff + +5 +00:00:14,414 --> 00:00:16,149 +今天 我很高兴与您讨论 + +6 +00:00:16,149 --> 00:00:19,520 +如何在 iPadOS 和 macOS 上 +为您的 SwiftUI App + +7 +00:00:19,520 --> 00:00:22,756 +引入多个窗口 + +8 +00:00:22,756 --> 00:00:25,659 +在本期视频中 我们将从 + +9 +00:00:25,659 --> 00:00:29,162 +SwiftUI 生命周期中 +各种场景类型的概览开始 + +10 +00:00:29,162 --> 00:00:32,799 +其中包括我们 +正在引入的一些新类型 + +11 +00:00:32,799 --> 00:00:35,135 +接下来展示这些场景类型如何 + +12 +00:00:35,135 --> 00:00:39,573 +通过添加辅助场景组合在一起 + +13 +00:00:39,573 --> 00:00:42,643 +然后我们将介绍 +一些用于在您的 App 中 + +14 +00:00:42,643 --> 00:00:45,512 +为特定场景打开窗口的新 API + +15 +00:00:45,512 --> 00:00:47,447 +我们将用几种方法来 + +16 +00:00:47,447 --> 00:00:51,018 +自定义 App 的场景 + +17 +00:00:51,018 --> 00:00:54,388 +在深入研究一些新类型之前 + +18 +00:00:54,388 --> 00:00:57,057 +我们先从现有场景类型的概览开始 + +19 +00:00:57,057 --> 00:01:00,894 +您还记得在之前的视频中 +SwiftUI 中的 App + +20 +00:01:00,894 --> 00:01:03,730 +是由场景和视图组成 + +21 +00:01:03,730 --> 00:01:08,001 +场景通常用屏幕上的 +窗口来展示其中的内容 + +22 +00:01:08,001 --> 00:01:10,170 +例如 这是我构建的一个 App + +23 +00:01:10,170 --> 00:01:12,206 +我用它跟踪我正在阅读的书籍 + +24 +00:01:12,206 --> 00:01:14,274 +我将其定义为单个窗口组 + +25 +00:01:14,274 --> 00:01:17,811 +以适合平台的方式 +显示我的阅读列表 + +26 +00:01:17,811 --> 00:01:20,581 +在支持多个窗口的平台上 + +27 +00:01:20,581 --> 00:01:22,983 +例如 iPadOS +和 macOS + +28 +00:01:22,983 --> 00:01:26,753 +可以使用多个窗口 +来展示一个场景中的内容 + +29 +00:01:26,753 --> 00:01:30,123 +场景的行为和表现形式 + +30 +00:01:30,123 --> 00:01:32,359 +根据使用的类型不尽相同 + +31 +00:01:32,359 --> 00:01:35,262 +例如 一个场景可能只用一个实例 + +32 +00:01:35,262 --> 00:01:36,930 +便可展示自身内容 + +33 +00:01:36,930 --> 00:01:39,433 +而无论平台能力如何 + +34 +00:01:39,433 --> 00:01:41,869 +我们来看看 +SwiftUI 中当前的 + +35 +00:01:41,869 --> 00:01:43,136 +场景类型列表 + +36 +00:01:43,136 --> 00:01:47,007 +WindowGroup 提供了 +一种跨 Apple 平台构建 + +37 +00:01:47,007 --> 00:01:49,776 +数据驱动 App 的方法 + +38 +00:01:49,776 --> 00:01:52,513 +DocumentGroup +可让您在 iOS 和 macOS 上 + +39 +00:01:52,513 --> 00:01:54,848 +构建基于文档的 App + +40 +00:01:54,848 --> 00:01:57,050 +并且 Settings 定义了 +一个接口 + +41 +00:01:57,050 --> 00:02:01,288 +用于表示 macOS +上的 App 内设置值 + +42 +00:02:01,288 --> 00:02:03,290 +这些场景类型可以组合在一起 + +43 +00:02:03,290 --> 00:02:05,492 +来扩展您 App 的功能 + +44 +00:02:05,492 --> 00:02:08,996 +我们正在通过两个 +新增内容扩展场景列表 + +45 +00:02:08,996 --> 00:02:12,432 +第一个是 Window +一个代表所有平台上 + +46 +00:02:12,432 --> 00:02:16,403 +单个 唯一窗口的场景 + +47 +00:02:16,403 --> 00:02:20,374 +以及适用于 macOS 的 +新场景类型:MenuBarExtra + +48 +00:02:20,374 --> 00:02:24,578 +在系统菜单栏中呈现为持久控件 + +49 +00:02:24,578 --> 00:02:26,180 +与其他场景类型一样 + +50 +00:02:26,180 --> 00:02:27,915 +您可以将 +Window 和 MenuBarExtra + +51 +00:02:27,915 --> 00:02:30,450 +作为独立的场景使用 + +52 +00:02:30,450 --> 00:02:33,253 +或与您 App 中的其他场景组合 + +53 +00:02:33,253 --> 00:02:36,523 +与 WindowGroup 不同的是 +Window 场景只会以单一 + +54 +00:02:36,523 --> 00:02:41,261 +唯一的窗口实例展示其中的内容 + +55 +00:02:41,261 --> 00:02:43,063 +此特性会很有用 + +56 +00:02:43,063 --> 00:02:46,500 +体现在当您的场景 +内容代表某个全局 App 状态 + +57 +00:02:46,500 --> 00:02:48,969 +且不一定适合 + +58 +00:02:48,969 --> 00:02:52,806 +macOS +和 iPadOS 上的 + +59 +00:02:52,806 --> 00:02:54,908 +WindowGroups +多窗口演示样式 + +60 +00:02:54,908 --> 00:02:58,011 +例如 游戏可能只允许 + +61 +00:02:58,011 --> 00:03:01,315 +单个主窗口来呈现其内容 + +62 +00:03:01,315 --> 00:03:04,751 +MenuBarExtra 是一种 +新的 macOS 专用场景类型 + +63 +00:03:04,751 --> 00:03:06,286 +其与其他场景 + +64 +00:03:06,286 --> 00:03:08,088 +行为略有不同 + +65 +00:03:08,088 --> 00:03:10,891 +MenuBarExtra 不会 +在窗口中呈现其内容 + +66 +00:03:10,891 --> 00:03:13,560 +而是将其标签放在菜单栏中 + +67 +00:03:13,560 --> 00:03:17,431 +并将其内容显示在锚定到标签上的 + +68 +00:03:17,431 --> 00:03:19,333 +菜单或窗口中 + +69 +00:03:19,333 --> 00:03:21,435 +此外 只要其关联 App +正在运行 + +70 +00:03:21,435 --> 00:03:24,671 +就可以使用 +MenuBarExtra + +71 +00:03:24,671 --> 00:03:27,474 +无论该 App 是否位于最前端 + +72 +00:03:27,474 --> 00:03:31,512 +MenuBarExtra 非常 +适合创建可轻松访问其功能的 + +73 +00:03:31,512 --> 00:03:34,481 +独立实用 App + +74 +00:03:34,481 --> 00:03:36,450 +或者可以与其他场景组合 + +75 +00:03:36,450 --> 00:03:41,321 +提供访问 App 功能的替代方式 + +76 +00:03:41,321 --> 00:03:45,225 +它还支持两种 +渲染风格:一是默认风格 + +77 +00:03:45,225 --> 00:03:47,594 +可在菜单中显示内容 + +78 +00:03:47,594 --> 00:03:50,364 +改菜单从菜单栏下拉显示 + +79 +00:03:50,364 --> 00:03:53,500 +以及在锚定到菜单栏的无镶边窗口中 + +80 +00:03:53,500 --> 00:03:56,904 +显示其内容的风格 + +81 +00:03:56,904 --> 00:03:59,873 +随着这两种新场景类型的加入 + +82 +00:03:59,873 --> 00:04:04,077 +SwiftUI App +可以代表我们平台上 + +83 +00:04:04,077 --> 00:04:07,047 +更丰富的功能集 + +84 +00:04:07,047 --> 00:04:09,816 +让我们看看如何将这些新的 API + +85 +00:04:09,816 --> 00:04:13,320 +与我们现有的场景类型结合使用 + +86 +00:04:13,320 --> 00:04:15,289 +这是我的 BookClub App 的定义 + +87 +00:04:15,289 --> 00:04:17,024 +我之前展示过 + +88 +00:04:17,024 --> 00:04:19,826 +其目前包含一个窗口组 + +89 +00:04:19,826 --> 00:04:22,696 +在 macOS 上 +我的 BookClub App 可能 + +90 +00:04:22,696 --> 00:04:24,431 +受益于一个额外的窗口 + +91 +00:04:24,431 --> 00:04:27,201 +来显示我们的阅读活动 + +92 +00:04:27,201 --> 00:04:31,271 +这是一个很好的例子 +其说明了 macOS App 如何利用 + +93 +00:04:31,271 --> 00:04:33,240 +该平台上存在的 + +94 +00:04:33,240 --> 00:04:35,209 +额外屏幕空间 + +95 +00:04:35,209 --> 00:04:37,177 +和灵活的窗口安排 + +96 +00:04:37,177 --> 00:04:39,146 +我们将在我们的 +App 中添加一个辅助场景 + +97 +00:04:39,146 --> 00:04:41,215 +用于表示此界面 + +98 +00:04:41,215 --> 00:04:43,584 +我们的 Activity 窗口 +数据来自 + +99 +00:04:43,584 --> 00:04:45,719 +我们的整体 App 状态 + +100 +00:04:45,719 --> 00:04:48,856 +所以窗口场景便是其理想选择 + +101 +00:04:48,856 --> 00:04:50,657 +打开多个具有相同状态的窗口 + +102 +00:04:50,657 --> 00:04:52,726 +不符合我们的设计 + +103 +00:04:52,726 --> 00:04:55,963 +提供给我们场景的 +标题将用作菜单项的标签 + +104 +00:04:55,963 --> 00:05:00,834 +该菜单项已 +添加到 Window 菜单部分 + +105 +00:05:00,834 --> 00:05:04,137 +选择此项时 +如果尚未打开场景的窗口 + +106 +00:05:04,137 --> 00:05:05,873 +则会将其打开 + +107 +00:05:05,873 --> 00:05:08,408 +否则 会将其带到前端 + +108 +00:05:08,408 --> 00:05:10,544 +现在我们已经 +介绍了将辅助场景添加到 + +109 +00:05:10,544 --> 00:05:12,179 +我们的 BookClub App + +110 +00:05:12,179 --> 00:05:15,249 +我想介绍一些我们 +即将推出的新的场景呈现 API + +111 +00:05:15,249 --> 00:05:18,318 +以及如何将其 +集成到您的 App 中 + +112 +00:05:18,318 --> 00:05:21,221 +来提供更丰富的体验 + +113 +00:05:21,221 --> 00:05:24,358 +我们的 BookClub App +具有一个上下文菜单 + +114 +00:05:24,358 --> 00:05:26,693 +可以为我们的 +“内容列表”窗格中的任何书籍调用 + +115 +00:05:26,693 --> 00:05:28,829 +此上下文菜单包含一个按钮 + +116 +00:05:28,829 --> 00:05:31,465 +用于触发我们的窗口展示 + +117 +00:05:31,465 --> 00:05:33,500 +稍后我会详解介绍 + +118 +00:05:33,500 --> 00:05:36,170 +SwiftUI 通过环境 +提供了几种 + +119 +00:05:36,170 --> 00:05:39,039 +新的可调用类型 用于呈现 + +120 +00:05:39,039 --> 00:05:41,909 +与您的 App 定义的 +场景相关联的窗口 + +121 +00:05:41,909 --> 00:05:44,578 +第一个是 +openWindow 操作 + +122 +00:05:44,578 --> 00:05:45,712 +可为 WindowGroup + +123 +00:05:45,712 --> 00:05:49,216 +或窗口场景呈现窗口 + +124 +00:05:49,216 --> 00:05:52,653 +传递给操作的标识符必须匹配 + +125 +00:05:52,653 --> 00:05:56,056 +您 App 中定义的场景的标识符 + +126 +00:05:56,056 --> 00:06:00,060 +openWindow 操作 +也可以取一个演示值 + +127 +00:06:00,060 --> 00:06:03,330 +已呈现的场景将用该值显示其内容 + +128 +00:06:03,330 --> 00:06:07,000 +这种形式的操作 +只有使用新初始化程序的 + +129 +00:06:07,000 --> 00:06:10,204 +WindowGroup 支持 +稍后我将详细介绍 + +130 +00:06:10,204 --> 00:06:12,339 +值的类型必须匹配 + +131 +00:06:12,339 --> 00:06:15,776 +提供给场景初始化程序的类型 + +132 +00:06:15,776 --> 00:06:17,945 +呈现文档窗口的环境中 + +133 +00:06:17,945 --> 00:06:22,349 +还有两种可调用类型: +一是 newDocument 操作 + +134 +00:06:22,349 --> 00:06:24,384 +支持为 +FileDocuments + +135 +00:06:24,384 --> 00:06:28,255 +和 ReferenceFileDocuments +打开新的文档窗口 + +136 +00:06:28,255 --> 00:06:31,358 +该操作需要您 App 中 +相应的 DocumentGroup + +137 +00:06:31,358 --> 00:06:34,895 +定义为具有编辑角色 + +138 +00:06:34,895 --> 00:06:37,397 +提供给此操作的文档将在 + +139 +00:06:37,397 --> 00:06:39,933 +每次呈现窗口时创建 + +140 +00:06:39,933 --> 00:06:43,237 +为了显示由磁盘上 +现有文件提供内容的 + +141 +00:06:43,237 --> 00:06:45,772 +文档窗口 + +142 +00:06:45,772 --> 00:06:48,008 +可以使用 +openDocument 操作 + +143 +00:06:48,008 --> 00:06:51,712 +此操作需要一个 +指向您要打开的文件的 URL + +144 +00:06:51,712 --> 00:06:53,747 +您的 App 必须 +定义一个用于展示窗口的 + +145 +00:06:53,747 --> 00:06:55,282 +DocumentGroup + +146 +00:06:55,282 --> 00:06:57,918 +并且该组的文档类型必须允许 + +147 +00:06:57,918 --> 00:07:01,588 +在提供的 URL 处 +读取文件的类型 + +148 +00:07:01,588 --> 00:07:03,857 +回到我们的按钮 我们将在 + +149 +00:07:03,857 --> 00:07:06,860 +我们的视图中添加 +openWindow 环境属性 + +150 +00:07:06,860 --> 00:07:10,097 +由于这种类型是可调用的 +我们可以直接 + +151 +00:07:10,097 --> 00:07:11,965 +从我们按钮的操作中调用 + +152 +00:07:11,965 --> 00:07:15,102 +我们的“书籍”类型是可识别的 + +153 +00:07:15,102 --> 00:07:18,872 +所以我们将其标识符 +作为要呈现的值传递 + +154 +00:07:18,872 --> 00:07:22,242 +在我们继续之前 我想介绍传递到 + +155 +00:07:22,242 --> 00:07:23,977 +openWindow 操作的值 + +156 +00:07:23,977 --> 00:07:26,980 +我注意到我正在传递该书籍的标识符 + +157 +00:07:26,980 --> 00:07:30,184 +且该标识符是 UUID 类型的值 + +158 +00:07:30,184 --> 00:07:32,986 +一般来说 您更倾向于 +用上述方式使用 + +159 +00:07:32,986 --> 00:07:35,422 +您模型的标识符 + +160 +00:07:35,422 --> 00:07:37,424 +而不使用值本身 + +161 +00:07:37,424 --> 00:07:39,826 +请注意 我们的 +“书籍”类型是一个值类型 + +162 +00:07:39,826 --> 00:07:43,530 +因此 如果我们将其用作呈现值 + +163 +00:07:43,530 --> 00:07:45,666 +我们的新窗口将获得一份 + +164 +00:07:45,666 --> 00:07:47,968 +原始演示的副本 + +165 +00:07:47,968 --> 00:07:50,904 +对其中任何一个的编辑 +都不会影响到另一个 + +166 +00:07:50,904 --> 00:07:53,640 +使用书籍的标识符让我们的模型存储 + +167 +00:07:53,640 --> 00:07:56,310 +成为这些值的真实来源 + +168 +00:07:56,310 --> 00:07:59,379 +而不是通过为单个值提供多个绑定 + +169 +00:07:59,379 --> 00:08:01,548 +有关值类型语义的更多信息 + +170 +00:08:01,548 --> 00:08:03,750 +请参阅开发者文档 + +171 +00:08:03,750 --> 00:08:06,220 +呈现的类型也必须符合 + +172 +00:08:06,220 --> 00:08:10,123 +Hashable +和 Codable 协议 + +173 +00:08:10,123 --> 00:08:13,694 +需要 Hashable 一致性 +来将呈现的值 + +174 +00:08:13,694 --> 00:08:15,195 +和打开的窗口关联 + +175 +00:08:15,195 --> 00:08:17,664 +需要 Codable 一致性 + +176 +00:08:17,664 --> 00:08:20,200 +来保持状态恢复的 + +177 +00:08:20,200 --> 00:08:21,502 +呈现值 + +178 +00:08:21,502 --> 00:08:23,036 +稍后 我将更详细地 + +179 +00:08:23,036 --> 00:08:24,872 +介绍这两种行为 + +180 +00:08:24,872 --> 00:08:29,109 +最后 如果可以的话 +尽量倾向于传递轻量级值 + +181 +00:08:29,109 --> 00:08:32,446 +我们书籍的标识符 +也是一个很好的例子 + +182 +00:08:32,446 --> 00:08:35,182 +由于 SwiftUI 将保留该值 + +183 +00:08:35,182 --> 00:08:38,118 +以进行状态恢复 因此使用较小的值 + +184 +00:08:38,118 --> 00:08:41,688 +将提高您 App 的响应速度 + +185 +00:08:41,688 --> 00:08:44,091 +现在 我们的按钮具备了必要组件 + +186 +00:08:44,091 --> 00:08:45,959 +来呈现我们的详细窗口 + +187 +00:08:45,959 --> 00:08:48,128 +但是将其选择后不会显示任何内容 + +188 +00:08:48,128 --> 00:08:51,498 +这是因为我们 +已告知 SwiftUI 呈现 + +189 +00:08:51,498 --> 00:08:53,333 +某种数据类型的窗口 + +190 +00:08:53,333 --> 00:08:56,170 +但尚未在我们的 App 中 +定义反映这一点的场景 + +191 +00:08:56,170 --> 00:08:58,505 +我们回到我们的 App +并进行更改 + +192 +00:08:58,505 --> 00:09:00,541 +除了我们主要的 +WindowGroup + +193 +00:09:00,541 --> 00:09:02,242 +和辅助窗口 + +194 +00:09:02,242 --> 00:09:04,178 +我们还将添加一个 +用于处理我们书籍详情的 + +195 +00:09:04,178 --> 00:09:05,913 +额外 WindowGroup + +196 +00:09:05,913 --> 00:09:09,583 +我们的书籍详情 WindowGroup +使用的是一个新的初始化程序 + +197 +00:09:09,583 --> 00:09:12,119 +除了标题 我们还注意到该组 + +198 +00:09:12,119 --> 00:09:15,022 +显示 Book.ID 类型的数据 + +199 +00:09:15,022 --> 00:09:16,957 +在我们的例子则是 UUID + +200 +00:09:16,957 --> 00:09:19,593 +此类型应与我们传递到之前添加的 + +201 +00:09:19,593 --> 00:09:22,596 +openWindow 操作的值 +相匹配 + +202 +00:09:22,596 --> 00:09:24,164 +当向 WindowGroup 提供 + +203 +00:09:24,164 --> 00:09:26,533 +给定值用于演示时 + +204 +00:09:26,533 --> 00:09:30,103 +SwiftUI 将为该值 +创建一个新的子场景 + +205 +00:09:30,103 --> 00:09:32,406 +并且该值将使用组的视图构建器 + +206 +00:09:32,406 --> 00:09:36,944 +定义场景窗口的根内容 + +207 +00:09:36,944 --> 00:09:40,681 +每个独特呈现的值将创造一个新场景 + +208 +00:09:40,681 --> 00:09:43,584 +该值的等同性将用于确定 + +209 +00:09:43,584 --> 00:09:45,686 +是否应该创建一个新窗口 + +210 +00:09:45,686 --> 00:09:48,055 +或者是否可以重新使用现有窗口 + +211 +00:09:48,055 --> 00:09:50,190 +当 openWindow 呈现一个 + +212 +00:09:50,190 --> 00:09:53,093 +已存在窗口的值时 + +213 +00:09:53,093 --> 00:09:56,463 +该组将使用该已存在窗口 +而不会创建一个新窗口 + +214 +00:09:56,463 --> 00:09:58,866 +以我们的 BookClub App 为例 + +215 +00:09:58,866 --> 00:10:01,502 +为已经在窗口中呈现的书籍 + +216 +00:10:01,502 --> 00:10:04,404 +选择上下文菜单操作 + +217 +00:10:04,404 --> 00:10:07,040 +将导致该窗口被排在前面 + +218 +00:10:07,040 --> 00:10:09,543 +而不是显示同一本书的第二个窗口 + +219 +00:10:09,543 --> 00:10:12,713 +呈现的值也将由 +SwiftUI 自动保留 + +220 +00:10:12,713 --> 00:10:16,216 +以用于状态恢复 + +221 +00:10:16,216 --> 00:10:18,285 +您的视图将被绑定到 + +222 +00:10:18,285 --> 00:10:20,687 +初始呈现值 + +223 +00:10:20,687 --> 00:10:22,723 +可在窗口打开时随时 + +224 +00:10:22,723 --> 00:10:24,057 +修改此绑定 + +225 +00:10:24,057 --> 00:10:26,927 +当重新创建场景以进行状态恢复时 + +226 +00:10:26,927 --> 00:10:29,429 +SwiftUI 将 +向窗口的内容视图 + +227 +00:10:29,429 --> 00:10:31,932 +传递最新的值 + +228 +00:10:31,932 --> 00:10:36,336 +在此 我们将 Book.ID +绑定到我们的详细视图 + +229 +00:10:36,336 --> 00:10:38,572 +该视图可以查找我们模型存储中的 + +230 +00:10:38,572 --> 00:10:40,707 +指定项以用于显示 + +231 +00:10:40,707 --> 00:10:42,342 +随着我们所有的组件都准备到位 + +232 +00:10:42,342 --> 00:10:45,212 +现在我们可以选择上下文菜单项 + +233 +00:10:45,212 --> 00:10:48,115 +并在单独的窗口中查看书籍详情 + +234 +00:10:48,115 --> 00:10:50,684 +最后 我想介绍一些 + +235 +00:10:50,684 --> 00:10:54,321 +可以让您在 App 中 +自定义场景的方法 + +236 +00:10:54,321 --> 00:10:57,591 +由于我们用两个 WindowGroup +场景定义了我们的 App + +237 +00:10:57,591 --> 00:10:59,193 +一个用于主查看器窗口 + +238 +00:10:59,193 --> 00:11:01,161 +另一个用于我们的详情窗口 + +239 +00:11:01,161 --> 00:11:04,298 +所以 SwiftUI 会 +默认为“文件”菜单中的 + +240 +00:11:04,298 --> 00:11:06,633 +每个组添加菜单项 + +241 +00:11:06,633 --> 00:11:08,235 +但是 我们详情窗口的菜单项 + +242 +00:11:08,235 --> 00:11:10,671 +不太适合我们的用例 + +243 +00:11:10,671 --> 00:11:13,407 +我更倾向于只能通过 + +244 +00:11:13,407 --> 00:11:16,376 +之前添加的上下文菜单打开窗口 + +245 +00:11:16,376 --> 00:11:19,613 +一个新的场景修改器 +commandsRemoved + +246 +00:11:19,613 --> 00:11:21,782 +允许您修改场景 + +247 +00:11:21,782 --> 00:11:25,252 +使其不再提供默认命令 + +248 +00:11:25,252 --> 00:11:26,954 +比如“文件”菜单中的命令 + +249 +00:11:26,954 --> 00:11:30,891 +应用此修改器后 +我们的“文件”菜单现在只包含 + +250 +00:11:30,891 --> 00:11:34,995 +用于为主要 +WindowGroup 打开窗口的项 + +251 +00:11:34,995 --> 00:11:37,064 +我对目前用于显示我阅读活动的 + +252 +00:11:37,064 --> 00:11:40,968 +辅助窗口场景的演示还不太满意 + +253 +00:11:40,968 --> 00:11:43,136 +那么 我们接下来仔细研究一下 + +254 +00:11:43,136 --> 00:11:46,273 +由于我要对其应用一些修改器 + +255 +00:11:46,273 --> 00:11:48,575 +所以我会将其提取到自定义场景中 + +256 +00:11:48,575 --> 00:11:50,844 +这将使我的 App 定义更加清晰 + +257 +00:11:50,844 --> 00:11:53,547 +没有任何以前的窗口状态 + +258 +00:11:53,547 --> 00:11:57,784 +SwiftUI 将默认 +将其放置在屏幕的中央 + +259 +00:11:57,784 --> 00:11:59,786 +但是 我更倾向于将“阅读活动” + +260 +00:11:59,786 --> 00:12:03,090 +默认放置于不同的位置 + +261 +00:12:03,090 --> 00:12:05,626 +通过添加新的 +defaultPosition 修改器 + +262 +00:12:05,626 --> 00:12:08,228 +当没有先前的状态可用时 + +263 +00:12:08,228 --> 00:12:11,031 +我可以指定要使用的位置 + +264 +00:12:11,031 --> 00:12:14,201 +该位置将适用屏幕大小 + +265 +00:12:14,201 --> 00:12:17,137 +并按照当前的位置设置 + +266 +00:12:17,137 --> 00:12:19,773 +将窗口放置在适当的位置 + +267 +00:12:19,773 --> 00:12:22,743 +该新位置有助于将我的“活动”窗口 + +268 +00:12:22,743 --> 00:12:25,579 +与屏幕上的其他查看窗口相区分 + +269 +00:12:25,579 --> 00:12:27,147 +我还想让我的“活动”窗口 + +270 +00:12:27,147 --> 00:12:31,418 +默认以特定大小显示 +但仍可调整大小 + +271 +00:12:31,418 --> 00:12:33,554 +除了 defaultPosition + +272 +00:12:33,554 --> 00:12:36,089 +我还将添加 +defaultSize 修饰器 + +273 +00:12:36,089 --> 00:12:39,826 +已向其提供的值将提供给布局系统 + +274 +00:12:39,826 --> 00:12:43,163 +来导出窗口的初始大小 + +275 +00:12:43,163 --> 00:12:46,300 +现在我已经自定义了窗口的呈现方式 + +276 +00:12:46,300 --> 00:12:49,469 +我们再添加 +一个修改器来自定义其行为 + +277 +00:12:49,469 --> 00:12:52,539 +keyboardShortcut 修饰器 + +278 +00:12:52,539 --> 00:12:54,675 +也已扩展为适用于场景类型 + +279 +00:12:54,675 --> 00:12:56,376 +在场景级别使用时 + +280 +00:12:56,376 --> 00:12:58,612 +此修改器影响创建 + +281 +00:12:58,612 --> 00:12:59,813 +新窗口的命令 + +282 +00:12:59,813 --> 00:13:03,483 +在此 我修改了我的“活动”窗口 +以便可以使用 + +283 +00:13:03,483 --> 00:13:06,787 +快捷键 Option-Command-0 +将其打开 + +284 +00:13:06,787 --> 00:13:09,756 +通过提供常用场景的快捷指令 + +285 +00:13:09,756 --> 00:13:13,227 +可以很好地自定义 App + +286 +00:13:13,227 --> 00:13:16,630 +也可用于自定义 +Command-N 的默认 + +287 +00:13:16,630 --> 00:13:18,031 +快捷方式 + +288 +00:13:18,031 --> 00:13:21,134 +且该快捷方式已添加到 +App 的主 WindowGroup 中 + +289 +00:13:21,134 --> 00:13:23,203 +介绍新场景 +和 SwiftUI 中窗口功能 + +290 +00:13:23,203 --> 00:13:25,639 +的旅途到此就结束了 + +291 +00:13:25,639 --> 00:13:28,642 +我们认为 +这些新 API 的潜力巨大 + +292 +00:13:28,642 --> 00:13:29,810 +希望您也如此认为! + +293 +00:13:29,810 --> 00:13:32,312 +有关如何在 +您的 iPadOS 和 macOS App 中 + +294 +00:13:32,312 --> 00:13:35,115 +添加功能的更多信息 + +295 +00:13:35,115 --> 00:13:37,451 +请查看其他视频 + +296 +00:13:37,451 --> 00:13:40,354 +“iPad 上的 SwiftUI: +组织您的界面” + +297 +00:13:40,354 --> 00:13:43,824 +和“iPad 上的 SwiftUI: +添加工具栏、标题等” + +298 +00:13:44,925 --> 00:13:46,527 +感谢您的观看 + +299 +00:13:46,527 --> 00:13:50,998 +♪ + diff --git a/zho/2022 Session 10062 Meet Transferable.srt b/zho/2022 Session 10062 Meet Transferable.srt new file mode 100644 index 0000000..0869d35 --- /dev/null +++ b/zho/2022 Session 10062 Meet Transferable.srt @@ -0,0 +1,1084 @@ +1 +00:00:00,200 --> 00:00:03,370 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,370 --> 00:00:09,643 +♪ + +3 +00:00:09,643 --> 00:00:13,347 +大家好 欢迎观看 +“Meet Transferable”讲座 + +4 +00:00:13,347 --> 00:00:16,717 +我是 SwiftUI 工程师 +Julia + +5 +00:00:16,717 --> 00:00:19,152 +很高兴能 +向大家介绍 Transferable + +6 +00:00:19,152 --> 00:00:21,889 +一种支持在您的 App 中 + +7 +00:00:21,889 --> 00:00:26,226 +拖放 复制/粘贴 +及其他功能的声明方式 + +8 +00:00:26,226 --> 00:00:29,997 +除了在 SwiftUI 工作 +和为 Mac 开发 App + +9 +00:00:29,997 --> 00:00:32,566 +我也很想了解 +在计算机行业打拼的女性 + +10 +00:00:32,566 --> 00:00:34,601 +想要倾听她们的故事 + +11 +00:00:34,601 --> 00:00:38,539 +我觉得英雄前辈们的 +事迹十分值得我们学习 + +12 +00:00:38,539 --> 00:00:41,208 +所以我决定创建一个目录 App + +13 +00:00:41,208 --> 00:00:46,580 +我可以在其中 +查看 添加和编辑一份名单 + +14 +00:00:46,580 --> 00:00:50,484 +该名单囊括了女性发明家 工程师 +和科学家的简介资料 + +15 +00:00:50,484 --> 00:00:54,188 +我希望该 App 能够完美地支持 + +16 +00:00:54,188 --> 00:00:58,659 +将科学家的肖像拖放到 App 中 + +17 +00:00:58,659 --> 00:01:01,528 +能够使用剪贴板内容 + +18 +00:01:01,528 --> 00:01:04,798 +来粘贴有趣的事迹 + +19 +00:01:04,798 --> 00:01:06,366 +并且我的 App 首次 + +20 +00:01:06,366 --> 00:01:10,003 +支持在 watchOS 上分享! + +21 +00:01:10,003 --> 00:01:12,606 +我的潜在用户表示他们希望 + +22 +00:01:12,606 --> 00:01:15,209 +能够从手表中 + +23 +00:01:15,209 --> 00:01:17,578 +分享个人资料 + +24 +00:01:17,578 --> 00:01:23,884 +此外 目前可以通过 SwiftUI +实现在 iOS 和 Mac 上的分享 + +25 +00:01:23,884 --> 00:01:29,523 +这也是今年 +ShareSheet 的全新设计 + +26 +00:01:29,523 --> 00:01:32,726 +在背后 启用所有这些功能 + +27 +00:01:32,726 --> 00:01:35,829 +需要将我们已有的模型 + +28 +00:01:35,829 --> 00:01:39,600 +支持发送到一个 +我们 app 里的接收方 + +29 +00:01:39,600 --> 00:01:42,336 +甚至其他 App + +30 +00:01:42,336 --> 00:01:46,039 +个人资料结构包含我们所掌握的 + +31 +00:01:46,039 --> 00:01:49,476 +个体的所有信息 + +32 +00:01:49,476 --> 00:01:52,212 +打包在存档中的所有个人资料 + +33 +00:01:52,212 --> 00:01:54,982 +可以在朋友之间分享 + +34 +00:01:54,982 --> 00:01:58,685 +我们将个体有趣事迹存储在字符串中 + +35 +00:01:58,685 --> 00:02:01,455 +甚至可以附加视频 + +36 +00:02:01,455 --> 00:02:06,059 +这里一种新的简单方法 +可以将所有这些模型类型 + +37 +00:02:06,059 --> 00:02:07,828 +支持分享功能 + +38 +00:02:07,828 --> 00:02:09,863 +这就是 Transferable! + +39 +00:02:09,863 --> 00:02:14,401 +这是一种 Swift 优先的声明方式 +说明了如何将您的模型 + +40 +00:02:14,401 --> 00:02:17,571 +序列化和反序列化 + +41 +00:02:17,571 --> 00:02:20,240 +来用于分享和数据传输 + +42 +00:02:20,240 --> 00:02:22,809 +今天我们就来聊聊 + +43 +00:02:22,809 --> 00:02:24,611 +什么是 Transferable + +44 +00:02:24,611 --> 00:02:28,448 +以及当我们在使用时 +它在幕后是怎样运作的 + +45 +00:02:28,448 --> 00:02:32,786 +以及如何符合自定义类型 最后 + +46 +00:02:32,786 --> 00:02:35,189 +我将分享一些高级技巧和窍门 + +47 +00:02:35,189 --> 00:02:37,658 +可以帮助自定义 Transferable + +48 +00:02:37,658 --> 00:02:40,827 +来精准地满足您的需求 + +49 +00:02:40,827 --> 00:02:43,197 +我们开始吧! + +50 +00:02:43,197 --> 00:02:46,633 +假设有两个 App 正在运行 + +51 +00:02:46,633 --> 00:02:50,337 +用户想从一个 App 传递数据 +到另一个 App + +52 +00:02:50,337 --> 00:02:54,975 +通过复制/粘贴 分享面板 拖拽 + +53 +00:02:54,975 --> 00:02:58,579 +或者使用一些其它的 App 功能 + +54 +00:02:58,579 --> 00:03:02,149 +当在两个不同的 App 间 +发送内容时 + +55 +00:03:02,149 --> 00:03:05,986 +数据将以二进制形式进行传输 + +56 +00:03:05,986 --> 00:03:08,755 +发送此数据的一个重要方面 + +57 +00:03:08,755 --> 00:03:12,226 +是确定其对应的内容 + +58 +00:03:12,226 --> 00:03:15,662 +可以是文字 视频 + +59 +00:03:15,662 --> 00:03:21,235 +我最喜欢的女工程师资料 +或整个存档 + +60 +00:03:21,235 --> 00:03:26,073 +这里是 +描述数据用途的 UTType + +61 +00:03:26,073 --> 00:03:31,144 +让我们仔细研究 App 是 +如何生成这种二进制数据的 + +62 +00:03:31,144 --> 00:03:34,448 +可以与其他 App +甚至在单个 App 中 + +63 +00:03:34,448 --> 00:03:36,750 +共享的所有类型 + +64 +00:03:36,750 --> 00:03:40,254 +都必须提供两个信息 + +65 +00:03:40,254 --> 00:03:45,526 +将其和二进制数据之间 +互相转换的方法 + +66 +00:03:45,526 --> 00:03:48,562 +与二进制数据结构对应的 + +67 +00:03:48,562 --> 00:03:55,002 +内容类型并告知接收方 +他们实际获取的数据类型 + +68 +00:03:55,002 --> 00:03:56,537 +内容类型 + +69 +00:03:56,537 --> 00:03:59,606 +也称为统一类型标识符 + +70 +00:03:59,606 --> 00:04:03,277 +是一种 Apple 特有的技术 +该技术描述不同 + +71 +00:04:03,277 --> 00:04:07,814 +二进制结构以及抽象概念的标识符 + +72 +00:04:07,814 --> 00:04:09,983 +该标识符形成一棵树 + +73 +00:04:09,983 --> 00:04:13,453 +并且我们还可以定义自定义标识符 + +74 +00:04:13,453 --> 00:04:18,959 +例如 一个用于由我们的配置文件 +使用的二进制结构 + +75 +00:04:18,959 --> 00:04:21,828 +要声明一个自定义标识符 + +76 +00:04:21,828 --> 00:04:26,366 +首先 将其声明 +添加到 Info.plist 文件中 + +77 +00:04:26,366 --> 00:04:30,304 +添加一个文件扩展名 +也是个不错的选择 + +78 +00:04:30,304 --> 00:04:32,739 +如果数据保存在磁盘上 + +79 +00:04:32,739 --> 00:04:37,110 +系统了解到您的 App +可以打开该文件 + +80 +00:04:37,110 --> 00:04:40,981 +其次 在代码中声明该标识符 + +81 +00:04:40,981 --> 00:04:43,483 +要了解有关内容类型的更多信息 + +82 +00:04:43,483 --> 00:04:45,586 +您可以观看视频 + +83 +00:04:45,586 --> 00:04:49,423 +“统一类型标识符 — 重新介绍” + +84 +00:04:49,423 --> 00:04:53,594 +我个人十分喜欢该视频 +其清晰地阐述了 + +85 +00:04:53,594 --> 00:04:58,899 +什么是统一类型标识符以及如何使用 + +86 +00:04:58,899 --> 00:05:01,835 +好消息是许多标准类型 + +87 +00:05:01,835 --> 00:05:04,238 +已符合 Transferable + +88 +00:05:04,238 --> 00:05:10,744 +例如 字符串 数据 +URL 属性字符串和图像 + +89 +00:05:10,744 --> 00:05:14,982 +您只需几行代码即可 +使用全新 SwiftUI 粘贴按钮界面 + +90 +00:05:14,982 --> 00:05:20,053 +将有趣的事迹粘贴到个人资料中 + +91 +00:05:20,053 --> 00:05:23,090 +支持从视图中拖动图像 + +92 +00:05:23,090 --> 00:05:27,794 +或从访达 +或其他 App 接收拖进来的图像 + +93 +00:05:27,794 --> 00:05:29,963 +使用全新的 ShareLink + +94 +00:05:29,963 --> 00:05:34,101 +现在可以从手表实现分享体验 + +95 +00:05:34,101 --> 00:05:37,871 +介绍了基础知识后 +现在您有了一个想法 + +96 +00:05:37,871 --> 00:05:40,941 +什么是 Transferable +且如何使用 + +97 +00:05:40,941 --> 00:05:43,477 +我们看看 +如何向我们 App 中的模型 + +98 +00:05:43,477 --> 00:05:47,514 +添加 +遵循 Transferable 协议 + +99 +00:05:47,514 --> 00:05:51,885 +正如我之前提到的 +我们的 App 中有四种要分享的 + +100 +00:05:51,885 --> 00:05:54,821 +模型类型 + +101 +00:05:54,821 --> 00:05:58,959 +其中一个是字符串 +已经遵循 Transferable + +102 +00:05:58,959 --> 00:06:01,728 +我们不需要再对其进行任何操作了 + +103 +00:06:01,728 --> 00:06:05,165 +但是单个个人资料 +ProfilesArchive + +104 +00:06:05,165 --> 00:06:09,136 +和我想分享的视频呢? + +105 +00:06:09,136 --> 00:06:11,939 +要使类型符合 +Transferable + +106 +00:06:11,939 --> 00:06:15,142 +只需实现一个属性 + +107 +00:06:15,142 --> 00:06:17,511 +TransferRepresentation + +108 +00:06:17,511 --> 00:06:22,049 +该属性描述了模型将如何被传输 + +109 +00:06:22,049 --> 00:06:25,786 +需要注意三个重要的表示形式 + +110 +00:06:25,786 --> 00:06:27,521 +CodableRepresentation + +111 +00:06:27,521 --> 00:06:29,256 +DataRepresentation + +112 +00:06:29,256 --> 00:06:31,358 +和 FileRepresentation + +113 +00:06:31,358 --> 00:06:34,094 +我将分别介绍 + +114 +00:06:34,094 --> 00:06:39,066 +但首先 先研究 +我们最重要的模型 Profile 结构 + +115 +00:06:39,066 --> 00:06:43,070 +其包括 ID 姓名 简历 +或许还包括有趣的事迹 + +116 +00:06:43,070 --> 00:06:46,106 +肖像和视频 + +117 +00:06:46,106 --> 00:06:48,742 +Profile 结构 +已符合 Codable + +118 +00:06:48,742 --> 00:06:52,112 +因此 我们可以将 +CodableRepresentation + +119 +00:06:52,112 --> 00:06:56,049 +包含到我们的 +Transferable 一致性中 + +120 +00:06:56,049 --> 00:06:59,019 +Codable 表示使用编码器 + +121 +00:06:59,019 --> 00:07:02,022 +将个人资料转换为二进制数据 + +122 +00:07:02,022 --> 00:07:05,158 +并且解码器进行相反的转化 + +123 +00:07:05,158 --> 00:07:09,162 +默认情况下 +其使用 JSON 但您也可以提供 + +124 +00:07:09,162 --> 00:07:12,566 +您自己的编码器/解码器对 + +125 +00:07:12,566 --> 00:07:15,169 +想要了解 +有关 Codable 协议 + +126 +00:07:15,169 --> 00:07:18,005 +以及编码器和解码器 +工作原理的更多信息 + +127 +00:07:18,005 --> 00:07:22,276 +我邀请您观看首次引入此协议的 + +128 +00:07:22,276 --> 00:07:26,413 +WWDC 讲座:“可信任的数据” + +129 +00:07:26,413 --> 00:07:28,348 +回到我们的个人资料 + +130 +00:07:28,348 --> 00:07:31,018 +Codable 唯一需要的 + +131 +00:07:31,018 --> 00:07:34,254 +就是了解所需的内容类型 + +132 +00:07:34,254 --> 00:07:37,124 +由于这是一种自定义格式 + +133 +00:07:37,124 --> 00:07:41,562 +所以我们将使用 +自定义声明的统一类型标识符 + +134 +00:07:41,562 --> 00:07:45,666 +添加个人资料内容类型后 +我们就可以开始了 + +135 +00:07:45,666 --> 00:07:49,603 +Profile 现在符合 +Transferable 了! + +136 +00:07:49,603 --> 00:07:54,441 +现在 我们看一下另一种类型 +ProfilesArchive + +137 +00:07:54,441 --> 00:07:58,078 +其已经支持转换为 CSV 数据 + +138 +00:07:58,078 --> 00:08:02,749 +我可以在 CSV 文件中 +导出女性个人资料列表 + +139 +00:08:02,749 --> 00:08:08,522 +然后可以与朋友分享 +或将其导入另一台计算机 + +140 +00:08:08,522 --> 00:08:13,760 +存档可以和数据之间来回转换 + +141 +00:08:13,760 --> 00:08:18,432 +这意味着我们可以用 +DataRepresentation + +142 +00:08:18,432 --> 00:08:20,434 +如果我们研究的更深一点 就会发现 + +143 +00:08:20,434 --> 00:08:23,737 +DataRepresentation +使用转换函数 + +144 +00:08:23,737 --> 00:08:26,740 +来直接创建二进制表示形式 + +145 +00:08:26,740 --> 00:08:30,677 +并重建接收器的值 + +146 +00:08:30,677 --> 00:08:34,114 +这就是用 +DataRepresentation + +147 +00:08:34,114 --> 00:08:36,583 +可以很容易地 +符合 Transferable + +148 +00:08:36,583 --> 00:08:41,388 +只需调用我们已有的两个函数 + +149 +00:08:41,388 --> 00:08:46,560 +初始化函数和转换为 CSV 的函数 + +150 +00:08:46,560 --> 00:08:50,163 +如果个体资料附有视频 + +151 +00:08:50,163 --> 00:08:53,867 +我还希望能将其拖动或分享 + +152 +00:08:53,867 --> 00:08:55,569 +但是视频可能很大 + +153 +00:08:55,569 --> 00:08:58,472 +我不想让其加载到内存中 + +154 +00:08:58,472 --> 00:09:02,109 +这时候就应该用到 +FileRepresentation + +155 +00:09:02,109 --> 00:09:04,311 +如果我们再次深究 + +156 +00:09:04,311 --> 00:09:06,780 +我们会发现 +FileRepresentation + +157 +00:09:06,780 --> 00:09:09,983 +把已提供的 URL +传递给了接收器 + +158 +00:09:09,983 --> 00:09:14,821 +并用 URL 为接收器 +重建了 Transferable 项 + +159 +00:09:14,821 --> 00:09:18,025 +FileRepresentation +允许我们共享项目 + +160 +00:09:18,025 --> 00:09:21,862 +且该项目由写入磁盘的 +二进制表示形式支持 + +161 +00:09:21,862 --> 00:09:23,597 +例如文件 + +162 +00:09:23,597 --> 00:09:25,132 +我们总结一下 + +163 +00:09:25,132 --> 00:09:27,734 +如果您只想为一个简单的用例 + +164 +00:09:27,734 --> 00:09:29,570 +选择一个表示形式 + +165 +00:09:29,570 --> 00:09:32,840 +首先检查模型 +是否具有 Codable 一致性 + +166 +00:09:32,840 --> 00:09:37,077 +并且是否没有 +任何特定的二进制格式要求 + +167 +00:09:37,077 --> 00:09:40,581 +如果具有一致性 便使用 +CodableRepresentation + +168 +00:09:40,581 --> 00:09:45,052 +如果不具有 请检查 +模型存储在内存中还是磁盘上 + +169 +00:09:45,052 --> 00:09:48,188 +如果存储在内存中 那么 +DataRepresentation 再适合不过了 + +170 +00:09:48,188 --> 00:09:51,558 +如果在磁盘上 +则是 FileRepresetnation + +171 +00:09:51,558 --> 00:09:54,962 +Transferable +不仅涵盖简单的用例 + +172 +00:09:54,962 --> 00:09:57,397 +还有一些复杂的用例 + +173 +00:09:57,397 --> 00:10:01,401 +大多数情况下 +只需几行代码便都可解决 + +174 +00:10:01,401 --> 00:10:04,338 +自己去发现吧! + +175 +00:10:04,338 --> 00:10:07,040 +之前 我们向个人资料中添加了 + +176 +00:10:07,040 --> 00:10:10,711 +Transferable 一致性 +现在我们看得更远一些 + +177 +00:10:10,711 --> 00:10:13,380 +将个人资料复制到粘贴板 + +178 +00:10:13,380 --> 00:10:16,483 +并粘贴到任何文本字段中时 + +179 +00:10:16,483 --> 00:10:19,686 +我想粘贴个人资料的名称 + +180 +00:10:19,686 --> 00:10:23,524 +这意味着我们 +需要额外添加一个表示形式 + +181 +00:10:23,524 --> 00:10:27,361 +ProxyRepresentation 允许 +其他 Transferable 类型 + +182 +00:10:27,361 --> 00:10:29,930 +来表示我们的模型 + +183 +00:10:29,930 --> 00:10:34,968 +只需一行 个人资料便可粘贴为文本 + +184 +00:10:34,968 --> 00:10:37,771 +请注意 +我是在 Codable 之后 + +185 +00:10:37,771 --> 00:10:41,475 +添加的 ProxyRepresentation +顺序不能反 + +186 +00:10:41,475 --> 00:10:44,144 +接收器将使用第一种表示形式 + +187 +00:10:44,144 --> 00:10:47,014 +和其支持的内容类型 + +188 +00:10:47,014 --> 00:10:50,984 +如果接收器检测到 +我们的自定义内容类型 Profile + +189 +00:10:50,984 --> 00:10:52,553 +便应让其使用 + +190 +00:10:52,553 --> 00:10:55,556 +如果没有检测到 但其支持文本类型 + +191 +00:10:55,556 --> 00:11:00,761 +便要让其使用 +ProxyRepresentation + +192 +00:11:00,761 --> 00:11:04,698 +现在 Profile +支持编码器/解码器转换 + +193 +00:11:04,698 --> 00:11:07,501 +并支持转换为文本 + +194 +00:11:07,501 --> 00:11:09,603 +本例中的 +ProxyRepresentation + +195 +00:11:09,603 --> 00:11:12,039 +仅描述导出为文本 + +196 +00:11:12,039 --> 00:11:15,442 +不从中重建配置文件 + +197 +00:11:15,442 --> 00:11:20,714 +任何表示形式都 +可以描述两种或一种转换 + +198 +00:11:20,714 --> 00:11:24,551 +现在 我们了解了 +ProxyRepresentations + +199 +00:11:24,551 --> 00:11:26,954 +我们需要对视频应用 + +200 +00:11:26,954 --> 00:11:28,622 +FileRepresentation 吗? + +201 +00:11:28,622 --> 00:11:31,491 +我们可以使用带有 URL 的代理 + +202 +00:11:31,491 --> 00:11:33,760 +差异很小 + +203 +00:11:33,760 --> 00:11:37,064 +FileRepresentation +是用来处理 + +204 +00:11:37,064 --> 00:11:38,432 +写入磁盘的 URL + +205 +00:11:38,432 --> 00:11:42,569 +并通过授予临时沙盒扩展程序 + +206 +00:11:42,569 --> 00:11:46,106 +来确保接收器 +可以访问此文件或其副本 + +207 +00:11:46,106 --> 00:11:49,376 +ProxyRepresentation +处理 URL 的方式 + +208 +00:11:49,376 --> 00:11:53,146 +与处理其他 Transferable 项一样 +例如字符串 + +209 +00:11:53,146 --> 00:11:55,983 +其不具备我们对文件所需的 + +210 +00:11:55,983 --> 00:11:58,485 +任何这些附加功能 + +211 +00:11:58,485 --> 00:12:01,088 +这意味着两个都可以使用 + +212 +00:12:01,088 --> 00:12:04,191 +首先是 FileRepresentation + +213 +00:12:04,191 --> 00:12:06,927 +允许接收器访问电影文件 + +214 +00:12:06,927 --> 00:12:08,929 +及其内容 + +215 +00:12:08,929 --> 00:12:11,665 +当我将已复制的 +视频粘贴到文本字段中时 + +216 +00:12:11,665 --> 00:12:15,269 +将用到 ProxyRepresentation + +217 +00:12:15,269 --> 00:12:18,305 +因此 以上两种 +处理 URL 的方式 + +218 +00:12:18,305 --> 00:12:21,108 +有很大不同 + +219 +00:12:21,108 --> 00:12:26,713 +在第一种情况下 +实际有效负载是磁盘上的资产 + +220 +00:12:26,713 --> 00:12:31,218 +第二种情况下 有效负载是可以指向 + +221 +00:12:31,218 --> 00:12:35,422 +远程网站的 URL 结构本身 + +222 +00:12:35,422 --> 00:12:39,993 +我还想升级另一个模型 +ProfilesArchive + +223 +00:12:39,993 --> 00:12:43,830 +在某些情况下 +其不支持转换为 CSV + +224 +00:12:43,830 --> 00:12:46,934 +我想在代码中体现这一点 + +225 +00:12:46,934 --> 00:12:48,168 +我们一起看看 + +226 +00:12:48,168 --> 00:12:52,973 +我们添加一个布尔属性 +来弄清是否可以导出为 CSV + +227 +00:12:52,973 --> 00:12:57,878 +和数据间的转换函数 + +228 +00:12:57,878 --> 00:13:03,016 +为了将这个想法在代码中体现 +我们可以使用 .exportingCondition + +229 +00:13:03,016 --> 00:13:05,786 +如果给定的存档不支持 CSV + +230 +00:13:05,786 --> 00:13:09,489 +则存档不会以这种格式导出 + +231 +00:13:09,489 --> 00:13:11,992 +使用此 API 您甚至可以构建 + +232 +00:13:11,992 --> 00:13:14,228 +customTransferRepresentation + +233 +00:13:14,228 --> 00:13:16,930 +就像 SwiftUI 中的 +customViews 一样 + +234 +00:13:16,930 --> 00:13:20,300 +只需要提供 body 属性 + +235 +00:13:20,300 --> 00:13:22,503 +您就可以在其中以您想要的方式 + +236 +00:13:22,503 --> 00:13:24,905 +配置其他表示形式 + +237 +00:13:24,905 --> 00:13:27,107 +如果您想重新使用表示形式的组合 + +238 +00:13:27,107 --> 00:13:29,476 +或者您有一些不想公开的 + +239 +00:13:29,476 --> 00:13:32,045 +私有数据表示形式 + +240 +00:13:32,045 --> 00:13:35,249 +这种方法都会起到很大的作用 + +241 +00:13:35,249 --> 00:13:38,685 +Transferable 帮助我 +快速构建了这个 App + +242 +00:13:38,685 --> 00:13:42,723 +并拥有了我想要的所有功能 + +243 +00:13:42,723 --> 00:13:46,460 +我希望它可以帮助您在最短的时间里 + +244 +00:13:46,460 --> 00:13:49,463 +构建出功能最丰富的 App + +245 +00:13:49,463 --> 00:13:51,665 +感谢您参加本期讲座 + +246 +00:13:51,665 --> 00:13:54,201 +祝您可以设计出最棒的 App! + +247 +00:13:54,201 --> 00:13:58,472 +♪ + diff --git a/zho/2022 Session 10063 Accelerate machine learning with Metal.srt b/zho/2022 Session 10063 Accelerate machine learning with Metal.srt new file mode 100644 index 0000000..c0fa520 --- /dev/null +++ b/zho/2022 Session 10063 Accelerate machine learning with Metal.srt @@ -0,0 +1,2008 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,510 --> 00:00:12,913 +Dhruva: 欢迎来到 WWDC 2022 + +3 +00:00:12,946 --> 00:00:16,517 +我叫 Dhruva 是一名 GPU 软件工程师 + +4 +00:00:16,550 --> 00:00:21,522 +今天 Matteo 和我将探索 +今年在 Metal 中 + +5 +00:00:21,555 --> 00:00:25,726 +为机器学习引入的 +所有新功能和增强功能 + +6 +00:00:25,759 --> 00:00:29,730 +机器学习训练是 ML 管线中 + +7 +00:00:29,763 --> 00:00:31,665 +计算最密集的过程 + +8 +00:00:31,698 --> 00:00:37,371 +由于其并行性 +GPU 在 ML 工作负载方面表现出色 + +9 +00:00:37,404 --> 00:00:41,074 +Metal 机器学习 API +是通过一个 + +10 +00:00:41,108 --> 00:00:44,811 +叫做 Metal Performance Shaders +或者简写为 MPS 的框架公开的 + +11 +00:00:44,845 --> 00:00:49,082 +MPS 是一个高性能 GPU 元操作的集合 + +12 +00:00:49,116 --> 00:00:53,387 +用于图像处理 线性代数 光线跟踪 + +13 +00:00:53,420 --> 00:00:56,290 +和机器学习等各个领域 + +14 +00:00:56,323 --> 00:01:00,460 +这些 Metal 内核经过优化 +可在我们的所有平台上 + +15 +00:01:00,494 --> 00:01:02,362 +提供最佳性能 + +16 +00:01:02,396 --> 00:01:05,699 +例如 MPSImageCanny 过滤器 + +17 +00:01:05,732 --> 00:01:08,702 +返回输入图像的边缘图 + +18 +00:01:08,735 --> 00:01:12,773 +这是图像分割 App 中的常见操作 + +19 +00:01:12,806 --> 00:01:16,143 +今年 Canny 滤波器处理 + +20 +00:01:16,176 --> 00:01:21,181 +4K 高分辨率图像的速度提高了八倍 + +21 +00:01:21,215 --> 00:01:24,618 +MPS Graph 是 GPU 的通用计算图 + +22 +00:01:24,651 --> 00:01:28,188 +基于 MPS 框架构建 + +23 +00:01:28,222 --> 00:01:32,025 +并扩展了对多维张量的支持 + +24 +00:01:32,059 --> 00:01:35,429 +我建议您观看上一个讲座 以获得更多 + +25 +00:01:35,462 --> 00:01:38,532 +关于如何使用 +MPS Graph 的详细信息 + +26 +00:01:38,565 --> 00:01:42,769 +像 CoreML 和 Tensorflow 这样的 +高层 ML 框架 + +27 +00:01:42,803 --> 00:01:44,972 +基于 MPS Graph 来实现 + +28 +00:01:45,005 --> 00:01:48,809 +您可以使用 TensorFlow Metal 插件 + +29 +00:01:48,842 --> 00:01:51,411 +在 GPU 上加速 TensorFlow 网络 + +30 +00:01:51,445 --> 00:01:54,581 +有关如何充分利用 +TensorFlow 的更多信息 + +31 +00:01:54,615 --> 00:01:57,417 +请查看去年的讲座 + +32 +00:01:57,451 --> 00:02:01,188 +Matteo 和我将在这个讲座里 +讨论三个主题 + +33 +00:02:01,221 --> 00:02:06,727 +首先 我将介绍 Apple GPU 支持的 +最新 ML 框架 + +34 +00:02:06,760 --> 00:02:07,828 +PyTorch + +35 +00:02:07,861 --> 00:02:14,034 +接下来 我将深入讨论 +今年对 TensorFlow 所做的增强 + +36 +00:02:14,067 --> 00:02:19,339 +最后 Matteo 将介绍 +MPS Graph 框架中的新功能 + +37 +00:02:20,674 --> 00:02:25,913 +我们非常高兴您现在能够 +在 Mac GPUs 上 + +38 +00:02:25,946 --> 00:02:27,948 +加速 PyTorch 网络 + +39 +00:02:27,981 --> 00:02:32,653 +PyTorch 是一个流行的 +开源机器学习框架 + +40 +00:02:32,686 --> 00:02:37,057 +PyTorch 社区中呼声最高的功能 + +41 +00:02:37,090 --> 00:02:41,361 +是支持 Apple 芯片上的 GPU 加速 + +42 +00:02:41,395 --> 00:02:44,364 +我们通过向 PyTorch 生态系统 +引入新的 MPS 后端 + +43 +00:02:44,398 --> 00:02:50,037 +将 Metal 的能力带入 PyTorch + +44 +00:02:50,070 --> 00:02:56,210 +这个后端将成为 +PyTorch 1.12 官方版本的一部分 + +45 +00:02:56,243 --> 00:03:00,380 +MPS 后端实现了 PyTorch 操作内核 + +46 +00:03:00,414 --> 00:03:02,749 +以及运行时框架 + +47 +00:03:02,783 --> 00:03:06,987 +操作调用 MPS Graph 和 MPS + +48 +00:03:07,020 --> 00:03:10,424 +运行时组件使用 Metal + +49 +00:03:10,457 --> 00:03:14,995 +这使得 PyTorch 能够使用 +MPS 的高效内核 + +50 +00:03:15,028 --> 00:03:17,364 +以及 Metal 的指令队列 + +51 +00:03:17,397 --> 00:03:20,901 +指令缓冲区和同步原语 + +52 +00:03:22,336 --> 00:03:26,974 +操作内核和 +PyTorch MPS 运行时组件 + +53 +00:03:27,007 --> 00:03:29,109 +是开源代码的一部分 + +54 +00:03:29,142 --> 00:03:32,579 +合并到了官方的 +PyTorch GitHub repo 中 + +55 +00:03:32,613 --> 00:03:37,484 +使用 MPS PyTorch 后端 +是一个简单的三步过程 + +56 +00:03:37,518 --> 00:03:40,854 +首先 从 PyTorch 1.12 开始 + +57 +00:03:40,888 --> 00:03:44,958 +您可以使用 +pip install torch 安装基础包 + +58 +00:03:44,992 --> 00:03:49,329 +这个包可以在官方 python +包存储库中找到 + +59 +00:03:49,363 --> 00:03:53,033 +有关环境设置和安装的更多详细信息 + +60 +00:03:53,066 --> 00:03:57,237 +请参阅 +Metal Developer Resources 网页 + +61 +00:03:57,271 --> 00:04:01,608 +然后导入 PyTorch 并创建 MPS 设备 + +62 +00:04:01,642 --> 00:04:04,945 +如果 MPS 设备后端可用 + +63 +00:04:04,978 --> 00:04:09,016 +此代码段将使用该后端 +否则将返回到 CPU + +64 +00:04:09,049 --> 00:04:14,621 +最后一步是转换您的模型和输入 +以使用 MPS 设备 + +65 +00:04:14,655 --> 00:04:16,590 +为了演示如何做到这一点 + +66 +00:04:16,623 --> 00:04:19,493 +我将使用一个示例 该示例在来自 + +67 +00:04:19,526 --> 00:04:23,664 +torchvision 预训练的 +ResNet50 模型上运行推理 + +68 +00:04:23,697 --> 00:04:27,301 +默认情况下 该模型将在 CPU 上运行 + +69 +00:04:27,334 --> 00:04:32,306 +您可以使用 to 方法 +将模型转换为使用 MPS 设备 + +70 +00:04:32,339 --> 00:04:36,443 +这确保了模型内部的中间张量 + +71 +00:04:36,476 --> 00:04:39,813 +也将使用加速的 MPS 后端 + +72 +00:04:39,847 --> 00:04:42,249 +最后 您可以运行模型了 + +73 +00:04:42,282 --> 00:04:47,521 +本示例将随机输入张量 +传递给 MPS 模型 + +74 +00:04:47,554 --> 00:04:51,592 +默认情况下 +所有张量都分配在 CPU 上 + +75 +00:04:51,625 --> 00:04:53,694 +为了使用 MPS 后端 + +76 +00:04:53,727 --> 00:04:58,031 +您还需要在此处提供 MPS 设备 + +77 +00:04:58,065 --> 00:05:03,770 +对这个张量的所有后续操作 +都将在 GPU 上加速 + +78 +00:05:03,804 --> 00:05:09,009 +最后 将样本输入 +传递给 MPS_model 以获得预测 + +79 +00:05:09,042 --> 00:05:12,112 +现在您已经知道了 +如何使用 MPS 设备 + +80 +00:05:12,145 --> 00:05:15,516 +我将向您展示 PyTorch 的一个实例 + +81 +00:05:15,549 --> 00:05:17,951 +我一直想成为一名著名的艺术家 + +82 +00:05:17,985 --> 00:05:21,889 +所以我决定使用机器学习 +和我的 GPU + +83 +00:05:21,922 --> 00:05:25,826 +来帮助我使用 StyleTransfer 网络 +创作艺术品 + +84 +00:05:25,859 --> 00:05:30,564 +这个网络允许您将不同的艺术风格 +应用于一幅图像 + +85 +00:05:30,597 --> 00:05:34,735 +在本实例中 我们的目标是学习如何 +将梵高在星夜中的风格 + +86 +00:05:34,768 --> 00:05:37,437 +应用于这张猫的照片 + +87 +00:05:37,471 --> 00:05:41,575 +借助新的 MPS 设备 +您将能够使用 GPU + +88 +00:05:41,608 --> 00:05:45,312 +更快地训练 PyTorch 网络 + +89 +00:05:45,345 --> 00:05:48,615 +为了演示这一点 我将在一台 + +90 +00:05:48,649 --> 00:05:53,320 +M1 Max 上同时 +在 CPU 和 GPU 上训练这个网络 + +91 +00:05:53,353 --> 00:05:56,857 +学习这种风格需要数千次迭代 + +92 +00:05:56,890 --> 00:06:01,929 +但 GPU 能够在更短的时间内 +收敛到一个合理的模型 + +93 +00:06:03,897 --> 00:06:07,568 +除了 StyleTransfer +我们还在所有 PyTorch 基准测试中 + +94 +00:06:07,601 --> 00:06:10,137 +看到了惊人的加速 + +95 +00:06:10,170 --> 00:06:15,075 +在 M1 Ultra 上 +我们看到速度提高了 20 倍 + +96 +00:06:15,108 --> 00:06:18,612 +平均速度提高了 8.3 倍 + +97 +00:06:18,645 --> 00:06:22,583 +PyTorch 使机器学习模型的开发 +变得很容易 + +98 +00:06:22,616 --> 00:06:27,688 +通过使用 Apple GPU 对其进行训练 +您将节省大量时间 + +99 +00:06:27,721 --> 00:06:33,727 +接下来 我将深入讨论我们今年 +对 TensorFlow 所做的所有增强 + +100 +00:06:33,760 --> 00:06:37,331 +从 Tensorflow 2.5 版开始 + +101 +00:06:37,364 --> 00:06:40,200 +Tensorflow Metal 加速就可以通过 + +102 +00:06:40,234 --> 00:06:42,970 +Tensorflow Metal 插件来使用了 + +103 +00:06:43,003 --> 00:06:47,741 +从那时起 +又增加了一些附加功能和改进 + +104 +00:06:47,774 --> 00:06:51,879 +其中对训练的增强包括包括更大批量 + +105 +00:06:51,912 --> 00:06:54,948 +新的操作和定制操作支持 + +106 +00:06:54,982 --> 00:06:58,452 +RNN 改进和分布式训练 + +107 +00:06:58,485 --> 00:07:00,854 +TensorFlow Metal 插件版本 + +108 +00:07:00,888 --> 00:07:04,091 +与 TensorFlow 主要版本保持一致 + +109 +00:07:04,124 --> 00:07:06,827 +因此请确保更新 +您的 TensorFlow 软件包 + +110 +00:07:06,860 --> 00:07:10,397 +以获得最新的功能和改进 + +111 +00:07:10,430 --> 00:07:13,367 +我们从更大批量开始 + +112 +00:07:13,400 --> 00:07:17,938 +今年 TensorFlow-Metal 的软件改进 + +113 +00:07:17,971 --> 00:07:21,875 +让您能够利用 +Apple 芯片架构的独特优势 + +114 +00:07:21,909 --> 00:07:26,513 +此图显示了使用不同批量大小 +训练 ResNet50 模型的 + +115 +00:07:26,547 --> 00:07:28,782 +加速效果 + +116 +00:07:28,815 --> 00:07:33,587 +数据显示 批量越大 性能越好 + +117 +00:07:33,620 --> 00:07:38,659 +因为每次梯度更新都更接近真实梯度 + +118 +00:07:38,692 --> 00:07:41,461 +Apple 芯片的统一内存架构 + +119 +00:07:41,495 --> 00:07:45,999 +允许您运行更大的网络或更大的批量 + +120 +00:07:46,033 --> 00:07:49,670 +现在您可以在单个 +Mac Studio 上运行您的工作负载 + +121 +00:07:49,703 --> 00:07:53,407 +而不是将其拆分为一个云集群 +这真的很棒 + +122 +00:07:53,440 --> 00:07:57,311 +Apple 芯片架构还具有高效能功耗比 + +123 +00:07:57,344 --> 00:08:01,381 +这意味着您的网络运行 +比以往任何时候都更高效 + +124 +00:08:01,415 --> 00:08:06,353 +接下来我将谈谈新操作和自定义操作 + +125 +00:08:06,386 --> 00:08:10,357 +Tensorflow Metal +插件现在为各种新操作 + +126 +00:08:10,390 --> 00:08:12,960 +提供了 GPU 加速 + +127 +00:08:12,993 --> 00:08:18,899 +包括 argMin +all pack 以及 adadelta 等等 + +128 +00:08:18,932 --> 00:08:22,569 +但是如果您想要为 tensorflow API +当前不支持的操作 + +129 +00:08:22,603 --> 00:08:26,073 +提供 GPU 加速该怎么办呢 + +130 +00:08:26,106 --> 00:08:30,844 +为此 您需要创建一个自定义操作 + +131 +00:08:30,878 --> 00:08:33,914 +下面是一个简单的卷积网络 + +132 +00:08:33,947 --> 00:08:36,149 +运行两次迭代的示例 + +133 +00:08:36,183 --> 00:08:40,387 +时间线分别表示 GPU 和 CPU 上 + +134 +00:08:40,420 --> 00:08:42,756 +完成的工作 + +135 +00:08:42,789 --> 00:08:46,460 +网络先进行卷积 +之后进行 maxpool-ing 运算 + +136 +00:08:46,493 --> 00:08:50,230 +然后进行 softmax 交叉熵损失运算 + +137 +00:08:50,264 --> 00:08:53,033 +所有这些操作都是通过 MPS Graph + +138 +00:08:53,066 --> 00:08:56,937 +在 TensorFlow Metal 插件中 +由 GPU 加速的 + +139 +00:08:56,970 --> 00:09:00,507 +但您可能希望使用自定义损失函数 + +140 +00:09:00,541 --> 00:09:04,511 +如果没有 MPS GPU 加速 +来实现这一自定义损失 + +141 +00:09:04,545 --> 00:09:08,782 +则需要在 CPU 时间线上 +执行这项工作 + +142 +00:09:08,815 --> 00:09:13,687 +这将引入同步开销并导致 GPU 饥饿状态 + +143 +00:09:13,720 --> 00:09:18,926 +通过在 GPU 上进行这种自定义损失 +您可以获得更好的性能 + +144 +00:09:18,959 --> 00:09:21,628 +为了实现自定义操作 + +145 +00:09:21,662 --> 00:09:26,500 +您需要了解 +TensorFlow MetalStream 协议 + +146 +00:09:26,533 --> 00:09:31,405 +这是用于编码 GPU 操作的协议 + +147 +00:09:31,438 --> 00:09:35,576 +MetalStream 会保留 +对用于编码 GPU 内核的 + +148 +00:09:35,609 --> 00:09:37,411 +MTLCommandBuffer 的引用 + +149 +00:09:37,444 --> 00:09:41,615 +它还暴露出 dispatch_queue +以便在编码时用于 + +150 +00:09:41,648 --> 00:09:45,786 +CPU 端同步 +因为可能有多个线程提交工作 + +151 +00:09:45,819 --> 00:09:51,158 +使用 commit 或 commitAndWait 方法 +将工作提交给 GPU + +152 +00:09:51,191 --> 00:09:55,963 +CommitAndWait 是一个调试工具 +它会一直等待当前命令缓冲区完成 + +153 +00:09:55,996 --> 00:09:59,666 +这样您就可以观察序列化提交 + +154 +00:09:59,700 --> 00:10:04,471 +现在让我们看看如何使用 +这些概念来实现自定义 op + +155 +00:10:04,505 --> 00:10:07,274 +编写自定义操作有三个步骤 + +156 +00:10:07,307 --> 00:10:09,877 +首先是注册操作 + +157 +00:10:09,910 --> 00:10:13,514 +接下来 使用 MetalStream +实现该操作 + +158 +00:10:13,547 --> 00:10:19,219 +最后将操作导入训练脚本并开始使用 + +159 +00:10:19,253 --> 00:10:22,189 +我将从注册操作开始 + +160 +00:10:22,222 --> 00:10:25,826 +使用 TensorFlow 核心 +公开的 REGISTER_OP 宏 + +161 +00:10:25,859 --> 00:10:28,095 +来指定 op 的语义 + +162 +00:10:28,128 --> 00:10:32,165 +以及如何在 +TensorFlow Metal 插件中定义它 + +163 +00:10:32,199 --> 00:10:36,603 +接下来使用 +TensorFlow_MetalStream 实现 op + +164 +00:10:36,637 --> 00:10:40,507 +首先定义 compute 函数 + +165 +00:10:40,541 --> 00:10:44,978 +现在 在这个函数中 +获取输入的 TensorFlow_Tensor 对象 + +166 +00:10:45,012 --> 00:10:50,417 +并定义输出 这可能需要分配 + +167 +00:10:50,450 --> 00:10:55,022 +然后使用 MetalStream 的命令缓冲区 +创建一个编码器 + +168 +00:10:55,055 --> 00:10:57,991 +接下来 定义自定义 GPU 内核 + +169 +00:10:58,025 --> 00:11:00,928 +您的操作应该在 MetalStream + +170 +00:11:00,961 --> 00:11:02,763 +提供的 dispatch_queue 中进行编码 + +171 +00:11:02,796 --> 00:11:07,000 +这确保了来自多个线程的提交 +被序列化 + +172 +00:11:08,802 --> 00:11:12,005 +然后使用 +TensorFlow_MetalStream 协议中 + +173 +00:11:12,039 --> 00:11:14,374 +提供的方法提交内核 + +174 +00:11:16,143 --> 00:11:19,947 +最后 删除对分配张量的引用 + +175 +00:11:21,315 --> 00:11:27,955 +最终 将操作导入到您的训练脚本中 +开始使用它 + +176 +00:11:27,988 --> 00:11:35,062 +在这一步中 构建定制 op 的 +共享动态库文件 zero_out.so + +177 +00:11:35,095 --> 00:11:37,130 +有关如何构建和导入 .so 文件的信息 + +178 +00:11:37,164 --> 00:11:41,235 +请参阅 Metal Developer Resources + +179 +00:11:41,268 --> 00:11:45,172 +此示例通过使用 +TensorFlow load_op_library + +180 +00:11:45,205 --> 00:11:48,141 +将操作导入到训练脚本中 + +181 +00:11:48,175 --> 00:11:50,043 +这是一个可选步骤 + +182 +00:11:50,077 --> 00:11:52,746 +现在 这就像一个 python 包装器 + +183 +00:11:52,779 --> 00:11:56,884 +我们的自定义 op +可以在训练脚本中调用 + +184 +00:11:56,917 --> 00:12:00,687 +接下来 我想给您看一个 +有趣的应用例子 + +185 +00:12:00,721 --> 00:12:04,024 +叫做神经辐射场 或 NeRF + +186 +00:12:04,057 --> 00:12:08,328 +我们编写了一个自定义操作 +通过启用 GPU 加速 + +187 +00:12:08,362 --> 00:12:12,766 +实现更好的算法 +从而提高了网络的性能 + +188 +00:12:13,901 --> 00:12:18,472 +NeRF 是一种用于合成 +模型 3D 视图的网络 + +189 +00:12:18,505 --> 00:12:23,710 +为了训练 NeRF 从不同角度 +获取一个物体的图像作为输入 + +190 +00:12:23,744 --> 00:12:28,382 +NeRF 网络由两个堆叠的 +多层感知器组成 + +191 +00:12:28,415 --> 00:12:32,819 +输出模型的体积化表示 + +192 +00:12:32,853 --> 00:12:35,956 +实时训练的关键性能优化 + +193 +00:12:35,989 --> 00:12:38,592 +使用哈希表来实现 + +194 +00:12:38,625 --> 00:12:43,564 +更新的网络允许更小的多层感知器 + +195 +00:12:43,597 --> 00:12:46,967 +TensorFlow 本身不支持哈希表 + +196 +00:12:47,000 --> 00:12:49,236 +所以我们使用自定义 op 功能 + +197 +00:12:49,269 --> 00:12:52,005 +在 Metal 插件中实现它们 + +198 +00:12:52,039 --> 00:12:58,011 +哈希表的 GPU 加速 +可以更快地训练 NeRF + +199 +00:12:58,045 --> 00:12:59,947 +我将从这台 MacBook 开始 + +200 +00:12:59,980 --> 00:13:03,817 +运行原始的多层感知器实现过程 + +201 +00:13:06,186 --> 00:13:10,724 +为了呈现出合理的内容 +我们至少需要 20 个 epoch + +202 +00:13:10,757 --> 00:13:13,727 +但每个 epoch 大约需要 100 秒 + +203 +00:13:13,760 --> 00:13:17,798 +这意味着大约需要30分钟 +才能看到一些东西 + +204 +00:13:17,831 --> 00:13:22,636 +因此 现在我将从预先训练的 +检查点文件中重新开始训练 + +205 +00:13:22,669 --> 00:13:26,073 +该文件需要提前 30 分钟进行训练 + +206 +00:13:26,106 --> 00:13:28,675 +这要从 epoch 20 开始 + +207 +00:13:28,709 --> 00:13:33,780 +即使经过 30 分钟的训练 +3D 模型也是模糊不清的 + +208 +00:13:33,814 --> 00:13:37,017 +网络需要更长的训练时间 + +209 +00:13:37,050 --> 00:13:38,719 +来学习更清晰的模型 + +210 +00:13:38,752 --> 00:13:42,256 +原有的两层堆叠多层感知器方法 + +211 +00:13:42,289 --> 00:13:45,559 +没有自定义哈希表 速度太慢 + +212 +00:13:45,592 --> 00:13:49,363 +现在 在这台 MacBook 上 +我将推出使用自定义哈希表的 + +213 +00:13:49,396 --> 00:13:52,299 +优化版本 + +214 +00:13:52,332 --> 00:13:57,037 +这种实现过程已经能够 +呈现更清晰的模型 + +215 +00:13:57,070 --> 00:14:00,641 +并且每个 epoch 仅需要 10 秒来学习 + +216 +00:14:00,674 --> 00:14:02,910 +有关该项目的更多信息 + +217 +00:14:02,943 --> 00:14:07,981 +请查看我们上传到 +Metal Developer Resources 的示例代码 + +218 +00:14:09,683 --> 00:14:13,253 +NeRF 只是众多网络中的一个 + +219 +00:14:13,287 --> 00:14:17,958 +它展示了如何为您自己的 +定制操作实现 GPU 加速 + +220 +00:14:17,991 --> 00:14:20,727 +从而使您的网络运行得非常快 + +221 +00:14:20,761 --> 00:14:24,331 +我期待着进一步了解 + +222 +00:14:24,364 --> 00:14:26,400 +您所做的所有创造性定制 + +223 +00:14:26,433 --> 00:14:30,270 +现在我想向您展示如何使用 + +224 +00:14:30,304 --> 00:14:33,207 +Apple GPU 来分布 +ML 工作负载的训练 + +225 +00:14:33,240 --> 00:14:35,976 +为了分布工作负载的训练 + +226 +00:14:36,009 --> 00:14:40,848 +您可以在单独的流程中 +运行训练脚本的多个实例 + +227 +00:14:40,881 --> 00:14:45,018 +其中每个进程评估模型的单个迭代 + +228 +00:14:46,286 --> 00:14:50,090 +每个进程将从中央数据存储中 +读取数据 + +229 +00:14:50,123 --> 00:14:55,662 +之后 它将运行模型并计算模型梯度 + +230 +00:14:55,696 --> 00:15:00,167 +接下来 该进程将计算梯度的平均值 +并相互通信 + +231 +00:15:00,200 --> 00:15:06,073 +以便在下一次迭代之前 +每个进程都具有相同的梯度 + +232 +00:15:06,106 --> 00:15:10,043 +最后 模型被更新 您可以重复这个过程 + +233 +00:15:10,077 --> 00:15:13,180 +直到所有的迭代都结束 + +234 +00:15:13,213 --> 00:15:15,415 +为了在 TensorFlow 上演示这一点 + +235 +00:15:15,449 --> 00:15:18,118 +我将使用一个分布式训练的例子 + +236 +00:15:18,151 --> 00:15:22,155 +我将使用一个流行的开源框架 +Horovod 来进行分布式训练 + +237 +00:15:23,724 --> 00:15:27,194 +Horovod 使用环形全归约算法 + +238 +00:15:27,227 --> 00:15:31,064 +在该算法中 N 个节点中的每个节点 +与其两个对等节点 + +239 +00:15:31,098 --> 00:15:34,101 +进行多次通信 + +240 +00:15:34,134 --> 00:15:37,938 +使用这种通信方式 +工作进程在每次迭代之前 + +241 +00:15:37,971 --> 00:15:40,741 +同步梯度 + +242 +00:15:40,774 --> 00:15:44,211 +我将使用四个通过 +Thunderbolt 电缆相互连接的 + +243 +00:15:44,244 --> 00:15:47,414 +Mac Studio 来展示这一点 + +244 +00:15:47,447 --> 00:15:53,120 +在这个示例中 我将训练 ResNet +这是一个图像分类器 + +245 +00:15:53,153 --> 00:15:58,025 +每个 Mac Studio 旁边的柱状图 +显示了训练此网络时 + +246 +00:15:58,058 --> 00:15:59,793 +GPU 的利用率 + +247 +00:15:59,826 --> 00:16:04,665 +对于单个 Mac Studio +性能约为每秒 200 张图像 + +248 +00:16:04,698 --> 00:16:08,468 +当我添加另一个通过 Thunderbolt +连接的 Mac Studio 时 + +249 +00:16:08,502 --> 00:16:12,706 +性能几乎翻了一番 +达到每秒 400 张图像 + +250 +00:16:12,739 --> 00:16:16,710 +因为两个 GPU 都得到了充分利用 + +251 +00:16:16,743 --> 00:16:19,713 +最后 当我连接 +两个以上的 Mac Studio 时 + +252 +00:16:19,746 --> 00:16:24,051 +性能提升到每秒 800 张图像 + +253 +00:16:24,084 --> 00:16:28,322 +受限于计算的训练工作负载 +几乎是以线性扩展 + +254 +00:16:30,090 --> 00:16:34,995 +现在我们来看一下 +TensorFlow 的分布式训练性能 + +255 +00:16:35,028 --> 00:16:41,034 +这个图表显示了一个 两个和四个 +Mac Studio 的相对加速 + +256 +00:16:41,068 --> 00:16:45,939 +它们以环形拓扑连接 +并使用最新的 TensorFlow Metal 插件 + +257 +00:16:45,973 --> 00:16:48,442 +和 Horovod 运行计算 +绑定 TensorFlow 网络 + +258 +00:16:48,475 --> 00:16:52,813 +如 resNet 和 DistilBERT + +259 +00:16:52,846 --> 00:16:57,050 +基础是单个 Mac Studio 上的性能 + +260 +00:16:57,084 --> 00:17:02,422 +该图显示 随着每个 GPU 的增加 +网络性能会随之扩展 + +261 +00:17:02,456 --> 00:17:05,859 +因此您现在可以 +在多个设备上使用 GPU + +262 +00:17:05,893 --> 00:17:07,394 +以加快您的训练时间 + +263 +00:17:07,427 --> 00:17:10,697 +并充分利用所有 Apple 设备 + +264 +00:17:12,032 --> 00:17:15,636 +今年针对 TensorFlow 的所有改进 + +265 +00:17:15,669 --> 00:17:19,373 +和功能最终都体现在这张图表中 + +266 +00:17:19,406 --> 00:17:21,542 +该图表显示了 +相对于 CPU 实现的性能 + +267 +00:17:21,575 --> 00:17:24,344 +未来还会有更多改进 + +268 +00:17:24,378 --> 00:17:29,449 +现在 Matteo 将分享 +MPS Graph 框架中的新内容 + +269 +00:17:30,184 --> 00:17:31,318 +Matteo: 谢谢您 Dhruva + +270 +00:17:31,351 --> 00:17:35,756 +大家好 我叫 Matteo +是一名 GPU 软件工程师 + +271 +00:17:35,789 --> 00:17:41,028 +PyTorch 和 TensorFlow +位于 MPS 图形框架之上 + +272 +00:17:41,061 --> 00:17:45,199 +反过来 MPS Graph 使用 MPS 框架 + +273 +00:17:45,232 --> 00:17:50,103 +提供的并行原语 +来加速 GPU 上的工作 + +274 +00:17:50,137 --> 00:17:54,241 +今天我将讨论使用 MPS Graph + +275 +00:17:54,274 --> 00:17:58,979 +进一步加速计算工作负载的两个功能 + +276 +00:17:59,012 --> 00:18:02,216 +首先 我将展示新的共享事件 API + +277 +00:18:02,249 --> 00:18:05,953 +它允许您在两个Graph 之间同步工作 + +278 +00:18:05,986 --> 00:18:08,922 +接着 我将介绍新的操作 + +279 +00:18:08,956 --> 00:18:13,060 +您可以使用 MPS Graph +做更多的事情 + +280 +00:18:13,093 --> 00:18:15,996 +我将从共享事件 API 开始 + +281 +00:18:16,029 --> 00:18:19,132 +在同一个命令队列上运行应用 + +282 +00:18:19,166 --> 00:18:22,736 +可以确保工作负载之间的同步 + +283 +00:18:22,769 --> 00:18:26,440 +在本例中 保证计算工作负载 + +284 +00:18:26,473 --> 00:18:29,209 +总是在调度其他工作负载之前终止 + +285 +00:18:29,243 --> 00:18:33,380 +如后期处理和显示 + +286 +00:18:33,413 --> 00:18:37,150 +在这种情况下 您将在每个调用中 + +287 +00:18:37,184 --> 00:18:39,753 +利用 GPU 并行性 + +288 +00:18:39,786 --> 00:18:44,358 +然而 一些 App 可能会受益于 +更多的并行性 + +289 +00:18:44,391 --> 00:18:47,995 +其中 GPU 的第一部分用于计算 + +290 +00:18:48,028 --> 00:18:52,666 +第二部分用于后处理和显示 + +291 +00:18:52,699 --> 00:18:58,605 +这可以通过在多个命令队列上 +向 GPU 提交工作来实现 + +292 +00:18:58,639 --> 00:19:01,975 +不幸的是 在这种情况下 +可能会在 + +293 +00:19:02,009 --> 00:19:06,146 +计算产生结果之前调度后处理管道 + +294 +00:19:06,180 --> 00:19:09,449 +从而引入数据竞争 + +295 +00:19:09,483 --> 00:19:13,554 +Shared Event API 可以用来解决这个问题 + +296 +00:19:13,587 --> 00:19:16,723 +并引入跨命令队列的同步 + +297 +00:19:16,757 --> 00:19:21,428 +以确保满足工作流依赖性 + +298 +00:19:21,461 --> 00:19:25,566 +在代码中使用共享事件非常简单 + +299 +00:19:25,599 --> 00:19:29,169 +我们假设您正在处理两个 Graph + +300 +00:19:29,203 --> 00:19:32,873 +第一个负责计算工作负载 + +301 +00:19:32,906 --> 00:19:37,277 +第二个负责后处理工作量 + +302 +00:19:37,311 --> 00:19:41,815 +我们还要假设计算图的结果被用作 + +303 +00:19:41,849 --> 00:19:43,550 +后处理图的输入 + +304 +00:19:43,584 --> 00:19:47,187 +并且它们运行在不同的命令队列上 + +305 +00:19:47,221 --> 00:19:51,258 +Metal System Trace 中的 +新 MPS Graph 轨迹 + +306 +00:19:51,291 --> 00:19:55,329 +表明命令队列相互重叠 + +307 +00:19:55,362 --> 00:19:58,398 +这会产生数据竞争 + +308 +00:19:58,432 --> 00:20:01,902 +您可以使用共享事件来解决这个问题 + +309 +00:20:01,935 --> 00:20:05,906 +首先 使用 Metal 设备创建事件 + +310 +00:20:05,939 --> 00:20:10,477 +接下来 调用执行描述符中的 +信号方法 + +311 +00:20:10,511 --> 00:20:14,248 +提供事件 动作和值 + +312 +00:20:14,281 --> 00:20:18,552 +然后您所要做的就是 +在第二个描述符上 + +313 +00:20:18,585 --> 00:20:20,087 +调用 wait 方法 + +314 +00:20:20,120 --> 00:20:23,156 +提供事件变量和值 + +315 +00:20:24,658 --> 00:20:29,596 +现在 Metal System Trace 表明 +两个命令队列是 + +316 +00:20:29,630 --> 00:20:32,866 +按顺序运行的 +并且计算和后处理图之间的 + +317 +00:20:32,900 --> 00:20:37,137 +依赖关系已经解决 + +318 +00:20:37,171 --> 00:20:41,141 +这就是如何使用共享事件 +来解决 App 中的 + +319 +00:20:41,175 --> 00:20:43,043 +同步问题 + +320 +00:20:43,076 --> 00:20:48,348 +接着 我来说说 +MPS Graph 支持的新操作 + +321 +00:20:48,382 --> 00:20:52,619 +这些操作允许您 +使用框架做更多的事情 + +322 +00:20:52,653 --> 00:20:58,458 +我将从 RNNs 开始 +介绍这些新操作的一些细节 + +323 +00:20:59,760 --> 00:21:03,797 +MPS Graph 现在公开了 +递归神经网络 App 中 + +324 +00:21:03,830 --> 00:21:07,334 +常用的三种操作 + +325 +00:21:07,367 --> 00:21:12,172 +就是 RNN LSTM 和 GRU 层 + +326 +00:21:12,206 --> 00:21:14,808 +这些操作都是相似的 + +327 +00:21:14,842 --> 00:21:18,979 +所以我今天只关注 LSTM + +328 +00:21:19,012 --> 00:21:23,217 +LSTM 运算通常用于自然语言处理 + +329 +00:21:23,250 --> 00:21:25,552 +和其他 App + +330 +00:21:25,586 --> 00:21:29,790 +下图显示了 LSTM 操作的工作原理 + +331 +00:21:29,823 --> 00:21:35,529 +想了解更多信息 +请查看我们之前的 WWDC 讲座 + +332 +00:21:35,562 --> 00:21:39,600 +您可以自己完成 LSTM 单元 + +333 +00:21:39,633 --> 00:21:43,637 +但要做到这一点 +您必须构建这个相当复杂的自定义子图 + +334 +00:21:43,670 --> 00:21:47,508 +相反 您可以使用新的 LSTM 操作 + +335 +00:21:47,541 --> 00:21:53,647 +它可以有效地对重复单元所需的 +所有 GPU 工作进行编码 + +336 +00:21:53,680 --> 00:21:59,586 +这种新操作大大加快了 +基于 LSTM 的 CoreML 推理模型的速度 + +337 +00:22:01,388 --> 00:22:03,557 +要使用新的 LSTM 操作 + +338 +00:22:03,590 --> 00:22:08,529 +首先创建一个 +MPS GraphLSTMDescriptor + +339 +00:22:08,562 --> 00:22:11,798 +您可以根据需要修改描述符属性 + +340 +00:22:11,832 --> 00:22:15,636 +例如选择激活函数 + +341 +00:22:15,669 --> 00:22:18,705 +接下来 将 LSTM 单元添加到图中 + +342 +00:22:18,739 --> 00:22:21,275 +提供输入张量 + +343 +00:22:21,308 --> 00:22:23,911 +您还可以提供一个偏差向量 + +344 +00:22:23,944 --> 00:22:27,714 +以及操作的初始状态和单元格 + +345 +00:22:27,748 --> 00:22:30,450 +最后 提供描述符 + +346 +00:22:30,484 --> 00:22:34,154 +这就是设置 LSTM 所需要做的全部工作 + +347 +00:22:34,188 --> 00:22:38,058 +RNN 的其他操作也类似 + +348 +00:22:38,091 --> 00:22:40,694 +我鼓励您尝试这些操作 + +349 +00:22:40,727 --> 00:22:44,431 +看看您的 App +可以获得什么样的加速 + +350 +00:22:44,464 --> 00:22:48,869 +接下来 我将向您展示 +对 Max Pooling 的改进支持 + +351 +00:22:48,902 --> 00:22:53,540 +Max Pooling 操作采用 +输入张量和窗口大小 + +352 +00:22:53,574 --> 00:22:56,543 +为窗口的每个应用 + +353 +00:22:56,577 --> 00:23:00,314 +计算窗口内输入的最大值 + +354 +00:23:00,347 --> 00:23:05,686 +它通常用于计算机视觉中 +以降低图像的维度 + +355 +00:23:05,719 --> 00:23:10,891 +该 API 已被扩展为 +返回池化操作符提取的 + +356 +00:23:10,924 --> 00:23:13,093 +最大值位置的索引 + +357 +00:23:13,126 --> 00:23:15,729 +您可以在梯度通道中使用索引 + +358 +00:23:15,762 --> 00:23:19,433 +其中梯度必须传播到 + +359 +00:23:19,466 --> 00:23:23,170 +已提取出最大值的位置 + +360 +00:23:23,203 --> 00:23:26,573 +新的 API 也适用于训练 + +361 +00:23:26,607 --> 00:23:30,844 +对于 PyTorch 和 TensorFlow +在训练期间重复使用索引的速度 + +362 +00:23:30,878 --> 00:23:33,380 +可以提高六倍 + +363 +00:23:34,515 --> 00:23:40,254 +要在代码中对此进行设置 +首先需要创建 GraphPooling 描述符 + +364 +00:23:40,287 --> 00:23:42,723 +您可以指定 returnIndicesMode + +365 +00:23:42,756 --> 00:23:46,593 +例如 globalFlatten4D + +366 +00:23:46,627 --> 00:23:53,233 +然后您可以使用 Return Indices API +来调用图上的池操作 + +367 +00:23:53,267 --> 00:23:56,203 +操作的结果是双重的 + +368 +00:23:56,236 --> 00:24:01,475 +第一个是 poolingTensor +第二个是 indicesTensor + +369 +00:24:01,508 --> 00:24:04,711 +您可以缓存索引张量以备后用 + +370 +00:24:04,745 --> 00:24:07,748 +例如在训练管道上使用 + +371 +00:24:09,316 --> 00:24:13,654 +MPS Graph 现在公开了 +一个新的并行随机数生成器 + +372 +00:24:13,687 --> 00:24:15,722 +举个例子 它可以用来 + +373 +00:24:15,756 --> 00:24:19,226 +初始化训练图的权重 + +374 +00:24:19,259 --> 00:24:22,863 +新的随机操作使用 Philox 算法 + +375 +00:24:22,896 --> 00:24:28,135 +并为给定的种子返回 +与 TensorFlow 相同的结果 + +376 +00:24:28,168 --> 00:24:31,772 +新的运算以一个状态张量作为输入 + +377 +00:24:31,805 --> 00:24:34,608 +它返回一个随机张量作为输出 + +378 +00:24:34,641 --> 00:24:38,078 +而且该随机张量可以用作 +新的状态张量 举个例子 + +379 +00:24:38,111 --> 00:24:41,148 +可以将其用作第二个随机操作的输入 + +380 +00:24:41,181 --> 00:24:43,517 +要使用新的随机运算 + +381 +00:24:43,550 --> 00:24:46,787 +请调用 +randomPhiloxStateTensor 方法 + +382 +00:24:46,820 --> 00:24:52,192 +这个方法用给定的种子 +初始化一个输入状态张量 + +383 +00:24:52,226 --> 00:24:55,329 +然后声明 RandomOp 描述符 + +384 +00:24:55,362 --> 00:24:59,466 +它将分布和数据类型作为输入 + +385 +00:24:59,499 --> 00:25:02,102 +在示例中 描述符指定了 + +386 +00:25:02,135 --> 00:25:07,574 +32 位浮点值的截断正态分布 + +387 +00:25:07,608 --> 00:25:11,745 +您也可以使用正态分布和均匀分布 + +388 +00:25:12,846 --> 00:25:15,782 +通过指定平均值 + +389 +00:25:15,816 --> 00:25:18,719 +标准差 最小值和最大值 + +390 +00:25:18,752 --> 00:25:21,889 +您可以进一步定义分布特征 + +391 +00:25:21,922 --> 00:25:26,326 +最后 您可以创建随机操作 +提供刚刚创建的 + +392 +00:25:26,360 --> 00:25:29,663 +形状张量 描述符和状态张量 + +393 +00:25:32,199 --> 00:25:34,067 +除了 Random 之外 + +394 +00:25:34,101 --> 00:25:37,905 +MPS Graph 现在还支持 +一种新的 GPU 加速操作 + +395 +00:25:37,938 --> 00:25:42,109 +来计算两个位向量之间的汉明距离 + +396 +00:25:42,142 --> 00:25:45,279 +汉明距离被定义为 + +397 +00:25:45,312 --> 00:25:48,215 +两个长度相同的输入之间不同的位数 + +398 +00:25:48,248 --> 00:25:51,718 +是两个序列之间编辑距离的度量 + +399 +00:25:51,752 --> 00:25:58,192 +它被用于从生物信息学 +到密码学的若干应用 + +400 +00:25:58,225 --> 00:26:01,728 +要使用汉明距离 +请在图形上调用 API + +401 +00:26:01,762 --> 00:26:06,867 +提供 primaryTensor +secondaryTensor 和结果数据类型 + +402 +00:26:06,900 --> 00:26:11,138 +请注意 新内核支持在 GPU 上 +通过批处理维度 + +403 +00:26:11,171 --> 00:26:13,941 +进行广播 + +404 +00:26:13,974 --> 00:26:18,612 +现在 我将向您展示新的张量操作 + +405 +00:26:18,645 --> 00:26:20,347 +这些操作非常容易使用 + +406 +00:26:20,380 --> 00:26:24,084 +您现在可以扩展张量的维度 + +407 +00:26:24,117 --> 00:26:26,720 +例如 从二维扩展到三维 + +408 +00:26:26,753 --> 00:26:28,889 +然后您可以把维度压缩回去 + +409 +00:26:30,524 --> 00:26:36,129 +您也可以平均分割一个张量 +提供多个切片和一个轴 + +410 +00:26:36,163 --> 00:26:39,233 +或者沿着给定的轴堆叠张量 + +411 +00:26:40,834 --> 00:26:44,638 +您还可以为给定的输入形状生成 +沿张量维度的 + +412 +00:26:44,671 --> 00:26:46,740 +坐标值 + +413 +00:26:46,773 --> 00:26:51,111 +例如 您可以用 0 轴上的坐标 + +414 +00:26:51,144 --> 00:26:54,348 +填充形状为 2 乘 4 的张量 + +415 +00:26:54,381 --> 00:26:59,720 +这也可用于实现 range1D 操作 + +416 +00:26:59,753 --> 00:27:03,490 +例如 假设您想要生成 + +417 +00:27:03,524 --> 00:27:07,928 +3 到 27 之间的数字范围 增量为 4 + +418 +00:27:07,961 --> 00:27:10,731 +要做到这一点 您可以先 + +419 +00:27:10,764 --> 00:27:15,002 +在维度 0 上的坐标创建 +形状为 6 的张量 + +420 +00:27:15,035 --> 00:27:21,008 +然后您所要做的就是乘以增量 +再加上偏移量 + +421 +00:27:21,041 --> 00:27:25,179 +这些都是今年新增的操作 + +422 +00:27:25,212 --> 00:27:29,016 +有了这些新的操作 +您将能够使用 MPS Graph + +423 +00:27:29,049 --> 00:27:34,288 +在整个 Apple 生态系统中 +做更多的事情并获得更高的性能 + +424 +00:27:34,321 --> 00:27:37,691 +现在 我将向大家展示 Apple 芯片 + +425 +00:27:37,724 --> 00:27:40,861 +在 MPS 图表之外的性能提升 + +426 +00:27:41,728 --> 00:27:45,766 +Blackmagic 刚刚发布了 +DaVinci Resolve 版本 18 + +427 +00:27:45,799 --> 00:27:50,470 +该版本使用 MPS Graph +来加速机器学习工作负载 + +428 +00:27:50,504 --> 00:27:54,808 +Magic Mask 是 Resolve 的一项功能 +它使用机器学习 + +429 +00:27:54,842 --> 00:28:00,814 +来识别屏幕上的移动对象 +并选择性地在对象上应用滤镜 + +430 +00:28:00,848 --> 00:28:05,185 +首先 我将演示这在以前版本的 +Resolve 中是如何工作的 + +431 +00:28:05,219 --> 00:28:08,889 +然后将它与当前版本进行比较 + +432 +00:28:08,922 --> 00:28:13,060 +要创建遮罩 您只需选择目标对象 + +433 +00:28:13,093 --> 00:28:16,730 +您可以通过切换覆盖来查看遮罩 + +434 +00:28:16,763 --> 00:28:19,399 +遮罩由红色区域标识 + +435 +00:28:19,433 --> 00:28:22,402 +该区域正确标记了主体的形状 + +436 +00:28:22,436 --> 00:28:28,709 +现在 如果我播放视频 当物体 +在屏幕上移动时 遮罩会跟踪它 + +437 +00:28:28,742 --> 00:28:32,212 +这看起来很棒 +但它在以相当低的帧速率运行 + +438 +00:28:32,246 --> 00:28:35,916 +因为机器学习管道在引擎盖下运行 + +439 +00:28:35,949 --> 00:28:39,419 +现在我将切换到最新版本的 Resolve + +440 +00:28:39,453 --> 00:28:44,424 +它使用 MPS Graph +来加速 Magic Mask 网络 + +441 +00:28:44,458 --> 00:28:49,763 +再次运行相同的时间线 +帧速率比以前快了很多 + +442 +00:28:49,796 --> 00:28:54,334 +这在 Apple 芯片上 +带来了更好的编辑体验 + +443 +00:28:55,402 --> 00:29:00,073 +这些是您仅仅通过 +采用 MPS Graph 就能得到的加速 + +444 +00:29:00,107 --> 00:29:04,645 +我鼓励您去探索它能给您的 App +带来什么样的性能 + +445 +00:29:04,678 --> 00:29:07,981 +总而言之 您现在能够 + +446 +00:29:08,015 --> 00:29:10,184 +使用 PyTorch 的 GPU 加速 + +447 +00:29:10,217 --> 00:29:13,420 +该项目现在是开源的 + +448 +00:29:13,453 --> 00:29:16,523 +您将发现用 TensorFlow Metal 插件 + +449 +00:29:16,557 --> 00:29:19,126 +加速训练工作量的新方法 + +450 +00:29:19,159 --> 00:29:23,463 +例如 使用自定义操作和分布式训练 + +451 +00:29:23,497 --> 00:29:28,202 +最后 您还能够利用 MPS Graph 框架 + +452 +00:29:28,235 --> 00:29:29,903 +优化最苛刻的机器学习任务 + +453 +00:29:29,937 --> 00:29:32,206 +利用共享事件和新操作 + +454 +00:29:32,239 --> 00:29:34,842 +充分使用 Apple 芯片 + +455 +00:29:34,875 --> 00:29:38,345 +Dhruva 和我迫不及待地想知道 +您将如何在您的 App 中 + +456 +00:29:38,378 --> 00:29:39,880 +使用这些新功能 + +457 +00:29:39,913 --> 00:29:43,851 +感谢您观看本期讲座 +祝您的 WWDC 之旅一切顺利 + diff --git a/zho/2022 Session 10064 Reach new players with Game Center dashboard.srt b/zho/2022 Session 10064 Reach new players with Game Center dashboard.srt new file mode 100644 index 0000000..310c9db --- /dev/null +++ b/zho/2022 Session 10064 Reach new players with Game Center dashboard.srt @@ -0,0 +1,708 @@ +1 +00:00:00,400 --> 00:00:06,406 +[欢快的音乐] + +2 +00:00:11,712 --> 00:00:16,617 +大家好 我是 Knott +来自 Game Center Engineering 团队 + +3 +00:00:16,650 --> 00:00:20,387 +今天 我给大家演示下我们今年 + +4 +00:00:20,420 --> 00:00:22,656 +Game Center 的改进 + +5 +00:00:22,689 --> 00:00:26,260 +Game Center 是 Apple 的 +社交游戏平台 + +6 +00:00:26,293 --> 00:00:30,931 +玩家可在 Game Center 中 +设置个人档案与好友联机 + +7 +00:00:31,965 --> 00:00:36,003 +您可以轻松使用 GameKit +将 Game Center 整合进来 + +8 +00:00:36,036 --> 00:00:40,307 +玩家可自动注册 与好友 +及排行榜的其他玩家 + +9 +00:00:40,340 --> 00:00:45,512 +对比得分 通过达成成就跟踪进度 + +10 +00:00:45,546 --> 00:00:49,716 +您可以整合资源 安排多人游戏配对 +和实时竞赛 + +11 +00:00:50,717 --> 00:00:54,488 +在过去数年来 +我们推出了 Access Point + +12 +00:00:54,521 --> 00:00:58,425 +重新设计了成就和排行榜体验 + +13 +00:00:58,458 --> 00:01:04,031 +推出好友 API +提升多人游戏体验 + +14 +00:01:04,064 --> 00:01:08,168 +此外 我们也将 Game Center 活动 +进行了跨设备扩展 + +15 +00:01:08,202 --> 00:01:11,839 +包括在 App Store 中查看 + +16 +00:01:11,872 --> 00:01:13,640 +您的好友正在玩的游戏 + +17 +00:01:13,674 --> 00:01:17,477 +创建全新小组件 如继续游戏(Continue Playing) +和朋友在玩(Friends are Playing) + +18 +00:01:18,946 --> 00:01:21,748 +今年 我们更进一步 + +19 +00:01:21,782 --> 00:01:25,719 +提升了所有玩家的游戏体验 +提供了更多渠道公开 + +20 +00:01:25,752 --> 00:01:28,755 +您在游戏中的傲人成绩 + +21 +00:01:28,789 --> 00:01:33,961 +为您提供与 Game Center 整合的 +全新工具 + +22 +00:01:33,994 --> 00:01:37,297 +Activity 将您在 Game Center 中的 +所有事件 + +23 +00:01:37,331 --> 00:01:41,435 +都整合到一个位置 +我会给大家进行演示 + +24 +00:01:41,468 --> 00:01:45,672 +但在演示之前 我要声明一下 + +25 +00:01:45,706 --> 00:01:50,010 +我知道许多游戏开发者们 +都使用 Unity + +26 +00:01:50,043 --> 00:01:53,747 +帮助建立 Apple 平台上的 +游戏体验 + +27 +00:01:53,780 --> 00:01:56,884 +今年 我们推出了专门为 + +28 +00:01:56,917 --> 00:02:00,220 +GameKit 打造的 Unity plug-in + +29 +00:02:01,522 --> 00:02:06,293 +该 plug-in 提供 +完整的 C# GameKit API + +30 +00:02:06,326 --> 00:02:10,330 +所以 您不必在使用 Unity 开发游戏 +以及完全使用 Game Center + +31 +00:02:10,364 --> 00:02:14,902 +一流的游戏功能这两者之间纠结 + +32 +00:02:16,370 --> 00:02:19,406 +在这个 Session 中 +您能同时看到 Swift 和 C# + +33 +00:02:19,439 --> 00:02:23,210 +提供的代码示例 + +34 +00:02:23,243 --> 00:02:27,948 +现在我们进入今年 +Game Center 最大的改变 + +35 +00:02:27,981 --> 00:02:30,417 +这就是活动(Activity) + +36 +00:02:30,450 --> 00:02:33,654 +汇聚了在您游戏中有许多激动人心的事件 + +37 +00:02:33,687 --> 00:02:36,924 +而这些一定也是玩家想和好友分享的 + +38 +00:02:36,957 --> 00:02:42,029 +比如 达成一个新成就 +排行榜排名提升 + +39 +00:02:42,062 --> 00:02:47,067 +今年 我们重新设计了 +Game Center 面板 您在游戏中 + +40 +00:02:47,100 --> 00:02:51,505 +和不同游戏中玩家好友的活动 +可在一个位置显示 + +41 +00:02:52,973 --> 00:02:57,511 +玩家打开面板后 可以看到 +您游戏中的最近活动 + +42 +00:02:57,544 --> 00:03:02,583 +如达成的成就 朋友排行榜排名 +大幅提升 + +43 +00:03:02,616 --> 00:03:06,353 +或一位好友 +超越了另一位好友的得分 + +44 +00:03:06,386 --> 00:03:12,559 +当然 这一功能在 iPad Mac +和 Apple TV 中均适用 + +45 +00:03:12,593 --> 00:03:15,896 +玩家能了解并参与到好友的游戏中 + +46 +00:03:15,929 --> 00:03:18,899 +真的是一件非常令人激动的事 + +47 +00:03:18,932 --> 00:03:22,202 +您的游戏和游戏中所有重大活动 + +48 +00:03:22,236 --> 00:03:24,137 +都能在不同的位置展现 + +49 +00:03:24,171 --> 00:03:29,409 +如果您的游戏已经使用了 +Game Center 那无需过多操作 + +50 +00:03:29,443 --> 00:03:33,046 +您的游戏就会自动 +出现在 Activity 中 + +51 +00:03:33,080 --> 00:03:36,617 +如果没有 要开始也并不难 + +52 +00:03:36,650 --> 00:03:40,053 +您只需要启动 +Game Center 功能 + +53 +00:03:40,087 --> 00:03:45,392 +写下几行代码 +确保能顺利通过验证 + +54 +00:03:45,425 --> 00:03:48,128 +首先 到您游戏的 Xcode 项目 + +55 +00:03:48,161 --> 00:03:51,798 +然后到 Signing +和 Capabilities 选项卡 + +56 +00:03:51,832 --> 00:03:56,837 +点击 add capability 按钮 +然后选择 Game Center + +57 +00:03:56,870 --> 00:03:59,573 +然后 在 App Store Connect +找到您的 App 记录 + +58 +00:03:59,606 --> 00:04:02,676 +从而在您游戏中 +启动 Game Center + +59 +00:04:02,709 --> 00:04:06,847 +您也是在这一界面 +配置 Game Center 功能 + +60 +00:04:06,880 --> 00:04:10,017 +如排行榜和成就 + +61 +00:04:10,050 --> 00:04:14,655 +最后 导入 GameKit +然后通过设置 authenticateHandler + +62 +00:04:14,688 --> 00:04:17,424 +验证本地玩家 + +63 +00:04:17,457 --> 00:04:21,495 +这个代码需尽早加入您游戏中 + +64 +00:04:21,528 --> 00:04:23,564 +甚至是在标题屏幕 + +65 +00:04:23,597 --> 00:04:27,034 +然后 如果 callback 中 +view controller 可用 + +66 +00:04:27,067 --> 00:04:29,102 +就在这里展示 + +67 +00:04:29,136 --> 00:04:34,074 +对 Unity 开发者来说 只需要在 +GKLocalPlayer 中调用 authenticate + +68 +00:04:34,107 --> 00:04:39,046 +这一静态方法在验证后 +就会返回本地玩家对象 + +69 +00:04:39,079 --> 00:04:43,584 +恭喜您 您的游戏现在已成功 +启用 Game Center + +70 +00:04:43,617 --> 00:04:46,954 +玩家登陆您的游戏时 +就能看到这个欢迎横幅 + +71 +00:04:46,987 --> 00:04:52,092 +在玩家的信息流中 +就会出现您游戏的活动 + +72 +00:04:52,125 --> 00:04:58,332 +现在 您只需要为玩家提供 +简单访问面板的方式即可 + +73 +00:04:58,365 --> 00:05:02,402 +通过 Game Center Access Point +无疑是最好的 + +74 +00:05:02,436 --> 00:05:06,273 +Access Point 为您的玩家 +提供了登陆 Game Center 面板的 + +75 +00:05:06,306 --> 00:05:08,542 +便捷方式 + +76 +00:05:08,575 --> 00:05:12,713 +我们回到代码 +展示 Access Point 很简单 + +77 +00:05:12,746 --> 00:05:16,717 +首先 您要决定展现的最佳时机 + +78 +00:05:16,750 --> 00:05:20,220 +您应考虑在游戏中最合理的 +展示方式是什么 + +79 +00:05:20,254 --> 00:05:24,658 +但对大多数游戏来说 +最理想的展示方式在游戏菜单页面 + +80 +00:05:24,691 --> 00:05:27,561 +做好决定后 您只需要 + +81 +00:05:27,594 --> 00:05:30,030 +为其展示确定一个位置 + +82 +00:05:30,063 --> 00:05:35,235 +然后将 GKAccessPoint 的 +isActive 属性设置为 true + +83 +00:05:35,269 --> 00:05:39,573 +最后 Access Point +就会在您的游戏中展示 + +84 +00:05:39,606 --> 00:05:43,877 +这是 Unity 开发者如何使用 +C# 的 GKAccessPoint 的说明 + +85 +00:05:43,911 --> 00:05:48,549 +设置 Access Point 的位置 +将 IsActive 设置为 true + +86 +00:05:48,582 --> 00:05:51,351 +当玩家操作 Access Point时 + +87 +00:05:51,385 --> 00:05:53,954 +系统弹出面板 + +88 +00:05:53,987 --> 00:05:58,091 +为玩家提供一个熟悉的地方 +来了解您的游戏 + +89 +00:05:58,125 --> 00:06:00,994 +以及查看最近活动 + +90 +00:06:01,028 --> 00:06:05,032 +玩家可以探索您游戏的 +独有成就和排行榜 + +91 +00:06:05,065 --> 00:06:10,470 +接下来 玩家会看到您的游戏活动 +在信息流首位展示 + +92 +00:06:10,504 --> 00:06:14,708 +这里您可以看到 我和 Cloeax +Jeezzzy 都在玩 The Coast + +93 +00:06:14,741 --> 00:06:16,543 +只需要这几行代码 + +94 +00:06:16,577 --> 00:06:19,713 +在 Apple 平台中尝试 +更广泛的游戏体验时 + +95 +00:06:19,746 --> 00:06:24,451 +您的游戏就会提高 +用户触及率及分配率 + +96 +00:06:24,484 --> 00:06:29,056 +您游戏中可以添加许多 +可生成 Activity 的功能 + +97 +00:06:29,089 --> 00:06:30,924 +我们首先看看排行榜 + +98 +00:06:30,958 --> 00:06:35,896 +排行榜(Leaderboard)是在 Activity 中 +增加您游戏曝光量的强大方法 + +99 +00:06:35,929 --> 00:06:37,998 +它们鼓励友好竞赛 + +100 +00:06:38,031 --> 00:06:41,969 +为玩家提供更多理由 +回到您的游戏中 + +101 +00:06:42,002 --> 00:06:44,371 +您设置游戏的排行榜后 + +102 +00:06:44,404 --> 00:06:48,876 +好友在排行榜中获得较好成绩时 +玩家会看到新活动 + +103 +00:06:48,909 --> 00:06:53,614 +这里 我的好友在排行榜中的 +排名在前 25% 中 + +104 +00:06:53,647 --> 00:06:58,385 +仅在玩家好友超越其排行榜分数时 +Activity 才会进行强调 + +105 +00:06:58,418 --> 00:07:01,989 +这里 Simundane 在游戏中超越了 +我们的分数 我们俩一直都在 + +106 +00:07:02,022 --> 00:07:03,957 +您追我赶地比拼 + +107 +00:07:03,991 --> 00:07:07,794 +在这个活动中 玩家会受到一则通知 + +108 +00:07:07,828 --> 00:07:10,831 +这一通知是 Game Center 发出的 + +109 +00:07:10,864 --> 00:07:12,900 +您无需担心如何为用户发送 + +110 +00:07:12,933 --> 00:07:16,970 +关于您游戏的通知 + +111 +00:07:17,004 --> 00:07:20,073 +如果您游戏可提供排行榜 + +112 +00:07:20,107 --> 00:07:23,544 +这些活动会自动展示 + +113 +00:07:23,577 --> 00:07:26,680 +即使您已经利用排行榜 + +114 +00:07:26,713 --> 00:07:29,416 +考虑扩展排行榜集合 + +115 +00:07:29,449 --> 00:07:33,554 +提供更多关于玩家及其好友的 +竞赛瞬间 + +116 +00:07:33,587 --> 00:07:38,158 +排行榜循环提供了及时性的感觉 + +117 +00:07:38,192 --> 00:07:42,196 +以及持续游戏的理由 + +118 +00:07:42,229 --> 00:07:45,666 +接下来 我再解释下 +Game Center Achievements 是如何 + +119 +00:07:45,699 --> 00:07:48,068 +在 Activity 中占据主要位置的 + +120 +00:07:48,101 --> 00:07:52,372 +Achievements 为玩家提供 +额外方式 从而参与您的游戏 + +121 +00:07:52,406 --> 00:07:56,944 +跟踪游戏进程及与好友共享进展 + +122 +00:07:56,977 --> 00:08:00,047 +当玩家在您的游戏中 +达成一项成就时 + +123 +00:08:00,080 --> 00:08:04,918 +这也会反映在他们的活动 +和好友活动中 + +124 +00:08:04,952 --> 00:08:07,754 +当玩家完成您游戏的 +每一项成就时 + +125 +00:08:07,788 --> 00:08:13,327 +我们会用一点时间 +进行特定的庆祝活动 + +126 +00:08:13,360 --> 00:08:17,364 +成就(Achievement)为玩家提供进步感 +和成就感 + +127 +00:08:17,397 --> 00:08:22,369 +也可以讲述玩家在您游戏中 +所完成的进程 + +128 +00:08:22,402 --> 00:08:27,207 +成就 Activity 的显眼位置呈现 +因此在 Game Center 社交网络中 + +129 +00:08:27,241 --> 00:08:31,144 +马上能有扩大的可见度 + +130 +00:08:31,178 --> 00:08:33,881 +玩家可以看到好友在做什么 + +131 +00:08:33,914 --> 00:08:38,185 +他们就有更多的理由 +加入您的游戏 一起竞赛 + +132 +00:08:38,218 --> 00:08:42,189 +您刚刚看到了 玩家登陆您的 +游戏面板后会看到什么界面 + +133 +00:08:42,222 --> 00:08:44,558 +玩家也可以访问好友个人资料 + +134 +00:08:44,591 --> 00:08:47,794 +在一个地方查看所有近期活动 + +135 +00:08:47,828 --> 00:08:50,964 +当然 您是否能查看 +好友的个人资料 + +136 +00:08:50,998 --> 00:08:53,400 +仍然是基于他们在 +Game Center 设置中的 + +137 +00:08:53,433 --> 00:08:55,636 +资料隐私选项的 + +138 +00:08:55,669 --> 00:08:59,506 +这就是 Activity +一个玩家能发现好友 + +139 +00:08:59,540 --> 00:09:01,808 +在您游戏中的活动 + +140 +00:09:01,842 --> 00:09:05,546 +以及不同游戏中的活动的地方 + +141 +00:09:05,579 --> 00:09:09,883 +总而言之 通过 Game Center +您的玩家可以与好友联机 + +142 +00:09:09,917 --> 00:09:13,720 +与好友竞赛 从而获得更多 +游戏乐趣 + +143 +00:09:13,754 --> 00:09:18,825 +Activity 是可以让玩家查看 +他们的游戏进程 + +144 +00:09:18,859 --> 00:09:23,564 +以及好友的游戏进程 +从而为您提供更多分发的机会 + +145 +00:09:23,597 --> 00:09:28,268 +对 Unity 开发者们来说 +现在可以通过我们全新的 + +146 +00:09:28,302 --> 00:09:33,106 +Unity plug-in 来完整 +使用 GameKit + +147 +00:09:33,140 --> 00:09:37,044 +您可以学习如何在您的游戏中 +最大化地 + +148 +00:09:37,077 --> 00:09:40,180 +发挥 Game Center 功能 +如何进行排行榜循环 + +149 +00:09:40,214 --> 00:09:42,616 +如何在您的 Unity 游戏中 +使用 GameKit + +150 +00:09:42,649 --> 00:09:45,485 +一切内容尽在与本次讲座 +相关的视频中 + +151 +00:09:45,519 --> 00:09:48,322 +我今天谈到了很多内容 + +152 +00:09:48,355 --> 00:09:53,126 +我们相信今年的更新会为您的 +游戏玩家带来更大的乐趣 + +153 +00:09:53,160 --> 00:09:55,462 +感谢观看 + +154 +00:09:55,495 --> 00:09:57,731 +[交谈声] + diff --git a/zho/2022 Session 10065 Plug-in and play - Add Apple frameworks to your Unity game projects.srt b/zho/2022 Session 10065 Plug-in and play - Add Apple frameworks to your Unity game projects.srt new file mode 100644 index 0000000..6af1a03 --- /dev/null +++ b/zho/2022 Session 10065 Plug-in and play - Add Apple frameworks to your Unity game projects.srt @@ -0,0 +1,2264 @@ +1 +00:00:00,033 --> 00:00:03,036 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,036 --> 00:00:09,443 +♪ + +3 +00:00:09,443 --> 00:00:13,981 +大家好 我是 Jared Marsau +在 Apple 游戏技术部门工作 + +4 +00:00:13,981 --> 00:00:16,416 +今天 我会和大家聊聊如何使用 + +5 +00:00:16,416 --> 00:00:19,186 +一些精选 Apple 框架 +为基于 Unity 开发的游戏 + +6 +00:00:19,186 --> 00:00:21,655 +添加新特性 + +7 +00:00:21,655 --> 00:00:25,526 +据我们所知 有许多开发者 +在使用诸如 Unity 之类的工具 + +8 +00:00:25,526 --> 00:00:27,427 +来构建游戏 + +9 +00:00:27,427 --> 00:00:29,696 +我们的目标是为您带来最新的功能 + +10 +00:00:29,696 --> 00:00:32,165 +无论您用的是哪一种工具 + +11 +00:00:32,165 --> 00:00:34,334 +从今天开始 +您可以使用一组新的 Unity 插件 + +12 +00:00:34,334 --> 00:00:37,237 +来增强您的游戏 + +13 +00:00:37,237 --> 00:00:39,940 +使用 Game Center 插件 +来添加 GameKit 功能 比如: + +14 +00:00:39,940 --> 00:00:43,710 +玩家身份验证 排行榜 和游戏配对 + +15 +00:00:43,710 --> 00:00:46,613 +使用 Game Controller 插件 +来自定义输入和图标 + +16 +00:00:46,613 --> 00:00:51,385 +进而获得支持 MFi 和第三方控制器的能力 + +17 +00:00:51,385 --> 00:00:54,321 +使用 Accessibility 插件 +来改善辅助功能使用 + +18 +00:00:54,321 --> 00:00:58,659 +调动起 旁白 和 动态字体 等系统特性 + +19 +00:00:58,659 --> 00:01:02,429 +如要集成 Apple 由数据驱动的 +完善的触觉反馈系统 + +20 +00:01:02,429 --> 00:01:04,965 +可以使用 Core Haptics 插件 + +21 +00:01:04,965 --> 00:01:07,634 +如要添加先进的几何感知空间音频 + +22 +00:01:07,634 --> 00:01:09,203 +可以使用 PHASE 插件 + +23 +00:01:09,203 --> 00:01:12,873 +最后 使用 Apple.Core 插件 +管理构建设置 + +24 +00:01:12,873 --> 00:01:16,577 +简化构建流程 + +25 +00:01:16,577 --> 00:01:18,745 +这一组插件初始套装能帮您 + +26 +00:01:18,745 --> 00:01:22,282 +添加新游戏玩法机制 +让您的游戏更加无障碍 + +27 +00:01:22,282 --> 00:01:24,151 +还能助您更快地 + +28 +00:01:24,151 --> 00:01:27,054 +利用上最新的功能和服务 + +29 +00:01:27,054 --> 00:01:29,423 +我已经迫不及待地想要看看大家会用 + +30 +00:01:29,423 --> 00:01:32,593 +这一组新的 Unity 插件 +做出多么棒的游戏了 + +31 +00:01:32,593 --> 00:01:35,662 +现在 +让我们来详细了解一下这个项目 + +32 +00:01:35,662 --> 00:01:38,966 +首先 +我们会讨论这个项目的设计原则 + +33 +00:01:38,966 --> 00:01:42,169 +然后 我会介绍项目概念和组织 + +34 +00:01:42,169 --> 00:01:44,505 +接下来 我会讲一些 + +35 +00:01:44,505 --> 00:01:47,140 +关于与项目库交互的关键点 + +36 +00:01:47,140 --> 00:01:50,544 +最后 我会详细介绍一下各个插件 + +37 +00:01:50,544 --> 00:01:52,279 +您可能已经知道 + +38 +00:01:52,279 --> 00:01:56,450 +Apple 框架 +是用模块化的方式封装各种功能的 + +39 +00:01:56,450 --> 00:01:58,819 +这种方式能让您 +为 App 挑选正确的技术 + +40 +00:01:58,819 --> 00:02:03,290 +同时还保持代码的简洁和高效 + +41 +00:02:03,290 --> 00:02:06,894 +在 Unity 插件中 +我们遵循类似的模式 + +42 +00:02:06,894 --> 00:02:10,163 +每个插件 +都映射到一个单一的底层框架 + +43 +00:02:10,163 --> 00:02:12,332 +这样您就可以根据游戏的需要 + +44 +00:02:12,332 --> 00:02:15,669 +挑选所需的插件组合 + +45 +00:02:15,669 --> 00:02:19,373 +每个插件都包含 +Unity 所需的 C# 脚本 + +46 +00:02:19,373 --> 00:02:21,275 +该脚本尽可能地直接映射 + +47 +00:02:21,275 --> 00:02:23,443 +到底层框架 + +48 +00:02:23,443 --> 00:02:26,580 +这种方法意味着 +您面对底层框架的经验 + +49 +00:02:26,580 --> 00:02:29,950 +可以直接继承到插件的使用上 + +50 +00:02:29,950 --> 00:02:33,187 +在很多情况下 +框架 API 以及基本概念 + +51 +00:02:33,187 --> 00:02:35,022 +都可以无缝过渡 + +52 +00:02:35,022 --> 00:02:38,525 +反过来说 通过学习这些插件 + +53 +00:02:38,525 --> 00:02:42,162 +您也会在潜移默化中 +学习底层框架 + +54 +00:02:42,162 --> 00:02:44,598 +另一个重要的细节是 +这些插件 + +55 +00:02:44,598 --> 00:02:48,202 +都是作为 +Apple 平台原生库开发的 + +56 +00:02:48,202 --> 00:02:51,638 +这些库 +像胶水一样连接着 C# 脚本 + +57 +00:02:51,638 --> 00:02:55,242 +和底层框架 API + +58 +00:02:55,242 --> 00:02:59,346 +Apple Unity 插件 +是以 Unity 资源包的形式组织的 + +59 +00:02:59,346 --> 00:03:02,082 +因此使用 Unity 编辑器的 +内置 Package Manager + +60 +00:03:02,082 --> 00:03:05,953 +就可以管理它们与您的项目的集成 + +61 +00:03:05,953 --> 00:03:09,356 +在某些情况下 插件还会包含 + +62 +00:03:09,356 --> 00:03:12,793 +编辑器的扩展功能 +让开发工作更加轻松 + +63 +00:03:12,793 --> 00:03:15,629 +并且与您已经熟练掌握的 +基于 Inspector 的 + +64 +00:03:15,629 --> 00:03:18,265 +Unity 工作流程保持一致 + +65 +00:03:18,265 --> 00:03:21,702 +当然 每个插件 +还附带有详细的自述文件 + +66 +00:03:21,702 --> 00:03:25,038 +示例 以及额外资源的链接 + +67 +00:03:25,038 --> 00:03:28,842 +比如相关的 +Apple Developer 文档 + +68 +00:03:28,842 --> 00:03:32,412 +接下来 +我会简要讲解一些关键工作流程概念 + +69 +00:03:32,412 --> 00:03:35,315 +以帮助您入门 + +70 +00:03:35,315 --> 00:03:38,652 +第一步是 +克隆 GitHub 上的源代码 + +71 +00:03:38,652 --> 00:03:42,456 +在那里您可以找到 +所有的项目源代码和文档 + +72 +00:03:42,456 --> 00:03:44,758 +这是每个人使用 + +73 +00:03:44,758 --> 00:03:47,261 +Apple Unity 插件的第一步 + +74 +00:03:47,261 --> 00:03:48,962 +克隆了代码库之后 + +75 +00:03:48,962 --> 00:03:52,299 +您的首要任务之一就是构建插件 + +76 +00:03:52,299 --> 00:03:55,135 +为了简化这个流程 代码库中包含了 + +77 +00:03:55,135 --> 00:03:59,806 +一个 Python 脚本 +存放在库根目录下:build.py + +78 +00:03:59,806 --> 00:04:02,176 +这个脚本会构建原生库 + +79 +00:04:02,176 --> 00:04:04,511 +把它们复制到正确的位置 + +80 +00:04:04,511 --> 00:04:08,081 +更新 Unity 元文件 打包插件 + +81 +00:04:08,081 --> 00:04:10,250 +以及构建插件测试 + +82 +00:04:10,250 --> 00:04:13,353 +这个插件是这样组织的: +用最简单的调用 + +83 +00:04:13,353 --> 00:04:17,090 +构建所有插件 +把它们打包成 tar 包 + +84 +00:04:17,090 --> 00:04:18,959 +并保存到 Build 文件夹中 + +85 +00:04:18,959 --> 00:04:22,729 +准备妥当 +等待集成入您的 Unity 项目 + +86 +00:04:22,729 --> 00:04:25,666 +请注意 完整构建和打包这些插件很重要 + +87 +00:04:25,666 --> 00:04:32,239 +需要 Xcode +Python3 npm 以及 Unity + +88 +00:04:32,239 --> 00:04:34,241 +最后 在项目库中 我们还有 + +89 +00:04:34,241 --> 00:04:38,879 +关于使用 build.py 的详细文档 + +90 +00:04:38,879 --> 00:04:40,614 +现在是时候让我们深入 + +91 +00:04:40,614 --> 00:04:42,549 +这些插件的细节了 + +92 +00:04:42,549 --> 00:04:44,718 +我会讲解如何把各个插件 + +93 +00:04:44,718 --> 00:04:49,056 +加入到您的 Unity 项目中 +简要介绍一下它们包含的功能 + +94 +00:04:49,056 --> 00:04:51,825 +关键脚本概念 以及一些代码片段 + +95 +00:04:51,825 --> 00:04:54,061 +或是 Unity 编辑器中的示例 + +96 +00:04:54,061 --> 00:04:57,798 +主要着眼于 +如何把它们集成入您的项目 + +97 +00:04:57,798 --> 00:05:00,000 +让我们从最基础的插件开始 + +98 +00:05:00,000 --> 00:05:01,768 +Apple.Core + +99 +00:05:01,768 --> 00:05:04,838 +Apple.Core +把各个插件的构建设置统一到 + +100 +00:05:04,838 --> 00:05:09,276 +Unity 项目设置窗口中 +的单个偏好设置面板上 + +101 +00:05:09,276 --> 00:05:12,412 +因为您编译了各个插件的原生库 + +102 +00:05:12,412 --> 00:05:15,215 +Apple.Core +进而包含了一个资源处理器 + +103 +00:05:15,215 --> 00:05:17,885 +它确保每个插件库在导入时 + +104 +00:05:17,885 --> 00:05:21,021 +都会根据相应平台配置好 + +105 +00:05:21,021 --> 00:05:24,024 +当构建您的项目时 +Apple.Core 还包含了 + +106 +00:05:24,024 --> 00:05:26,660 +用于后处理项目的脚本 + +107 +00:05:26,660 --> 00:05:29,696 +以确保正确引用了这些原生库 + +108 +00:05:29,696 --> 00:05:32,399 +尤其是在您的 Xcode 中间项目 + +109 +00:05:32,399 --> 00:05:35,669 +由于每个插件都与一个底层框架互动 + +110 +00:05:35,669 --> 00:05:37,104 +Apple.Core 还定义了 + +111 +00:05:37,104 --> 00:05:40,707 +一些运行时交互操作类型 +以简化 C# 脚本 + +112 +00:05:40,707 --> 00:05:44,311 +和原生代码层之间的数据传递 + +113 +00:05:44,311 --> 00:05:46,647 +最后 Apple.Core + +114 +00:05:46,647 --> 00:05:49,516 +是所有其他 +Apple Unity 插件的依赖项 + +115 +00:05:49,516 --> 00:05:51,585 +也就是它应该优先导入您的项目 + +116 +00:05:51,585 --> 00:05:55,889 +一定要早于其它插件 + +117 +00:05:55,889 --> 00:05:57,925 +在这个演示中 我会展示 + +118 +00:05:57,925 --> 00:06:00,460 +如何把 Apple.Core 插件 +导入一个新项目 + +119 +00:06:00,460 --> 00:06:04,965 +并简单介绍一下 +Apple 构建设置的偏好设置 + +120 +00:06:04,965 --> 00:06:07,467 +一旦插件构建和打包完成 + +121 +00:06:07,467 --> 00:06:11,738 +就可以用 Unity Package Manager +导入 Apple.Core + +122 +00:06:11,738 --> 00:06:14,708 +只需选择 +“Add package from tarball…” 选项 + +123 +00:06:14,708 --> 00:06:17,978 +并找到打包好的插件 + +124 +00:06:23,183 --> 00:06:26,920 +编辑器就会 +加载这个包并编译脚本 + +125 +00:06:26,920 --> 00:06:31,391 +完成之后 +Apple.Core 就可以用了 + +126 +00:06:34,761 --> 00:06:37,264 +Apple.Core +主要的面向用户的功能 + +127 +00:06:37,264 --> 00:06:39,633 +是在编辑器的项目设置窗口中 + +128 +00:06:39,633 --> 00:06:43,537 +新增的 Apple 构建设置选项卡 + +129 +00:06:46,540 --> 00:06:49,009 +导入一个 +Apple Unity 插件之后 + +130 +00:06:49,009 --> 00:06:52,613 +它所有的 +可用构建选项都会出现在这里 + +131 +00:06:52,613 --> 00:06:53,780 +无需额外设置 开箱即用 + +132 +00:06:53,780 --> 00:06:56,783 +Apple.Core +有一些默认的配置选项 + +133 +00:06:56,783 --> 00:07:00,754 +比如支持的最低 OS 版本 + +134 +00:07:00,754 --> 00:07:03,156 +请注意 您还可以禁用 + +135 +00:07:03,156 --> 00:07:07,127 +任何插件构建的后处理步骤 + +136 +00:07:10,531 --> 00:07:13,467 +最后 您可以配置常用的安全设置 + +137 +00:07:13,467 --> 00:07:18,438 +它会应用至 +您的中间 Xcode 项目中 + +138 +00:07:18,438 --> 00:07:21,108 +使用 Game Center 插件 +来为您的游戏 + +139 +00:07:21,108 --> 00:07:23,844 +带来更多趣味和互动 + +140 +00:07:23,844 --> 00:07:26,413 +Game Center +是 Apple 的游戏社交网络 + +141 +00:07:26,413 --> 00:07:29,016 +Game Center 能让玩家在 Apple 平台上 + +142 +00:07:29,016 --> 00:07:32,085 +建立自己的身份 +并启用很多功能 比如: + +143 +00:07:32,085 --> 00:07:35,822 +安全可靠的玩家身份验证 +游戏内成就系统 + +144 +00:07:35,822 --> 00:07:39,560 +共享的排行榜 玩家之间发送挑战 + +145 +00:07:39,560 --> 00:07:41,995 +以及多人游戏匹配 + +146 +00:07:41,995 --> 00:07:44,331 +您可以选择 +把哪些 Game Center 功能 + +147 +00:07:44,331 --> 00:07:45,999 +集成入您的游戏中 + +148 +00:07:45,999 --> 00:07:49,203 +但一切都从玩家身份验证开始 + +149 +00:07:49,203 --> 00:07:51,672 +把 Game Center +玩家身份验证加入您的游戏 + +150 +00:07:51,672 --> 00:07:53,841 +Game Center 小组件 +就可以在玩家的主屏幕 + +151 +00:07:53,841 --> 00:07:57,978 +或是 App Store 中 +展示您的游戏 + +152 +00:07:57,978 --> 00:07:59,813 +而且 只需要很少的编程工作 + +153 +00:07:59,813 --> 00:08:02,182 +就可以添加玩家身份验证 + +154 +00:08:02,182 --> 00:08:04,618 +第一步是把 Apple.Core + +155 +00:08:04,618 --> 00:08:06,787 +和 GameKit 插件 +添加到您的项目中 + +156 +00:08:06,787 --> 00:08:10,457 +GameKit 插件 +会连接到 Game Center 服务 + +157 +00:08:10,457 --> 00:08:13,594 +进行身份验证时 +它会连接到 Game Center 服务 + +158 +00:08:13,594 --> 00:08:16,964 +并初始化 +一个 GKLocalPlayer 对象 + +159 +00:08:16,964 --> 00:08:19,733 +初始化完成之后 +开始根据本地玩家资料 + +160 +00:08:19,733 --> 00:08:22,336 +询问玩家限制情况 + +161 +00:08:22,336 --> 00:08:26,139 +包括限制未成年玩家 + +162 +00:08:26,139 --> 00:08:29,343 +访问成人或露骨内容 + +163 +00:08:29,343 --> 00:08:32,079 +限制使用多人游戏功能 + +164 +00:08:32,079 --> 00:08:34,815 +或禁用游戏内交流 + +165 +00:08:34,815 --> 00:08:37,684 +管理 GKLocalPlayer 以及 + +166 +00:08:37,684 --> 00:08:40,153 +它与 Game Center 服务 +交互的一个简单方法是: + +167 +00:08:40,153 --> 00:08:43,190 +在 Unity 中定义一个组件 + +168 +00:08:43,190 --> 00:08:44,391 +比如 + +169 +00:08:44,391 --> 00:08:47,661 +这是一个简单的 +Game Manager 组件定义 + +170 +00:08:47,661 --> 00:08:50,864 +这个组件引用了 +一个 GKLocalPlayer + +171 +00:08:50,864 --> 00:08:53,567 +它还在 Start 方法中 + +172 +00:08:53,567 --> 00:08:56,003 +处理身份验证并询问玩家限制情况 + +173 +00:08:56,003 --> 00:08:58,605 +玩家身份验证在游戏生命周期内 + +174 +00:08:58,605 --> 00:09:01,074 +只需要发生一次 + +175 +00:09:01,074 --> 00:09:04,211 +这就是这个 +GameManager 组件的脚本 + +176 +00:09:04,211 --> 00:09:07,214 +这是缓存 GKLocalPlayer 的字段 + +177 +00:09:07,214 --> 00:09:09,316 +在组件的 Start 方法中 + +178 +00:09:09,316 --> 00:09:12,986 +有对 GKLocalPlayer.Authenticate +的单次调用 + +179 +00:09:12,986 --> 00:09:17,124 +这是一种返回 +GKLocalPlayer 实例的静态方法 + +180 +00:09:17,124 --> 00:09:19,927 +成功验证本地玩家的身份后 + +181 +00:09:19,927 --> 00:09:22,963 +就该检查玩家的限制情况了 + +182 +00:09:22,963 --> 00:09:24,798 +在代码中 检查玩家限制情况 + +183 +00:09:24,798 --> 00:09:27,734 +体现为一系列的 Bool 检查 + +184 +00:09:27,734 --> 00:09:31,572 +可以添加到 GameManager +组件脚本中的 try 代码块中 + +185 +00:09:31,572 --> 00:09:33,774 +此处 True 意味着应该 + +186 +00:09:33,774 --> 00:09:36,276 +限制本地玩家访问露骨内容 + +187 +00:09:36,276 --> 00:09:38,045 +此处 True 意味着 + +188 +00:09:38,045 --> 00:09:40,848 +应该限制本地玩家参与多人游戏 + +189 +00:09:40,848 --> 00:09:43,951 +最后 此处 True 意味着 + +190 +00:09:43,951 --> 00:09:46,320 +应该禁用游戏内交流 + +191 +00:09:46,320 --> 00:09:48,455 +这就是在您的游戏中添加 + +192 +00:09:48,455 --> 00:09:51,325 +玩家身份验证要更改的所有代码了 + +193 +00:09:51,325 --> 00:09:54,328 +接下来 还需要两个额外步骤 + +194 +00:09:54,328 --> 00:09:58,632 +以使您的游戏 +充分利用 Game Center 的优势 + +195 +00:09:58,632 --> 00:10:01,535 +首先 您需要把 +Game Center 功能 + +196 +00:10:01,535 --> 00:10:04,304 +添加到您的中间 Xcode 项目中 + +197 +00:10:04,304 --> 00:10:07,441 +这使用 Xcode 项目 UI 即可完成 + +198 +00:10:07,441 --> 00:10:09,176 +更多信息请查看 + +199 +00:10:09,176 --> 00:10:11,645 +Apple Developer 文档文章 + +200 +00:10:11,645 --> 00:10:14,882 +“Enabling and Configuring +Game Center” + +201 +00:10:14,882 --> 00:10:17,818 +接下来 您需要使用 +App Store Connect + +202 +00:10:17,818 --> 00:10:20,020 +把 Game Center 功能 +加入到您的 App 中 + +203 +00:10:20,020 --> 00:10:23,924 +更多信息请查看 +App Store Connect 网页 + +204 +00:10:23,924 --> 00:10:26,627 +完成这些步骤后 +您就可以进行玩家身份验证 + +205 +00:10:26,627 --> 00:10:30,197 +并确保一个安全的游戏环境了 + +206 +00:10:30,197 --> 00:10:33,300 +玩家身份验证只是 +Game Center Unity 插件 + +207 +00:10:33,300 --> 00:10:34,902 +所提供的功能的 + +208 +00:10:34,902 --> 00:10:37,538 +很小一部分 + +209 +00:10:37,538 --> 00:10:40,641 +要学习如何提高您的游戏的曝光量 + +210 +00:10:40,641 --> 00:10:42,142 +请查看 + +211 +00:10:42,142 --> 00:10:45,345 +“Reach new players +with Game Center dashboard”讲座 + +212 +00:10:45,345 --> 00:10:47,981 +要学习更多 +关于多人游戏和匹配的内容 + +213 +00:10:47,981 --> 00:10:52,486 +请观看去年 +“What’s new in Game Center” 讲座 + +214 +00:10:52,486 --> 00:10:56,123 +控制器(主要是游戏手柄) +是玩家与 + +215 +00:10:56,123 --> 00:10:58,425 +您创造的游戏世界 +交互的主要途径 + +216 +00:10:58,425 --> 00:11:02,062 +Game Controller 插件 +可以轻松为您的游戏 + +217 +00:11:02,062 --> 00:11:04,998 +带来灵活可靠的游戏控制器支持 + +218 +00:11:04,998 --> 00:11:08,068 +Game Controller 插件 +有相当多的功能 + +219 +00:11:08,068 --> 00:11:11,138 +比如支持游戏控制器自定义 + +220 +00:11:11,138 --> 00:11:13,106 +这个功能让玩家可以在一个地方 + +221 +00:11:13,106 --> 00:11:15,843 +为所有游戏重新映射按键 + +222 +00:11:15,843 --> 00:11:19,713 +按键图标功能 +能保证连贯一致的用户体验 + +223 +00:11:19,713 --> 00:11:22,115 +还有对所有 MFi 控制器 + +224 +00:11:22,115 --> 00:11:23,784 +以及第三方控制器的支持 + +225 +00:11:23,784 --> 00:11:27,354 +比如一部分索尼和微软的控制器 + +226 +00:11:27,354 --> 00:11:29,022 +只需和其它插件一样 + +227 +00:11:29,022 --> 00:11:31,325 +使用 Package Manager +把 Apple.Core + +228 +00:11:31,325 --> 00:11:34,228 +和 Game Controller 插件 +添加到您的项目中 + +229 +00:11:34,228 --> 00:11:36,196 +载入 Game Controller 插件后 + +230 +00:11:36,196 --> 00:11:40,501 +第一步就是初始化 +GCControllerService + +231 +00:11:40,501 --> 00:11:43,403 +我们接下来就会看到 这个服务 + +232 +00:11:43,403 --> 00:11:46,473 +如何访问 +控制器和它们的连接事件 + +233 +00:11:46,473 --> 00:11:49,209 +初始化完成后 +向 GCControllerService 询问 + +234 +00:11:49,209 --> 00:11:52,546 +连接到系统的所有控制器情况 + +235 +00:11:52,546 --> 00:11:54,581 +已连接的控制器会作为 + +236 +00:11:54,581 --> 00:11:58,919 +GCController 对象 +表示在 Game Controller 插件中 + +237 +00:11:58,919 --> 00:12:01,388 +向每个已连接的 GCController + +238 +00:12:01,388 --> 00:12:03,757 +轮询控制器更新状态 + +239 +00:12:03,757 --> 00:12:06,660 +轮询频率或高或低 +主要根据您的游戏的需要 + +240 +00:12:06,660 --> 00:12:08,862 +但 Unity 的定期更新循环 + +241 +00:12:08,862 --> 00:12:11,632 +是一个比较好的起始点 + +242 +00:12:11,632 --> 00:12:13,667 +一旦控制器状态更新之后 + +243 +00:12:13,667 --> 00:12:15,969 +会开始测试各控制器上的 + +244 +00:12:15,969 --> 00:12:19,406 +单独输入元素 比如按键 摇杆 + +245 +00:12:19,406 --> 00:12:20,908 +等等 + +246 +00:12:20,908 --> 00:12:23,410 +别忘了 在您的游戏生命周期内 + +247 +00:12:23,410 --> 00:12:26,513 +玩家可能会添加或移除控制器 + +248 +00:12:26,513 --> 00:12:30,050 +您可以注册回调函数 +来管理控制器连接与断开事件 + +249 +00:12:30,050 --> 00:12:32,619 +有个简单的方法可以用于 +集成 Game Controller 插件 + +250 +00:12:32,619 --> 00:12:36,557 +就是创建一个简单的输入管理组件 + +251 +00:12:36,557 --> 00:12:39,293 +该组件有三个关键元素: + +252 +00:12:39,293 --> 00:12:40,794 +一个容器 + +253 +00:12:40,794 --> 00:12:43,697 +其中包含了所有当前连接的控制器 + +254 +00:12:43,697 --> 00:12:46,066 +一个 Start 方法 用于初始化 + +255 +00:12:46,066 --> 00:12:48,268 +还有一个 Update 方法 用于处理 + +256 +00:12:48,268 --> 00:12:50,637 +对输入信号的轮询和测试 + +257 +00:12:50,637 --> 00:12:53,941 +首先 让我们来看看 Start 方法 + +258 +00:12:53,941 --> 00:12:56,476 +这里可以很方便的布置所有必要的 + +259 +00:12:56,476 --> 00:12:58,912 +一次性设置任务 + +260 +00:12:58,912 --> 00:13:01,315 +游戏控制器服务的初始化 + +261 +00:13:01,315 --> 00:13:02,749 +就应该在这里进行 + +262 +00:13:02,749 --> 00:13:05,986 +还有已连接控制器的初始检查 + +263 +00:13:05,986 --> 00:13:07,888 +以及为连接和断开事件 + +264 +00:13:07,888 --> 00:13:11,124 +注册的回调函数 + +265 +00:13:11,124 --> 00:13:14,494 +这是输入管理组件的脚本 + +266 +00:13:14,494 --> 00:13:16,063 +所以的一次性设置代码 + +267 +00:13:16,063 --> 00:13:19,700 +都在组件的 Start 方法里 +包括调用了一次 + +268 +00:13:19,700 --> 00:13:23,370 +GCControllerService.Initialize() + +269 +00:13:23,370 --> 00:13:26,640 +调用 GetConnectedControllers +会得到一个可枚举的容器 + +270 +00:13:26,640 --> 00:13:30,177 +其中包含了所有当前连接的控制器 + +271 +00:13:30,177 --> 00:13:33,447 +初始化的最后一步是注册回调函数 + +272 +00:13:33,447 --> 00:13:37,551 +用于处理控制器连接和断开事件 + +273 +00:13:37,551 --> 00:13:39,887 +初始化完成之后 + +274 +00:13:39,887 --> 00:13:42,723 +输入管理器还需要一个 Update 方法 + +275 +00:13:42,723 --> 00:13:45,158 +主要是为了轮询各已连接的控制器 + +276 +00:13:45,158 --> 00:13:48,095 +以更新输入状态 + +277 +00:13:48,095 --> 00:13:50,831 +并处理各控制器输入信号的状态 + +278 +00:13:50,831 --> 00:13:53,066 +要轮询输入信号 首先 + +279 +00:13:53,066 --> 00:13:55,602 +对已连接的控制器进行迭代 + +280 +00:13:55,602 --> 00:13:57,771 +调用 GCController 的轮询方法 + +281 +00:13:57,771 --> 00:13:59,740 +来收集最新状态 + +282 +00:13:59,740 --> 00:14:05,012 +然后检查各个按键状态 +并给出相应的响应 + +283 +00:14:05,012 --> 00:14:08,348 +我简单介绍了一下如何使用 +Game Controller 插件 + +284 +00:14:08,348 --> 00:14:12,786 +来访问连接的控制器 +并获取输入信号 + +285 +00:14:12,786 --> 00:14:15,989 +要获取更多关于 +Game Controller 框架的细节 + +286 +00:14:15,989 --> 00:14:18,725 +了解第三方控制器 + +287 +00:14:18,725 --> 00:14:22,796 +和非标准输入方式等主题 +请查看往年的讲座: + +288 +00:14:22,796 --> 00:14:24,531 +“Supporting New Game Controllers” + +289 +00:14:24,531 --> 00:14:27,334 +以及“Advancements +in Game Controllers” + +290 +00:14:27,334 --> 00:14:30,838 +辅助功能是让技术触手可及 + +291 +00:14:30,838 --> 00:14:32,639 +进而造福所有人 + +292 +00:14:32,639 --> 00:14:36,176 +Accessibility 插件可以将 + +293 +00:14:36,176 --> 00:14:38,478 +Apple 丰富的辅助技术 + +294 +00:14:38,478 --> 00:14:41,248 +集成到您的 Unity 游戏中 + +295 +00:14:41,248 --> 00:14:43,750 +Accessibility 插件可以让您 + +296 +00:14:43,750 --> 00:14:46,520 +添加许多关键功能 +比如 旁白(VoiceOver) + +297 +00:14:46,520 --> 00:14:50,190 +这个功能可以把以编程方式 +标记的内容读给您的用户听 + +298 +00:14:50,190 --> 00:14:51,358 +切换控制功能(Switch Control) + +299 +00:14:51,358 --> 00:14:54,795 +允许用户使用多种辅助输入设备 + +300 +00:14:54,795 --> 00:14:57,798 +动态字体(Dynamic Type) +可以随用户所需 + +301 +00:14:57,798 --> 00:15:00,868 +轻松缩放游戏内文本和 UI + +302 +00:15:00,868 --> 00:15:03,737 +以及 UI 适应性设置选项(UI Accommodation) + +303 +00:15:03,737 --> 00:15:07,274 +用来同步系统层级的 +辅助功能偏好设置 + +304 +00:15:07,274 --> 00:15:09,877 +关于 Accessibility +插件还有许多内容可以深入探讨 + +305 +00:15:09,877 --> 00:15:11,879 +您可以查看讲座 + +306 +00:15:11,879 --> 00:15:14,781 +“Add accessibility to your Unity games” + +307 +00:15:14,781 --> 00:15:18,685 +获得更多关于 +Accessibility Unity 插件的知识 + +308 +00:15:18,685 --> 00:15:21,922 +这个讲座中不仅有示例和应用实例 + +309 +00:15:21,922 --> 00:15:23,757 +还能帮助您理解 + +310 +00:15:23,757 --> 00:15:26,159 +Apple 平台上的辅助功能 + +311 +00:15:26,159 --> 00:15:28,262 +可以做到些什么 + +312 +00:15:28,262 --> 00:15:32,332 +有机会的话请务必看看那个讲座 + +313 +00:15:32,332 --> 00:15:34,801 +在您的游戏中添加触觉反馈 + +314 +00:15:34,801 --> 00:15:38,672 +能够大幅增强沉浸感 提高游戏体验 + +315 +00:15:38,672 --> 00:15:41,408 +Core Haptics 插件 +可以将 Apple 的 + +316 +00:15:41,408 --> 00:15:43,810 +先进的触觉功能集成入您的游戏中 + +317 +00:15:43,810 --> 00:15:47,080 +Core Haptics 插件 +可以用一组触觉和声音事件 + +318 +00:15:47,080 --> 00:15:49,917 +构建自定义的触觉模式 + +319 +00:15:49,917 --> 00:15:52,886 +播放同步好的自定义声音和触觉 + +320 +00:15:52,886 --> 00:15:55,956 +通过编程实时调整参数 + +321 +00:15:55,956 --> 00:15:58,625 +定义或更新触觉反馈 + +322 +00:15:58,625 --> 00:16:02,496 +Apple Haptic and Audio Pattern +文件格式 简称 AHAP + +323 +00:16:02,496 --> 00:16:04,765 +能以资源文件的形式 + +324 +00:16:04,765 --> 00:16:07,134 +设计和存储您的触觉模式 + +325 +00:16:07,134 --> 00:16:09,703 +使用 Unity 编辑器的 +Inspector 窗口 调整您的 + +326 +00:16:09,703 --> 00:16:12,472 +Core Haptics 模式 + +327 +00:16:12,472 --> 00:16:14,842 +为了充分利用 +Core Haptics 插件 + +328 +00:16:14,842 --> 00:16:17,211 +您需要了解 Core Haptics 四个基本元素 + +329 +00:16:17,211 --> 00:16:20,681 +以及它们之间的相互关系 + +330 +00:16:20,681 --> 00:16:24,518 +其中 最高层级的元素是 +CHHapticEngine + +331 +00:16:24,518 --> 00:16:27,321 +触觉引擎(Haptic Engine)代表了 +通往设备上触觉模块的链接 + +332 +00:16:27,321 --> 00:16:31,859 +要播放任何一种触觉模式 +它都是不可或缺的 + +333 +00:16:31,859 --> 00:16:35,896 +CHHapticEngine 创建了 +CHHapticPatternPlayers + +334 +00:16:35,896 --> 00:16:39,066 +模式播放器(Pattern Player)用于控制 +CHHapticPatterns 的播放 + +335 +00:16:39,066 --> 00:16:44,137 +实现诸如播放 停止 +暂停和恢复之类的功能 + +336 +00:16:44,137 --> 00:16:47,274 +一个 CHHapticPattern +就是一个或多个 + +337 +00:16:47,274 --> 00:16:50,511 +触觉与声音事件组成的逻辑组 + +338 +00:16:50,511 --> 00:16:54,882 +CHHapticEngine +用这些模式来创建播放器 + +339 +00:16:54,882 --> 00:16:57,251 +CHHapticEvents 是定义 + +340 +00:16:57,251 --> 00:17:00,554 +一种触觉体验的构建单元 + +341 +00:17:00,554 --> 00:17:02,990 +Core Haptics +则是数据驱动的 API + +342 +00:17:02,990 --> 00:17:06,627 +有了它 才能实现 +以编程方式 直接写入脚本的方法 + +343 +00:17:06,627 --> 00:17:11,331 +或是修改 AHAP 文件的方法 +定义触觉模式 + +344 +00:17:11,331 --> 00:17:13,834 +有一个简单的方法 +在您的项目中添加 Core Haptics + +345 +00:17:13,834 --> 00:17:16,637 +就是创建一个 Haptics 组件 + +346 +00:17:16,637 --> 00:17:20,707 +用来管理各个必要的 +Core Haptics 对象 + +347 +00:17:20,707 --> 00:17:22,910 +这是一个 Haptics 组件示例 + +348 +00:17:22,910 --> 00:17:25,012 +其中包含了一个 CHHapticEngine + +349 +00:17:25,012 --> 00:17:29,283 +一个 CHHapticPatternPlayer +和一个 AHAP 资源文件 + +350 +00:17:29,283 --> 00:17:31,852 +AHAP 资源文件是 +由 Core Haptics 插件定义的 + +351 +00:17:31,852 --> 00:17:34,655 +一种自定义 Unity 资源 + +352 +00:17:34,655 --> 00:17:38,025 +它可以让您轻松地 +导入导出 AHAP 文件 + +353 +00:17:38,025 --> 00:17:40,060 +还可以作为一个 + +354 +00:17:40,060 --> 00:17:43,230 +自定义的编辑器拓展 +来管理模式的创建和自定义 + +355 +00:17:43,230 --> 00:17:46,366 +让我们详细了解一下 + +356 +00:17:46,366 --> 00:17:48,802 +首先 +我会确保我的项目已经安装好了 + +357 +00:17:48,802 --> 00:17:52,606 +Apple.Core +和 Core Haptics 插件 + +358 +00:17:52,606 --> 00:17:53,740 +添加好之后 + +359 +00:17:53,740 --> 00:17:59,346 +我就可以开始 +使用触觉来改善游戏体验了 + +360 +00:17:59,346 --> 00:18:01,548 +这是我基于之前的框图 + +361 +00:18:01,548 --> 00:18:03,784 +创建的一个触觉组件 + +362 +00:18:03,784 --> 00:18:06,153 +我们稍后再来看它的实现方法 + +363 +00:18:06,153 --> 00:18:09,656 +现在 先把它附到我的飞机上 + +364 +00:18:12,359 --> 00:18:13,560 +附加上去之后 + +365 +00:18:13,560 --> 00:18:16,763 +会看到这个组件 +需要一个 AHAP 资源文件 + +366 +00:18:16,763 --> 00:18:20,167 +但我的 AHAP 资源文件夹是空的 + +367 +00:18:20,167 --> 00:18:21,702 +让我新建一个 + +368 +00:18:21,702 --> 00:18:29,710 +点击 Assets Create Apple +CoreHaptics AHAP + +369 +00:18:29,710 --> 00:18:31,678 +创建好之后 让我给它 + +370 +00:18:31,678 --> 00:18:39,219 +起一个酷炫而有创意的名字: +MyHapticPattern + +371 +00:18:39,219 --> 00:18:41,955 +Core Haptics 插件 +自带 编辑器拓展 + +372 +00:18:41,955 --> 00:18:46,727 +让我可以直接在 +Inspector 窗口中调整触觉模式 + +373 +00:18:46,727 --> 00:18:49,096 +在这里 我可以定义 +CHHapticEvents + +374 +00:18:49,096 --> 00:18:50,931 +它构成了 CHHapticPattern + +375 +00:18:50,931 --> 00:18:53,100 +用于播放的部分 + +376 +00:18:53,100 --> 00:18:55,702 +默认状况下 这是一个瞬态事件 + +377 +00:18:55,702 --> 00:19:01,775 +但我也可以 +很轻松地添加一个连续事件 + +378 +00:19:01,775 --> 00:19:06,780 +UI 中有导入(Import) 导出(Export) +和重置(Reset)按键 + +379 +00:19:06,780 --> 00:19:08,882 +重置会清空所有 + +380 +00:19:08,882 --> 00:19:13,453 +我添加的事件 +把触觉模式恢复到默认状态 + +381 +00:19:13,453 --> 00:19:16,089 +导入和导出也是很棒的功能 + +382 +00:19:16,089 --> 00:19:23,096 +它们让您可以 +载入和保存项目 AHAP 文件 + +383 +00:19:23,096 --> 00:19:25,999 +在这里 我导入了一个准备好的 AHAP 文件 +名叫 Rumble + +384 +00:19:25,999 --> 00:19:28,569 +它会触发一个很棒的触觉效果 + +385 +00:19:28,569 --> 00:19:34,875 +但我觉得需要做一点修改 + +386 +00:19:34,875 --> 00:19:36,476 +现在我更新了触觉模式 + +387 +00:19:36,476 --> 00:19:38,645 +我可以把它导出到 +一个新的 AHAP 文件 + +388 +00:19:38,645 --> 00:19:40,814 +好让我把这个改善过的触觉模式 + +389 +00:19:40,814 --> 00:19:45,152 +共享给团队同事 + +390 +00:19:51,158 --> 00:19:53,227 +现在我已经创建并调整了资源文件 + +391 +00:19:53,227 --> 00:19:59,233 +让我回到飞机这里 +把它指向 MyHapticPattern + +392 +00:19:59,233 --> 00:20:03,337 +好极了!一切就绪 + +393 +00:20:03,337 --> 00:20:06,206 +定义并连接好触觉模式之后 + +394 +00:20:06,206 --> 00:20:08,242 +剩下的就是要给 Haptics 组件 + +395 +00:20:08,242 --> 00:20:11,812 +添加一些逻辑 好让它播放触觉模式 + +396 +00:20:11,812 --> 00:20:14,414 +这可以分为两个方法: + +397 +00:20:14,414 --> 00:20:17,618 +PrepareHaptics 和 Play + +398 +00:20:17,618 --> 00:20:21,255 +在 PrepareHaptics 中 +触觉引擎会初始化 + +399 +00:20:21,255 --> 00:20:24,391 +触觉模式播放器会被创建出来 + +400 +00:20:24,391 --> 00:20:25,926 +Play 则会调用 + +401 +00:20:25,926 --> 00:20:30,831 +CHHapticPatternPlayer +的 Start 方法来开始播放 + +402 +00:20:30,831 --> 00:20:34,101 +这就是 Haptics 组件的脚本 + +403 +00:20:34,101 --> 00:20:36,870 +字段被分别定义为触觉引擎 + +404 +00:20:36,870 --> 00:20:39,106 +和触觉播放器 + +405 +00:20:39,106 --> 00:20:41,942 +请注意 在字段中 +添加一个 serializeField 属性 + +406 +00:20:41,942 --> 00:20:46,146 +才可以在 editor UI 中 +设置这个 AHAP 资源 + +407 +00:20:46,146 --> 00:20:50,884 +接下来 添加创建 +CHHapticEngine 的代码 启动它 + +408 +00:20:50,884 --> 00:20:52,853 +然后通过 +直接从引用资源中访问 AHAP + +409 +00:20:52,853 --> 00:20:56,924 +创建一个触觉模式播放器 + +410 +00:20:56,924 --> 00:20:59,226 +当然 为播放器调用 Start + +411 +00:20:59,226 --> 00:21:02,296 +就会播放这个触觉模式 + +412 +00:21:02,296 --> 00:21:05,098 +Core Haptics Unity +插件提供的工具 + +413 +00:21:05,098 --> 00:21:08,936 +可以助您把游戏的沉浸感 +上升到一个新的高度 + +414 +00:21:08,936 --> 00:21:11,672 +请使用 Core Haptics 插件 + +415 +00:21:11,672 --> 00:21:15,742 +去创造那些亦真亦幻的游戏时刻吧 + +416 +00:21:15,742 --> 00:21:17,644 +要更深入了解 Core Haptics + +417 +00:21:17,644 --> 00:21:21,548 +请查看 +“Introducing Core Haptics”讲座 + +418 +00:21:21,548 --> 00:21:25,152 +要了解优秀的触觉体验的设计细节 + +419 +00:21:25,152 --> 00:21:28,622 +请务必观看“Designing +Audio-Haptic Experiences” + +420 +00:21:28,622 --> 00:21:32,059 +以及“Practice audio +haptic design” + +421 +00:21:32,059 --> 00:21:34,995 +沉浸式的音频对优秀的游戏体验 + +422 +00:21:34,995 --> 00:21:37,197 +无比重要 + +423 +00:21:37,197 --> 00:21:41,168 +PHASE Unity 插件 +可以助您释放创造潜力 + +424 +00:21:41,168 --> 00:21:45,572 +在您的游戏世界中构建丰富的声景 + +425 +00:21:45,572 --> 00:21:47,908 +PHASE 让您可以为游戏 + +426 +00:21:47,908 --> 00:21:51,278 +提供复杂的动态声音体验 + +427 +00:21:51,278 --> 00:21:54,481 +几何感知音频意味着声音是 + +428 +00:21:54,481 --> 00:21:57,251 +从场景中发出的 +并与其中的网格交互 + +429 +00:21:57,251 --> 00:21:59,686 +有了回响和反射 您的游戏中的环境 + +430 +00:21:59,686 --> 00:22:02,789 +听起来会更加逼真 + +431 +00:22:02,789 --> 00:22:05,292 +您可以构建分层音频图 + +432 +00:22:05,292 --> 00:22:09,763 +来实现游戏中的动态音频控制 + +433 +00:22:09,763 --> 00:22:13,133 +PHASE 插件包括了 +一组预定义的组件 + +434 +00:22:13,133 --> 00:22:14,935 +可以直接使用 + +435 +00:22:14,935 --> 00:22:17,104 +只需把它们附加到您的游戏对象上 + +436 +00:22:17,104 --> 00:22:18,372 +就可以开始使用 PHASE 了 + +437 +00:22:18,372 --> 00:22:21,208 +甚至连一行代码都不用写 + +438 +00:22:21,208 --> 00:22:24,678 +第一个组件是 PHASEListener + +439 +00:22:24,678 --> 00:22:27,247 +它充当您的游戏场景中的“耳朵” + +440 +00:22:27,247 --> 00:22:31,485 +它根据位置 方向和回响预设值 + +441 +00:22:31,485 --> 00:22:33,787 +处理音频 + +442 +00:22:33,787 --> 00:22:36,790 +接下来是 PHASEOccluder 组件 + +443 +00:22:36,790 --> 00:22:38,959 +PHASEOccluder 附加在游戏对象上 + +444 +00:22:38,959 --> 00:22:41,595 +它附带几何数据 + +445 +00:22:41,595 --> 00:22:46,099 +会在对象阻挡场景中的音源时 +降低音量 + +446 +00:22:46,099 --> 00:22:48,836 +接下来是 PHASESource 组件 + +447 +00:22:48,836 --> 00:22:50,370 +它们附加在游戏对象上 + +448 +00:22:50,370 --> 00:22:53,006 +会根据对象的 Transform + +449 +00:22:53,006 --> 00:22:55,042 +在您的游戏世界中定位声音 + +450 +00:22:55,042 --> 00:22:57,377 +除了这些内置组件之外 + +451 +00:22:57,377 --> 00:23:00,581 +PHASE 插件还定义了 +一个自定义资源 + +452 +00:23:00,581 --> 00:23:02,749 +即 SoundEvent 资源文件 + +453 +00:23:02,749 --> 00:23:06,153 +声音事件描述了声音播放事件 + +454 +00:23:06,153 --> 00:23:09,957 +还定义了场景中音源播放的声音 + +455 +00:23:09,957 --> 00:23:11,825 +要启用 PHASE 插件 + +456 +00:23:11,825 --> 00:23:14,261 +首先要确保项目中已经安装了 + +457 +00:23:14,261 --> 00:23:17,898 +Apple.Core 和 PHASE 插件 + +458 +00:23:17,898 --> 00:23:21,134 +安装好之后 我就可以把自带的组件 + +459 +00:23:21,134 --> 00:23:22,636 +添加到场景中了 + +460 +00:23:22,636 --> 00:23:23,937 +在这个示例项目中 + +461 +00:23:23,937 --> 00:23:26,740 +有三个相关的游戏对象 + +462 +00:23:26,740 --> 00:23:31,745 +飞机 建筑物和摄像机 + +463 +00:23:31,745 --> 00:23:34,147 +首先 我会把 +PHASEListener 组件 + +464 +00:23:34,147 --> 00:23:36,283 +附加到摄像机上 + +465 +00:23:36,283 --> 00:23:40,087 +如此一来 +我就添加了这个场景中的“耳朵” + +466 +00:23:40,087 --> 00:23:42,122 +接下来 我会把建筑物设置为遮挡物 + +467 +00:23:42,122 --> 00:23:45,826 +给它附加 PHASEOccluder 组件 + +468 +00:23:48,829 --> 00:23:51,632 +最后 我要给这个场景添加一个音源 + +469 +00:23:51,632 --> 00:23:55,836 +把 PHASESource 添加到飞机上 + +470 +00:23:55,836 --> 00:23:59,106 +现在 这个音源要播放一些声音 + +471 +00:23:59,106 --> 00:24:01,441 +所以我要给它附加一个声音事件 + +472 +00:24:01,441 --> 00:24:04,745 +但 Sound Events文件夹是空的 + +473 +00:24:04,745 --> 00:24:06,547 +让我们创建一个 + +474 +00:24:06,547 --> 00:24:14,288 +点击 Assets Create Apple +PHASE SoundEvent + +475 +00:24:14,288 --> 00:24:15,923 +创建好一个声音事件之后 + +476 +00:24:15,923 --> 00:24:17,791 +PHASE 插件会立即打开 + +477 +00:24:17,791 --> 00:24:20,861 +PHASE 声音事件编辑器窗口 + +478 +00:24:20,861 --> 00:24:24,598 +这就是您构建声音事件的画布 + +479 +00:24:24,598 --> 00:24:27,534 +我首先右键点击窗口的任意位置 + +480 +00:24:27,534 --> 00:24:31,371 +弹出菜单允许我 +为这个事件添加一个节点 + +481 +00:24:31,371 --> 00:24:36,109 +因为我想播放一个音频片段(Clip) +或者创建一个采样器(Sampler)节点 + +482 +00:24:36,109 --> 00:24:39,146 +我已经为这个项目 +添加好了一架待机状态飞机的 + +483 +00:24:39,146 --> 00:24:45,619 +音频素材 所以在这里我直接引用 + +484 +00:24:45,619 --> 00:24:47,087 +我启用了循环播放 + +485 +00:24:47,087 --> 00:24:50,157 +这样这架飞机就会一直发出嗡嗡声 + +486 +00:24:50,157 --> 00:24:53,794 +要听到这架飞机的声音 +我要把它路由至混音器(Mixer) + +487 +00:24:53,794 --> 00:24:55,062 +要创建混音器 + +488 +00:24:55,062 --> 00:24:58,966 +我只需把输出线 +拖拽到事件编辑器画布上 + +489 +00:24:58,966 --> 00:25:02,469 +它就会显示创建混音器的选项 + +490 +00:25:05,472 --> 00:25:10,944 +这样我的声音事件 +就创建完成 准备就绪了 + +491 +00:25:10,944 --> 00:25:13,213 +点击声音事件 + +492 +00:25:13,213 --> 00:25:16,583 +我可以直接在 +Inspector 中查看其设置 + +493 +00:25:16,583 --> 00:25:19,786 +这样我调整数值时 就不必回到 + +494 +00:25:19,786 --> 00:25:22,289 +声音事件编辑器中了 + +495 +00:25:22,289 --> 00:25:23,790 +声音事件创建好后 + +496 +00:25:23,790 --> 00:25:26,293 +就可以在之前附加到飞机上的 + +497 +00:25:26,293 --> 00:25:30,964 +PHASESource 组件中引用它了 + +498 +00:25:30,964 --> 00:25:33,367 +如此一来 就路由并配置好了 + +499 +00:25:33,367 --> 00:25:35,969 +场景中的声音 可以播放了 + +500 +00:25:35,969 --> 00:25:39,106 +PHASE Unity 插件 +为游戏内声音设计 + +501 +00:25:39,106 --> 00:25:41,441 +带来了全新的可能性 + +502 +00:25:41,441 --> 00:25:43,744 +要更深入学习 PHASE + +503 +00:25:43,744 --> 00:25:45,946 +了解我今天介绍的这些概念 + +504 +00:25:45,946 --> 00:25:49,283 +请务必查看 +Apple Developer 文档网站 + +505 +00:25:49,283 --> 00:25:54,888 +以及去年的 WWDC 讲座视频 + +506 +00:25:54,888 --> 00:25:59,560 +我们对新 Apple Unity 插件的 +概述就到这里 + +507 +00:25:59,560 --> 00:26:02,162 +我今天讲了很多内容 如果您想要 + +508 +00:26:02,162 --> 00:26:05,399 +了解更多关于 +Apple Unity 插件的知识 + +509 +00:26:05,399 --> 00:26:09,636 +我们在 GitHub 上的仓库 +是一个绝佳的起点 + +510 +00:26:09,636 --> 00:26:12,239 +那里有源代码 + +511 +00:26:12,239 --> 00:26:17,311 +详细文档 以及各个插件的示例 + +512 +00:26:17,311 --> 00:26:19,980 +要了解更多 +关于在 Unity 游戏中 + +513 +00:26:19,980 --> 00:26:21,849 +集成辅助功能的内容 + +514 +00:26:21,849 --> 00:26:24,952 +请查看“Add accessiblity +to your Unity games”讲座 + +515 +00:26:24,952 --> 00:26:26,353 +也别忘了查看 + +516 +00:26:26,353 --> 00:26:29,256 +“Reach new players +with Game Center dashboard”讲座 + +517 +00:26:29,256 --> 00:26:32,326 +来学习如何增加您的游戏的曝光量 + +518 +00:26:32,326 --> 00:26:34,027 +感谢收看 + +519 +00:26:34,027 --> 00:26:38,599 +♪ + diff --git a/zho/2022 Session 10068 What's new in UIKit.srt b/zho/2022 Session 10068 What's new in UIKit.srt new file mode 100644 index 0000000..c2b8246 --- /dev/null +++ b/zho/2022 Session 10068 What's new in UIKit.srt @@ -0,0 +1,1440 @@ +1 +00:00:00,501 --> 00:00:06,507 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:14,214 +欢迎收看 iOS 16 的 +“What's New in UIKit” + +3 +00:00:14,248 --> 00:00:18,785 +我是 Dima +是 UIKit 团队的工程经理 + +4 +00:00:19,586 --> 00:00:23,757 +UIKit 是App 开发用到的一个强大的核心框架 + +5 +00:00:23,790 --> 00:00:28,529 +它已经更新 +以支持 iOS 16 中的新功能 + +6 +00:00:29,663 --> 00:00:35,636 +在这个视频中 我将介绍 +为提升效率进行的 UI 改进 + +7 +00:00:35,669 --> 00:00:37,838 +控件增强 + +8 +00:00:37,871 --> 00:00:40,374 +API 的改进 + +9 +00:00:40,407 --> 00:00:43,644 +我还将谈到令人振奋的 + +10 +00:00:43,677 --> 00:00:48,048 +同步使用 UIKit 和 SwiftUI 的新方法 + +11 +00:00:50,684 --> 00:00:57,124 +我们让在 UIKit 中开发出 +精简 可发现的用户界面更容易 + +12 +00:00:57,157 --> 00:01:01,395 +它有着改进过的导航栏 +包含新的标题菜单 + +13 +00:01:01,428 --> 00:01:05,265 +查找和替换 +以及重新定义编辑交互用户界面的 + +14 +00:01:05,299 --> 00:01:07,134 +剪切 复制和粘贴 + +15 +00:01:07,167 --> 00:01:10,704 +你将能够增强基于文档的应用程序 + +16 +00:01:11,405 --> 00:01:15,809 +我会先从仔细研究导航栏开始 + +17 +00:01:15,843 --> 00:01:20,113 +它经过了更新 +以支持桌面类工具栏功能 + +18 +00:01:22,416 --> 00:01:28,055 +在 iOS 16 中 +UIKit 引入了两种新的导航样式 + +19 +00:01:28,088 --> 00:01:31,291 +以更好地支持基于文档的 App + +20 +00:01:31,325 --> 00:01:34,494 +浏览器和编辑器 + +21 +00:01:35,729 --> 00:01:41,335 +浏览器风格是为使用历史记录 +或文件夹结构导航的 App + +22 +00:01:41,368 --> 00:01:45,539 +如网页和文档浏览器而设计的 + +23 +00:01:47,040 --> 00:01:53,280 +该编辑器主要用于 +以编辑文档为中心的界面 + +24 +00:01:55,148 --> 00:02:00,721 +在 iOS 16 中 你可以在 App 中 +添加各种各样的栏按钮项 + +25 +00:02:00,754 --> 00:02:06,059 +它们的一个子集会显示在 +导航栏中心 + +26 +00:02:07,294 --> 00:02:10,998 +点击菜单中的 +“customize toolbar”条目 + +27 +00:02:11,031 --> 00:02:16,436 +就可以通过拖拽 +来重新排列弹出的项目 + +28 +00:02:17,871 --> 00:02:22,409 +由此产生的新配置 +在 App 启动时持续存在 + +29 +00:02:25,312 --> 00:02:28,615 +例如 为了适应大小的变化 + +30 +00:02:28,649 --> 00:02:32,519 +当使用另一个 App +进入并排模式时 + +31 +00:02:32,553 --> 00:02:36,857 +系统会自动提供一个悬浮菜单 + +32 +00:02:36,890 --> 00:02:40,794 +来访问任何不适合的项目 + +33 +00:02:42,796 --> 00:02:47,467 +我们添加了一个标题菜单 +它与新的导航样式一起运作 + +34 +00:02:47,501 --> 00:02:50,704 +并支持一些标准功能 + +35 +00:02:50,737 --> 00:02:54,007 +复制 移动 重命名 + +36 +00:02:54,041 --> 00:02:56,844 +导出和打印 + +37 +00:02:57,711 --> 00:03:00,981 +当要实施相应的委托方法时 + +38 +00:03:01,014 --> 00:03:05,185 +这些将自动显示在菜单中 + +39 +00:03:05,219 --> 00:03:10,624 +也可以在标题菜单中 +添加完全自定义的条目 + +40 +00:03:15,028 --> 00:03:18,832 +此外 使用 Mac Catalyst 构建的 App + +41 +00:03:18,866 --> 00:03:21,869 +无需额外的代码便可与 + +42 +00:03:21,902 --> 00:03:25,005 +NSToolbar 无缝集成 + +43 +00:03:25,038 --> 00:03:28,108 +充分利用了改进的导航栏 + +44 +00:03:29,309 --> 00:03:34,214 +iOS 16 引入了在不同的 App 中 + +45 +00:03:34,248 --> 00:03:37,384 +一致地操作文本的新方法 + +46 +00:03:37,417 --> 00:03:41,588 +第一个是新的查找和替换 + +47 +00:03:41,622 --> 00:03:46,760 +从概念上讲 +它不同于对数据模型对象 + +48 +00:03:46,793 --> 00:03:52,966 +如照片或日历事件进行操作的 +更高级的 App 内搜索项目 + +49 +00:03:53,000 --> 00:03:58,705 +相反 查找与替换 +是专门用于处理文本的 + +50 +00:03:58,739 --> 00:04:02,409 +它只需要设置一个标志 +来激活如 UITextView + +51 +00:04:02,442 --> 00:04:08,448 +和 WKWebView 的内置 UIKit 视图功能 + +52 +00:04:09,650 --> 00:04:14,254 +此外 它无缝地跨越了 +选入该系统的多个视图 + +53 +00:04:14,288 --> 00:04:16,490 +和文档工作 + +54 +00:04:17,891 --> 00:04:22,729 +接下来 编辑菜单进行了重大升级 + +55 +00:04:22,763 --> 00:04:26,934 +它现在因输入法不同而有所区别 + +56 +00:04:26,967 --> 00:04:30,771 +在触摸交互方面 +重新设计的菜单 + +57 +00:04:30,804 --> 00:04:33,373 +更具互动性 + +58 +00:04:35,209 --> 00:04:37,211 +当使用指针时 + +59 +00:04:37,244 --> 00:04:41,081 +你会得到一个 +功能更全面的快捷菜单 + +60 +00:04:42,382 --> 00:04:46,420 +为了无缝提供这两种体验 + +61 +00:04:46,453 --> 00:04:50,224 +我们引入了 UIEditMenuInteraction + +62 +00:04:50,257 --> 00:04:55,329 +完全替代现在已弃用的 +UIMenuController + +63 +00:04:56,496 --> 00:05:01,768 +还有新的 API 可以将操作 +插入到文本视图的菜单中 + +64 +00:05:03,537 --> 00:05:06,673 +你可以观看 “Adopt desktop class +editing interactions” + +65 +00:05:06,707 --> 00:05:10,944 +来学习新编辑菜单上的所有细节 + +66 +00:05:10,978 --> 00:05:15,015 +并学习如何为自定义视图 +采用查找交互 + +67 +00:05:17,718 --> 00:05:21,188 +我还想说说一个可视化 UI 更新 + +68 +00:05:22,055 --> 00:05:26,026 +在 iOS 16 中 侧边栏会在 + +69 +00:05:26,059 --> 00:05:28,395 +滑动模式下自动显示 + +70 +00:05:28,428 --> 00:05:31,298 +不需要任何额外的代码 + +71 +00:05:31,331 --> 00:05:36,170 +为了实现这一点 +UIKit 会代你管理一组私有视图 + +72 +00:05:38,005 --> 00:05:41,575 +这些是 UIKit 中 +用于提高生产力的新功能 + +73 +00:05:41,608 --> 00:05:44,811 +新的可自定义导航栏 + +74 +00:05:44,845 --> 00:05:48,448 +查找与替换 编辑交互 + +75 +00:05:48,482 --> 00:05:52,119 +以及强大的标题菜单 + +76 +00:05:52,152 --> 00:05:54,621 +我只是提到了皮毛 + +77 +00:05:54,655 --> 00:05:59,293 +要了解更多 请查看课程 +“Meet desktop class iPad” + +78 +00:05:59,326 --> 00:06:03,830 +以及更深入的 +“Build a desktop class iPad app” + +79 +00:06:03,864 --> 00:06:07,134 +在那里 你将通过 +一个示例 App 的改进 + +80 +00:06:07,167 --> 00:06:11,572 +了解 iOS 16 中新的高级 UIKit 功能 + +81 +00:06:13,106 --> 00:06:17,211 +现在 我将介绍我们添加的 +两个新控件 + +82 +00:06:17,244 --> 00:06:21,782 +谈谈对 UIPageControl 的一些增强 + +83 +00:06:22,983 --> 00:06:28,488 +UIDatePicker 的内联日历样式 + +84 +00:06:28,522 --> 00:06:31,158 +现在作为一个独立的全功能组件 + +85 +00:06:31,191 --> 00:06:34,628 +以 UICalendarView 的形式提供 + +86 +00:06:34,661 --> 00:06:39,533 +UICalendarView +支持不同类型的选择行为 + +87 +00:06:39,566 --> 00:06:41,535 +如可选单个日期 + +88 +00:06:41,568 --> 00:06:44,972 +也支持选择多个日期 + +89 +00:06:45,005 --> 00:06:47,407 +除了可用日期范围 + +90 +00:06:47,441 --> 00:06:52,513 +它还支持禁用个别日期选择 + +91 +00:06:53,647 --> 00:06:58,919 +此外 你可以用装饰来注释单个日期 + +92 +00:07:00,287 --> 00:07:03,657 +UICalendarView 和 UIDatePicker +之间的一个主要区别 + +93 +00:07:03,690 --> 00:07:08,662 +在于 UICalendarView +将日期表示为 + +94 +00:07:08,695 --> 00:07:13,400 +NSDateComponents 而不是 NSDate + +95 +00:07:13,433 --> 00:07:16,937 +与 NSDate 不同 日期组件是更好的 + +96 +00:07:16,970 --> 00:07:20,507 +更正确的日期表示 + +97 +00:07:20,541 --> 00:07:25,712 +而 NSDate 是时间点的表示 + +98 +00:07:27,381 --> 00:07:31,151 +因为 NSDateComponents +提供了很大的灵活性 + +99 +00:07:31,185 --> 00:07:33,220 +你应该能明确组件 + +100 +00:07:33,253 --> 00:07:37,591 +是由哪个 NSCalendar 来表示的 + +101 +00:07:38,692 --> 00:07:43,530 +注意 你不应该对当前日历的类型 +做出假设 + +102 +00:07:43,564 --> 00:07:45,966 +如果你需要将日历设置为公历 + +103 +00:07:45,999 --> 00:07:50,137 +请明确指定公历 + +104 +00:07:53,040 --> 00:07:57,277 +要像前面显示的那样 +配置 Calendar 视图 + +105 +00:07:57,311 --> 00:08:02,816 +首先创建 Calendar 视图 +并设置其委托 + +106 +00:08:02,850 --> 00:08:08,188 +要确保 Calendar +有 Gregorian NSCalendar 支持 + +107 +00:08:08,222 --> 00:08:11,625 +将 calendarView 上的 Calendar 属性 + +108 +00:08:11,658 --> 00:08:14,528 +设置为 Gregorian NSCalendar + +109 +00:08:15,829 --> 00:08:19,733 +接下来 要配置多日期选择 + +110 +00:08:19,766 --> 00:08:24,304 +创建一个 +UICalendarSelectionMultiDate 对象 + +111 +00:08:24,338 --> 00:08:26,473 +并将选择对象上的选定日期属性 + +112 +00:08:26,507 --> 00:08:31,979 +设置为数据模型中 +显示在 Calendar 视图里的 + +113 +00:08:32,012 --> 00:08:34,481 +现有日期 + +114 +00:08:35,782 --> 00:08:41,922 +然后 将选择对象设置为 +日历视图的选择行为 + +115 +00:08:44,892 --> 00:08:49,229 +为了防止日历中单个日期的选择 + +116 +00:08:49,263 --> 00:08:53,467 +执行 multidateselect: +canSelectDate: method + +117 +00:08:53,500 --> 00:08:56,170 +通过日历选择委托 + +118 +00:08:56,203 --> 00:08:59,273 +控制哪些日期可以被选择 + +119 +00:09:00,607 --> 00:09:06,213 +无法选择的日期 +将在日历视图中显示为灰色 + +120 +00:09:07,748 --> 00:09:11,552 +要用装饰来注释单个日期 + +121 +00:09:11,585 --> 00:09:14,021 +执行日历委托的 + +122 +00:09:14,054 --> 00:09:17,691 +calendarView: +decorationForDateComponents:Method + +123 +00:09:19,426 --> 00:09:22,462 +如果不要装饰 只需返回 nil 即可 + +124 +00:09:23,564 --> 00:09:28,235 +对于默认的灰圆 返回默认装饰 + +125 +00:09:29,670 --> 00:09:35,909 +你还可以通过自定义颜色选项 +来创建图像装饰 + +126 +00:09:35,943 --> 00:09:40,247 +如果你需要做到更多 +可以使用 customView 装饰 + +127 +00:09:40,280 --> 00:09:43,083 +并在视图提供程序中返回你的视图 + +128 +00:09:44,484 --> 00:09:48,889 +请注意 自定义视图装饰不允许交互 + +129 +00:09:48,922 --> 00:09:52,226 +并会被裁剪到可用空间 + +130 +00:09:53,594 --> 00:09:56,697 +页面控件也得到了改进 + +131 +00:09:56,730 --> 00:10:01,268 +我们为当前页面添加了 +支持自定义指示器图像 + +132 +00:10:01,301 --> 00:10:03,737 +这样你现在就可以根据页面 +是否被选中 + +133 +00:10:03,770 --> 00:10:06,773 +来选择不同的图像 + +134 +00:10:08,308 --> 00:10:12,479 +你现在还可以完全自定义 + +135 +00:10:12,513 --> 00:10:14,748 +页面控件的方位和方向 + +136 +00:10:16,450 --> 00:10:20,888 +下面是配置垂直页控件的示例 + +137 +00:10:20,921 --> 00:10:26,126 +该控件的指示器 +在当前页与非当前页之间更改 + +138 +00:10:27,794 --> 00:10:31,765 +我将页面控件的方向 +设置为从上到下 + +139 +00:10:31,798 --> 00:10:36,670 +并设置了首选指示器图像 +首选当前指示器图像 + +140 +00:10:36,703 --> 00:10:38,338 +这样就大功告成了 + +141 +00:10:41,241 --> 00:10:46,580 +Apple 致力于保护用户隐私和安全 + +142 +00:10:46,613 --> 00:10:49,950 +在 iOS 15 中 +当 App 以编程方式访问粘贴板 + +143 +00:10:49,983 --> 00:10:54,788 +而不使用系统提供的 Paste 接口时 + +144 +00:10:54,821 --> 00:10:59,359 +将出现一个横幅 +表明该粘贴板已被访问 + +145 +00:11:00,594 --> 00:11:04,831 +在新的 iOS 16 中 +系统行为发生了变化 + +146 +00:11:04,865 --> 00:11:06,800 +现在 我们会显示 + +147 +00:11:06,834 --> 00:11:11,738 +请求使用粘贴板许可的提示 +而不是横幅 + +148 +00:11:13,073 --> 00:11:16,810 +与用户交互的系统粘贴接口 + +149 +00:11:16,844 --> 00:11:19,780 +提供了对粘贴板的隐式访问 + +150 +00:11:19,813 --> 00:11:22,349 +从而避免了提示 + +151 +00:11:23,817 --> 00:11:26,253 +如果你有自定义的粘贴控件 + +152 +00:11:26,286 --> 00:11:30,023 +就可以用新的 UIPasteControl +替换它们 + +153 +00:11:30,057 --> 00:11:33,560 +它的外观和行为 +都像一个填充过的 UIButton + +154 +00:11:34,895 --> 00:11:39,266 +当粘贴板获得与控件的粘贴目标 +兼容的内容时 + +155 +00:11:39,299 --> 00:11:42,202 +将启用该选项 + +156 +00:11:43,670 --> 00:11:47,007 +这些是新的强大的 UICalendarView + +157 +00:11:47,040 --> 00:11:49,643 +改进过的 UIPageControl + +158 +00:11:49,676 --> 00:11:53,814 +以及重视安全的 UIPasteControl + +159 +00:11:53,847 --> 00:11:56,783 +去试试吧 + +160 +00:11:57,718 --> 00:12:01,955 +现在 我将向你介绍 +我们所做的一些 API 改进 + +161 +00:12:03,690 --> 00:12:07,528 +在 iOS 15 中 +锁止器被添加到了工作表中 + +162 +00:12:07,561 --> 00:12:11,765 +这能支持构建灵活 动态的 UI + +163 +00:12:11,798 --> 00:12:16,770 +在 iOS 16 中 +我们增加了支持自定义锁止器 + +164 +00:12:16,803 --> 00:12:20,007 +这样你就可以制作任意大小的工作表 + +165 +00:12:21,308 --> 00:12:26,446 +要利用这个功能 +请使用新的 “.custom” 锁止器 + +166 +00:12:26,480 --> 00:12:31,885 +并在关联块中 +以点为单位指定工作表的高度 + +167 +00:12:31,919 --> 00:12:35,055 +你可以返回一个常量值 + +168 +00:12:35,088 --> 00:12:39,459 +或最大锁止高度的百分比 + +169 +00:12:42,396 --> 00:12:47,134 +如果你需要从其他 API 引用它 + +170 +00:12:47,167 --> 00:12:50,103 +也可以为自己的自定义锁止器 +提供一个标识符 + +171 +00:12:50,137 --> 00:12:54,575 +例如禁用超越自定义锁止器的调光 + +172 +00:12:57,444 --> 00:13:01,148 +请注意 从自定义块返回的值 + +173 +00:13:01,181 --> 00:13:05,352 +不应该包含底部嵌入式安全区域 + +174 +00:13:05,385 --> 00:13:11,725 +因此浮动和 +侧附加工作表的计算方法相同 + +175 +00:13:13,894 --> 00:13:19,700 +要了解更多关于有系统锁止器 +和其他选项的自定义工作表 + +176 +00:13:19,733 --> 00:13:24,872 +请观看视频“Customize +and resize sheets in UIKit” + +177 +00:13:24,905 --> 00:13:28,609 +那个视频的示例代码也进行了更新 + +178 +00:13:28,642 --> 00:13:31,879 +以展示这些新的自定义锁止器 API + +179 +00:13:33,547 --> 00:13:37,851 +UIKit 中的 SF 符号有新功能 + +180 +00:13:38,785 --> 00:13:41,655 +符号支持四种呈现模式 + +181 +00:13:41,688 --> 00:13:44,057 +单色 多色 + +182 +00:13:44,091 --> 00:13:47,928 +分层和调色 + +183 +00:13:47,961 --> 00:13:51,164 +UIKit 会默认使用单色呈现 + +184 +00:13:51,198 --> 00:13:55,769 +除非符号被配置为不同的呈现模式 + +185 +00:13:55,802 --> 00:13:59,940 +在 iOS 16 中 +如果没有指定呈现模式 + +186 +00:13:59,973 --> 00:14:02,376 +UIKit 可以使用单色以外的模式 + +187 +00:14:02,409 --> 00:14:05,279 +呈现单个符号 + +188 +00:14:07,047 --> 00:14:10,284 +以这些设备符号为例 + +189 +00:14:10,317 --> 00:14:13,453 +在 iOS 15 及之前的版本中 + +190 +00:14:13,487 --> 00:14:16,456 +如果没有指定呈现模式 + +191 +00:14:16,490 --> 00:14:19,226 +这些符号将使用单色呈现 + +192 +00:14:20,427 --> 00:14:25,699 +在 iOS 16 中 +这些符号默认为分层呈现 + +193 +00:14:26,867 --> 00:14:29,736 +通常 符号的默认呈现模式 + +194 +00:14:29,770 --> 00:14:33,473 +是展示该符号的首选方式 + +195 +00:14:33,507 --> 00:14:38,245 +因此在这种情况下 +你应该允许默认的分层呈现 + +196 +00:14:38,278 --> 00:14:40,781 +生效 + +197 +00:14:40,814 --> 00:14:45,786 +不过 单色呈现可以通过新的 + +198 +00:14:45,819 --> 00:14:51,825 +UIImage.SymbolConfiguration. +preferringMonochrome() API 来明确请求 + +199 +00:14:55,596 --> 00:14:58,765 +UIKit 增加了对可变符号的支持 + +200 +00:14:58,799 --> 00:15:02,169 +它允许 App 根据从 0 到 1 的值 + +201 +00:15:02,202 --> 00:15:06,173 +显示符号的变化 + +202 +00:15:06,206 --> 00:15:10,978 +假设一个 App 想要用一个符号 +描述当前音量级别 + +203 +00:15:11,011 --> 00:15:15,682 +该 App 可以使用 +speaker.3.wave.fill 符号 + +204 +00:15:15,716 --> 00:15:20,254 +它已被更新 以支持变量呈现 + +205 +00:15:20,287 --> 00:15:24,758 +在值为 0 时 扬声器波逐渐消失 + +206 +00:15:24,791 --> 00:15:27,861 +表示最低音量水平 + +207 +00:15:27,895 --> 00:15:30,430 +当该值增加到 1 时 + +208 +00:15:30,464 --> 00:15:33,800 +扬声器的波形逐渐填充 + +209 +00:15:33,834 --> 00:15:36,170 +表明更高的音量水平 + +210 +00:15:37,471 --> 00:15:40,307 +如果一个符号支持变量呈现 + +211 +00:15:40,340 --> 00:15:43,477 +那么 App 就可以请求一个 + +212 +00:15:43,510 --> 00:15:47,247 +反映 0 到 1 之间值的版本的符号 + +213 +00:15:48,982 --> 00:15:53,687 +使用变量符号很直白 + +214 +00:15:53,720 --> 00:15:57,457 +你可以通过标准的 SF Symbols API + +215 +00:15:57,491 --> 00:16:02,095 +在 UIImage 上获得一个 +常规非变量版符号 + +216 +00:16:03,830 --> 00:16:07,634 +要获得带有特定变量值的该符号版本 + +217 +00:16:07,668 --> 00:16:10,771 +只需添加 variableValue 参数 + +218 +00:16:12,039 --> 00:16:15,943 +你甚至可以将变量呈现 +与其他呈现模式 + +219 +00:16:15,976 --> 00:16:19,279 +如调色 混合 +以进一步设计符号的样式 + +220 +00:16:20,914 --> 00:16:25,686 +许多系统符号现在支持可变呈现 + +221 +00:16:25,719 --> 00:16:30,757 +并且 App 可以 +更新它们的自定义符号来支持可变性 + +222 +00:16:32,192 --> 00:16:35,529 +要学习如何创建自定义变量符号 + +223 +00:16:35,562 --> 00:16:40,267 +记得观看“Adopt variable color +in SF Symbols” + +224 +00:16:40,300 --> 00:16:43,604 +和 “What's new in SF Symbols 4” +这两个课程 + +225 +00:16:45,439 --> 00:16:49,877 +我们已经更新了 UIKit 以和新的 +Swift Concurrency 功能同时使用 + +226 +00:16:49,910 --> 00:16:52,045 +包括使不可变类型 + +227 +00:16:52,079 --> 00:16:56,216 +如 UIImage 和 UIColor +符合 Sendable + +228 +00:16:56,250 --> 00:16:58,986 +这样你就可以在 MainActor + +229 +00:16:59,019 --> 00:17:02,456 +和自定义 actor 之间发送它们 +而不会收到编译器警告 + +230 +00:17:03,957 --> 00:17:09,930 +例如 我们有一个叫做处理器的 +自定义 actor + +231 +00:17:09,963 --> 00:17:12,900 +以及一个被绑定到 MainActor 的 + +232 +00:17:12,933 --> 00:17:15,969 +叫做 ImageViewer 的视图控制器 + +233 +00:17:16,003 --> 00:17:18,572 +在 sendImageForProcessing 方法中 + +234 +00:17:18,605 --> 00:17:24,077 +ImageViewer 将图像发送给 +处理器 actor 进行处理 + +235 +00:17:24,111 --> 00:17:28,448 +使其看起来 +像添加了闪光和彩虹一样漂亮 + +236 +00:17:28,482 --> 00:17:32,386 +这是安全的 因为 UIImage 是不可变的 + +237 +00:17:32,419 --> 00:17:34,755 +处理器必须创建新的拷贝 + +238 +00:17:34,788 --> 00:17:36,990 +来添加彩虹和闪光 + +239 +00:17:38,358 --> 00:17:41,862 +任何引用原始图像的代码 + +240 +00:17:41,895 --> 00:17:44,364 +都不会显示这些修改 + +241 +00:17:44,398 --> 00:17:48,135 +共享状态也不会发生不安全的变化 + +242 +00:17:49,870 --> 00:17:52,973 +对比一下因为可变 + +243 +00:17:53,006 --> 00:17:56,543 +而不可发送的 UIBezierPath + +244 +00:17:57,845 --> 00:18:02,082 +以前只能在文档中表示的东西 +现在可以 + +245 +00:18:02,115 --> 00:18:06,753 +由编译器进行检查 这多棒啊 + +246 +00:18:09,056 --> 00:18:12,693 +要了解更多关于 Sendable +和 Swift Concurrency 的知识 + +247 +00:18:12,726 --> 00:18:17,464 +请查看视频“Eliminate data races +using Swift Concurrency” + +248 +00:18:17,497 --> 00:18:23,337 +和“Visualize +and optimize Swift Concurrency” + +249 +00:18:25,405 --> 00:18:30,644 +iOS 16 对外部显示器 +提供了新的强大支持 + +250 +00:18:31,245 --> 00:18:36,583 +好消息是 +你不需要更新你的 App 来利用它 + +251 +00:18:36,617 --> 00:18:40,487 +除非你使用的是旧版 UIScreen API + +252 +00:18:41,588 --> 00:18:45,459 +你不能再默认你的 App 在主屏幕上 + +253 +00:18:46,260 --> 00:18:49,763 +相反 你要遵从更具体的 API + +254 +00:18:49,796 --> 00:18:53,000 +比如 trait collection +和 UIScene API + +255 +00:18:53,033 --> 00:18:55,702 +来获得你需要的信息 + +256 +00:18:55,736 --> 00:18:58,438 +如果你的 App 仍未使用 UIScene + +257 +00:18:58,472 --> 00:19:03,911 +现在你有了更多的理由升级 +以支持多窗口 + +258 +00:19:05,445 --> 00:19:08,115 +UICollectionView +和 UITableView 中的 + +259 +00:19:08,148 --> 00:19:12,586 +自定大小单元格受到了重大升级 + +260 +00:19:12,619 --> 00:19:16,523 +现在单元格也可以自我调整大小了 + +261 +00:19:16,557 --> 00:19:21,595 +在 iOS 16 中 +当可见单元格内的内容发生变化时 + +262 +00:19:21,628 --> 00:19:26,633 +单元格将自动调整大小 +以适应新内容 + +263 +00:19:28,235 --> 00:19:31,371 +这个新行为是默认启用的 + +264 +00:19:31,405 --> 00:19:34,141 +UICollectionView 和 UITableView + +265 +00:19:34,174 --> 00:19:38,178 +各有一个新的 +selfSizingInvalidation 属性 + +266 +00:19:38,212 --> 00:19:41,548 +让你能控制这个新功能 + +267 +00:19:43,016 --> 00:19:44,785 +以下是它的运作方式 + +268 +00:19:46,220 --> 00:19:49,690 +当启用 selfSizingInvalidation 时 + +269 +00:19:49,723 --> 00:19:52,259 +单元格可以请求通过其包含的集合 + +270 +00:19:52,292 --> 00:19:55,162 +或表视图来调整大小 + +271 +00:19:56,930 --> 00:20:01,768 +如果你用了 UIListContentConfiguration +配置单元格 + +272 +00:20:01,802 --> 00:20:04,204 +那么每当单元格的配置发生更改时 + +273 +00:20:04,238 --> 00:20:07,474 +失效就会自动发生 + +274 +00:20:08,942 --> 00:20:11,011 +对于任何其他情况 + +275 +00:20:11,044 --> 00:20:14,915 +你都可以调用单元格 +invalidateIntrinsicContentSize 方法 + +276 +00:20:14,948 --> 00:20:19,086 +或它的 contentView +来调整单元格的大小 + +277 +00:20:20,888 --> 00:20:24,558 +默认情况下 +单元格会随着动画而调整大小 + +278 +00:20:24,591 --> 00:20:28,428 +但是你可以用 +performWithoutAnimation 中的 + +279 +00:20:28,462 --> 00:20:33,734 +invalidateIntrinsicContentSize 绕过指令 +从而不使用动画调整大小 + +280 +00:20:33,767 --> 00:20:38,539 +UICollectionView 和 UITableView +将单元格的 + +281 +00:20:38,572 --> 00:20:40,474 +大小无效智能合并为 + +282 +00:20:40,507 --> 00:20:44,645 +在最佳时间执行的单个更新 + +283 +00:20:47,247 --> 00:20:49,950 +如果你在单元格中使用 Auto Layout + +284 +00:20:49,983 --> 00:20:53,754 +你可以通过选择 +enabledinclingconstraints + +285 +00:20:53,787 --> 00:20:57,691 +来完成一个更全面的行为 + +286 +00:20:57,724 --> 00:21:03,564 +这意味着当一个单元格检测到它的 +contentView 内部的任何自动布局变化时 + +287 +00:21:03,597 --> 00:21:08,702 +它将自动调用 +invalidateIntrinsicContentSize + +288 +00:21:08,735 --> 00:21:14,074 +这样包含的集合或表格视图 +就可以在必要时调整它的大小 + +289 +00:21:15,008 --> 00:21:17,044 +这使得单元格 + +290 +00:21:17,077 --> 00:21:20,147 +随内容或布局更新自动调整大小 + +291 +00:21:20,180 --> 00:21:23,450 +变得非常容易 + +292 +00:21:25,419 --> 00:21:28,689 +UIKit 强大而灵活 + +293 +00:21:28,722 --> 00:21:32,125 +你也可以利用通过 SwiftUI + +294 +00:21:32,159 --> 00:21:36,330 +来执行 UI 的可表达性 + +295 +00:21:36,363 --> 00:21:41,935 +我们已经使在同一个 App 中 +合并这两个框架容易了很多 + +296 +00:21:43,971 --> 00:21:50,177 +在iOS 16 中 有一种全新的 +使用 SwiftUI 为集合和表格视图 + +297 +00:21:50,210 --> 00:21:53,647 +构建单元格的方式 + +298 +00:21:55,048 --> 00:21:59,520 +这是通过一个名为 +UIHostingConfiguration 的 + +299 +00:21:59,553 --> 00:22:03,290 +新内容配置类型实现的 + +300 +00:22:03,323 --> 00:22:05,592 +只需一行代码 + +301 +00:22:05,626 --> 00:22:10,063 +你就可以在单元格中 +开始编写 SwiftUI + +302 +00:22:10,097 --> 00:22:14,001 +完全不需要额外的视图 +或视图控制器 + +303 +00:22:15,869 --> 00:22:19,540 +下面是一个在 SwiftUI 中 +使用 UIHostingConfiguration 编写的 + +304 +00:22:19,573 --> 00:22:22,476 +简单的自定义单元格 + +305 +00:22:22,509 --> 00:22:25,646 +构建这个单元格非常容易 + +306 +00:22:27,147 --> 00:22:33,587 +这不仅是开始将 SwiftUI +集成到你的 App 中的一个很好的方式 + +307 +00:22:33,620 --> 00:22:39,426 +而且 SwiftUI 的表达力意味着 +前所未有的 在 UIKit 中 + +308 +00:22:39,459 --> 00:22:42,996 +构建自定义单元格的强大方式 + +309 +00:22:43,797 --> 00:22:46,266 +关于这个话题还有很多值得讨论 + +310 +00:22:46,300 --> 00:22:49,169 +所以一定要看看视频 + +311 +00:22:49,203 --> 00:22:53,674 +“Use SwiftUI with UIKit”来深入了解 + +312 +00:22:56,643 --> 00:23:02,249 +有几个微小但重要的变化 +你应该知道 + +313 +00:23:02,983 --> 00:23:06,286 +为了防止用户被指纹识别 + +314 +00:23:06,320 --> 00:23:10,123 +UIDevice.name 现在会报告模型名称 + +315 +00:23:10,157 --> 00:23:14,027 +而非用户自定义的设备名称 + +316 +00:23:14,061 --> 00:23:18,799 +现在使用自定义名称需要获得授权 + +317 +00:23:20,534 --> 00:23:24,805 +不再支持设置 UIDevice.orientation + +318 +00:23:24,838 --> 00:23:28,509 +相反 要使用 UIViewController API + +319 +00:23:28,542 --> 00:23:31,512 +如 preferredInterfaceOrientation + +320 +00:23:31,545 --> 00:23:35,516 +来表达你界面的预期方向 + +321 +00:23:36,783 --> 00:23:38,785 +接下来是什么 + +322 +00:23:38,819 --> 00:23:43,690 +使用 iOS 16 SDK 编译你的 App + +323 +00:23:43,724 --> 00:23:47,594 +测试新功能 如文本编辑菜单 + +324 +00:23:47,628 --> 00:23:50,197 +查找和替换 + +325 +00:23:50,230 --> 00:23:55,002 +采用新的 UIKit API +来使用新的加强控件 + +326 +00:23:55,035 --> 00:23:57,571 +和用于提高生产力的新功能 + +327 +00:23:57,604 --> 00:24:00,507 +并尝试在你的 UIKit app 中 + +328 +00:24:00,541 --> 00:24:04,311 +加入 SwiftUI 的新方式 + +329 +00:24:05,179 --> 00:24:06,680 +谢谢大家 + diff --git a/zho/2022 Session 10069 Meet desktop class iPad.srt b/zho/2022 Session 10069 Meet desktop class iPad.srt new file mode 100644 index 0000000..ec8996c --- /dev/null +++ b/zho/2022 Session 10069 Meet desktop class iPad.srt @@ -0,0 +1,999 @@ +1 +00:00:01,134 --> 00:00:07,140 +[古怪的音乐] + +2 +00:00:10,077 --> 00:00:13,614 +David Duncan: 大家好, 我是David Duncan +在这个视频里 + +3 +00:00:13,647 --> 00:00:17,384 +我将为大家介绍 +桌面级 iPad + +4 +00:00:18,151 --> 00:00:24,992 +iOS 16 全新升级了 +设计和构建强大 App 的工具 + +5 +00:00:25,025 --> 00:00:28,829 +为前端带来更多更好用工具的Apps + +6 +00:00:28,862 --> 00:00:34,368 +充分利用了内置及附加的硬件 + +7 +00:00:34,401 --> 00:00:39,506 +UIKit 增加了许多工具 +可以帮助您实现 App 的这些目标 + +8 +00:00:39,540 --> 00:00:43,677 +UINavigationBar 的更新 +让您可以更好地利用 + +9 +00:00:43,710 --> 00:00:48,348 +屏幕可显示面积 并在 Apple 所有平台 +都建立绝佳的体验感 + +10 +00:00:49,583 --> 00:00:54,288 +这个全新的 Find and Replace UI +是可以启用内置视图 + +11 +00:00:54,321 --> 00:00:57,291 +并可轻松添加自定义视图的快照 + +12 +00:00:57,324 --> 00:01:01,828 +编辑菜单已全面改造 +为基于交互的 API + +13 +00:01:01,862 --> 00:01:03,897 +与菜单系统整合 + +14 +00:01:04,665 --> 00:01:08,268 +Collection 视图的改进也让构建界面 +前所未有的简便 + +15 +00:01:08,302 --> 00:01:13,574 +您的用户可根据内容 +选择及操作 + +16 +00:01:15,475 --> 00:01:19,546 +您可查看“Adopt desktop +class editing interactions” + +17 +00:01:19,580 --> 00:01:24,451 +获取更多关于 Find and Replace +以及编辑菜单的信息 + +18 +00:01:24,484 --> 00:01:27,888 +也可查看 +“Build a desktop class iPad app” + +19 +00:01:27,921 --> 00:01:30,991 +了解这些功能是如何整合协作的 + +20 +00:01:32,059 --> 00:01:35,395 +在这个视频中 我将与大家 +共同探讨导航的变化 + +21 +00:01:35,429 --> 00:01:38,899 +这会影响您何如设计 iOS 16 的 App + +22 +00:01:40,901 --> 00:01:47,508 +首先 我们有一些新功能 能让您 +更简便地构建可发现的接口 + +23 +00:01:47,541 --> 00:01:53,914 +还有对基于文档的 App 来说 +尤为强大的功能 + +24 +00:01:53,947 --> 00:01:59,219 +最后 Search 进行了更新 +从而帮助加速和改进体验感 + +25 +00:02:00,821 --> 00:02:05,759 +UINavigationBar 在 iOS 中 +有不同的使用目的 + +26 +00:02:05,792 --> 00:02:08,362 +iOS 16 同样也搭载这一功能 + +27 +00:02:08,395 --> 00:02:13,033 +提供了许多这些使用场景中 +全新优化的 UI + +28 +00:02:13,066 --> 00:02:16,803 +UINavigationItem 增加了一个 +样式属性 + +29 +00:02:16,837 --> 00:02:22,843 +可用于选择以下样式 +导航 浏览和编辑 + +30 +00:02:22,876 --> 00:02:25,712 +我将为大家逐一解释 + +31 +00:02:26,580 --> 00:02:30,017 +默认的样式是导航 + +32 +00:02:30,050 --> 00:02:34,021 +与传统 UINavigationBar +完全一样 + +33 +00:02:35,389 --> 00:02:40,494 +标题居中 有前端 +和后端工具栏按钮项 + +34 +00:02:40,527 --> 00:02:45,532 +以及视图堆栈有超出 1 个项目时 +显示的后退按钮 + +35 +00:02:45,566 --> 00:02:50,938 +浏览样式重新排列了内容 +从而更好地优化接口 + +36 +00:02:50,971 --> 00:02:56,076 +历史记录与定位同样重要 +如在 Files 或 Safari 中 + +37 +00:02:57,144 --> 00:02:59,913 +在这个样式中 标题移到了前方 + +38 +00:03:00,948 --> 00:03:04,651 +编辑样式的优化是针对 +主要功能为 + +39 +00:03:04,685 --> 00:03:06,486 +文档编辑时所做的 + +40 +00:03:06,520 --> 00:03:10,724 +如浏览样式一样 +标题在最前方排列对齐 + +41 +00:03:10,757 --> 00:03:15,462 +编辑 UI 通常是一个终点 +如用文档选择器 + +42 +00:03:15,495 --> 00:03:17,164 +选择文档后 + +43 +00:03:17,197 --> 00:03:21,201 +因此显示一个后退按钮 +从而便于访问该 UI + +44 +00:03:23,103 --> 00:03:27,908 +浏览和编辑样式在工具栏中间 +都有许多自由空间 + +45 +00:03:29,543 --> 00:03:33,547 +iOS 16 正是 +利用了这一自由空间 + +46 +00:03:33,580 --> 00:03:37,050 +允许您将额外的控制按钮 +放入该区域 + +47 +00:03:38,852 --> 00:03:41,655 +中心项目是其中一项改变 + +48 +00:03:41,688 --> 00:03:44,925 +以利用屏幕可显示面积 + +49 +00:03:44,958 --> 00:03:48,428 +并涵盖 +UIBarButtonItemGroup 支持 + +50 +00:03:48,462 --> 00:03:51,265 +自定义支持及溢出 + +51 +00:03:52,666 --> 00:03:55,936 +溢出支持在所有模式都可用 + +52 +00:03:55,969 --> 00:03:58,605 +也让导航样式 + +53 +00:03:58,639 --> 00:04:01,175 +可间接支持中心项目 + +54 +00:04:02,676 --> 00:04:07,981 +单独控制继续 +指定为 UIBarButtonItems + +55 +00:04:08,015 --> 00:04:11,785 +但现在如 UIBarButtonItemGroups +一样组织 + +56 +00:04:12,519 --> 00:04:17,257 +这样在空间有限时可紧密展示 + +57 +00:04:17,291 --> 00:04:23,997 +在这个例子中 工具栏有 5 个项目 +组成了 4 个组 + +58 +00:04:26,633 --> 00:04:30,904 +第一组包含一个单栏按钮项目 + +59 +00:04:30,938 --> 00:04:34,041 +因此这一案例使用的是 +UIBarButtonItem 的 + +60 +00:04:34,074 --> 00:04:39,046 +简易方式 creatingFixedGroup +来创建的 + +61 +00:04:40,447 --> 00:04:43,350 +如果您需要超过 +1 个项目的固定组 + +62 +00:04:43,383 --> 00:04:46,653 +可使用 UIBarButtonItemGroup 方法 + +63 +00:04:47,788 --> 00:04:50,958 +固定组通常在工具栏首位 + +64 +00:04:50,991 --> 00:04:54,795 +不能移动或自定义 + +65 +00:04:54,828 --> 00:04:58,866 +绘制组包含一个单一项目 + +66 +00:04:58,899 --> 00:05:02,169 +因此也使用了简易 API + +67 +00:05:02,202 --> 00:05:06,840 +即 creatingMovableGroup +(customizationIdentifier) + +68 +00:05:06,874 --> 00:05:11,912 +如固定组一样 可移动组不能移除 +但可移动 + +69 +00:05:13,113 --> 00:05:16,583 +因此 需要 customizationIdentifier + +70 +00:05:16,617 --> 00:05:20,220 +来追踪和保存它们的位置 + +71 +00:05:20,254 --> 00:05:22,756 +如果您需要超过 1 个项目的组 + +72 +00:05:22,789 --> 00:05:25,726 +可使用 UIBarButtonItemGroup 方法 + +73 +00:05:28,395 --> 00:05:32,499 +这一图形组包含多个项目 + +74 +00:05:32,533 --> 00:05:35,836 +因此使用 UIBarButtonItemGroup API +来创建组 + +75 +00:05:37,437 --> 00:05:39,706 +该组在工具栏中应为可移动 + +76 +00:05:39,740 --> 00:05:43,810 +同时也是可移除的 +因此创建为选项组 + +77 +00:05:45,012 --> 00:05:48,582 +该组同样指定了 +一个 representativeItem + +78 +00:05:48,615 --> 00:05:52,486 +让 UIKit 在必要时刻拆散组 +从而获得更多空间 + +79 +00:05:53,820 --> 00:05:58,592 +representativeItem 并不指定操作 +进一步允许 UIKit + +80 +00:05:58,625 --> 00:06:02,496 +合成可选择组项目的菜单 + +81 +00:06:05,499 --> 00:06:10,370 +当调用自定义 UI 时 +UIKit 自动应用 + +82 +00:06:10,404 --> 00:06:15,342 +您基于如何创建组 +所指定的规则 + +83 +00:06:15,375 --> 00:06:18,912 +当固定和可移动组 +必须保留在工具栏时 + +84 +00:06:18,946 --> 00:06:22,282 +可选组可用任意方式增加或移除 + +85 +00:06:23,450 --> 00:06:25,719 +UIKit 会尝试粉碎组 + +86 +00:06:25,752 --> 00:06:29,189 +从而保证工具栏的功能 + +87 +00:06:29,223 --> 00:06:33,427 +但如果空间不可用 +额外的项目将被移到工作或溢出 + +88 +00:06:34,328 --> 00:06:40,067 +溢出菜单包含自定义部分的 + +89 +00:06:40,100 --> 00:06:42,302 +所有不适用于工具栏的项目 + +90 +00:06:42,336 --> 00:06:44,671 +以及自定义工具栏的选项 + +91 +00:06:45,839 --> 00:06:50,978 +UIKit 为每个工具栏按钮项 +合成默认菜单元素时 + +92 +00:06:51,011 --> 00:06:55,916 +您可按需选择 +自定义 menuRepresentation + +93 +00:06:55,949 --> 00:06:59,887 +最后 这一例子可自定义 + +94 +00:06:59,920 --> 00:07:01,688 +以及添加 centerItemGroups + +95 +00:07:02,823 --> 00:07:08,295 +您通过设置 UINavigationItem. +CustomizationIdentifier 启动自定义 + +96 +00:07:09,363 --> 00:07:14,101 +customizationIdentifier 定义 +工具栏的独特自定义 + +97 +00:07:14,134 --> 00:07:18,272 +因此选择一个不会与 App 内 +其它自定义冲突的字符串 + +98 +00:07:19,840 --> 00:07:24,745 +UIKit 基于该标识符 +自动保存及存储自定义 + +99 +00:07:25,779 --> 00:07:30,450 +接下来 自提供 centerItemGroups + +100 +00:07:30,484 --> 00:07:33,253 +我已经提到了刚开始的四个组 + +101 +00:07:34,621 --> 00:07:40,494 +格式组是可选组 +不再默认自定义中 + +102 +00:07:40,527 --> 00:07:44,198 +因此该代码替换 +isInDefaultCustomization 参数的 + +103 +00:07:44,231 --> 00:07:48,569 +默认值 从而将其排除在外 + +104 +00:07:49,169 --> 00:07:52,573 +即使没有设置 UINavigationItem. +customizationIdentifier + +105 +00:07:52,606 --> 00:07:59,546 +您仍可以使用 centerItemGroups +但自定义不可用 + +106 +00:07:59,580 --> 00:08:02,583 +在 Mac Catalyst 中 UINavigationBar + +107 +00:08:02,616 --> 00:08:06,019 +自动将其内容 +转译到 NSToolbar + +108 +00:08:06,954 --> 00:08:10,123 +前端 中间及后端组 + +109 +00:08:10,157 --> 00:08:14,561 +都按顺序添加 中间组合项的 +自定义属性 + +110 +00:08:14,595 --> 00:08:19,800 +当使用 NSToolbar 自定义时 +需谨慎处理 + +111 +00:08:21,101 --> 00:08:25,272 +所有预期的 NSToolbar 行为 + +112 +00:08:25,305 --> 00:08:29,443 +以及其它属性 如标题和窗口代理 +均可用 + +113 +00:08:30,544 --> 00:08:35,249 +这些在优化 Mac 时 +都是默认触发的 + +114 +00:08:35,282 --> 00:08:40,120 +接下来 我们主要来看 +强大的交互功能 + +115 +00:08:40,153 --> 00:08:43,056 +尤其在处理文档时 + +116 +00:08:43,090 --> 00:08:47,828 +UINavigationBar 现在支持 +向标题视图添加菜单 + +117 +00:08:47,861 --> 00:08:54,134 +提供中央单元以添加整体操作 +内容的动作 + +118 +00:08:54,168 --> 00:08:57,538 +此外 您可以为共享表添加支持 + +119 +00:08:57,571 --> 00:08:59,606 +及从菜单中拖拽 + +120 +00:09:00,374 --> 00:09:04,011 +首先 我先着重介绍菜单项 + +121 +00:09:04,044 --> 00:09:08,282 +一旦启用后 默认标题菜单 +提供 5 个指令 + +122 +00:09:08,315 --> 00:09:13,854 +复制 移动 重命名 导出及打印 + +123 +00:09:13,887 --> 00:09:15,656 +这些项目将根据 + +124 +00:09:15,689 --> 00:09:20,027 +响应者链中的特定方法进行筛选 + +125 +00:09:20,060 --> 00:09:23,864 +UINavigationBar 具有对重命名的 +特定支持 + +126 +00:09:23,897 --> 00:09:27,868 +因此如果您执行了 renameDelegate +它也将包括在内 + +127 +00:09:30,103 --> 00:09:34,708 +若要启用标题菜单 +请设置 titleMenuProvider + +128 +00:09:34,741 --> 00:09:38,078 +该闭包会返回要显示的最终菜单 + +129 +00:09:39,446 --> 00:09:43,383 +闭包位于建议元素数组的后面 + +130 +00:09:43,417 --> 00:09:48,422 +您可以直接使用 过滤 +或者添加自己的 + +131 +00:09:48,455 --> 00:09:53,927 +在我们的示例中 我们将向菜单 +添加一个附加操作 + +132 +00:09:53,961 --> 00:09:56,763 +最后 返回合成的 UIMenu + +133 +00:09:58,398 --> 00:10:02,936 +标题菜单还允许通过 +活动 view controller + +134 +00:10:02,970 --> 00:10:04,671 +进行共享 并支持拖拽 + +135 +00:10:06,106 --> 00:10:10,711 +要启用这些功能 +请提供描述文档的 + +136 +00:10:10,744 --> 00:10:12,546 +UIDocumentProperties 实例 + +137 +00:10:14,248 --> 00:10:18,585 +UIDocumentProperties 代表 +文档的元数据 + +138 +00:10:18,619 --> 00:10:21,121 +包括预览 + +139 +00:10:21,154 --> 00:10:23,924 +这个示例创建了一个 URL + +140 +00:10:23,957 --> 00:10:27,995 +允许 UIKit 自动获取必要的元数据 + +141 +00:10:29,329 --> 00:10:32,266 +为启用其它功能 此示例创建一个 + +142 +00:10:32,299 --> 00:10:34,968 +NSItemProvider 来代表文档 + +143 +00:10:36,570 --> 00:10:40,607 +设置 dragItemsProvider +以启用拖拽功能 + +144 +00:10:40,641 --> 00:10:47,181 +此闭包经过 UIDragSession +并返回 UIDragItems 数组 + +145 +00:10:47,214 --> 00:10:50,417 +此示例返回代表文档的单个项 + +146 +00:10:52,219 --> 00:10:56,123 +设置 activityViewControllerProvider +可启用共享 + +147 +00:10:56,156 --> 00:11:00,360 +该闭包配置并 +返回一个 UIActivityViewController + +148 +00:11:01,628 --> 00:11:04,164 +最后 将填写好的对象分配给 + +149 +00:11:04,198 --> 00:11:09,102 +UINavigationItem.documentPropertiesc +当点击标题时 + +150 +00:11:09,136 --> 00:11:13,006 +UIKit 会将 header +与其他 titleMenu 项一起显示 + +151 +00:11:15,843 --> 00:11:18,745 +在 Mac Catalyst 上 + +152 +00:11:18,779 --> 00:11:22,082 +即将传递给 titleMenuProvider 的 +建议项目 + +153 +00:11:22,115 --> 00:11:25,252 +已经存在于 File 菜单中 + +154 +00:11:25,285 --> 00:11:28,789 +您要添加到标题菜单的任何项目 + +155 +00:11:28,822 --> 00:11:31,158 +都需要通过其它方式提供 + +156 +00:11:32,359 --> 00:11:36,630 +您可以使用 +UIMenuBuilder API 添加这些项目 + +157 +00:11:36,663 --> 00:11:39,266 +或根据需要过滤现有项目 + +158 +00:11:40,267 --> 00:11:44,304 +如果您指定了文档属性 +UIKit 将自动使用 + +159 +00:11:44,338 --> 00:11:48,041 +提供的 URL +来管理 macOS 代理图标 + +160 +00:11:49,142 --> 00:11:53,180 +如果手动设置 windowScene 的 +representedURL + +161 +00:11:53,213 --> 00:11:55,749 +则将取代 UIKit 的管理 + +162 +00:11:57,217 --> 00:12:01,588 +UIKit 提供了两种机制来启用重命名 + +163 +00:12:01,622 --> 00:12:07,261 +内联重命名是通过设置 +UINavigationItem.renameDelegate 来提供的 + +164 +00:12:07,294 --> 00:12:11,732 +它为在所有平台上编辑标题 +提供了一个专门的 UI + +165 +00:12:12,966 --> 00:12:16,403 +完成后 生成的名称将传递给代理 + +166 +00:12:17,504 --> 00:12:22,342 +或者 您可以通过 +执行 UIResponder.rename (_:) + +167 +00:12:22,376 --> 00:12:28,649 +并提供您喜欢的任何 UI +来完全控制重命名体验 + +168 +00:12:30,150 --> 00:12:34,655 +在iOS上 UINavigationBar 直接在 + +169 +00:12:34,688 --> 00:12:37,257 +标题视图中提供重命名 UI + +170 +00:12:37,291 --> 00:12:41,428 +在 macOS 上 +当导航栏位于 NSToolbar 中时 + +171 +00:12:41,461 --> 00:12:44,464 +窗口的标题将提供重命名 UI + +172 +00:12:45,432 --> 00:12:50,470 +要实现内联重命名 请遵循 +UINavigationItemRenameDelegate 协议 + +173 +00:12:50,504 --> 00:12:56,076 +并设置导航项的 renameDelegate + +174 +00:12:56,109 --> 00:13:01,815 +只有一个必需的方法 +即 NavigationItem(_:didEndRenamingWith:) + +175 +00:13:01,849 --> 00:13:04,985 +用于接收用户接受的标题 + +176 +00:13:06,253 --> 00:13:09,556 +对于基于文件的 app +即 UIDocumentBrowserViewController + +177 +00:13:09,590 --> 00:13:11,258 +现在提供了一个重命名的 API + +178 +00:13:12,459 --> 00:13:16,864 +Search 是指有多少用户 +找到他们最重要的数据 + +179 +00:13:16,897 --> 00:13:23,170 +iOS 16 的进步使其更容易 +提供出色的搜索体验 + +180 +00:13:23,203 --> 00:13:27,307 +首先要注意的是 iPadOS 上的导航栏 + +181 +00:13:27,341 --> 00:13:31,111 +和 MacOS 上的工具栏 +现在排成一排 + +182 +00:13:31,144 --> 00:13:33,881 +搜索占用的空间更少了 + +183 +00:13:33,914 --> 00:13:36,984 +在 iPadOS上 您可以用 + +184 +00:13:37,017 --> 00:13:40,954 +UINavigationItem.preferredSearchBarPlacement +恢复历史行为 + +185 +00:13:40,988 --> 00:13:44,358 +此外 搜索栏可以粉碎成一个按钮 + +186 +00:13:44,391 --> 00:13:46,994 +为其它控件提供更多空间 + +187 +00:13:47,728 --> 00:13:51,298 +当搜索被激活时 将显示搜索建议 + +188 +00:13:51,331 --> 00:13:55,736 +并且可以将其与 +更新搜索查询一起更新 + +189 +00:13:55,769 --> 00:14:00,007 +从而使您有机会帮助用户进行搜索 + +190 +00:14:00,807 --> 00:14:04,211 +接下来 我将介绍设置搜索建议 +所需的代码 + +191 +00:14:06,013 --> 00:14:11,685 +要管理搜索建议 +请遵循 UISearchResultsUpdate + +192 +00:14:11,718 --> 00:14:16,056 +并设置 searchController 的 +SearchResultsUpdate + +193 +00:14:16,089 --> 00:14:19,927 +这使您可以在查询更改时更新建议 + +194 +00:14:19,960 --> 00:14:22,663 +并对选定的搜索建议执行操作 + +195 +00:14:24,097 --> 00:14:29,303 +当查询更改时 +将调用 updateSearchResults(for:) + +196 +00:14:29,336 --> 00:14:31,805 +允许您更新搜索建议 + +197 +00:14:33,040 --> 00:14:36,643 +您可自行决定提供什么建议 + +198 +00:14:36,677 --> 00:14:39,780 +设置空数组将清除建议 UI + +199 +00:14:41,114 --> 00:14:46,486 +UIKit 提供 UISearchSuggestionItem +来指定建议内容 + +200 +00:14:48,021 --> 00:14:51,491 +要响应建议的选择 + +201 +00:14:51,525 --> 00:14:55,996 +请执行 +updateSearchResults(for:Choosing:) + +202 +00:14:56,029 --> 00:14:59,333 +该方法传递所选择的搜索建议 + +203 +00:14:59,366 --> 00:15:02,369 +因此您可以对它作出适当的响应 + +204 +00:15:02,402 --> 00:15:07,007 +在本例中 我通过将当前查询 + +205 +00:15:07,040 --> 00:15:10,444 +替换为搜索建议指定的查询 +来更新搜索 + +206 +00:15:10,477 --> 00:15:13,947 +UISearchTextField +也有 searchSuggestions + +207 +00:15:13,981 --> 00:15:16,850 +所以如果您喜欢单独使用该类 + +208 +00:15:16,884 --> 00:15:19,753 +仍然可以执行搜索建议 + +209 +00:15:19,786 --> 00:15:24,558 +但如您使用的是 UISearchController +则应改用其属性 + +210 +00:15:25,759 --> 00:15:29,463 +在 iOS 16 中 UIKit 提供了 +新的 API + +211 +00:15:29,496 --> 00:15:33,233 +来帮助您提高用户的工作效率 + +212 +00:15:33,267 --> 00:15:36,570 +通过中间项目和标题菜单 + +213 +00:15:36,603 --> 00:15:38,772 +为高级功能带来更多可查找性 + +214 +00:15:39,940 --> 00:15:43,177 +通过直接从导航栏 +提供拖拽和共享功能 + +215 +00:15:43,210 --> 00:15:46,113 +改进文档支持 + +216 +00:15:46,980 --> 00:15:52,920 +通过提供搜索建议 +让搜索变得更容易 更快 + +217 +00:15:52,953 --> 00:15:56,190 +并立即获得良好的 Mac 体验 + +218 +00:15:56,223 --> 00:15:58,192 +且几乎不费吹灰之力 + +219 +00:15:58,225 --> 00:15:59,927 +感谢您的观看 + +220 +00:15:59,960 --> 00:16:03,864 +我迫不及待想看您是如何 +将 app 提升到桌面级了 + +221 +00:16:03,897 --> 00:16:05,966 +[古怪的音乐] + diff --git a/zho/2022 Session 10070 Build a desktop-class iPad app.srt b/zho/2022 Session 10070 Build a desktop-class iPad app.srt new file mode 100644 index 0000000..9bf39ec --- /dev/null +++ b/zho/2022 Session 10070 Build a desktop-class iPad app.srt @@ -0,0 +1,1418 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,843 --> 00:00:12,112 +Mohammed: 大家好 +我是 UIKit 的 Mohammed + +3 +00:00:12,145 --> 00:00:14,114 +感谢大家和我一起 + +4 +00:00:14,147 --> 00:00:17,584 +深入探索 +桌面级 iPad App 的构建 + +5 +00:00:17,618 --> 00:00:20,954 +在这个视频中 +我们使用 iPadOS 16 API + +6 +00:00:20,988 --> 00:00:25,092 +来将当前 iPad App 更新为 +桌面级体验 + +7 +00:00:25,125 --> 00:00:28,362 +我们首先使用全新的 +导航工具栏 API + +8 +00:00:28,395 --> 00:00:30,664 +展示其强大的功能 + +9 +00:00:30,697 --> 00:00:34,334 +增加 UI 密度 提供自定义 + +10 +00:00:35,836 --> 00:00:39,573 +然后 我们应用 +新的 UICollectionView 和 Menu API + +11 +00:00:39,606 --> 00:00:45,212 +以启用复杂工作流 +及多重选择的快速活动栏 + +12 +00:00:45,245 --> 00:00:49,316 +最后以启用新的 +查找和替换体验结束整个操作 + +13 +00:00:49,349 --> 00:00:52,753 +使用新的编辑菜单 +增强文本编辑 + +14 +00:00:52,786 --> 00:00:57,858 +我们更新的 App 是为 iPadOS 15 +构建的 Markdown 编辑器 + +15 +00:00:57,891 --> 00:01:01,495 +我们查看现代化过程的 +每个步骤时 + +16 +00:01:01,528 --> 00:01:05,299 +我会与大家解释该选择背后的 +最佳实践方法及动机 + +17 +00:01:05,332 --> 00:01:08,435 +以便您在将 App 应用到 +类似的流程中时 + +18 +00:01:08,468 --> 00:01:12,072 +能知道需要考虑的因素有哪些 + +19 +00:01:13,140 --> 00:01:15,809 +如果开始前 +您需要一些入门知识 + +20 +00:01:15,843 --> 00:01:18,045 +可查看“桌面级 iPad 简介”视频 + +21 +00:01:18,078 --> 00:01:22,549 +里面有所有 UIKit 全新 +iPadOS API 分类 + +22 +00:01:22,583 --> 00:01:25,152 +以及”iPad App 设计的 +最新更新”视频 + +23 +00:01:25,185 --> 00:01:30,090 +了解更多关于设计最佳的 +桌面级 iPad App 的技巧 + +24 +00:01:30,123 --> 00:01:31,925 +好了 我们开始吧 + +25 +00:01:32,659 --> 00:01:37,197 +在开始前 我们先想一下 +我们 App 控制的配置 + +26 +00:01:37,231 --> 00:01:41,401 +由于该 App 是为 iPadOS 15 +设计的 在导航工具栏中 + +27 +00:01:41,435 --> 00:01:44,571 +已经展示了最重要的控制功能 + +28 +00:01:44,605 --> 00:01:49,276 +并在不同的菜单和 popover 弹出框中 +置入了二级控制功能 + +29 +00:01:50,878 --> 00:01:55,916 +在 iPadOS 16 中 UIKit 使当前的 +导航样式更正式 + +30 +00:01:55,949 --> 00:02:01,188 +并推出了两个全新的样式 +布局更紧密 自定义程度更高 + +31 +00:02:01,221 --> 00:02:05,826 +这让 App 可以用最适配内容的 +布局方式 + +32 +00:02:05,859 --> 00:02:09,229 +并为前端 UI 带来更多功能 + +33 +00:02:11,265 --> 00:02:16,603 +导航 App 有类似的推送 +或弹出的导航模型 + +34 +00:02:16,637 --> 00:02:20,340 +这整体来说 对展示 +层级数据的 App 是适用的 + +35 +00:02:20,374 --> 00:02:22,142 +如设置 + +36 +00:02:23,443 --> 00:02:27,714 +诸如 Safari 等浏览器或文件 +适用于浏览 + +37 +00:02:27,748 --> 00:02:32,386 +及在多个文档或文件夹结构中 +往返导航 + +38 +00:02:34,655 --> 00:02:39,993 +而编辑器 则对集中查看或编辑 +独立文档非常适用 + +39 +00:02:42,029 --> 00:02:46,200 +对 Markdown 编辑器来说 +这一样式最适配我们的 App + +40 +00:02:48,302 --> 00:02:52,506 +编辑样式的标题在工具栏 +前端对齐 + +41 +00:02:52,539 --> 00:02:55,909 +中间是项目组 + +42 +00:02:55,943 --> 00:02:58,912 +在其它视图或菜单中隐藏的 + +43 +00:02:58,946 --> 00:03:02,916 +额外功能 在这个样式中 +就能看到 + +44 +00:03:02,950 --> 00:03:07,454 +我们尽可能利用这种设计 +做更多的操作 + +45 +00:03:07,487 --> 00:03:12,059 +首先是自定义内置的返回动作 +来响应我们的需求 + +46 +00:03:12,092 --> 00:03:15,162 +然后在标题菜单加上文档信息 + +47 +00:03:15,195 --> 00:03:18,165 +以及常用的文档操作 + +48 +00:03:18,198 --> 00:03:23,237 +我们还添加支持使用新内置 +重命名 UI 来重命名文档 + +49 +00:03:23,270 --> 00:03:28,242 +最后 我们将之前隐藏的功能 +放到工具栏中间 + +50 +00:03:28,275 --> 00:03:30,177 +让它们更易于访问 + +51 +00:03:30,944 --> 00:03:34,047 +首先 我们将 view controller 的 +navigationItem 样式属性 + +52 +00:03:34,081 --> 00:03:38,285 +设置为 .editor 以选择编辑样式 + +53 +00:03:39,987 --> 00:03:42,923 +这一操作后 标题马上调整为 +向前对齐 + +54 +00:03:42,956 --> 00:03:44,892 +并留空了中心区域 + +55 +00:03:47,394 --> 00:03:51,098 +随后 移除后面的完成按钮 + +56 +00:03:51,131 --> 00:03:55,636 +并用新的 backAction API +进行替换 + +57 +00:03:55,669 --> 00:03:58,505 +这样样式外观更标准 + +58 +00:03:58,539 --> 00:04:01,975 +摒弃了这一视图 +并返回文档选择器 + +59 +00:04:05,078 --> 00:04:09,750 +接下来 我们看下这一标题菜单 +对我们的 App 是否有用 + +60 +00:04:09,783 --> 00:04:12,653 +正如它的名字所述 标题菜单正是 + +61 +00:04:12,686 --> 00:04:15,656 +显示在导航工具栏的标题视图 + +62 +00:04:15,689 --> 00:04:18,192 +这里显示文档元数据 + +63 +00:04:18,225 --> 00:04:22,062 +及展示整个文档的操作 +是非常合适的 + +64 +00:04:22,095 --> 00:04:26,366 +如果您的 App 不是基于文档的 +这个地方最适合展示应用 + +65 +00:04:26,400 --> 00:04:28,335 +完整视图的操作 + +66 +00:04:29,203 --> 00:04:33,240 +对我们的 App 来说 +可使用文档菜单的标头 + +67 +00:04:33,273 --> 00:04:37,544 +来展示关于该文档的 +更多有用信息 + +68 +00:04:37,578 --> 00:04:41,548 +我们还可以提供 +文档的可拖拽表示 + +69 +00:04:41,582 --> 00:04:45,686 +并让共享功能更易访问 + +70 +00:04:45,719 --> 00:04:48,121 +现在 该是时候写一些代码了 + +71 +00:04:49,857 --> 00:04:51,892 +我们的 App 是 +UIDocument 支持的 + +72 +00:04:51,925 --> 00:04:54,862 +所以我们可以使用 +UIDocument 的 fileURL + +73 +00:04:54,895 --> 00:04:58,966 +来例举 +UIDocumentProperties 对象 + +74 +00:05:00,501 --> 00:05:05,105 +接下来 我们使用同样的 URL +来创建一个 NSItemProvider + +75 +00:05:07,608 --> 00:05:11,879 +然后我们使用项目提供程序 +来创建一个从属性对象的 + +76 +00:05:11,912 --> 00:05:16,416 +dragItemsProvider +返回的 UIDragItem + +77 +00:05:18,252 --> 00:05:22,022 +我们还可用其构建一个从属性对象的 +activityViewControllerProvider 中 + +78 +00:05:22,055 --> 00:05:26,994 +返回的 UIActivityViewController + +79 +00:05:27,027 --> 00:05:31,198 +最后 我们设置属性对象为 +编辑 view controller 的 + +80 +00:05:31,231 --> 00:05:34,134 +navigationItem 的 +documentProperties + +81 +00:05:34,168 --> 00:05:37,371 +我们刚刚写的代码 +显示的是这个文档标头 + +82 +00:05:37,404 --> 00:05:39,973 +可提供文档快速概览 + +83 +00:05:40,007 --> 00:05:44,211 +包括其名称 文件大小和 +图标 + +84 +00:05:44,244 --> 00:05:48,081 +由于我们指定了拖动项目 +和活动 view controller 提供程序 + +85 +00:05:48,115 --> 00:05:51,485 +我可以拖动图标 +将文档复制到 App 之外 + +86 +00:05:51,518 --> 00:05:55,355 +或点击共享按钮 +触发 activity view controller + +87 +00:05:57,057 --> 00:05:59,693 +除了展示文档标头 + +88 +00:05:59,726 --> 00:06:02,696 +标题菜单这一位置也可用于 + +89 +00:06:02,729 --> 00:06:05,799 +提供应用于整个文档的功能 + +90 +00:06:05,832 --> 00:06:09,536 +这一菜单中可显示两种操作 + +91 +00:06:09,570 --> 00:06:14,842 +预设的本地化标题和字符图像的 +系统提供操作 + +92 +00:06:14,875 --> 00:06:17,945 +以及 App 提供的自定义操作 + +93 +00:06:19,546 --> 00:06:21,481 +由于附带了一些额外功能 + +94 +00:06:21,515 --> 00:06:24,284 +我们首先看看重命名操作 + +95 +00:06:24,318 --> 00:06:26,954 +我们可以通过遵照重命名 +代理协议 + +96 +00:06:26,987 --> 00:06:30,057 +将这一操作添加到我们的菜单中 + +97 +00:06:30,090 --> 00:06:34,561 +触发后 这一操作会出现在 +工具栏的内置重命名 UI 中 + +98 +00:06:35,963 --> 00:06:40,868 +首先 我们将 view controller 指定为 +其导航项的 renameDelegate + +99 +00:06:43,403 --> 00:06:48,041 +然后 我们执行 +navigationItemDidEndRenamingWithTitle + +100 +00:06:48,075 --> 00:06:51,345 +来进行所展示文档 +实际重命名操作 + +101 +00:06:52,846 --> 00:06:56,717 +这一功能在重命名操作 +提交后调用 + +102 +00:06:56,750 --> 00:07:02,322 +App 负责重命名文档 +处理此操作 + +103 +00:07:02,356 --> 00:07:04,825 +有意打开的 API 最后 + +104 +00:07:04,858 --> 00:07:08,228 +可支持您 App 可能有的 +各种数据模型 + +105 +00:07:08,262 --> 00:07:10,797 +接着看另一个系统提供操作 + +106 +00:07:10,831 --> 00:07:15,602 +我们首先需要在我们的 +编辑 view controller 中重写它们的功能 + +107 +00:07:15,636 --> 00:07:20,474 +这里我们应用了复制和移动功能 + +108 +00:07:20,507 --> 00:07:23,877 +UIKit自动在 +navigationItem 的 titleMenuProvider 中 + +109 +00:07:23,911 --> 00:07:25,612 +作为建议 UIMenuElements 的数组 + +110 +00:07:25,646 --> 00:07:28,482 +展示系统提供操作 + +111 +00:07:28,515 --> 00:07:32,319 +包括重命名操作 + +112 +00:07:32,352 --> 00:07:34,321 +要将其置入我们的标题菜单中 + +113 +00:07:34,354 --> 00:07:37,558 +只需将它们添加到 +返回菜单的 children 中 + +114 +00:07:39,159 --> 00:07:41,094 +除了系统指定操作 + +115 +00:07:41,128 --> 00:07:43,797 +我们可以添加完整的自定义操作 + +116 +00:07:43,830 --> 00:07:47,067 +甚至整个菜单层级 + +117 +00:07:47,100 --> 00:07:53,006 +这里我添加了 Export 子菜单 +包括导出为 HTML 和 PDF 的子 Action + +118 +00:07:54,408 --> 00:07:57,444 +因此 点击标题视图可调出 + +119 +00:07:57,477 --> 00:08:01,481 +包含文档标头 +以及新添加的所有操作的菜单 + +120 +00:08:01,515 --> 00:08:03,050 +我选择重命名时 + +121 +00:08:03,083 --> 00:08:05,219 +可激活内置重命名 UI + +122 +00:08:05,252 --> 00:08:07,221 +我可以重命名文档 + +123 +00:08:08,755 --> 00:08:11,892 +现在我们开始建立 App 的 +基础结构 + +124 +00:08:11,925 --> 00:08:14,161 +我们用 Mac catalyst +搭建 App 时 + +125 +00:08:14,194 --> 00:08:17,064 +就可以查看其外观了 + +126 +00:08:17,097 --> 00:08:20,167 +当我们在 Mac 上运行 App 时 +会发现编辑样式中的 + +127 +00:08:20,200 --> 00:08:23,370 +标题向前对齐已经被完美转译 + +128 +00:08:24,872 --> 00:08:27,307 +我们的返回动作也可继续 + +129 +00:08:27,341 --> 00:08:30,444 +单击后 会调出文件浏览器 + +130 +00:08:31,745 --> 00:08:34,381 +系统提供动作和重命名功能 + +131 +00:08:34,414 --> 00:08:37,584 +自动显示在 App 的文件菜单中 + +132 +00:08:37,618 --> 00:08:41,655 +Mac Catalyst 不会 +调用 titleMenuProvider + +133 +00:08:41,688 --> 00:08:45,993 +所以我们的自定义操作 +并不包含在文件菜单中 + +134 +00:08:46,026 --> 00:08:48,962 +要显示此操作 我们需要使用 +主 UIMenuSystem + +135 +00:08:48,996 --> 00:08:52,966 +手动添加到 App 的主菜单中 + +136 +00:08:55,202 --> 00:08:57,905 +好了 我们继续现代化进程 + +137 +00:08:57,938 --> 00:09:01,942 +我们继续在 Mac 中查看 +以逐步达成目标 + +138 +00:09:01,975 --> 00:09:06,880 +我们想想工具栏中间区域 +提供的可用选项 + +139 +00:09:06,914 --> 00:09:10,083 +iOS 15 版本的 App +有一个菜单 + +140 +00:09:10,117 --> 00:09:13,520 +可显示许多二级控制功能 +和工具 + +141 +00:09:13,554 --> 00:09:17,524 +使用中间项目 我们可以让 +这些工具更容易被搜索和发现 + +142 +00:09:19,092 --> 00:09:23,463 +由于中间区域是可自定义的 +我们可以加入一大组控制按钮 + +143 +00:09:23,497 --> 00:09:28,068 +而无需担心用不常用按钮 +充填 UI + +144 +00:09:28,101 --> 00:09:32,973 +每个人都可以自定义工具栏内容 +使其适应自己的工作流 + +145 +00:09:33,006 --> 00:09:37,878 +启用自定义的第一步是 +在 navigationItem 中 + +146 +00:09:37,911 --> 00:09:39,880 +指定一个 customizationIdentifier + +147 +00:09:41,181 --> 00:09:46,019 +接下来 我们将中间项 +定义为 UIBarButtonItemGroups + +148 +00:09:46,053 --> 00:09:50,424 +Groups 是一个现有概念 +扩展到 UINavigationBar + +149 +00:09:50,457 --> 00:09:54,962 +并增强了对 iOS 16 自定义的支持 + +150 +00:09:54,995 --> 00:09:59,499 +这一屏幕快照展示了一组 +我们想要默认显示的中间项 + +151 +00:09:59,533 --> 00:10:01,835 +左边的同步滚动按钮 + +152 +00:10:01,869 --> 00:10:04,872 +提供了其它任何方式 + +153 +00:10:04,905 --> 00:10:07,374 +都无法企及的重要功能 + +154 +00:10:07,407 --> 00:10:09,977 +因此可以用 UIBarButtonItem +新创建的 creatingFixedGroup() 功能 + +155 +00:10:10,010 --> 00:10:15,682 +来将其置于固定组中 + +156 +00:10:15,716 --> 00:10:20,087 +固定组不可自定义 +也不能被用户移动 + +157 +00:10:22,022 --> 00:10:25,993 +另一方面 添加链接按钮 +不提供关键功能 + +158 +00:10:26,026 --> 00:10:30,531 +同样的任务可以通过在编辑器中 +输入链接标签来实现 + +159 +00:10:30,564 --> 00:10:36,470 +所以我们使用 creatingOptionalGroup +来创建一个完整的自定义项目 + +160 +00:10:36,503 --> 00:10:39,773 +我们为其指定一个 +独特的 customizationIdentifier + +161 +00:10:39,806 --> 00:10:43,544 +这样在 App 的登陆期间 +自定义操作能保持一致 + +162 +00:10:45,112 --> 00:10:47,848 +我们用类似的流程在默认组中 + +163 +00:10:47,881 --> 00:10:51,385 +定义剩余的项目 +然后继续操作无需默认的 + +164 +00:10:51,418 --> 00:10:54,488 +低优先级项目 + +165 +00:10:54,521 --> 00:10:58,392 +其中之一就是文本格式组 +包括粗体 + +166 +00:10:58,425 --> 00:11:00,761 +斜体 下划线项目 + +167 +00:11:01,995 --> 00:11:04,231 +这些项目不是特别重要 +无需在默认中显示 + +168 +00:11:04,264 --> 00:11:08,836 +但我们希望能在自定义的 popover 弹出框中 +显示 这样能被拖入工具栏中 + +169 +00:11:10,470 --> 00:11:13,540 +要实现这一效果 我们可以 +使用 UIBarButtonItemGroup 的 + +170 +00:11:13,574 --> 00:11:18,812 +optionalGroup 初始化器 +isInDefaultCustomization 设置为 false + +171 +00:11:21,248 --> 00:11:24,218 +我们也要为该组指定代表项目 + +172 +00:11:24,251 --> 00:11:26,353 +因此在 popover 弹出框中 +能显示标题 + +173 +00:11:26,386 --> 00:11:28,388 +以及在工具栏空间有限时 + +174 +00:11:28,422 --> 00:11:31,692 +能显示缩略的信息 + +175 +00:11:33,227 --> 00:11:35,662 +回到 iPad 中 我们定义的中间项 + +176 +00:11:35,696 --> 00:11:38,465 +会显示在工具栏的中间区域 + +177 +00:11:38,498 --> 00:11:40,734 +如果我点击新增的“更多”按钮 + +178 +00:11:40,767 --> 00:11:44,705 +会显示一个带有 +“自定义工具栏”的菜单 + +179 +00:11:44,738 --> 00:11:48,108 +单击后 自定义模式会被激活 + +180 +00:11:49,376 --> 00:11:53,847 +我们标记为固定的同步滚动按钮 +不再强调且变为静态 + +181 +00:11:53,881 --> 00:11:58,318 +其它所有项目都弹起并抖动 +表示它们都是可自定义的 + +182 +00:12:00,220 --> 00:12:04,258 +可选项如格式组在 +popover 弹出框中显示 + +183 +00:12:04,291 --> 00:12:06,393 +可被拖入工具栏中 + +184 +00:12:09,596 --> 00:12:12,499 +我们在 Mac 中运行 App 时 +会发现中间项 + +185 +00:12:12,533 --> 00:12:16,837 +已经被转换为完全自定义的 +macOS 工具栏按钮 + +186 +00:12:19,106 --> 00:12:24,378 +我们继续下一步前 先暂时 +回到 iPad 重新调整 App 的大小 + +187 +00:12:24,411 --> 00:12:27,080 +现在 我们工具栏上的 +可用空间更少了 + +188 +00:12:27,114 --> 00:12:30,684 +中间项已不可见 + +189 +00:12:30,717 --> 00:12:34,821 +UIKit 会自动处理中间项 +的显示和隐藏 + +190 +00:12:34,855 --> 00:12:37,691 +来适应不同的可用空间 + +191 +00:12:37,724 --> 00:12:42,462 +无法包含的额外项目都会 +在溢出菜单中显示 + +192 +00:12:42,496 --> 00:12:45,332 +标准工具栏按钮项将自动转换为 + +193 +00:12:45,365 --> 00:12:47,401 +对应的菜单选项 + +194 +00:12:47,434 --> 00:12:52,873 +但如果需要的话 +我们也可以提供自定义菜单选项 + +195 +00:12:52,906 --> 00:12:56,877 +由于 UIKit 对自定义视图项的目的 +没有对应方案 + +196 +00:12:56,910 --> 00:13:00,047 +我们的滑块项并不会自动转译 + +197 +00:13:00,080 --> 00:13:03,317 +我们需要手动指定菜单项目 + +198 +00:13:04,751 --> 00:13:06,086 +这是我们的滑块项 + +199 +00:13:06,119 --> 00:13:08,722 +这是有自定义视图的 +单一工具栏按钮项 + +200 +00:13:08,755 --> 00:13:12,426 +隐藏于可选工具栏按钮组之下 + +201 +00:13:12,459 --> 00:13:15,162 +为了提供滑块的核心功能 + +202 +00:13:15,195 --> 00:13:19,867 +我们将 menuRepresentation 定义为 +带有减少 重置 + +203 +00:13:19,900 --> 00:13:22,603 +和增加动作的 UIMenu + +204 +00:13:25,038 --> 00:13:28,642 +使用 UIMenu 的 +新 preferredElementSize 属性 + +205 +00:13:28,675 --> 00:13:33,313 +我们可以为菜单提供 +更紧凑的并行动作 + +206 +00:13:35,516 --> 00:13:38,585 +使用新的 +keepsMenuPresented 属性 + +207 +00:13:38,619 --> 00:13:42,489 +我们可以保证每个动作后的 +菜单展示都能正常运行 + +208 +00:13:42,523 --> 00:13:45,092 +在不取消 +或重新显示菜单的情况下 + +209 +00:13:45,125 --> 00:13:48,929 +让字体大小 +可以多次修改 + +210 +00:13:48,962 --> 00:13:51,331 +让我们再次在 iPad 中运行看看 + +211 +00:13:51,365 --> 00:13:54,001 +现在我们调出溢出菜单 + +212 +00:13:54,034 --> 00:13:58,739 +滑块显示为有三个并行行动的 +内联菜单 + +213 +00:13:58,772 --> 00:14:01,175 +包含了滑块的全部功能 + +214 +00:14:02,576 --> 00:14:05,445 +由于 Mac 中不存在 +小元素尺寸 + +215 +00:14:05,479 --> 00:14:09,716 +动作将显示为标准 mac OS +菜单项 + +216 +00:14:09,750 --> 00:14:12,986 +以上是 UI 配置和自定义 + +217 +00:14:13,020 --> 00:14:16,023 +接下来 我们看看如何在 App 中 +使用新的集合视图和菜单 API + +218 +00:14:16,056 --> 00:14:19,259 +加速一些工作流程 + +219 +00:14:19,293 --> 00:14:22,396 +我们的 App 有一个 +侧边栏内容表格 + +220 +00:14:22,429 --> 00:14:27,401 +可用于快速导航文档 +或操作顶层标签 + +221 +00:14:27,434 --> 00:14:31,371 +在 iOS 16 之前 +增加编辑多重项目的能力 + +222 +00:14:31,405 --> 00:14:34,775 +不一定意味着执行 +不同的编辑模式 + +223 +00:14:34,808 --> 00:14:37,911 +将批量操作 +降低为工具栏中的按钮 + +224 +00:14:40,914 --> 00:14:44,718 +iOS 16 推出多项目菜单的 +全新设计 + +225 +00:14:44,751 --> 00:14:49,122 +有一系列的项目明确指出了 +菜单影响是哪个项目 + +226 +00:14:49,156 --> 00:14:53,460 +提供了多项目拖拽的直接转换 + +227 +00:14:53,493 --> 00:14:57,464 +在桌面级 iPad App 中 +这个新的菜单设计与 + +228 +00:14:57,497 --> 00:15:00,734 +轻量型选择样式最为匹配 + +229 +00:15:00,767 --> 00:15:03,637 +这里的“轻量型” +是指选择多重项目时 + +230 +00:15:03,670 --> 00:15:06,540 +无需在编辑模式中开启 +集合视图 + +231 +00:15:06,573 --> 00:15:09,610 +或对 App 的 UI 做出 +重大改变 + +232 +00:15:09,643 --> 00:15:15,082 +我们使用当前 API 即可实现 +并启动键盘聚焦 + +233 +00:15:15,115 --> 00:15:18,285 +首先 我们将 allowsMultipleSelection +设置为 true + +234 +00:15:21,121 --> 00:15:25,626 +然后将 allowsFocus 设置 为 true +启动键盘聚焦 + +235 +00:15:28,128 --> 00:15:33,600 +我们可以设置 selectionFollowsFocus +为 true 将聚焦转变为驱动选择 + +236 +00:15:36,270 --> 00:15:39,306 +如果在 iPad 上运行 +我们马上就能注意到 + +237 +00:15:39,339 --> 00:15:41,775 +每个项目都添加到了选择中 + +238 +00:15:41,808 --> 00:15:44,211 +但仍然触发了选择动作 + +239 +00:15:44,244 --> 00:15:46,580 +导致编辑器视图滚动 + +240 +00:15:46,613 --> 00:15:49,650 +我们回到代码 看下是什么原因 + +241 +00:15:51,285 --> 00:15:52,286 +找到了 + +242 +00:15:52,319 --> 00:15:54,855 +didSelectItemAtIndexPath 中的代码 + +243 +00:15:54,888 --> 00:15:57,724 +尝试在编辑模式中 +通过检查collectionView 的 + +244 +00:15:57,758 --> 00:16:01,695 +isEditing 属性来禁止滚动 + +245 +00:16:01,728 --> 00:16:05,098 +现在我们已经允许了编辑模式外的 +多重选择 + +246 +00:16:05,132 --> 00:16:08,001 +这一代码在每次选择时都会运行 + +247 +00:16:08,035 --> 00:16:11,972 +我们可以通过使用新的 +UICollectionViewDelegate 方法来修正 + +248 +00:16:12,005 --> 00:16:16,510 +我们执行 +performPrimaryActionForItemAtIndexPath + +249 +00:16:16,543 --> 00:16:21,215 +将滚动代码移动到这个新功能中 + +250 +00:16:21,248 --> 00:16:24,251 +由于这个功能仅在点击 +单个项目时才会调用 + +251 +00:16:24,284 --> 00:16:26,420 +集合视图并没有编辑 + +252 +00:16:26,453 --> 00:16:29,089 +我们不需要检查编辑模式 + +253 +00:16:31,658 --> 00:16:34,795 +由于我们没有与选择相关的行为 + +254 +00:16:34,828 --> 00:16:39,333 +就可以将 indexPath 中 +所做的选择项操作移除 + +255 +00:16:43,237 --> 00:16:46,874 +回到 iPad 编辑器视图中 + +256 +00:16:46,907 --> 00:16:50,177 +选择多重项目不再滚动到 +对应的文本中 + +257 +00:16:50,210 --> 00:16:53,080 +完成这一操作后 +我们将其真正添加到菜单支持中 + +258 +00:16:55,382 --> 00:17:00,554 +在 iPadOS 16 中 +UICollectionViewDelegate 当前单一项菜单方法 + +259 +00:17:00,587 --> 00:17:02,256 +已不适用 + +260 +00:17:02,289 --> 00:17:08,328 +其替代方法支持在任意位置从 0 +到多重项目显示菜单 + +261 +00:17:08,362 --> 00:17:11,298 +指定 indexPaths 数组中的项目数量 + +262 +00:17:11,331 --> 00:17:13,500 +取决于项目是如何选取的 + +263 +00:17:13,534 --> 00:17:15,636 +以及菜单是在何处激活的 + +264 +00:17:17,271 --> 00:17:22,042 +如果数组为空 则菜单在单元格 +之间的空白区激活 + +265 +00:17:25,012 --> 00:17:26,914 +如果有单一的 indexPath + +266 +00:17:26,947 --> 00:17:30,150 +则在取消选择 + +267 +00:17:30,184 --> 00:17:32,386 +或单一选择项目上激活 + +268 +00:17:35,088 --> 00:17:37,824 +如果有超过一个项目 则菜单在 + +269 +00:17:37,858 --> 00:17:41,461 +多重选择部分激活 + +270 +00:17:44,031 --> 00:17:47,668 +如果我回到 iPad 中 +再次选择上面的四个项目 + +271 +00:17:47,701 --> 00:17:50,103 +双指单击其中一个选择项目 + +272 +00:17:50,137 --> 00:17:52,706 +会出现新的多项菜单 + +273 +00:17:56,343 --> 00:17:58,111 +当我在 Mac 中做同样的操作时 + +274 +00:17:58,145 --> 00:18:01,248 +在选择单元格周围 +会绘制一个圆环以突出强调 + +275 +00:18:02,783 --> 00:18:04,685 +多项菜单完成后 + +276 +00:18:04,718 --> 00:18:07,321 +我们看看使用新的 +查找和替换和编辑菜单功能 + +277 +00:18:07,354 --> 00:18:10,624 +增强文本编辑体验 + +278 +00:18:10,657 --> 00:18:13,660 +我们的 App 使用 +UITextView 作为编辑器 + +279 +00:18:13,694 --> 00:18:17,931 +无需任何自定义的 +查找和替换行为 + +280 +00:18:17,965 --> 00:18:21,602 +因此 我们启用默认系统功能 + +281 +00:18:21,635 --> 00:18:26,807 +只需要将文本视图的 +isFindInteractionEnabled 属性设置为 true + +282 +00:18:26,840 --> 00:18:29,743 +这一设置完成后 编辑文本时 +按 Command+F + +283 +00:18:29,776 --> 00:18:31,979 +调出查找和替换 UI + +284 +00:18:33,180 --> 00:18:37,084 +在文本视图的编辑菜单中增加 +自定义行动并不需要多大成本 + +285 +00:18:37,117 --> 00:18:40,988 +但却能启动一些强大 快速的 +编辑功能 + +286 +00:18:41,021 --> 00:18:44,057 +我们只用执行新的 +UITextViewDelegate 方法 + +287 +00:18:44,091 --> 00:18:48,495 +在范围建议行动内编辑文本菜单 + +288 +00:18:48,529 --> 00:18:52,699 +在执行操作中 我们可以构建 +和返回结合自定义行动的 + +289 +00:18:52,733 --> 00:18:55,636 +与系统菜单的 UIMenu + +290 +00:18:55,669 --> 00:18:57,204 +如这个隐藏行动 + +291 +00:18:59,907 --> 00:19:01,308 +结果如下 + +292 +00:19:01,341 --> 00:19:04,011 +当我选择文本 调用编辑菜单时 + +293 +00:19:04,044 --> 00:19:08,615 +自定义操作和 +系统提供操作都会显示 + +294 +00:19:08,649 --> 00:19:11,952 +您可观看“采用桌面级 +编辑交互”视频 + +295 +00:19:11,985 --> 00:19:16,223 +以获取更多关于 +查找和替换及编辑菜单的信息 + +296 +00:19:16,256 --> 00:19:17,090 +就是这样 + +297 +00:19:17,124 --> 00:19:20,127 +有了这些改变 我们就能通过 +一些重大的基础步骤 + +298 +00:19:20,160 --> 00:19:22,496 +制作桌面级 App + +299 +00:19:22,529 --> 00:19:25,599 +并将其无缝转译到 Mac 中 + +300 +00:19:25,632 --> 00:19:28,435 +使用 iPadOS 16 提供的 API + +301 +00:19:28,468 --> 00:19:31,338 +用类似的流程操作您的 App + +302 +00:19:31,371 --> 00:19:35,642 +首先选择适合您 App 的 +导航样式 + +303 +00:19:35,676 --> 00:19:39,947 +用文档属性和标题菜单 +增强文档工作流程 + +304 +00:19:39,980 --> 00:19:45,452 +用中间项显示重要功能 +提供自定义功能 + +305 +00:19:45,485 --> 00:19:49,289 +在多项目菜单中启动 +多重项目的快速活动栏 + +306 +00:19:49,323 --> 00:19:53,093 +用查找和替换 +以及全新的编辑菜单 + +307 +00:19:53,126 --> 00:19:54,795 +增强 App 的文本编辑体验 + +308 +00:19:54,828 --> 00:19:58,031 +不管您是构建一个新的 App +还是更新现有 App + +309 +00:19:58,065 --> 00:20:01,668 +我都迫不及待想使用 +您应用了这些新工具的 App 了 + +310 +00:20:01,702 --> 00:20:04,171 +感谢大家的观看 + diff --git a/zho/2022 Session 10071 Adopt desktop class editing interactions.srt b/zho/2022 Session 10071 Adopt desktop class editing interactions.srt new file mode 100644 index 0000000..b0d2a1e --- /dev/null +++ b/zho/2022 Session 10071 Adopt desktop class editing interactions.srt @@ -0,0 +1,1416 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:12,112 --> 00:00:13,180 +Andy: 大家好 + +3 +00:00:13,213 --> 00:00:17,117 +欢迎来到“Adopt desktop class +editing interactions” + +4 +00:00:17,150 --> 00:00:20,654 +我是 Andy 一名 UIKit 框架工程师 + +5 +00:00:20,687 --> 00:00:24,491 +稍后我的同事 James 也会加入 + +6 +00:00:24,525 --> 00:00:27,027 +iPad 一直在不断优化 + +7 +00:00:27,060 --> 00:00:32,366 +但不会影响使其简单易用的交互 + +8 +00:00:32,399 --> 00:00:36,670 +在本视频中 大家将了解令人兴奋的 +全新编辑交互工具 + +9 +00:00:36,703 --> 00:00:41,642 +使你们的应用程序变得桌面类 + +10 +00:00:41,675 --> 00:00:48,282 +首先 我将介绍一下新的编辑菜单 +它在 iOS 16 中有了重大改进 + +11 +00:00:49,283 --> 00:00:55,322 +稍后 James 将深入探讨新系统的 +查找和替换经验 + +12 +00:00:55,355 --> 00:00:59,860 +在iOS 16 中 编辑菜单 +采用了一种全新的设计 + +13 +00:00:59,893 --> 00:01:03,063 +这种设计既熟悉又更具交互性 + +14 +00:01:03,096 --> 00:01:05,799 +并且更容易发现操作 + +15 +00:01:06,733 --> 00:01:09,503 +编辑菜单现在具有 + +16 +00:01:09,536 --> 00:01:12,673 +基于所有输入法的替代显示 + +17 +00:01:12,706 --> 00:01:13,974 +对于触摸交互 + +18 +00:01:14,007 --> 00:01:17,811 +编辑菜单仍然具有熟悉的紧凑外观 + +19 +00:01:17,845 --> 00:01:20,013 +但改进了调页行为 + +20 +00:01:20,047 --> 00:01:23,483 +使操作比以前更容易被发现 + +21 +00:01:26,486 --> 00:01:29,423 +通过妙控键盘或触控板 + +22 +00:01:29,456 --> 00:01:33,160 +在二次点击或右击时 +会显示上下文菜单 + +23 +00:01:33,193 --> 00:01:38,966 +以获得更多桌面类体验 + +24 +00:01:38,999 --> 00:01:45,072 +同样 iPhone 上的触摸交互 +也会显示新的编辑菜单 + +25 +00:01:46,707 --> 00:01:48,809 +对于 Mac Catalyst 应用程序 + +26 +00:01:48,842 --> 00:01:53,647 +它会提供 Mac 用户 +熟悉的上下文菜单 + +27 +00:01:53,680 --> 00:01:59,019 +在 iOS 16 中 文本编辑菜单 +集成新的数据探测器 + +28 +00:01:59,052 --> 00:02:02,022 +获得了重大提升 + +29 +00:02:02,055 --> 00:02:06,126 +这包括内联单元和货币转换 + +30 +00:02:06,159 --> 00:02:07,728 +以及根据 + +31 +00:02:07,761 --> 00:02:13,467 +所选文本显示上下文操作的 +智能查找 + +32 +00:02:13,500 --> 00:02:14,868 +例如 + +33 +00:02:14,902 --> 00:02:17,404 +如果你在 Safari 浏览器中 +选择一个地址 + +34 +00:02:17,437 --> 00:02:19,406 +那么你就会在 +现有的编辑菜单操作之上 + +35 +00:02:19,439 --> 00:02:22,843 +获得基于地图的操作 + +36 +00:02:22,876 --> 00:02:27,114 +比如 Get Directions +或 Open in Maps + +37 +00:02:27,147 --> 00:02:31,118 +最棒的是 不需要采用 + +38 +00:02:31,151 --> 00:02:34,955 +这些功能在每个 +文本编辑菜单中都可用 + +39 +00:02:34,988 --> 00:02:40,794 +包括文本交互视图 WebKit +和 Safari 以及 PDFKit + +40 +00:02:42,996 --> 00:02:48,302 +要在文本视图的菜单中插入操作 +执行新的 TextViewDelegate 方法 + +41 +00:02:48,335 --> 00:02:51,705 +用系统提供的操作 +为给定范围内的文本 + +42 +00:02:51,738 --> 00:02:55,008 +自定义显示菜单 + +43 +00:02:55,042 --> 00:02:57,244 +如果你不需要自定义任何内容 + +44 +00:02:57,277 --> 00:03:01,415 +请返回 nil 以获取标准系统菜单 + +45 +00:03:01,448 --> 00:03:06,119 +UITextFieldDelegate 和 UITextInput + +46 +00:03:06,153 --> 00:03:08,655 +也有类似的方法来自定义菜单 + +47 +00:03:08,689 --> 00:03:13,026 +请注意 现在在 iOS 16 中已不支持 + +48 +00:03:13,060 --> 00:03:15,896 +使用 UIMenuController +来插入菜单项 + +49 +00:03:15,929 --> 00:03:18,365 +你们应该使用新方法将菜单元素 + +50 +00:03:18,398 --> 00:03:21,802 +添加到你的文本编辑菜单中 + +51 +00:03:21,835 --> 00:03:26,673 +因为我们的目标是 +不再需要 menu controller + +52 +00:03:27,574 --> 00:03:31,979 +这是一个带有一些自定义操作的 +文本视图示例 + +53 +00:03:32,012 --> 00:03:35,182 +当在某些文本选择上显示菜单时 + +54 +00:03:35,215 --> 00:03:38,452 +系统建议的操作后面会显示自定义的 + +55 +00:03:38,485 --> 00:03:41,622 +高亮和插入图片 + +56 +00:03:41,655 --> 00:03:47,661 +选择高亮显示操作 +将按预期对文本执行高亮显示 + +57 +00:03:47,694 --> 00:03:52,332 +接下来 当菜单没有任何文本选择 + +58 +00:03:52,366 --> 00:03:54,568 +而没有突出显示任何内容时 + +59 +00:03:54,601 --> 00:03:57,404 +菜单只会在系统建议的操作之后 + +60 +00:03:57,437 --> 00:04:01,008 +显示插入照片操作 + +61 +00:04:01,041 --> 00:04:05,612 +我将向你们展示如何 +使用新的 API 添加这些操作 + +62 +00:04:05,646 --> 00:04:09,616 +要将操作插入到动态菜单中 + +63 +00:04:09,650 --> 00:04:12,753 +执行 UITextViewDelegate 方法 + +64 +00:04:12,786 --> 00:04:17,758 +textView editMenuForTextInRange: +suggestedActions + +65 +00:04:17,791 --> 00:04:21,228 +在这个例子中 +我只想在有选中文本时 + +66 +00:04:21,261 --> 00:04:23,363 +添加高亮显示动作 + +67 +00:04:23,397 --> 00:04:27,467 +所以我可以 +通过这个方法动态添加动作 + +68 +00:04:29,803 --> 00:04:32,906 +Insert Photo 操作始终有效 + +69 +00:04:32,940 --> 00:04:39,847 +所以我可以将它添加到数组中 +总是在菜单中显示 + +70 +00:04:39,880 --> 00:04:44,551 +最后 我将把我的操作 +添加到系统建议的操作中 + +71 +00:04:44,585 --> 00:04:49,990 +其中包括剪切 复制和粘贴等项 +然后返回菜单 + +72 +00:04:50,023 --> 00:04:54,361 +就是这样 + +73 +00:04:54,394 --> 00:05:01,001 +UIEditMenuInteraction 是支持 +新编辑菜单的 UIInteraction API + +74 +00:05:02,002 --> 00:05:04,471 +此交互允许你们以编程方式 +基于自己的手势 + +75 +00:05:04,505 --> 00:05:07,541 +在文本视图之外 + +76 +00:05:07,574 --> 00:05:09,977 +显示轻量级编辑菜单 + +77 +00:05:10,010 --> 00:05:15,782 +并支持在二次单击时 +显示上下文菜单 + +78 +00:05:15,816 --> 00:05:20,821 +在 iOS 16 中 UIMenuController +及其所有相关 API + +79 +00:05:20,854 --> 00:05:24,124 +都被新的编辑菜单交互所取代 + +80 +00:05:25,425 --> 00:05:28,095 +要从头开始呈现编辑菜单 + +81 +00:05:28,128 --> 00:05:33,700 +首先 创建交互 并将其添加到视图中 + +82 +00:05:33,734 --> 00:05:39,006 +接下来 配置一个手势识别器 +来显示菜单 + +83 +00:05:39,039 --> 00:05:42,009 +为确保菜单仅在直接触控 + +84 +00:05:42,042 --> 00:05:44,678 +而不是间接光标单击时出现 + +85 +00:05:44,711 --> 00:05:46,947 +请确保将手势识别器的 +allowedTouchTypes 属性 + +86 +00:05:46,980 --> 00:05:50,784 +设置为仅支持直接触控 + +87 +00:05:50,817 --> 00:05:56,290 +然后 将手势识别器添加到视图中 + +88 +00:05:56,323 --> 00:05:59,626 +最后 当手势识别器触发时 + +89 +00:05:59,660 --> 00:06:02,796 +确定手势所在的位置 + +90 +00:06:02,829 --> 00:06:06,066 +是否有可以显示菜单的内容 + +91 +00:06:06,099 --> 00:06:08,936 +然后 在手势位置创建一个 + +92 +00:06:08,969 --> 00:06:12,773 +带有源点的编辑菜单配置 + +93 +00:06:12,806 --> 00:06:16,009 +源点用于确定交互视图中 + +94 +00:06:16,043 --> 00:06:20,180 +要显示在菜单中的可执行操作 + +95 +00:06:22,316 --> 00:06:26,453 +配置完成后 调用 +presentEditMenuWithConfiguration + +96 +00:06:26,486 --> 00:06:28,789 +来显示菜单 + +97 +00:06:30,891 --> 00:06:35,295 +当我右键单击所选的 +Jello there 视图中的任意位置时 + +98 +00:06:35,329 --> 00:06:38,832 +上下文菜单显示了 App 内容的 + +99 +00:06:38,866 --> 00:06:41,535 +可执行系统操作 + +100 +00:06:41,568 --> 00:06:44,838 +甚至 当我点击选中的视图时 + +101 +00:06:44,872 --> 00:06:48,041 +编辑菜单就会出现在我的触控位置 + +102 +00:06:48,075 --> 00:06:52,012 +显示与上下文菜单相同的操作 + +103 +00:06:52,045 --> 00:06:55,682 +这很好 但还能更好 + +104 +00:06:55,716 --> 00:06:58,752 +虽然菜单出现在触控的地方很好 + +105 +00:06:58,785 --> 00:07:02,422 +但它实际上阻止了所选视图的内容 + +106 +00:07:02,456 --> 00:07:07,127 +此外 我想在菜单中插入 +一个新的 Duplicate 操作 + +107 +00:07:07,160 --> 00:07:10,397 +这不是系统默认操作 + +108 +00:07:10,430 --> 00:07:12,900 +我们返回修改一下 + +109 +00:07:12,933 --> 00:07:15,836 +要在选定的视图周围显示菜单 + +110 +00:07:15,869 --> 00:07:17,571 +实施委托方法 + +111 +00:07:17,604 --> 00:07:22,176 +editMenuInteraction: +targetRectForConfiguration: + +112 +00:07:22,209 --> 00:07:27,014 +这个方法返回一个 CGRect +用于确定从哪里显示菜单 + +113 +00:07:27,047 --> 00:07:32,819 +并且位于交互视图的坐标空间中 + +114 +00:07:32,853 --> 00:07:37,958 +如果没有实施该方法 +或提供了一个空的 CGRect + +115 +00:07:37,991 --> 00:07:42,896 +则菜单将从配置的源点显示 + +116 +00:07:42,930 --> 00:07:46,867 +在这种情况下 +为防止菜单遮挡所选视图 + +117 +00:07:46,900 --> 00:07:49,403 +返回它的参照系 + +118 +00:07:49,436 --> 00:07:52,272 +接下来 要添加 Duplicate 操作 + +119 +00:07:52,306 --> 00:07:57,578 +执行 editMenuInteraction: +menuForConfiguration:suggestedActions: + +120 +00:07:57,611 --> 00:08:01,515 +并在系统建议的操作之后 +添加自定义操作 + +121 +00:08:01,548 --> 00:08:06,587 +类似于之前将操作插入 +文本视图菜单的方式 + +122 +00:08:07,588 --> 00:08:10,791 +现在 当我再次点击所选视图时 + +123 +00:08:10,824 --> 00:08:15,562 +菜单不再遮挡 Jello there +而是围绕它显示 + +124 +00:08:15,596 --> 00:08:19,900 +出现菜单时还包括新的 +Duplicate 操作 + +125 +00:08:19,933 --> 00:08:22,669 +只需要几行代码 + +126 +00:08:22,703 --> 00:08:23,871 +棒极了 + +127 +00:08:25,906 --> 00:08:27,574 +对于 Mac Catalyst 应用程序 + +128 +00:08:27,608 --> 00:08:30,644 +编辑菜单连接到熟悉的上下文菜单 + +129 +00:08:30,677 --> 00:08:32,479 +用户在 Mac 上 + +130 +00:08:32,513 --> 00:08:36,216 +右键单击交互视图时就会看到 + +131 +00:08:36,250 --> 00:08:38,719 +对于 iPad 惯用的 +Mac Catalyst 应用程序 + +132 +00:08:38,752 --> 00:08:44,291 +以编程方式呈现的编辑菜单 +也可连接到上下文菜单 + +133 +00:08:44,324 --> 00:08:48,262 +请注意 Mac idiom 应用程序 +不支持编辑菜单的 + +134 +00:08:48,295 --> 00:08:53,734 +程序化显示 + +135 +00:08:53,767 --> 00:08:57,437 +为了在不同的演示风格之间 +提供无缝衔接 + +136 +00:08:57,471 --> 00:09:02,976 +UIEditMenuInteraction 构建在 +UIMenuElement 系列 API 之上 + +137 +00:09:03,010 --> 00:09:07,014 +它们提供了比之前更大的灵活性 +和可定制性 + +138 +00:09:07,047 --> 00:09:10,651 +包括对子菜单和图像的支持 + +139 +00:09:10,684 --> 00:09:13,086 +如果这是你们第一次使用 UIMenus + +140 +00:09:13,120 --> 00:09:19,993 +请观看“Modernizing Your UI for iOS 13” +以了解有关菜单和操作的更多信息 + +141 +00:09:20,027 --> 00:09:22,930 +建立在 UIMenuElement 之上 +还意味着 + +142 +00:09:22,963 --> 00:09:26,633 +编辑菜单可访问已经支持它的 + +143 +00:09:26,667 --> 00:09:31,238 +各种 API 比如 UIMenuSystem + +144 +00:09:31,271 --> 00:09:36,176 +编辑菜单使用现有的 +UIMenuSystem.context 系统 + +145 +00:09:36,210 --> 00:09:38,445 +来构建其菜单 + +146 +00:09:38,478 --> 00:09:40,614 +要了解更多关于菜单生成器的信息 + +147 +00:09:40,647 --> 00:09:45,219 +以及更深入地了解 +响应链遍历和命令验证 + +148 +00:09:45,252 --> 00:09:50,290 +请观看“Taking your iPad apps +to the next level” + +149 +00:09:51,892 --> 00:09:57,598 +说到菜单 iOS 16 中的 UIMenu +做了几项新的改进 + +150 +00:09:57,631 --> 00:10:00,701 +UIMenu 现在有一个首选元素大小属性 + +151 +00:10:00,734 --> 00:10:06,106 +可以在上下文菜单的 +不同布局之间进行选择 + +152 +00:10:06,139 --> 00:10:10,811 +较小的尺寸使菜单具有 +更紧凑的并排外观 + +153 +00:10:10,844 --> 00:10:15,148 +在一行中可容纳更多操作 + +154 +00:10:15,182 --> 00:10:19,086 +中等大小也以并排的外观显示操作 + +155 +00:10:19,119 --> 00:10:21,388 +但有更多的细节 + +156 +00:10:21,421 --> 00:10:26,894 +文本编辑菜单用它来 +显示标准编辑菜单 + +157 +00:10:26,927 --> 00:10:30,764 +最后 大单元尺寸为菜单提供了默认的 + +158 +00:10:30,797 --> 00:10:34,334 +全屏宽度外观 + +159 +00:10:34,368 --> 00:10:38,005 +此外 UIMenuElement 上 +有一个新的 + +160 +00:10:38,038 --> 00:10:41,074 +keepMenuPresented 属性 +以在执行操作后 + +161 +00:10:41,108 --> 00:10:44,211 +保持显示菜单 + +162 +00:10:44,244 --> 00:10:48,048 +使用此属性可允许多次执行操作 + +163 +00:10:48,081 --> 00:10:50,984 +而无需重新显示菜单 + +164 +00:10:51,018 --> 00:10:55,189 +这些只是新编辑菜单的冰山一角 + +165 +00:10:55,222 --> 00:11:00,627 +通过自定义文本编辑菜单 +扩展文本编辑功能 + +166 +00:11:00,661 --> 00:11:03,463 +确保你们的操作具有标题和图像 + +167 +00:11:03,497 --> 00:11:08,468 +以便菜单在不同的显示样式中 +看起来是完整的 + +168 +00:11:08,502 --> 00:11:12,472 +最重要的是 采用新的 +UIEditMenuInteraction + +169 +00:11:12,506 --> 00:11:16,710 +来获得更好的可定制性 +并提高跨平台 + +170 +00:11:16,743 --> 00:11:19,046 +以及不同输入法的一致性 + +171 +00:11:19,079 --> 00:11:24,084 +第一步添加 +对新编辑菜单的支持是不错的 + +172 +00:11:24,117 --> 00:11:27,154 +为了完成桌面类编辑体验 + +173 +00:11:27,187 --> 00:11:29,289 +我将让 James 来谈谈 + +174 +00:11:29,323 --> 00:11:32,492 +新系统的查找和替换体验 + +175 +00:11:34,194 --> 00:11:37,197 +James Magahern: 啊 它在那儿 + +176 +00:11:37,231 --> 00:11:41,201 +大家好 我是 James Magahern +一名 UIKit 工程师 + +177 +00:11:41,235 --> 00:11:44,905 +我今天要讲的是查找和替换 + +178 +00:11:44,938 --> 00:11:46,707 +在 iOS 16 中 + +179 +00:11:46,740 --> 00:11:51,912 +我们推出了一个新的 UI 组件 +以查找和替换应用程序中的文本 + +180 +00:11:51,945 --> 00:11:53,881 +它是整个系统的标准配置 + +181 +00:11:53,914 --> 00:11:56,283 +包含在许多内置应用程序中 + +182 +00:11:56,316 --> 00:11:58,552 +允许用户使用更常用的编辑快捷方式 + +183 +00:11:58,585 --> 00:12:02,322 +来锻炼他们的肌肉记忆 + +184 +00:12:02,356 --> 00:12:06,493 +这是在 iPad 上运行的新发现面板 + +185 +00:12:06,527 --> 00:12:10,464 +当连接了硬件键盘时 我们将自动从 + +186 +00:12:10,497 --> 00:12:12,766 +与快捷栏的浮动内联 + +187 +00:12:12,799 --> 00:12:19,206 +过渡到没有硬件键盘时 +静止于软件键盘顶部 + +188 +00:12:19,239 --> 00:12:22,543 +在 iPhone 上 +我们将使用更紧凑的布局 + +189 +00:12:22,576 --> 00:12:25,779 +来适应更小的屏幕尺寸 + +190 +00:12:25,812 --> 00:12:29,316 +自动退出 +最小化和 keyboard avoidance + +191 +00:12:29,349 --> 00:12:33,387 +均由系统负责 + +192 +00:12:33,420 --> 00:12:35,222 +在 Mac 上运行 App 时 + +193 +00:12:35,255 --> 00:12:38,192 +我们将显示与内容内联的查找面板 + +194 +00:12:38,225 --> 00:12:41,128 +就像 AppKit 的查找栏一样 + +195 +00:12:41,161 --> 00:12:44,965 +并使用用户期望在 Mac 上的熟悉布局 + +196 +00:12:46,466 --> 00:12:51,471 +如果你们使用 UITextView +WKWebView 或 PDFViews + +197 +00:12:51,505 --> 00:12:54,408 +在应用程序中显示文本内容 + +198 +00:12:54,441 --> 00:12:59,847 +你们所需要做的就是在 +内置查找交互中 + +199 +00:12:59,880 --> 00:13:02,182 +将 isFindInteractionEnabled +设置为真 + +200 +00:13:02,216 --> 00:13:04,551 +很简单吧 + +201 +00:13:04,585 --> 00:13:08,922 +另外 如果你们想要使用 QuickLook +来显示文本内容 + +202 +00:13:08,956 --> 00:13:12,626 +这将无需你的任何操作就可用 + +203 +00:13:14,795 --> 00:13:16,597 +使用硬件键盘 + +204 +00:13:16,630 --> 00:13:20,534 +所有标准系统快捷方式 +例如 command+F 用于查找 + +205 +00:13:20,567 --> 00:13:22,269 +command+G 用于查找下一个 + +206 +00:13:22,302 --> 00:13:28,442 +command+shift+G 用于查找上一个等 +都可以正常运行 + +207 +00:13:28,475 --> 00:13:33,213 +当在 Mac 上运行时 +可以通过菜单栏访问这些命令 + +208 +00:13:33,247 --> 00:13:36,850 +你所需要做的就是确保 +显示内容的视图 + +209 +00:13:36,884 --> 00:13:40,521 +能够并且确实成为第一响应者 + +210 +00:13:40,554 --> 00:13:43,190 +对于不使用硬件键盘的用户 + +211 +00:13:43,223 --> 00:13:46,293 +可以通过 presentFindNavigator + +212 +00:13:46,326 --> 00:13:51,732 +在包含的查找交互属性上 +以编程方式调用查找交互 + +213 +00:13:51,765 --> 00:13:53,667 +例如 通过导航条项目使用 + +214 +00:13:53,700 --> 00:13:56,703 +可能是个不错的方法 + +215 +00:13:58,172 --> 00:14:02,176 +在 Mac 上运行时 +还有几件事需要记住 + +216 +00:14:02,209 --> 00:14:05,379 +例如 在 iOS 上 查找面板 + +217 +00:14:05,412 --> 00:14:09,316 +显示为软件键盘或快捷栏的一部分 + +218 +00:14:09,349 --> 00:14:13,554 +在 Mac 上 +我们会将其显示在你的内容中 + +219 +00:14:13,587 --> 00:14:16,590 +如果你们在滚动视图上安装查找交互 + +220 +00:14:16,623 --> 00:14:21,195 +我们将自动调整内容插入 +以适应查找面板 + +221 +00:14:21,228 --> 00:14:25,866 +并自动适应特征集合的更改 + +222 +00:14:25,899 --> 00:14:28,202 +否则 你应该确保在 +macOS 上的 UI 中 + +223 +00:14:28,235 --> 00:14:31,805 +有足够的空间来存储查找面板 + +224 +00:14:33,140 --> 00:14:38,679 +此外 点击放大镜图标时 +会显示一个包含一组 + +225 +00:14:38,712 --> 00:14:41,915 +标准查找选项的菜单 + +226 +00:14:41,949 --> 00:14:44,451 +你可以使用 UIFindInteraction 上的 + +227 +00:14:44,484 --> 00:14:49,857 +optionsMenuProvider 属性 +来定制该菜单的内容 + +228 +00:14:49,890 --> 00:14:53,594 +这对于实现自定义更为重要 + +229 +00:14:53,627 --> 00:14:55,863 +如果你在使用的是我之前提到的 + +230 +00:14:55,896 --> 00:14:59,633 +一个内建视图 那么就是这些了 + +231 +00:14:59,666 --> 00:15:02,870 +如果你的 App 通过其他方式 +显示文本内容 + +232 +00:15:02,903 --> 00:15:08,075 +比如完全自定义视图或列表视图 +如这里所示 + +233 +00:15:08,108 --> 00:15:11,478 +那么你仍然可以 +将查找交互添加到应用中 + +234 +00:15:11,512 --> 00:15:12,946 +我来展示一下怎么添加 + +235 +00:15:14,515 --> 00:15:16,717 +关于查找交互的好消息是 + +236 +00:15:16,750 --> 00:15:21,021 +你可以将其安装在任意视图上 + +237 +00:15:21,054 --> 00:15:24,892 +如果你的 App 中 +有现成的查找和替换实现 + +238 +00:15:24,925 --> 00:15:28,061 +则可以快速过渡到 UIFindInteraction + +239 +00:15:28,095 --> 00:15:32,266 +并利用系统的 UI + +240 +00:15:32,299 --> 00:15:37,037 +如果你们还没有现成的 +用于自定义视图的查找实现 + +241 +00:15:37,070 --> 00:15:39,339 +那么上手仍然非常容易 + +242 +00:15:39,373 --> 00:15:43,677 +特别是如果你们已经实现了 +UITextInput 协议 + +243 +00:15:43,710 --> 00:15:46,246 +以便与系统键盘一起工作 + +244 +00:15:46,280 --> 00:15:51,084 +以下是 UIFindInteraction +如何与自定义视图一起使用 + +245 +00:15:51,118 --> 00:15:55,355 +在自定义视图上安装 +UIFindInteraction 后 + +246 +00:15:55,389 --> 00:15:58,892 +设置查找交互委托 + +247 +00:15:58,926 --> 00:16:01,995 +查找交互委托 除了接收通知 + +248 +00:16:02,029 --> 00:16:05,499 +查找讲座何时开始或结束 + +249 +00:16:05,532 --> 00:16:10,537 +还负责处理 UIFindSession + +250 +00:16:10,571 --> 00:16:14,107 +UIFindSession 是一个抽象基类 + +251 +00:16:14,141 --> 00:16:17,811 +它压缩了给定讲座的所有状态 + +252 +00:16:17,845 --> 00:16:21,582 +如当前高亮显示的结果 + +253 +00:16:21,615 --> 00:16:25,352 +它还为从 UI 请求的所有操作提供服务 + +254 +00:16:25,385 --> 00:16:30,090 +例如“go to the next result” +或 “search for this string” + +255 +00:16:30,123 --> 00:16:32,826 +如果你想自己管理所有这些状态 + +256 +00:16:32,860 --> 00:16:37,164 +那么你可以从查找交互委托中选择 + +257 +00:16:37,197 --> 00:16:39,032 +提供 UIFindSession 的子类 + +258 +00:16:40,601 --> 00:16:43,770 +如果你的 App 中已经有了一个 + +259 +00:16:43,804 --> 00:16:46,573 +现成的查找和替换实现 + +260 +00:16:46,607 --> 00:16:50,043 +并且希望将其连接到系统 UI +这是个不错的选择 + +261 +00:16:50,077 --> 00:16:52,513 +另外 让系统为你处理状态 + +262 +00:16:52,546 --> 00:16:55,482 +将是个更好的主意 + +263 +00:16:55,516 --> 00:16:59,186 +而不是在 +任何封装显示文档内容的类上 + +264 +00:16:59,219 --> 00:17:05,259 +采用 UITextSearching 协议 + +265 +00:17:05,292 --> 00:17:09,897 +为此 你将返回一个 +UITextSearchingFindSession + +266 +00:17:09,930 --> 00:17:12,733 +并将它与你的文档类连接 + +267 +00:17:13,534 --> 00:17:16,403 +如果你还没有 +自定义视图的查找实现 + +268 +00:17:16,436 --> 00:17:19,640 +这是最好的选择 + +269 +00:17:19,673 --> 00:17:21,475 +以下是如何在代码中执行此操作 + +270 +00:17:22,709 --> 00:17:25,546 +这个例子有一个自定义文档类 + +271 +00:17:25,579 --> 00:17:30,584 +和一个显示该文档的自定义视图 + +272 +00:17:30,617 --> 00:17:34,421 +UIFindInteraction +将安装在这个视图上 + +273 +00:17:34,454 --> 00:17:38,458 +UITextSearchingFindSession +将作为 searchable object + +274 +00:17:38,492 --> 00:17:41,995 +随该文档一起提供 + +275 +00:17:42,029 --> 00:17:45,299 +确保你的视图控制器或自定义视图 + +276 +00:17:45,332 --> 00:17:50,537 +可以成为第一响应者 +这样键盘快捷方式就能正常工作 + +277 +00:17:51,872 --> 00:17:55,042 +创建查找交互 并提供讲座委托 + +278 +00:17:55,075 --> 00:17:57,311 +来处理查找讲座 + +279 +00:17:57,344 --> 00:18:01,181 +这里 视图控制器就是讲座委托 + +280 +00:18:01,215 --> 00:18:04,718 +然后 当交互询问查找讲座时 + +281 +00:18:04,751 --> 00:18:08,088 +只需返回一个新的 +UITextSearchingFindSession + +282 +00:18:08,121 --> 00:18:12,426 +将你的文档提供为可搜索对象 + +283 +00:18:12,459 --> 00:18:15,062 +当然 你需要确保自己的文档类 + +284 +00:18:15,095 --> 00:18:17,898 +符合 UITextSearching 协议 + +285 +00:18:19,867 --> 00:18:23,237 +实现 UITextSearching 协议的类 + +286 +00:18:23,270 --> 00:18:27,975 +负责在文档中实际查找文本 + +287 +00:18:28,008 --> 00:18:31,111 +系统将调用 performTextSearch + +288 +00:18:31,144 --> 00:18:36,750 +并为你提供一个聚合器对象 +你可以向其提供结果 + +289 +00:18:36,783 --> 00:18:42,823 +聚合器与 UITextRange 一起使用 +以表示文档中的结果 + +290 +00:18:42,856 --> 00:18:46,293 +这是另一个抽象类 你可以用它 + +291 +00:18:46,326 --> 00:18:51,765 +来封装任何对你如何 +存储文本有意义的数据 + +292 +00:18:51,798 --> 00:18:54,535 +例如 这可以代表 +使用 WebKit 呈现文本的 + +293 +00:18:54,568 --> 00:18:58,405 +客户端的 DOM 范围 + +294 +00:18:58,438 --> 00:19:00,507 +聚合器也是线程安全的 + +295 +00:19:00,541 --> 00:19:04,545 +因此你们可以在后台线程上 +为它提供结果 + +296 +00:19:04,578 --> 00:19:06,780 +最后 由于发现交互 + +297 +00:19:06,813 --> 00:19:11,018 +不知道如何使用自定义视图显示结果 + +298 +00:19:11,051 --> 00:19:16,490 +因此你还需要在调用 decorate 时 +为给定样式装饰结果 + +299 +00:19:16,523 --> 00:19:19,393 +UITextSearching 查找讲座和协议 + +300 +00:19:19,426 --> 00:19:23,830 +还支持使用相同的交互 +跨多个可见文档 + +301 +00:19:23,864 --> 00:19:25,699 +进行多路复用 + +302 +00:19:26,567 --> 00:19:28,936 +换句话说 如果你的 App + +303 +00:19:28,969 --> 00:19:32,439 +以类似于 Mail 的对话视图的方式 +显示内容 + +304 +00:19:32,472 --> 00:19:36,343 +在这种情况下 +每个 document 都是一个邮件消息 + +305 +00:19:36,376 --> 00:19:41,381 +你可以在根级集合视图上 +安装单个查找交互 + +306 +00:19:41,415 --> 00:19:45,719 +同时在所有文档中执行查找 + +307 +00:19:45,752 --> 00:19:52,059 +从而使你的用户可以轻松地 +在不同文档结果之间跳转 + +308 +00:19:52,092 --> 00:19:57,331 +这就是开始使用 iOS 16 中 +新的查找交互所需的全部内容 + +309 +00:19:57,364 --> 00:20:00,334 +对于显示大量文本内容的系统视图 + +310 +00:20:00,367 --> 00:20:04,371 +请确保启用 +isFindInteractionEnabled + +311 +00:20:04,404 --> 00:20:08,709 +将现有的查找实现移动到 +UIFindInteraction + +312 +00:20:08,742 --> 00:20:13,080 +如果你的 App 中还没有文本搜索 + +313 +00:20:13,113 --> 00:20:16,383 +请执行 UITextSearching +并使用 UITextSearchingFindSession + +314 +00:20:16,416 --> 00:20:19,286 +最后 检查并确保你的 App 中 + +315 +00:20:19,319 --> 00:20:22,723 +没有任何冲突的键盘快捷键 + +316 +00:20:22,756 --> 00:20:27,761 +这就是为 iOS 16 刷新你的 +App 的编辑交互 + +317 +00:20:27,794 --> 00:20:30,764 +并使它们成为 +真正的桌面类所需要做的 + +318 +00:20:31,498 --> 00:20:34,535 +在你的 App 中尝试新的文本编辑菜单 + +319 +00:20:34,568 --> 00:20:38,272 +并采用自定义 UI 的编辑菜单交互 + +320 +00:20:38,305 --> 00:20:42,843 +通过使你的 App 的文本内容可搜索 +来提高工作效率 + +321 +00:20:42,876 --> 00:20:47,714 +我期待着在你的 App 中 +发现这些很棒的新功能 + +322 +00:20:47,748 --> 00:20:52,286 +感谢收看 一定要点赞 评论并订阅哦 + +323 +00:20:52,319 --> 00:20:55,322 +[欢快的音乐] + diff --git a/zho/2022 Session 10072 Use SwiftUI with UIKit.srt b/zho/2022 Session 10072 Use SwiftUI with UIKit.srt new file mode 100644 index 0000000..b05c1c0 --- /dev/null +++ b/zho/2022 Session 10072 Use SwiftUI with UIKit.srt @@ -0,0 +1,2156 @@ +1 +00:00:00,000 --> 00:00:03,070 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,070 --> 00:00:09,943 +♪ + +3 +00:00:09,943 --> 00:00:14,047 +大家好 我是 Sara Frederixon +Health App 的工程师 + +4 +00:00:14,047 --> 00:00:18,051 +我将和您讨论如何将 +SwiftUI 与 UIKit 结合使用 + +5 +00:00:18,051 --> 00:00:22,189 +像您们中的许多人一样 +我在已有的 UIKit App 上工作 + +6 +00:00:22,189 --> 00:00:25,158 +对我来说这就是 Health App + +7 +00:00:25,158 --> 00:00:27,494 +Health App 有许多可视化信息 + +8 +00:00:27,494 --> 00:00:30,430 +以帮助人们了解自己的健康数据 + +9 +00:00:30,430 --> 00:00:33,867 +但是构建这些视图可能非常复杂 + +10 +00:00:33,867 --> 00:00:36,803 +我一直对 +使用 SwiftUI 带来的优势很感兴趣 + +11 +00:00:36,803 --> 00:00:39,740 +所以我与 UIKit +和 SwiftUI 团队一起工作 + +12 +00:00:39,740 --> 00:00:43,477 +以了解如何 +将两者集成到同一个 App 中 + +13 +00:00:43,477 --> 00:00:46,613 +在这个视频中 我将为您展示 + +14 +00:00:46,613 --> 00:00:50,784 +在您自己的 UIKit App 中 +使用 SwiftUI 多么简单 + +15 +00:00:50,784 --> 00:00:54,354 +首先 我将介绍现有 +UIHostingController + +16 +00:00:54,354 --> 00:00:58,959 +它包含一些更新内容 灵活性也更强 + +17 +00:00:58,959 --> 00:01:01,962 +接下来我将深入讲解用您的 App + +18 +00:01:01,962 --> 00:01:05,165 +中的现有 +数据填充 SwiftUI 视图 + +19 +00:01:05,165 --> 00:01:07,935 +以及如何确保在数据出现变更时 + +20 +00:01:07,935 --> 00:01:11,071 +及时更新 SwiftUI 视图 + +21 +00:01:11,071 --> 00:01:14,107 +然后 我将介绍一些 +令人兴奋的新功能 + +22 +00:01:14,107 --> 00:01:16,276 +它们可以让您用 SwiftUI + +23 +00:01:16,276 --> 00:01:20,514 +构建 UICollectionView +和 UITableView 单元格 + +24 +00:01:20,514 --> 00:01:24,251 +最后 我将介绍数据流 +有哪些独特的方面 + +25 +00:01:24,251 --> 00:01:25,919 +当您在 collection 和 table view 单元格内 + +26 +00:01:25,919 --> 00:01:29,890 +使用 SwiftUI 视图 + +27 +00:01:29,890 --> 00:01:33,727 +我们先来讨论一下 +UIHostingController + +28 +00:01:33,727 --> 00:01:36,763 +UIHostingController +是一个 UIViewController + +29 +00:01:36,763 --> 00:01:39,967 +它包含 SwiftUI 视图层次结构 + +30 +00:01:39,967 --> 00:01:41,735 +能在 UIKit 中 +使用视图控制器的地方 + +31 +00:01:41,735 --> 00:01:45,372 +就可以使用托管控制器 + +32 +00:01:45,372 --> 00:01:46,974 +这让 UIHostingController + +33 +00:01:46,974 --> 00:01:50,444 +成为了开始使用 +SwiftUI 的简便方法 + +34 +00:01:50,444 --> 00:01:53,814 +让我们来看看 +托管控制器是如何工作的 + +35 +00:01:53,814 --> 00:01:56,817 +托管控制器是一个视图控制器 + +36 +00:01:56,817 --> 00:02:01,355 +这意味着它的视图属性中 +存储了一个 UIView + +37 +00:02:01,355 --> 00:02:02,589 +那个视图里面就是 + +38 +00:02:02,589 --> 00:02:05,559 +绘制 SwiftUI 内容的地方 + +39 +00:02:05,559 --> 00:02:09,696 +让我们举例说明如何使用托管控制器 + +40 +00:02:09,696 --> 00:02:14,434 +在这里 我们创建一个 HeartRateView +一个 SwiftUI 视图 + +41 +00:02:14,434 --> 00:02:17,571 +然后 我们创建一个托管控制器 + +42 +00:02:17,571 --> 00:02:21,041 +将 HeartRateView +作为它的根视图 并呈现出来 + +43 +00:02:21,041 --> 00:02:22,709 +UIHostingController 可与所有 + +44 +00:02:22,709 --> 00:02:26,880 +UIKit 视图控制器 +API 搭配使用 + +45 +00:02:26,880 --> 00:02:30,484 +让我们来看看另一个例子 + +46 +00:02:30,484 --> 00:02:32,119 +我们有相同的 HeartRateView + +47 +00:02:32,119 --> 00:02:34,922 +以及和以前一样的托管控制器 + +48 +00:02:34,922 --> 00:02:36,957 +在这里 我们添加托管控制器 + +49 +00:02:36,957 --> 00:02:39,193 +将其作为子视图控制器 + +50 +00:02:39,193 --> 00:02:43,830 +然后 我们可以调整 +托管控制器的视图位置和大小 + +51 +00:02:43,830 --> 00:02:47,968 +当 UIHostingController 中的 +SwiftUI 内容发生变化时 + +52 +00:02:47,968 --> 00:02:51,471 +您需要调整视图的大小 + +53 +00:02:51,471 --> 00:02:54,908 +作为 iOS 16 中的新功能 +UIHostingController + +54 +00:02:54,908 --> 00:02:57,511 +允许您启用 + +55 +00:02:57,511 --> 00:03:00,380 +视图控制器首选内容大小 + +56 +00:03:00,380 --> 00:03:03,851 +和视图固有内容大小的自动更新 + +57 +00:03:03,851 --> 00:03:07,221 +您可以使用 +UIHostingController 上的 + +58 +00:03:07,221 --> 00:03:09,189 +新 sizingOptions 属性 +启用此功能 + +59 +00:03:09,189 --> 00:03:12,292 +我们举个例子 + +60 +00:03:12,292 --> 00:03:14,795 +首先 我们制作 HeartRateView + +61 +00:03:14,795 --> 00:03:18,031 +并创建 hostingController + +62 +00:03:18,031 --> 00:03:22,336 +我们使用新 sizingOptions API +让托管控制器 + +63 +00:03:22,336 --> 00:03:27,641 +自动更新其 preferredContentSize + +64 +00:03:27,641 --> 00:03:30,077 +然后 我们进行设置 + +65 +00:03:30,077 --> 00:03:31,712 +让 modalPresentationStyle 弹出 + +66 +00:03:31,712 --> 00:03:35,682 +使用新 sizingOptions API 可确保 + +67 +00:03:35,682 --> 00:03:41,221 +弹出框的大小适合 SwiftUI 内容 + +68 +00:03:41,221 --> 00:03:43,690 +现在您已经熟悉了 +UIHostingController + +69 +00:03:43,690 --> 00:03:46,827 +我们来谈谈 +如何将 UIKit App 的 + +70 +00:03:46,827 --> 00:03:49,730 +其他部分中的数据 +导入 SwiftUI + +71 +00:03:49,730 --> 00:03:52,399 +并确保当该数据发生变更时 + +72 +00:03:52,399 --> 00:03:55,502 +您的 SwiftUI 视图 +能及时更新 + +73 +00:03:55,502 --> 00:03:58,438 +这是您 UIKit App 的图表 + +74 +00:03:58,438 --> 00:04:00,440 +它包含一个现有的模型层 + +75 +00:04:00,440 --> 00:04:04,411 +它拥有并管理 +App 的数据模型对象 + +76 +00:04:04,411 --> 00:04:07,848 +您的 App 还包含 +许多视图控制器 + +77 +00:04:07,848 --> 00:04:11,585 +如果您想开始使用 SwiftUI +您需要一个托管控制器 + +78 +00:04:11,585 --> 00:04:15,589 +其中一个视图控制器中 +有 SwiftUI 视图 + +79 +00:04:15,589 --> 00:04:18,892 +您将用仍然您现有模型层所有的数据 + +80 +00:04:18,892 --> 00:04:22,496 +填充此 SwiftUI 视图 + +81 +00:04:22,496 --> 00:04:25,999 +在本部分 我们将重点介绍如何 + +82 +00:04:25,999 --> 00:04:30,370 +跨越 UIKit +和 SwiftUI 的界限桥接数据 + +83 +00:04:30,370 --> 00:04:33,574 +SwiftUI 提供了多种数据流原语 + +84 +00:04:33,574 --> 00:04:36,443 +以帮助您管理 App 中的数据 + +85 +00:04:36,443 --> 00:04:39,413 +让我们来看看不同的选项 + +86 +00:04:39,413 --> 00:04:44,418 +要存储由 SwiftUI 视图 +创建和拥有的数据 + +87 +00:04:44,418 --> 00:04:49,556 +SwiftUI 提供了 @State +和 @StateObject 属性包装器 + +88 +00:04:49,556 --> 00:04:52,993 +由于我们专注于 +SwiftUI 之外的数据 + +89 +00:04:52,993 --> 00:04:56,296 +这些属性包装器并不合适 + +90 +00:04:56,296 --> 00:04:58,765 +所以 我不会在 +本视频中介绍这些内容 + +91 +00:04:58,765 --> 00:05:01,435 +观看“SwiftUI 中的数据要点” + +92 +00:05:01,435 --> 00:05:06,039 +以了解有关 SwiftUI 视图 +拥有的数据的更多信息 + +93 +00:05:06,039 --> 00:05:08,809 +处理 SwiftUI +外部数据的一种方法 + +94 +00:05:08,809 --> 00:05:12,846 +是在初始化视图时直接传递数值 + +95 +00:05:12,846 --> 00:05:15,249 +因为只是传递并非由 SwiftUI + +96 +00:05:15,249 --> 00:05:18,819 +拥有或管理的原始数据 + +97 +00:05:18,819 --> 00:05:22,623 +所以您负责在数据发生变化时 + +98 +00:05:22,623 --> 00:05:25,225 +手动更新 UIHostingController + +99 +00:05:25,225 --> 00:05:27,528 +我们举个例子 + +100 +00:05:27,528 --> 00:05:31,665 +这是一个名为 +HeartRateView 的 SwiftUI 视图 + +101 +00:05:31,665 --> 00:05:33,600 +这个视图只有一个属性 + +102 +00:05:33,600 --> 00:05:37,004 +以整数形式 +存储的每分钟的 beatsPerMinute 即心率 + +103 +00:05:37,004 --> 00:05:39,940 +并将此数值显示为文本 + +104 +00:05:39,940 --> 00:05:41,608 +我们通过在现有的名为 + +105 +00:05:41,608 --> 00:05:43,777 +HeartRateViewController 的 +视图控制器中 + +106 +00:05:43,777 --> 00:05:45,812 +嵌入一个 +UIHostingController + +107 +00:05:45,812 --> 00:05:48,515 +来显示这个 +HeartRateView + +108 +00:05:48,515 --> 00:05:50,684 +我们保存对托管控制器的引用 + +109 +00:05:50,684 --> 00:05:53,253 +以便稍后更新它的根视图 + +110 +00:05:53,253 --> 00:05:57,357 +请记住 SwiftUI HeartRateView +是一个值类型 + +111 +00:05:57,357 --> 00:06:00,827 +所以单独存储它 +会创建一个单独的副本 + +112 +00:06:00,827 --> 00:06:04,431 +让我们不能更新 UI + +113 +00:06:04,431 --> 00:06:06,900 +HeartRateViewController 拥有 + +114 +00:06:06,900 --> 00:06:09,770 +用于填充 HeartRateView 数据 + +115 +00:06:09,770 --> 00:06:13,240 +此数据存储在 +beatsPerMinute 属性中 + +116 +00:06:13,240 --> 00:06:15,542 +当 beatsPerMinute 值发生变化时 + +117 +00:06:15,542 --> 00:06:19,413 +我们将调用一个方法来更新视图 + +118 +00:06:19,413 --> 00:06:23,383 +在更新方法中 我们使用 +最新的 beatsPerMinute 值 + +119 +00:06:23,383 --> 00:06:26,119 +创建一个新的 HeartRateView + +120 +00:06:26,119 --> 00:06:28,155 +然后将该视图指定为 + +121 +00:06:28,155 --> 00:06:31,225 +托管控制器的 rootView + +122 +00:06:31,225 --> 00:06:37,064 +这是将数据从 UIKit +导入 SwiftUI 的简单方法 + +123 +00:06:37,064 --> 00:06:39,766 +但您需要在数据发生变化时 + +124 +00:06:39,766 --> 00:06:43,871 +及时手动更新托管控制器的 rootView + +125 +00:06:43,871 --> 00:06:46,540 +让我们看看 +其他 SwiftUI 数据原语 + +126 +00:06:46,540 --> 00:06:49,743 +以实现数据自动更新 + +127 +00:06:49,743 --> 00:06:52,246 +@ObservedObject +和 @EnvironmentObject + +128 +00:06:52,246 --> 00:06:54,548 +属性包装器允许您引用 + +129 +00:06:54,548 --> 00:06:56,283 +ObservableObject 协议的 + +130 +00:06:56,283 --> 00:06:59,853 +外部模型对象 + +131 +00:06:59,853 --> 00:07:01,688 +当您使用这些属性包装器时 + +132 +00:07:01,688 --> 00:07:07,294 +SwiftUI 会在数据更改时 +自动更新您的视图 + +133 +00:07:07,294 --> 00:07:10,364 +在此视频中 我们将重点介绍 + +134 +00:07:10,364 --> 00:07:12,032 +@ObservedObject 属性包装器 + +135 +00:07:12,032 --> 00:07:14,902 +您可以在前面提到的 + +136 +00:07:14,902 --> 00:07:18,805 +“SwiftUI 中的数据要”点视频中 +了解 EnvironmentObject 的更多内容 + +137 +00:07:18,805 --> 00:07:22,576 +让我们来看看 +如何创建 @ObservedObject + +138 +00:07:22,576 --> 00:07:25,078 +第一步是取一个 App 的现有部分 + +139 +00:07:25,078 --> 00:07:27,614 +拥有的模型对象 + +140 +00:07:27,614 --> 00:07:31,985 +并使其符合 +ObservableObject 协议 + +141 +00:07:31,985 --> 00:07:35,522 +接下来 +我们在我 SwiftUI 视图中 + +142 +00:07:35,522 --> 00:07:38,759 +将模型存储为 +@ObservedObject 属性 + +143 +00:07:38,759 --> 00:07:42,129 +将 ObservableObject +连接到 SwiftUI + +144 +00:07:42,129 --> 00:07:46,567 +使它能够 +在其中一个属性更改时更新视图 + +145 +00:07:46,567 --> 00:07:48,769 +回顾一下 HeartRateView 示例 + +146 +00:07:48,769 --> 00:07:51,038 +并将其连接起来 + +147 +00:07:51,038 --> 00:07:53,340 +我们的 App 有一个 +名为 HeartData 的类别 + +148 +00:07:53,340 --> 00:07:56,777 +其中包含每分钟 +beatsPerMinute 属性 + +149 +00:07:56,777 --> 00:08:01,548 +我们按照协议使其成为 +ObservableObject + +150 +00:08:01,548 --> 00:08:04,218 +然后我们将 +@Published 属性包装器 + +151 +00:08:04,218 --> 00:08:06,720 +添加到 beatsPerMinute 属性中 + +152 +00:08:06,720 --> 00:08:09,456 +此属性包装器会在发生变化时 + +153 +00:08:09,456 --> 00:08:12,926 +触发 SwiftUI 更新我们的视图 + +154 +00:08:12,926 --> 00:08:15,462 +在 HeartRateView 里 +我们将 HeartData 存储在 + +155 +00:08:15,462 --> 00:08:17,397 +标有 @ObservedObject + +156 +00:08:17,397 --> 00:08:20,567 +属性包装器的属性中 + +157 +00:08:20,567 --> 00:08:23,637 +在视图的主体部分 +我们显示直接来源于 + +158 +00:08:23,637 --> 00:08:26,240 +HeartData 的 beatsPerMinute + +159 +00:08:26,240 --> 00:08:30,043 +现在 让我们 +在视图控制器中使用一下所有功能 + +160 +00:08:30,043 --> 00:08:33,347 +这是我们的 +HeartRateViewController + +161 +00:08:33,347 --> 00:08:37,751 +它将 HeartData +ObservableObject 存储在一个属性中 + +162 +00:08:37,751 --> 00:08:40,821 +因为这个属性 +不在 SwiftUI 视图中 + +163 +00:08:40,821 --> 00:08:44,157 +所以我们不需要 +在这里使用属性包装器 + +164 +00:08:44,157 --> 00:08:46,193 +HeartRateViewController +已用 HeartData 实例 + +165 +00:08:46,193 --> 00:08:47,895 +进行了初始化 + +166 +00:08:47,895 --> 00:08:50,130 +该数据用于 +创建 HeartRateView + +167 +00:08:50,130 --> 00:08:54,468 +此视图将成为托管控制器的 rootView + +168 +00:08:54,468 --> 00:08:57,671 +该图说明了它们是如何结合在一起的 + +169 +00:08:57,671 --> 00:09:00,307 +我们获取 +当前的 HeartData 实例 + +170 +00:09:00,307 --> 00:09:04,278 +其中包含心率每分钟 78 次 + +171 +00:09:04,278 --> 00:09:07,748 +然后我们 +用此 HeartData 实例 + +172 +00:09:07,748 --> 00:09:09,950 +创建一个 +新 HeartRateViewController + +173 +00:09:09,950 --> 00:09:14,555 +并将 HeartData 连接到 +SwiftUI HeartRateView + +174 +00:09:14,555 --> 00:09:15,923 +几秒钟后 + +175 +00:09:15,923 --> 00:09:18,692 +即当下一个心率数据样本到达时 + +176 +00:09:18,692 --> 00:09:24,231 +HeartData 的 +beatsPerMinute 属性更新为 94 + +177 +00:09:24,231 --> 00:09:26,433 +因为这更改了 +ObservableObject + +178 +00:09:26,433 --> 00:09:29,036 +上的 published 属性 + +179 +00:09:29,036 --> 00:09:33,307 +HeartRateView +会自动更新以显示新值 + +180 +00:09:33,307 --> 00:09:36,443 +所以我们不再需要在数据发生变更时 + +181 +00:09:36,443 --> 00:09:38,178 +手动更新托管控制器 + +182 +00:09:38,178 --> 00:09:41,782 +这就是为什么 ObservableObject + +183 +00:09:41,782 --> 00:09:44,785 +是桥接从 UIKit +到 SwiftUI 的数据的好方法 + +184 +00:09:44,785 --> 00:09:48,889 +接下来说一下在集合视图以及 + +185 +00:09:48,889 --> 00:09:52,292 +表格视图单元格中使用 SwiftUI + +186 +00:09:52,292 --> 00:09:56,296 +iOS 16 中的新功能是 +UIHostingConfiguration + +187 +00:09:56,296 --> 00:09:58,999 +它可以让您在您现有的 +UIKit、集合和表格视图中 + +188 +00:09:58,999 --> 00:10:03,470 +使用 SwiftUI 的强大功能 + +189 +00:10:03,470 --> 00:10:06,273 +UIHostingConfiguration +让您可以轻松地 + +190 +00:10:06,273 --> 00:10:09,643 +使用 SwiftUI 实现自定义单元格 + +191 +00:10:09,643 --> 00:10:13,514 +同时您不必担心嵌入 +额外的视图或视图控制器 + +192 +00:10:13,514 --> 00:10:16,383 +在我们深入了解 +UIHostingConfiguration 之前 + +193 +00:10:16,383 --> 00:10:20,420 +让我们介绍一下 +UIKit 中的单元格配置 + +194 +00:10:20,420 --> 00:10:23,190 +单元格配置是一种 +在 UIKit 中定义 + +195 +00:10:23,190 --> 00:10:28,228 +单元格的内容、样式 +和行为的现代方式 + +196 +00:10:28,228 --> 00:10:31,198 +与 UIView +或 UIViewController 不同 + +197 +00:10:31,198 --> 00:10:34,101 +配置只是一个轻量级结构 + +198 +00:10:34,101 --> 00:10:36,770 +创建成本不高 + +199 +00:10:36,770 --> 00:10:38,972 +配置只是描述单元格的外观 + +200 +00:10:38,972 --> 00:10:41,742 +因此需要应用 + +201 +00:10:41,742 --> 00:10:45,078 +到单元格才有效果 + +202 +00:10:45,078 --> 00:10:46,880 +配置是可组合的 + +203 +00:10:46,880 --> 00:10:48,882 +并可用于 UICollectionView + +204 +00:10:48,882 --> 00:10:51,385 +和 UITableView 单元格 + +205 +00:10:51,385 --> 00:10:56,123 +要了解更多详情 +您可以观看“现代单元格配置” + +206 +00:10:56,123 --> 00:10:58,325 +有了这些知识 + +207 +00:10:58,325 --> 00:11:02,429 +我们将开始探究并使用 +UIHostingConfiguration + +208 +00:11:02,429 --> 00:11:05,332 +UIHostingConfiguration +是一个内容配置 + +209 +00:11:05,332 --> 00:11:08,902 +它使用 SwiftUI ViewBuilder +进行初始化 + +210 +00:11:08,902 --> 00:11:11,305 +这意味着我们可以 +开始编写 SwiftUI 代码 + +211 +00:11:11,305 --> 00:11:15,142 +以直接在其中创建视图 + +212 +00:11:15,142 --> 00:11:17,744 +为了渲染托管配置 + +213 +00:11:17,744 --> 00:11:20,347 +我们将其设置为 UICollectionView + +214 +00:11:20,347 --> 00:11:23,951 +或 UITableView 单元格中的 +contentConfiguration 属性 + +215 +00:11:23,951 --> 00:11:25,986 +让我们开始在此托管配置中 +编写一些 SwiftUI 代码 + +216 +00:11:25,986 --> 00:11:30,624 +以构建自定义心率单元格 + +217 +00:11:30,624 --> 00:11:34,394 +首先 我们将创建一个 label +带有“Heart Rate”文本 + +218 +00:11:34,394 --> 00:11:36,463 +和一颗心形图像 + +219 +00:11:36,463 --> 00:11:38,999 +SwiftUI 视图根据其使用环境 + +220 +00:11:38,999 --> 00:11:41,835 +接收默认样式 + +221 +00:11:41,835 --> 00:11:43,770 +但我们可以使用标准的 + +222 +00:11:43,770 --> 00:11:47,841 +SwiftUI 视图修饰符自定义样式 + +223 +00:11:47,841 --> 00:11:51,345 +我们将 foregroundStyle +和 font 修饰符添加到标签中 + +224 +00:11:51,345 --> 00:11:55,649 +以将图像和文本设置为粉红色并加粗 + +225 +00:11:55,649 --> 00:11:58,485 +因为我们只是在 +编写常规的 SwiftUI 代码 + +226 +00:11:58,485 --> 00:12:01,021 +我们可以根据需要随时 + +227 +00:12:01,021 --> 00:12:03,857 +将代码提出为一个独立的视图 + +228 +00:12:03,857 --> 00:12:06,827 +在这里 我们创建一个 +新的 SwiftUI 视图 + +229 +00:12:06,827 --> 00:12:09,696 +命名为 HeartRateTitleView + +230 +00:12:09,696 --> 00:12:12,299 +并将前面的代码移动到其 body 中 + +231 +00:12:12,299 --> 00:12:14,635 +然后在托管配置中嵌入 + +232 +00:12:14,635 --> 00:12:16,637 +HeartRateTitleView + +233 +00:12:16,637 --> 00:12:17,838 +如单元格所示 + +234 +00:12:17,838 --> 00:12:22,276 +结果是完全相同的 + +235 +00:12:22,276 --> 00:12:24,811 +现在我们可以在 +HeartRateTitleView 中 + +236 +00:12:24,811 --> 00:12:27,514 +开始添加更多视图 + +237 +00:12:27,514 --> 00:12:32,152 +我将 label 和 spacer 放在 +HStack 里面 + +238 +00:12:32,152 --> 00:12:36,156 +然后在旁边的 +Text 视图中添加当前时间 + +239 +00:12:36,156 --> 00:12:38,392 +到目前为止看起来还不错 + +240 +00:12:38,392 --> 00:12:41,428 +我们来向 +HeartRateTitleView 下方的 + +241 +00:12:41,428 --> 00:12:44,865 +自定义单元格中添加更多内容 + +242 +00:12:44,865 --> 00:12:47,434 +为此 我们将在托管配置中 + +243 +00:12:47,434 --> 00:12:49,203 +插入一个 Vstack 堆栈 + +244 +00:12:49,203 --> 00:12:53,774 +这样我们就可以在 +HeartRateTitleView 下添加更多内容 + +245 +00:12:53,774 --> 00:12:56,610 +然后 我们将两个 Text 视图一起 + +246 +00:12:56,610 --> 00:13:00,714 +放在 HStack 中 +以显示 90 BPM + +247 +00:13:00,714 --> 00:13:05,319 +然后 应用一些修饰符 +以按照需要设置样式 + +248 +00:13:05,319 --> 00:13:08,155 +就像我们之前对 +HeartRateTitleView 所做的那样 + +249 +00:13:08,155 --> 00:13:14,294 +我们可以将这个新代码移动到 +其自己的 SwiftUI 视图中 + +250 +00:13:14,294 --> 00:13:17,431 +现在 相同的代码被提取到了 + +251 +00:13:17,431 --> 00:13:20,033 +HeartRateBPMView 的 body 中 + +252 +00:13:20,033 --> 00:13:21,768 +我们的单元格看起来很棒 + +253 +00:13:21,768 --> 00:13:25,305 +不过我觉得我们还可以添加一个东西 + +254 +00:13:25,305 --> 00:13:29,743 +iOS 16 中有一个新功能是 +Swift Charts 框架 + +255 +00:13:29,743 --> 00:13:33,113 +只需编写几行代码 + +256 +00:13:33,113 --> 00:13:35,816 +您就可以用漂亮的图表来显示数据 + +257 +00:13:35,816 --> 00:13:38,552 +让我们试着用它在单元格内 + +258 +00:13:38,552 --> 00:13:41,889 +显示一个小的折线图 + +259 +00:13:41,889 --> 00:13:45,459 +我们使用新的 Chart 视图 +创建一个小折线图 + +260 +00:13:45,459 --> 00:13:47,895 +以显示最近的心率样本 + +261 +00:13:47,895 --> 00:13:52,566 +并把它放在 +单元格中的 BPM 视图旁边 + +262 +00:13:52,566 --> 00:13:53,700 +要生成图表 + +263 +00:13:53,700 --> 00:13:56,937 +我们需要传入一组心率样本 + +264 +00:13:56,937 --> 00:14:01,074 +并绘制一个连接所有样本的 LineMark + +265 +00:14:01,074 --> 00:14:02,609 +我们可以添加圆圈符号 + +266 +00:14:02,609 --> 00:14:04,811 +以表示折线上的每个样本 + +267 +00:14:04,811 --> 00:14:07,214 +并应用粉色的前景样式 + +268 +00:14:07,214 --> 00:14:11,285 +以为图表着色 从而匹配 +HeartRateTitleView + +269 +00:14:11,285 --> 00:14:14,154 +我们仅仅介绍了 + +270 +00:14:14,154 --> 00:14:16,890 +新 Swift Charts 框架的几个功能 + +271 +00:14:16,890 --> 00:14:20,260 +请务必观看 +“Hello Swift Charts”视频 + +272 +00:14:20,260 --> 00:14:22,229 +以了解更多信息 + +273 +00:14:22,229 --> 00:14:25,732 +我们制作的心率单元格很棒 + +274 +00:14:25,732 --> 00:14:29,269 +而且只需要几分钟就可以完成 + +275 +00:14:29,269 --> 00:14:32,039 +用 UIHostingConfiguration 和 SwiftUI + +276 +00:14:32,039 --> 00:14:35,509 +构建自定义单元格就是这么简单 + +277 +00:14:35,509 --> 00:14:37,377 +我们来聊一聊 +UIHostingConfiguration + +278 +00:14:37,377 --> 00:14:40,848 +支持的四大特别功能 + +279 +00:14:40,848 --> 00:14:44,418 +默认情况下 +根级 SwiftUI 内容 + +280 +00:14:44,418 --> 00:14:46,687 +和单元格边缘有一定间距 + +281 +00:14:46,687 --> 00:14:50,691 +是基于 UIKit 中 +单元格的布局边距决定的 + +282 +00:14:50,691 --> 00:14:52,626 +这确保了单元格内容 + +283 +00:14:52,626 --> 00:14:55,729 +与相邻单元格的内容和导航栏等 + +284 +00:14:55,729 --> 00:14:59,900 +其他 UI 元素正确对齐 + +285 +00:14:59,900 --> 00:15:02,936 +有时 您可能想使用不同的边距 + +286 +00:15:02,936 --> 00:15:07,074 +或让内容延伸到单元格的边缘 + +287 +00:15:07,074 --> 00:15:10,177 +对于这些情况 您可以在 +UIHostingConfiguration 上 + +288 +00:15:10,177 --> 00:15:15,415 +使用边距修饰符以更改默认边距 + +289 +00:15:15,415 --> 00:15:18,051 +如果您想 用 SwiftUI +自定义单元格的背景外观 + +290 +00:15:18,051 --> 00:15:21,588 +您可以使用 +UIHostingConfiguration 上的 + +291 +00:15:21,588 --> 00:15:24,491 +background 修饰符 + +292 +00:15:24,491 --> 00:15:26,560 +UIHostingConfiguration 的 +背景及其内容 + +293 +00:15:26,560 --> 00:15:31,632 +之间有几个关键区别 + +294 +00:15:31,632 --> 00:15:34,735 +背景位于单元格的背面 + +295 +00:15:34,735 --> 00:15:39,173 +即单元格内容视图中的 +SwiftUI 内容下方 + +296 +00:15:39,173 --> 00:15:41,508 +此外 虽然内容通常是 + +297 +00:15:41,508 --> 00:15:43,944 +从单元格边缘插入的 + +298 +00:15:43,944 --> 00:15:48,182 +但背景通常会从 +单元格的一边拓展到另一边 + +299 +00:15:48,182 --> 00:15:51,151 +最后 当使用自定尺寸单元格时 + +300 +00:15:51,151 --> 00:15:56,690 +只有单元格的内容 +会影响单元格的大小 + +301 +00:15:56,690 --> 00:15:59,626 +接下来 让我们看看 +UIHostingConfiguration + +302 +00:15:59,626 --> 00:16:02,095 +的另外两个特殊功能 + +303 +00:16:02,095 --> 00:16:04,731 +您可以将其用于集合视图列表 + +304 +00:16:04,731 --> 00:16:06,700 +或表格视图中的单元格 + +305 +00:16:06,700 --> 00:16:08,969 +在列表中 托管配置默认将 + +306 +00:16:08,969 --> 00:16:11,905 +单元格下方的间隔符 + +307 +00:16:11,905 --> 00:16:14,875 +自动与 SwiftUI 文本对齐 + +308 +00:16:14,875 --> 00:16:18,178 +在本例中 请注意间隔符的前缘 + +309 +00:16:18,178 --> 00:16:21,915 +是如何跳过图像 + +310 +00:16:21,915 --> 00:16:23,383 +以与单元格中的文本对齐 + +311 +00:16:23,383 --> 00:16:24,985 +如果需要使间隔符与托管配置中 + +312 +00:16:24,985 --> 00:16:28,422 +的不同 SwiftUI 视图对齐 + +313 +00:16:28,422 --> 00:16:32,226 +请使用 alignmentGuide 修饰符 + +314 +00:16:32,226 --> 00:16:34,995 +在集合视图列表或表格视图中 + +315 +00:16:34,995 --> 00:16:40,300 +您可以直接使用 +SwiftUI 为一行配置滑动操作 + +316 +00:16:40,300 --> 00:16:43,770 +通过在 swipeActions +修饰符中创建按钮 + +317 +00:16:43,770 --> 00:16:45,639 +您将能够滑动单元格 + +318 +00:16:45,639 --> 00:16:49,142 +以显示和执行自定义操作 + +319 +00:16:49,142 --> 00:16:50,911 +下载此视频的示例代码 + +320 +00:16:50,911 --> 00:16:53,714 +以找到一个完整的例子 + +321 +00:16:53,714 --> 00:16:55,482 +定义滑动操作时 + +322 +00:16:55,482 --> 00:16:57,985 +确保您的按钮使用所代表的项目 + +323 +00:16:57,985 --> 00:17:01,755 +的稳定标识符执行其操作 + +324 +00:17:01,755 --> 00:17:03,524 +不要使用索引路径 因为它可能会 + +325 +00:17:03,524 --> 00:17:06,059 +在单元格可见的情况下发生变化 + +326 +00:17:06,059 --> 00:17:10,597 +从而导致滑动操作作用于错误的项目 + +327 +00:17:10,597 --> 00:17:12,900 +当在单元格中使用 +UIHostingConfiguration 时 + +328 +00:17:12,900 --> 00:17:16,370 +请记住单元格的交互 + +329 +00:17:16,370 --> 00:17:18,805 +例如点击处理 高亮显示 + +330 +00:17:18,805 --> 00:17:21,208 +和选择将仍然通过 + +331 +00:17:21,208 --> 00:17:24,411 +集合视图或表格视图处理 + +332 +00:17:24,411 --> 00:17:27,281 +如果需要为 +任何这些 UIKit 单元格状态 + +333 +00:17:27,281 --> 00:17:29,683 +自定义 SwiftUI 视图 + +334 +00:17:29,683 --> 00:17:32,085 +您可以在单元格的 +configurationUpdateHandler 中 + +335 +00:17:32,085 --> 00:17:35,923 +创建您的托管配置 + +336 +00:17:35,923 --> 00:17:40,394 +并使用 SwiftUI 代码中提供的状态 + +337 +00:17:40,394 --> 00:17:43,030 +只要单元格状态发生变化 + +338 +00:17:43,030 --> 00:17:45,699 +configurationUpdateHandler +就会再次运行 + +339 +00:17:45,699 --> 00:17:47,868 +为新状态创建一个 +新 UIHostingConfiguration + +340 +00:17:47,868 --> 00:17:51,205 +并将其应用于单元格 + +341 +00:17:51,205 --> 00:17:54,541 +在此例中 我们使用状态 +来添加一个复选标记图像 + +342 +00:17:54,541 --> 00:17:57,511 +它代表单元格被选中 + +343 +00:17:57,511 --> 00:18:00,013 +现在您已经熟悉了 +UIHostingConfiguration + +344 +00:18:00,013 --> 00:18:04,218 +让我们讨论一下如何管理 +数据流动 从模型层传递到 + +345 +00:18:04,218 --> 00:18:07,020 +UICollectionView 或者 +UITableView 的单元格 + +346 +00:18:07,020 --> 00:18:10,557 +其内部由 SwiftUI 填充 + +347 +00:18:10,557 --> 00:18:14,561 +我们的目标是建立病症清单 + +348 +00:18:14,561 --> 00:18:17,931 +在此例中 我们使用了一个 +UICollectionView + +349 +00:18:17,931 --> 00:18:22,769 +但我们讨论的所有内容 +都同样适用于 UITableView + +350 +00:18:22,769 --> 00:18:25,939 +让我们来看看所涉及的构件 + +351 +00:18:25,939 --> 00:18:30,377 +我们的 App 有一个 +MedicalCondition 模型对象集合 + +352 +00:18:30,377 --> 00:18:33,347 +我们将在集合视图中显示 + +353 +00:18:33,347 --> 00:18:35,616 +对于此集合中的每个项目 + +354 +00:18:35,616 --> 00:18:38,318 +我们想在集合视图中创建一个单元格 + +355 +00:18:38,318 --> 00:18:41,588 +以显示该病症 + +356 +00:18:41,588 --> 00:18:44,992 +为此 我们将创建一个连接到 + +357 +00:18:44,992 --> 00:18:47,561 +集合视图的可区分的数据源 + +358 +00:18:47,561 --> 00:18:51,965 +然后 我们需要 +填充一个可区分数据源快照 + +359 +00:18:51,965 --> 00:18:55,669 +以及数据集合中的 + +360 +00:18:55,669 --> 00:18:58,739 +MedicalCondition 模型对象的标识符 + +361 +00:18:58,739 --> 00:19:01,775 +可区分数据源快照必须 + +362 +00:19:01,775 --> 00:19:05,546 +包含每个 MedicalCondition 的唯一标识符 + +363 +00:19:05,546 --> 00:19:08,882 +而不是 MedicalCondition 对象本身 + +364 +00:19:08,882 --> 00:19:13,053 +这确保了可区分数据源可以准确跟踪 + +365 +00:19:13,053 --> 00:19:15,189 +每个项目本身 + +366 +00:19:15,189 --> 00:19:17,758 +并在稍后应用新快照时 + +367 +00:19:17,758 --> 00:19:20,627 +计算正确的变化 + +368 +00:19:20,627 --> 00:19:23,497 +通过将具有这些项目标识符的快照 + +369 +00:19:23,497 --> 00:19:25,365 +应用于可区分数据源 + +370 +00:19:25,365 --> 00:19:28,068 +它会自动更新集合视图 + +371 +00:19:28,068 --> 00:19:32,239 +这将为每个项目创建一个新单元格 + +372 +00:19:32,239 --> 00:19:36,376 +在 UIHostingConfiguration 中 +使用 SwiftUI 视图 + +373 +00:19:36,376 --> 00:19:42,282 +将每个单元格配置为 +显示一个 MedicalCondition + +374 +00:19:42,282 --> 00:19:45,018 +现在我们正在显示使用 +SwiftUI 构建的单元格 + +375 +00:19:45,018 --> 00:19:49,323 +当数据发生变更时 +我们需要处理 UI 更新 + +376 +00:19:49,323 --> 00:19:51,058 +有两种不同类型的变化 + +377 +00:19:51,058 --> 00:19:54,061 +我们需要分别单独处理 + +378 +00:19:54,061 --> 00:19:58,465 +第一种是数据集合本身发生变化时 + +379 +00:19:58,465 --> 00:20:04,538 +例如插入、重新排序或删除项目 + +380 +00:20:04,538 --> 00:20:07,841 +这些变更通过将新快照 + +381 +00:20:07,841 --> 00:20:10,844 +应用于可区分数据源来处理 + +382 +00:20:10,844 --> 00:20:14,748 +可区分数据源将区分新旧快照 + +383 +00:20:14,748 --> 00:20:18,218 +并对集合视图执行必要的更新 + +384 +00:20:18,218 --> 00:20:23,257 +以插入、移动或删除单元格 + +385 +00:20:23,257 --> 00:20:25,893 +因为数据集合本身的变化 + +386 +00:20:25,893 --> 00:20:28,762 +不会影响单元格内的任何东西 + +387 +00:20:28,762 --> 00:20:31,365 +您以相同的方式处理这些类型的更改 + +388 +00:20:31,365 --> 00:20:35,802 +无论是使用 UIKit +还是 SwiftUI 构建单元格 + +389 +00:20:35,802 --> 00:20:37,971 +我们需要处理的第二种变更 + +390 +00:20:37,971 --> 00:20:43,343 +是单个模型对象的属性发生变更 + +391 +00:20:43,343 --> 00:20:46,146 +这些变更通常需要 + +392 +00:20:46,146 --> 00:20:48,115 +您更新现在单元格中的视图 + +393 +00:20:48,115 --> 00:20:49,883 +因为可区分数据源 + +394 +00:20:49,883 --> 00:20:53,120 +仅在其快照中包含项目标识符 + +395 +00:20:53,120 --> 00:20:55,088 +它不知道现有项目 + +396 +00:20:55,088 --> 00:20:57,991 +的属性何时发生变更 + +397 +00:20:57,991 --> 00:21:01,562 +按照传统 +使用 UIKit 时您需要手动 + +398 +00:21:01,562 --> 00:21:04,998 +告知可变数据源这些变更 + +399 +00:21:04,998 --> 00:21:08,802 +方式是重新配置 +或重新加载快照中的项目 + +400 +00:21:08,802 --> 00:21:13,373 +但是当在单元格中使用 SwiftUI 时 +您就不再需要这么做了 + +401 +00:21:13,373 --> 00:21:16,410 +通过在我们的 SwiftUI 视图的 +ObservableObject 属性中 + +402 +00:21:16,410 --> 00:21:20,447 +存储 ObservedObject 模型 + +403 +00:21:20,447 --> 00:21:22,583 +对模型的已发布属性的更改 + +404 +00:21:22,583 --> 00:21:25,686 +会自动触发 SwiftUI + +405 +00:21:25,686 --> 00:21:27,254 +刷新视图 + +406 +00:21:27,254 --> 00:21:30,791 +这在模型和单元格内的 SwiftUI 视图 + +407 +00:21:30,791 --> 00:21:34,161 +之间建立了直接连接 + +408 +00:21:34,161 --> 00:21:35,429 +当做出更改时 + +409 +00:21:35,429 --> 00:21:38,932 +单元格中的 SwiftUI 视图直接更新 + +410 +00:21:38,932 --> 00:21:41,335 +无需通过可区分数据源 + +411 +00:21:41,335 --> 00:21:44,404 +或 UICollectionView 进行更新 + +412 +00:21:44,404 --> 00:21:45,973 +当单元格的数据发生变更时 + +413 +00:21:45,973 --> 00:21:48,675 +单元格可能需要扩大或缩小 + +414 +00:21:48,675 --> 00:21:51,144 +以适应新的内容 + +415 +00:21:51,144 --> 00:21:54,982 +但是如果直接更新 +SwiftUI 单元格内容 + +416 +00:21:54,982 --> 00:21:56,917 +而无需通过 UIKit + +417 +00:21:56,917 --> 00:22:00,754 +集合视图如何知道 +需要调整单元格的大小呢? + +418 +00:22:00,754 --> 00:22:04,358 +UIHostingConfiguration +利用了 UIKit 中的 + +419 +00:22:04,358 --> 00:22:07,327 +一项全新功能以完成这项工作 + +420 +00:22:07,327 --> 00:22:11,999 +在 iOS 16 中 +UICollectionView 和 UITableView 中的 + +421 +00:22:11,999 --> 00:22:16,537 +自行调整大小单元格 +现在也可以自行调整大小! + +422 +00:22:16,537 --> 00:22:18,172 +这是默认启用的 + +423 +00:22:18,172 --> 00:22:21,041 +这样当您使用 +UIHostingConfiguration + +424 +00:22:21,041 --> 00:22:24,411 +并且 SwiftUI 内容发生变更时 + +425 +00:22:24,411 --> 00:22:28,682 +相应的单元格 +就会视需要自动调整大小 + +426 +00:22:28,682 --> 00:22:31,151 +请在 WWDC 2022 的 +UIKit 中的新功能视频中 + +427 +00:22:31,151 --> 00:22:37,691 +详细了解这项新功能的工作原理 + +428 +00:22:37,691 --> 00:22:39,493 +您可能需要处理数据流的另一个问题 + +429 +00:22:39,493 --> 00:22:43,463 +那就是将 SwiftUI 视图中的数据 + +430 +00:22:43,463 --> 00:22:48,035 +发回到 App 的其他部分 + +431 +00:22:48,035 --> 00:22:52,606 +ObservableObject +也可以帮您解决这个问题! + +432 +00:22:52,606 --> 00:22:55,642 +您可以为一个 +ObservableObject 的已发布属性 + +433 +00:22:55,642 --> 00:22:57,911 +创建一个双向绑定 + +434 +00:22:57,911 --> 00:23:02,683 +不仅数据会从 +ObservableObject 流入 SwiftUI + +435 +00:23:02,683 --> 00:23:06,019 +SwiftUI 也可将变更写回到 + +436 +00:23:06,019 --> 00:23:08,755 +模型对象的属性上 + +437 +00:23:08,755 --> 00:23:10,490 +我们来举一个简单的示例 + +438 +00:23:10,490 --> 00:23:12,226 +介绍一下通过使 +MedicalCondition 单元格中的文本可编辑 + +439 +00:23:12,226 --> 00:23:16,997 +创建双向绑定 + +440 +00:23:16,997 --> 00:23:21,401 +这是我们的 ObservableObject +即 MedicalCondition + +441 +00:23:21,401 --> 00:23:25,672 +它将唯一标识符 +存储在 ID 属性中 + +442 +00:23:25,672 --> 00:23:27,674 +这是用于填充可区分 + +443 +00:23:27,674 --> 00:23:30,711 +数据源快照的标识符 + +444 +00:23:30,711 --> 00:23:33,046 +这个 published 属性 + +445 +00:23:33,046 --> 00:23:35,916 +存储病症文本 + +446 +00:23:35,916 --> 00:23:37,651 +这是 MedicalConditionView + +447 +00:23:37,651 --> 00:23:42,422 +它显示每个单元格内的病症文本 + +448 +00:23:42,422 --> 00:23:44,892 +现在这个文本是只读的 + +449 +00:23:44,892 --> 00:23:47,594 +我们要让它变成可编辑的 + +450 +00:23:47,594 --> 00:23:52,399 +我们需要做的就是 +将 Text 视图更改为 TextField + +451 +00:23:52,399 --> 00:23:54,935 +并通过添加 $ 符号前缀 + +452 +00:23:54,935 --> 00:23:59,439 +创建 MedicalCondition +文本属性的绑定 + +453 +00:23:59,439 --> 00:24:01,141 +当您在 TextField 中键入时 + +454 +00:24:01,141 --> 00:24:04,645 +此绑定允许 SwiftUI + +455 +00:24:04,645 --> 00:24:07,481 +直接将更改写回到 +ObservableObject + +456 +00:24:07,481 --> 00:24:09,183 +使用 SwiftUI 设置双向数据流 + +457 +00:24:09,183 --> 00:24:14,454 +就是这么简单 + +458 +00:24:14,454 --> 00:24:16,924 +UIHostingController 非常强大 + +459 +00:24:16,924 --> 00:24:21,595 +可将 SwiftUI 内容 +嵌入到 UIKit App 中 + +460 +00:24:21,595 --> 00:24:23,397 +您的 SwiftUI 视图 + +461 +00:24:23,397 --> 00:24:25,832 +在托管控制器的视图内渲染 + +462 +00:24:25,832 --> 00:24:27,601 +并且只要可以 +在 UIKit 中使用视图控制器 + +463 +00:24:27,601 --> 00:24:33,440 +就可以使用托管控制器 + +464 +00:24:33,440 --> 00:24:35,342 +使用 UIHostingController 时 + +465 +00:24:35,342 --> 00:24:37,945 +请务必在 App 中 + +466 +00:24:37,945 --> 00:24:41,381 +添加视图控制器和视图 + +467 +00:24:41,381 --> 00:24:45,752 +许多 SwiftUI 功能 比如 +工具栏、键盘快捷键 + +468 +00:24:45,752 --> 00:24:49,089 +以及使用了 UIViewControllerRepresentable +的视图 + +469 +00:24:49,089 --> 00:24:51,992 +需要连接到 UIKit 中的 +视图控制器层次结构 + +470 +00:24:51,992 --> 00:24:54,995 +以正确集成 + +471 +00:24:54,995 --> 00:24:57,664 +所以切勿将托管控制器视图 + +472 +00:24:57,664 --> 00:25:01,168 +和托管控制器本身分隔开来 + +473 +00:25:01,168 --> 00:25:03,070 +为了形成对比 + +474 +00:25:03,070 --> 00:25:05,939 +在将 UIHostingConfiguration +应用于单元格时 + +475 +00:25:05,939 --> 00:25:08,308 +您的 SwiftUI 视图 +会托管在单元格中 + +476 +00:25:08,308 --> 00:25:11,111 +而没有 UIViewController + +477 +00:25:11,111 --> 00:25:14,081 +UIHostingConfiguration +支持绝大多数 + +478 +00:25:14,081 --> 00:25:16,049 +SwiftUI 功能 + +479 +00:25:16,049 --> 00:25:18,285 +但请记住 依赖于 +UIViewControllerRepresentable + +480 +00:25:18,285 --> 00:25:20,988 +的 SwiftUI 视图 + +481 +00:25:20,988 --> 00:25:23,590 +不能在单元格内使用 + +482 +00:25:23,590 --> 00:25:26,860 +在 UIHostingController +和 UIHostingConfiguration 的帮助下 + +483 +00:25:26,860 --> 00:25:29,897 +您可以通过两种绝佳方式 + +484 +00:25:29,897 --> 00:25:32,966 +将 SwiftUI 整合到 +UIKit App 中 + +485 +00:25:32,966 --> 00:25:37,638 +SwiftUI 可无缝集成 +到现有的 UIKit App 中 + +486 +00:25:37,638 --> 00:25:42,943 +使用 UIHostingController +在整个 App 中添加 SwiftUI + +487 +00:25:42,943 --> 00:25:46,046 +使用 UIHostingConfiguration +在集合和表格视图 + +488 +00:25:46,046 --> 00:25:49,449 +中创建自定义单元格 + +489 +00:25:49,449 --> 00:25:51,952 +并利用 ObservableObject + +490 +00:25:51,952 --> 00:25:55,422 +使数据和 UI 始终保持同步 + +491 +00:25:55,422 --> 00:25:59,259 +立即将 SwiftUI +添加到您的 App 中吧! + +492 +00:25:59,259 --> 00:26:00,727 +谢谢收看! + +493 +00:26:00,727 --> 00:26:05,566 +♪ + diff --git a/zho/2022 Session 10074 What's new in AppKit.srt b/zho/2022 Session 10074 What's new in AppKit.srt new file mode 100644 index 0000000..4f553b8 --- /dev/null +++ b/zho/2022 Session 10074 What's new in AppKit.srt @@ -0,0 +1,1738 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:10,043 --> 00:00:13,447 +Jeff Nadeau: 大家好 欢迎收看 +“AppKit 的新功能” + +3 +00:00:13,480 --> 00:00:16,717 +我是 Jeff Nadeau +是 AppKit 团队的一名工程师 + +4 +00:00:16,750 --> 00:00:19,686 +我在这里和大家分享一下 +为 macOS Ventura 构建 App 的 + +5 +00:00:19,720 --> 00:00:21,622 +最新最棒的功能 + +6 +00:00:21,655 --> 00:00:24,591 +对于 Mac 来说 这是一个 +前所未有的激动人心的时刻 + +7 +00:00:24,625 --> 00:00:28,195 +现在我们拥有 +Apple 芯片的性能和效率 + +8 +00:00:28,228 --> 00:00:29,897 +macOS 的力量 + +9 +00:00:29,930 --> 00:00:33,567 +以及一个比以往任何时候 +都更丰富的 App 生态系统 + +10 +00:00:33,600 --> 00:00:36,236 +而您的 App 是这个故事的 +重要组成部分 + +11 +00:00:36,270 --> 00:00:38,305 +我们将继续推动 AppKit 发展 + +12 +00:00:38,338 --> 00:00:41,742 +这样您们就可以继续构建 +最好的 App + +13 +00:00:42,342 --> 00:00:45,179 +我将谈及各种各样的主题 + +14 +00:00:45,212 --> 00:00:47,915 +从台前调度开始 + +15 +00:00:47,948 --> 00:00:50,417 +接着是偏好设置 + +16 +00:00:50,450 --> 00:00:52,753 +其次是各种控件 + +17 +00:00:52,786 --> 00:00:54,688 +SF Symbols + +18 +00:00:54,721 --> 00:00:57,257 +和共享 + +19 +00:00:57,291 --> 00:00:59,259 +我首先要聊一聊台前调度 + +20 +00:01:00,460 --> 00:01:04,398 +台前调度会清理 +工作区中的非活动窗口 + +21 +00:01:04,431 --> 00:01:07,701 +而活动窗口会采取对象居中 + +22 +00:01:07,734 --> 00:01:11,071 +对于更高级的工作流程 +您还可以将窗口合并到一个 + +23 +00:01:11,104 --> 00:01:14,541 +作为一组交换进出的集合中 + +24 +00:01:15,709 --> 00:01:19,847 +这将影响您的 App 窗口的呈现方式 + +25 +00:01:19,880 --> 00:01:23,016 +台前调度试图保持 +工作区的整洁 + +26 +00:01:23,050 --> 00:01:24,885 +所以当出现一个新窗口时 + +27 +00:01:24,918 --> 00:01:29,156 +现有的窗口将退出 stage +以腾出空间 + +28 +00:01:29,189 --> 00:01:33,293 +这就是“主”窗口 +比如您的文档所需要的 + +29 +00:01:33,327 --> 00:01:38,599 +辅助窗口 如面板 +弹窗 设置和其他窗口 + +30 +00:01:38,632 --> 00:01:42,970 +应该继续出现在现有窗口的上方 + +31 +00:01:43,003 --> 00:01:45,472 +NSWindow 已经有了很多 API + +32 +00:01:45,506 --> 00:01:49,343 +可以帮助您定义 +您想要特定窗口完成的行为 + +33 +00:01:51,545 --> 00:01:54,915 +默认情况下 +如果您显示一个浮动面板 + +34 +00:01:54,948 --> 00:01:58,318 +一个模态窗口 +或一个带有首选项样式工具栏的窗口 + +35 +00:01:58,352 --> 00:02:01,388 +台前调度不会调出其他窗口 + +36 +00:02:03,824 --> 00:02:07,628 +台前调度也会遵守窗口的 +collectionBehavior + +37 +00:02:07,661 --> 00:02:10,264 +这个 OptionSet 定义了窗口在空间 + +38 +00:02:10,297 --> 00:02:12,599 +和全屏中的行为方式 + +39 +00:02:12,633 --> 00:02:15,102 +现在它还会帮助台前调度 + +40 +00:02:15,135 --> 00:02:18,639 +理解窗口是被视为辅助还是浮动的 + +41 +00:02:19,540 --> 00:02:23,977 +如果一个窗口的 collectionBehavior +包含辅助 moveToActiveSpace + +42 +00:02:24,011 --> 00:02:26,947 +固定的或暂态选项 + +43 +00:02:26,980 --> 00:02:30,784 +那么它就不会将活动窗口 +移到居中的位置 + +44 +00:02:31,718 --> 00:02:34,454 +通过使用正确的收集行为设置窗口 + +45 +00:02:34,488 --> 00:02:37,257 +您可以确保它们在每个情景中 +都能很好地工作 + +46 +00:02:37,291 --> 00:02:42,829 +无论是在桌面空间 全屏 +还是现在在台前调度中 + +47 +00:02:42,863 --> 00:02:46,934 +接下来 我将介绍偏好设置的 +一些重要更改 + +48 +00:02:46,967 --> 00:02:49,937 +在 macOS Ventura 中 +“系统偏好设置”App + +49 +00:02:49,970 --> 00:02:52,239 +已采用了全新的外观 + +50 +00:02:52,272 --> 00:02:57,277 +具有全新的导航方案 +和全新的视觉设计 + +51 +00:02:57,311 --> 00:03:00,948 +为了与其他操作系统的设置 +保持一致 + +52 +00:03:00,981 --> 00:03:04,451 +我们还将 App 重命名为 +“系统设置” + +53 +00:03:05,219 --> 00:03:08,222 +这些更改也会扩展到您的 App + +54 +00:03:08,255 --> 00:03:11,091 +例如 今天的 +“系统偏好设置”App 中 + +55 +00:03:11,124 --> 00:03:14,695 +可能会出现一个首选项面板包 + +56 +00:03:14,728 --> 00:03:18,532 +您的 App 中可能也有一个设置区域 + +57 +00:03:18,565 --> 00:03:21,935 +它也有一个新的设计系统 +用于控制丰富的表单 + +58 +00:03:21,969 --> 00:03:26,640 +它可能是设置界面 +或检查器的完美选择 + +59 +00:03:26,673 --> 00:03:29,209 +如果您发布了一个自定义的预组件包 + +60 +00:03:29,243 --> 00:03:32,145 +它将继续与新的“设置”App +一起运作 + +61 +00:03:32,179 --> 00:03:34,748 +您的自定义面板将出现在侧边栏 + +62 +00:03:34,781 --> 00:03:36,617 +App 会加载您的组件包 + +63 +00:03:36,650 --> 00:03:40,988 +并显示您的设置 UI +如在 Monterey 中和早前一样 + +64 +00:03:41,855 --> 00:03:44,691 +为了匹配新命名“系统设置”App + +65 +00:03:44,725 --> 00:03:48,529 +我们已将 App 内的首选项 +重命名为“设置” + +66 +00:03:48,562 --> 00:03:52,399 +为了帮助您上手 +一旦您使用最新的 SDK 进行构建 + +67 +00:03:52,432 --> 00:03:55,702 +AppKit 将自动更新 App 菜单中的 + +68 +00:03:55,736 --> 00:03:57,804 +偏好设置菜单项的名称 + +69 +00:03:57,838 --> 00:04:02,042 +不过 您可能会在很多其他地方 +使用 Preferences (偏好设置) 这个词 + +70 +00:04:02,075 --> 00:04:04,645 +比如在窗口标题 描述性标签 + +71 +00:04:04,678 --> 00:04:07,414 +或 App 周围的其他控件上 + +72 +00:04:07,447 --> 00:04:11,552 +搜索本地化文本 +找到同样需要更新的地方 + +73 +00:04:12,986 --> 00:04:18,058 +例如 TextEdit 的设置窗口 +过去被称为“偏好设置” + +74 +00:04:18,091 --> 00:04:23,030 +我们选择将该窗口重命名为“设置” +以匹配系统的其余部分 + +75 +00:04:23,063 --> 00:04:26,333 +“系统设置”App 也使用了 +一个新的界面样式 + +76 +00:04:26,366 --> 00:04:29,269 +来显示它的所有配置选项 + +77 +00:04:29,303 --> 00:04:32,239 +设置界面通常包含大量控件 + +78 +00:04:32,272 --> 00:04:36,176 +因此这种样式旨在以清晰有序的方式 + +79 +00:04:36,210 --> 00:04:39,079 +显示包含大量控件的表单 + +80 +00:04:40,948 --> 00:04:44,184 +由于表单本身提供了大量的视觉结构 + +81 +00:04:44,218 --> 00:04:46,854 +许多系统控件 +通过使用较低的视觉权重 + +82 +00:04:46,887 --> 00:04:49,389 +来适应这种环境 + +83 +00:04:49,423 --> 00:04:53,293 +它们会同时在 rollover 上 +展现出更突出的备份 + +84 +00:04:54,828 --> 00:04:57,764 +如果您想编写使用这种新设计的接口 + +85 +00:04:57,798 --> 00:05:00,901 +SwiftUI 会让它变得非常简单 + +86 +00:05:00,934 --> 00:05:03,537 +将您的控件放到 Form 视图中 + +87 +00:05:03,570 --> 00:05:06,640 +然后应用 insetGrouped 表单样式 + +88 +00:05:06,673 --> 00:05:08,842 +SwiftUI 会负责剩下的事情 + +89 +00:05:08,876 --> 00:05:11,211 +表单的视觉样式 滚动行为 + +90 +00:05:11,245 --> 00:05:15,015 +和布局都会自动应用 + +91 +00:05:16,650 --> 00:05:18,952 +如果您还没有开始使用 SwiftUI + +92 +00:05:18,986 --> 00:05:22,089 +这是个尝试一下的好机会 + +93 +00:05:22,122 --> 00:05:26,360 +Settings 窗口通常是 +App 界面的一个独立区域 + +94 +00:05:26,393 --> 00:05:29,363 +所以它是进行 +incremental adoption 的完美场所 + +95 +00:05:30,264 --> 00:05:34,434 +我们甚至制作了一个关于同时使用 +SwiftUI 和 AppKit 的视频 + +96 +00:05:34,468 --> 00:05:37,538 +它可以让您进行深入了解 + +97 +00:05:37,571 --> 00:05:42,176 +接下来 我想分享 +我们控件的一些更新 + +98 +00:05:42,209 --> 00:05:45,345 +我们有很多令人兴奋的控件增强 +值得分享 + +99 +00:05:45,379 --> 00:05:49,449 +首先是一个叫做 +NSComboButton 的新控件 + +100 +00:05:49,483 --> 00:05:52,085 +我们还更新了 NSColorWell + +101 +00:05:52,119 --> 00:05:55,689 +对 NSToolbar API 做了一些增强 + +102 +00:05:55,722 --> 00:05:58,525 +调整了 NSAlert 的设计 + +103 +00:05:58,559 --> 00:06:02,629 +改善了 NSTableView 的性能 + +104 +00:06:02,663 --> 00:06:05,566 +首先是 NSComboButton + +105 +00:06:05,599 --> 00:06:09,469 +NSComboButton 的主旨在于 +结合一个即时按钮动作 + +106 +00:06:09,503 --> 00:06:11,738 +和一个有附加选项的菜单 + +107 +00:06:13,240 --> 00:06:15,142 +在今天的控件视图中 + +108 +00:06:15,175 --> 00:06:18,545 +传统上 人们使用按钮 +来执行一些即时操作 + +109 +00:06:18,579 --> 00:06:23,684 +或者使用下拉按钮来显示 +带有多个选项的菜单 + +110 +00:06:23,717 --> 00:06:28,589 +NSComboButton 将两个元素 +组合成了一个控件 + +111 +00:06:28,622 --> 00:06:33,694 +它将主操作和下拉菜单 +结合在了一起 + +112 +00:06:33,727 --> 00:06:37,664 +这种设计通常用于像 Mail 这样的用例 + +113 +00:06:37,698 --> 00:06:40,667 +这样 要获取预估的文件夹 +就只需单击一下即可 + +114 +00:06:40,701 --> 00:06:44,738 +但您仍然可以访问菜单 +来将消息归档到任何地方 + +115 +00:06:44,771 --> 00:06:47,641 +以前 您可能已经使用分段控件 API + +116 +00:06:47,674 --> 00:06:50,244 +组装过类似的东西 + +117 +00:06:50,277 --> 00:06:52,913 +但现在有了专门的控件做这件事 + +118 +00:06:53,881 --> 00:06:56,416 +NSComboButton 有两种样式 + +119 +00:06:56,450 --> 00:07:00,287 +分别规定了按钮的外观和行为 + +120 +00:07:00,320 --> 00:07:02,623 +默认样式称为 split + +121 +00:07:02,656 --> 00:07:06,426 +它包括一个只用于菜单的 +单独的箭头部分 + +122 +00:07:08,262 --> 00:07:13,600 +第二种样式是 unified +看起来更像一个普通的按钮 + +123 +00:07:13,634 --> 00:07:16,436 +此样式在单击时执行其主要操作 + +124 +00:07:16,470 --> 00:07:20,174 +如果单击并按住它 则会显示其菜单 + +125 +00:07:20,207 --> 00:07:21,942 +这就是 NSComboButton + +126 +00:07:21,975 --> 00:07:25,379 +NSColorWell 也有一些 +很棒的新的更新 + +127 +00:07:25,412 --> 00:07:27,781 +首先是一个全新的外观 + +128 +00:07:27,814 --> 00:07:31,151 +现在颜色很好地采用了一种新风格 + +129 +00:07:31,185 --> 00:07:33,720 +取代了经典的方形渐变外观 + +130 +00:07:33,754 --> 00:07:37,591 +并让人能联想到整个系统的 +其他按钮外壳 + +131 +00:07:37,624 --> 00:07:40,060 +这个更改是完全自动的 + +132 +00:07:40,093 --> 00:07:43,597 +因此您不需要采取任何措施 +来获得这个新版外观 + +133 +00:07:44,231 --> 00:07:47,334 +然而 我们知道颜色选择 +是有创造性的 + +134 +00:07:47,367 --> 00:07:49,937 +专业 App 的重要组成部分 + +135 +00:07:49,970 --> 00:07:51,505 +所以我们更进一步 + +136 +00:07:51,538 --> 00:07:54,508 +为 NSColorWell 引入了两种新的样式 + +137 +00:07:55,843 --> 00:07:58,278 +第一种是最小样式 + +138 +00:07:58,312 --> 00:08:00,747 +它在 rollover 上会显示一个披露箭头 + +139 +00:08:00,781 --> 00:08:03,116 +并用弹出完整的 NSColorPanel 选项 + +140 +00:08:03,150 --> 00:08:07,254 +通过显示可以立即从调色板中 +进行选择的弹出窗口 + +141 +00:08:07,287 --> 00:08:11,525 +来提供一个快速的颜色选择体验 + +142 +00:08:11,558 --> 00:08:14,995 +默认情况下 +它会使用系统标准的颜色网格 + +143 +00:08:15,028 --> 00:08:16,797 +但如果您有不同的 UI 或调色板 + +144 +00:08:16,830 --> 00:08:19,933 +您可以自定义这里显示的内容 + +145 +00:08:22,269 --> 00:08:24,705 +第二种是扩展样式 + +146 +00:08:24,738 --> 00:08:27,941 +您可以在 iWork App 中看到 + +147 +00:08:27,975 --> 00:08:30,944 +这种风格结合了两种交互模型 + +148 +00:08:30,978 --> 00:08:33,480 +左边的键有相同的披露箭头 + +149 +00:08:33,514 --> 00:08:35,682 +和用于快速选择的弹出窗口 + +150 +00:08:35,716 --> 00:08:38,385 +而右边的按钮可以拉出整个面板 + +151 +00:08:38,418 --> 00:08:40,654 +以进行更细致的颜色选择 + +152 +00:08:43,123 --> 00:08:48,095 +有了这个 NSColorWell 现在 +能提供三种不同的选择颜色的方式 + +153 +00:08:49,997 --> 00:08:55,035 +您可以使用 NSColorWell 上的 +新 colorWellStyle 属性访问这些样式 + +154 +00:08:55,068 --> 00:08:57,504 +它有每个样式的案例 + +155 +00:08:57,538 --> 00:09:00,941 +默认 扩展和最小 + +156 +00:09:02,342 --> 00:09:05,879 +NSColorWel 也因其 pulldown action + +157 +00:09:05,913 --> 00:09:08,248 +获得了一个新的目标-操作对 + +158 +00:09:08,282 --> 00:09:11,652 +该操作会确定当您单击 +最小或扩展颜色的下拉部分时 + +159 +00:09:11,685 --> 00:09:15,088 +会发生什么 + +160 +00:09:15,122 --> 00:09:17,457 +默认情况下 这些属性是 nil + +161 +00:09:17,491 --> 00:09:21,995 +这意味着 NSColorWell +应该使用系统标准的弹出窗口 + +162 +00:09:22,029 --> 00:09:24,398 +但是 您可以自定义此操作 + +163 +00:09:24,431 --> 00:09:27,768 +并用它来显示您自己的 +自定义弹出窗口 + +164 +00:09:27,801 --> 00:09:32,840 +或者您甚至可以显示一个 +不同的选择界面 如菜单 + +165 +00:09:32,873 --> 00:09:35,008 +这就是新的 NSColorWell + +166 +00:09:35,042 --> 00:09:39,580 +它有一个全新的外观 +和两种快速挑选颜色的新方法 + +167 +00:09:40,314 --> 00:09:42,850 +接下来是一些 +关于 NSToolbar 的新闻 + +168 +00:09:42,883 --> 00:09:44,985 +我们对它进行了各种 API 增强 + +169 +00:09:45,018 --> 00:09:47,821 +让您更好地控制自定义 + +170 +00:09:47,855 --> 00:09:50,824 +并增加布局的灵活性 + +171 +00:09:51,725 --> 00:09:53,293 +在自定义方面 + +172 +00:09:53,327 --> 00:09:55,095 +我们添加了两个新的委托方法 + +173 +00:09:55,128 --> 00:09:58,999 +让您更好地控制工具栏的可自定义性 + +174 +00:09:59,032 --> 00:10:03,604 +首先是 +toolbar immovable item identifiers + +175 +00:10:03,637 --> 00:10:07,140 +如果您执行此方法 +以返回一组项目标识符 + +176 +00:10:07,174 --> 00:10:11,378 +那么这些项目 +将不能被用户移动或移除 + +177 +00:10:11,411 --> 00:10:14,781 +并且当您进入自定义模式时 +它们不会显示动画 + +178 +00:10:16,183 --> 00:10:19,353 +例如“邮件”App 希望过滤按钮 + +179 +00:10:19,386 --> 00:10:22,990 +一直出现在这里 在消息列表的上方 + +180 +00:10:23,023 --> 00:10:27,561 +通过使用这个 API +它们可以防止它被从这个位置移走 + +181 +00:10:29,963 --> 00:10:35,636 +第二种方法称为“toolbaritem +identifier can be inserted at” + +182 +00:10:35,669 --> 00:10:39,773 +此委托方法让您可以 +对工具栏中任何特定的重新排序 + +183 +00:10:39,806 --> 00:10:43,343 +插入 或删除操作行使否决权 + +184 +00:10:43,377 --> 00:10:47,047 +您可以使用它来实现自己的 +自定义规则 + +185 +00:10:47,080 --> 00:10:48,382 +例如 + +186 +00:10:48,415 --> 00:10:52,219 +您可以创建一个工具栏项 +使它在工具栏的一个部分中被允许 + +187 +00:10:52,252 --> 00:10:54,521 +但在另一个部分中被禁用 + +188 +00:10:56,957 --> 00:11:00,093 +现在您可以使用新的 +centeredItemIdentifiers 属性 + +189 +00:11:00,127 --> 00:11:03,664 +为工具栏指定多个居中项 + +190 +00:11:03,697 --> 00:11:06,633 +如果工具栏是可自定义的 +那么您就仍可以从工具栏中 + +191 +00:11:06,667 --> 00:11:09,369 +添加或删除此集中的项 + +192 +00:11:09,403 --> 00:11:12,806 +但您只能在居中的组中 +对它们进行重新排序 + +193 +00:11:12,840 --> 00:11:15,409 +在这个例子中 所有的照片编辑工具 + +194 +00:11:15,442 --> 00:11:18,278 +都集中在工具栏的中心 + +195 +00:11:18,312 --> 00:11:22,850 +而与前后有多少项无关 + +196 +00:11:23,584 --> 00:11:26,019 +一旦您按喜欢的方式自定义了工具栏 + +197 +00:11:26,053 --> 00:11:28,589 +您不会希望项目到处移动 + +198 +00:11:28,622 --> 00:11:31,325 +而这对于根据其他状态 +改变含义的工具栏项目来说 + +199 +00:11:31,358 --> 00:11:33,260 +是很困难的 + +200 +00:11:33,293 --> 00:11:35,929 +比如“邮件”中的静音和取消静音按钮 + +201 +00:11:35,963 --> 00:11:37,831 +它们在轻点后会互相切换 + +202 +00:11:39,433 --> 00:11:41,502 +由于标签有不同的大小 + +203 +00:11:41,535 --> 00:11:46,039 +工具栏中的其他项必须四处移动 +以适应变动 + +204 +00:11:48,542 --> 00:11:52,679 +在这样的场景中 +您可以用 NSToolbarItem 上 + +205 +00:11:52,713 --> 00:11:56,116 +新的 possibleLabels 属性来提供一组 + +206 +00:11:56,149 --> 00:11:58,252 +将用于该项的本地化字符串 + +207 +00:11:59,887 --> 00:12:04,157 +NSToolbar 会自动调整条目的大小 +以适应最长的标签 + +208 +00:12:04,191 --> 00:12:08,829 +因此 即使重新配置条目 +您的布局也会保持不变 + +209 +00:12:08,862 --> 00:12:12,232 +接下来 是对警报设计的更新 + +210 +00:12:12,266 --> 00:12:15,269 +macOS 上的警报使用紧凑的布局 + +211 +00:12:15,302 --> 00:12:17,738 +它经过了针对有几个明确选择的 + +212 +00:12:17,771 --> 00:12:20,807 +少量文本的优化 + +213 +00:12:20,841 --> 00:12:24,144 +总的来说 这是一个很好的 +组合警报的方式 + +214 +00:12:24,178 --> 00:12:26,947 +警报最适合较短的文本 + +215 +00:12:26,980 --> 00:12:29,483 +您可以更直接地传达信息 + +216 +00:12:29,516 --> 00:12:31,718 +而且人们更有可能在 +越过警报进行下一步前 + +217 +00:12:31,752 --> 00:12:34,321 +阅读您写的内容 + +218 +00:12:35,989 --> 00:12:39,593 +然而 有时您确实无法缩短描述 + +219 +00:12:39,626 --> 00:12:43,830 +尤其是在需要传达一些 +复杂而微妙的信息时 + +220 +00:12:43,864 --> 00:12:45,866 +比如这个 Disk Utility 警报 + +221 +00:12:45,899 --> 00:12:50,204 +它传达了一个关于文件系统数据的 +非常重要的选择 + +222 +00:12:50,237 --> 00:12:54,575 +紧凑的布局并不适合这种情况 + +223 +00:12:54,608 --> 00:12:58,812 +对于这些情况 我们调整了 NSAlert + +224 +00:12:58,846 --> 00:13:01,582 +以提供适合较长文本的更宽的布局 + +225 +00:13:01,615 --> 00:13:05,686 +当提示文本太长 +而无法容纳在紧凑的尺寸中时 + +226 +00:13:05,719 --> 00:13:09,923 +这种调整会自动发生 + +227 +00:13:09,957 --> 00:13:12,659 +如果附属视图太大 +无法放进紧凑的警报窗口 + +228 +00:13:12,693 --> 00:13:16,797 +我们也会使用这种样式 + +229 +00:13:16,830 --> 00:13:19,800 +您的 App 不需要选择这个行为 + +230 +00:13:19,833 --> 00:13:22,903 +它会在整个系统范围自动应用 + +231 +00:13:22,936 --> 00:13:25,005 +需要注意的是 + +232 +00:13:25,038 --> 00:13:26,974 +布局是在显示警报时确定的 + +233 +00:13:27,007 --> 00:13:29,743 +因此 如果警报已经显示在屏幕上 + +234 +00:13:29,776 --> 00:13:31,845 +则样式无法切换 + +235 +00:13:33,881 --> 00:13:37,684 +您仍然应该尽可能地 +减短警报文本的长度 + +236 +00:13:37,718 --> 00:13:40,220 +但这个设计更新将改善那些 + +237 +00:13:40,254 --> 00:13:42,456 +您无法减短文本长度时的用户体验 + +238 +00:13:43,657 --> 00:13:47,261 +接下来是 +NSTableView 的一个重要新功能 + +239 +00:13:47,294 --> 00:13:51,999 +NSTableView +旨在通过在滚动时惰性填充 + +240 +00:13:52,032 --> 00:13:55,636 +和重用视图来高效地处理大量的行 + +241 +00:13:56,370 --> 00:13:59,573 +但是 对于每一行 +都有不同高度的表来说 + +242 +00:13:59,606 --> 00:14:01,308 +这是一个挑战 + +243 +00:14:01,341 --> 00:14:04,178 +因为为了提供良好的滚动体验 + +244 +00:14:04,211 --> 00:14:06,280 +表格需要知道它的总高度 + +245 +00:14:06,313 --> 00:14:10,083 +以及每一行在滚动区域中的位置 + +246 +00:14:11,185 --> 00:14:15,889 +过去 NSTableView 通过调整 +表中所有行的大小来实现这一点 + +247 +00:14:15,923 --> 00:14:19,526 +而这可能会对初始加载时间产生影响 + +248 +00:14:19,560 --> 00:14:22,963 +在 macOS Ventura 中 +NSTableView 实现了这些目标 + +249 +00:14:22,996 --> 00:14:25,866 +同时提供了更好的性能 + +250 +00:14:27,968 --> 00:14:31,138 +NSTableView 不再即时计算 +每一行的高度 + +251 +00:14:31,171 --> 00:14:33,974 +而是根据滚动视口内 + +252 +00:14:34,007 --> 00:14:38,278 +或附近的行惰性来计算行高度 + +253 +00:14:39,646 --> 00:14:41,748 +对于那些没有被测量的行 + +254 +00:14:41,782 --> 00:14:44,818 +NSTableView 使用的是一个 + +255 +00:14:44,852 --> 00:14:48,255 +基于它已经测量的行高度 +得出的运行估计高度 + +256 +00:14:48,288 --> 00:14:49,890 +当您滚动表格时 + +257 +00:14:49,923 --> 00:14:52,793 +NSTableView 根据需要 +来请求行高度 + +258 +00:14:52,826 --> 00:14:56,296 +用实际测量值替换估计高度 + +259 +00:14:56,330 --> 00:14:59,867 +同时会注意保持正确的滚动位置 + +260 +00:15:02,269 --> 00:15:07,174 +这种优化显著改善了 +过大的表的加载时间 + +261 +00:15:07,207 --> 00:15:09,576 +这个变化改变了 +table view: height of row 之类的 + +262 +00:15:09,610 --> 00:15:11,678 +委托调用的时间 + +263 +00:15:11,712 --> 00:15:13,113 +所以您不应该假设 + +264 +00:15:13,146 --> 00:15:16,850 +NSTableView 何时会向您请求行高 + +265 +00:15:18,185 --> 00:15:23,023 +这个优化同时适用于 +NSTableView 和 SwiftUI 的 List 视图 + +266 +00:15:23,056 --> 00:15:26,326 +并且自动用于 macOS Ventura 上的 +所有 App + +267 +00:15:26,360 --> 00:15:28,695 +无需采用 + +268 +00:15:28,729 --> 00:15:31,298 +这就是 NSTableView 的功能 + +269 +00:15:32,232 --> 00:15:35,736 +接下来是 SF Symbols 的一些更新 + +270 +00:15:35,769 --> 00:15:39,106 +macOS Ventura 包括 SF Symbols 4 + +271 +00:15:39,139 --> 00:15:42,109 +它增加了超过 450 个新符号图像 + +272 +00:15:42,142 --> 00:15:44,678 +涵盖了各种主题 + +273 +00:15:45,979 --> 00:15:48,949 +这些新符号包括桂冠 + +274 +00:15:48,982 --> 00:15:51,919 +各种家居用品 + +275 +00:15:51,952 --> 00:15:54,922 +世界各地的货币符号 + +276 +00:15:54,955 --> 00:15:58,258 +甚至各种与体育相关的符号 + +277 +00:15:58,292 --> 00:16:00,694 +有了数以千计的符号目录 + +278 +00:16:00,727 --> 00:16:04,031 +SF symbols 很可能包含了 +可以代表您想表达的任何想法的 + +279 +00:16:04,064 --> 00:16:07,134 +专业设计的图标 + +280 +00:16:07,167 --> 00:16:08,936 +但我们没有止步于此 + +281 +00:16:08,969 --> 00:16:11,471 +SF Symbols 4 还包括一些新的功能 + +282 +00:16:11,505 --> 00:16:13,907 +以进一步增强您的图标 + +283 +00:16:14,808 --> 00:16:18,278 +总结一下 +符号图像支持多种呈现模式 + +284 +00:16:18,312 --> 00:16:21,448 +您可以依据自己的设计来选择 + +285 +00:16:21,481 --> 00:16:24,384 +它有使用一种颜色的单色呈现 + +286 +00:16:24,418 --> 00:16:27,521 +使用不同颜色的不透明度来强调 + +287 +00:16:27,554 --> 00:16:30,724 +符号某些部分的分层呈现 + +288 +00:16:30,757 --> 00:16:32,926 +有允许您为符号的每个部分 + +289 +00:16:32,960 --> 00:16:35,629 +指定不同颜色的调色呈现 + +290 +00:16:35,662 --> 00:16:40,400 +以及使用直接设计到 +符号作品颜色的多色呈现 + +291 +00:16:41,568 --> 00:16:45,973 +这些选择使您能够灵活地 +实现各种各样的设计 + +292 +00:16:46,006 --> 00:16:49,910 +但我们也希望符号图像 +在不需要应用任何配置的情况下 + +293 +00:16:49,943 --> 00:16:52,746 +就能完美呈现 + +294 +00:16:53,747 --> 00:16:56,216 +因此我们在 macOS Ventura 中 + +295 +00:16:56,250 --> 00:16:59,953 +为符号引入了一个新功能 +首选呈现模式 + +296 +00:16:59,987 --> 00:17:01,555 +有了首选呈现模式 + +297 +00:17:01,588 --> 00:17:04,925 +符号就可以明确 +它们选择的呈现样式 + +298 +00:17:04,958 --> 00:17:09,429 +在运行时 +AppKit 将自动使用该样式 + +299 +00:17:09,463 --> 00:17:12,366 +这对于像 AirPods Pro 这样更倾向于 + +300 +00:17:12,399 --> 00:17:14,601 +用分层呈现来增加细节清晰度的 + +301 +00:17:14,635 --> 00:17:18,172 +符号来说 是非常棒的 + +302 +00:17:18,205 --> 00:17:20,841 +当然 如果您有不同的设计思路 + +303 +00:17:20,874 --> 00:17:24,444 +您就随时可以使用 +NSImageSymbolConfiguration 对象 + +304 +00:17:24,478 --> 00:17:26,880 +来选择您喜欢的样式 + +305 +00:17:28,615 --> 00:17:31,118 +有些符号不只是代表一个概念 + +306 +00:17:31,151 --> 00:17:34,821 +它们还要传达一些值或数量 + +307 +00:17:34,855 --> 00:17:38,725 +比如 Wi-Fi 信号强度或音频音量 + +308 +00:17:38,759 --> 00:17:41,995 +对于这样的情况 +我们引入了一种新的符号类型 + +309 +00:17:42,029 --> 00:17:44,898 +我们称之为 variable symbol + +310 +00:17:44,932 --> 00:17:48,335 +使用变量符号 +可以直接向 NSImage + +311 +00:17:48,368 --> 00:17:50,304 +提供一个浮点值 + +312 +00:17:50,337 --> 00:17:52,539 +该符号会嵌入数值阈值 + +313 +00:17:52,573 --> 00:17:56,743 +来决定每个路径 +应该如何根据该值变化 + +314 +00:17:56,777 --> 00:17:58,445 +这是 API + +315 +00:17:58,478 --> 00:18:02,015 +变量符号由新的初始化器创建 + +316 +00:18:02,049 --> 00:18:05,252 +它类似于现有的符号图像初始化器 + +317 +00:18:05,285 --> 00:18:07,988 +只是增加了一个 + +318 +00:18:08,021 --> 00:18:11,758 +0 到 1 之间的浮点数作为值参数 + +319 +00:18:11,792 --> 00:18:15,229 +如果符号图像没有定义任何可变阈值 + +320 +00:18:15,262 --> 00:18:19,566 +则该值将被忽略 +符号将按照正常方式绘制 + +321 +00:18:19,600 --> 00:18:23,003 +如果是这样 您将发现符号路径 + +322 +00:18:23,036 --> 00:18:25,472 +根据您提供的值而有不同的绘制 + +323 +00:18:26,807 --> 00:18:31,111 +每个变量符号 +都可以以自己独特的方式表示值 + +324 +00:18:31,144 --> 00:18:33,447 +通过在 API 级别提供该值 + +325 +00:18:33,480 --> 00:18:36,149 +您可以访问所有这些变量 + +326 +00:18:36,183 --> 00:18:40,120 +而不必了解符号组成方式的细节 + +327 +00:18:41,188 --> 00:18:44,491 +可变符号与呈现样式 +如调色板和多色 + +328 +00:18:44,525 --> 00:18:47,361 +结合使用效果很好 + +329 +00:18:47,394 --> 00:18:50,297 +所以您可以将它们应用到 +几乎任何设计中 + +330 +00:18:50,330 --> 00:18:54,701 +最后 我想谈谈关于 +“共享”的一些重大更新 + +331 +00:18:54,735 --> 00:18:58,305 +macOS Ventura 提升了 +Mac 上的分享体验 + +332 +00:18:58,338 --> 00:19:00,841 +引入了如建议用户 + +333 +00:19:00,874 --> 00:19:05,812 +以及邀请和管理合作用户的新方法 +等功能 + +334 +00:19:05,846 --> 00:19:09,249 +您可以采用一些新的 API +以便您的 App 能够最大限度地 + +335 +00:19:09,283 --> 00:19:11,151 +利用这些增强功能 + +336 +00:19:13,754 --> 00:19:18,692 +分享体验中最显著的更新 +是新的分享弹窗 + +337 +00:19:18,725 --> 00:19:22,095 +它用一个丰富的界面 +取代了现有的共享菜单 + +338 +00:19:22,129 --> 00:19:25,132 +它包含更多 +关于您正在共享的文档的信息 + +339 +00:19:25,165 --> 00:19:28,602 +以及熟悉的功能 比如推荐用户 + +340 +00:19:28,635 --> 00:19:33,173 +它与前一个选择器支持相同的 +API 和委托方法 + +341 +00:19:33,207 --> 00:19:36,610 +因此您仍然可以进行 +如过滤共享服务列表 + +342 +00:19:36,643 --> 00:19:40,380 +或将您自己的自定义服务插入到 +选择器中之类的操作 + +343 +00:19:42,382 --> 00:19:44,418 +如果您正在共享一个文件 URL + +344 +00:19:44,451 --> 00:19:48,822 +nsshareingservicepicker +可以自动为 Header 填充图标 + +345 +00:19:48,856 --> 00:19:52,426 +名称 和其他关于文件的元数据 + +346 +00:19:52,459 --> 00:19:55,395 +但是如果您要共享一个自定义类型 + +347 +00:19:55,429 --> 00:19:57,831 +您可以让您的条目 +符合 NSSharingServicePicker + +348 +00:19:57,865 --> 00:20:02,236 +请求那个信息所用的新协议 + +349 +00:20:03,437 --> 00:20:08,041 +这个协议叫做 +NSPreviewRepresentableActivityItem + +350 +00:20:08,075 --> 00:20:12,145 +符合类型必须能够返回 +要共享的底层项 + +351 +00:20:12,179 --> 00:20:14,414 +比如 NSItemProvider + +352 +00:20:14,448 --> 00:20:16,884 +它们还要能有选择地返回标题 + +353 +00:20:16,917 --> 00:20:19,853 +图像提供程序和图标提供程序 + +354 +00:20:21,555 --> 00:20:24,491 +为了方便起见 +AppKit 中有一个符合规范的级 + +355 +00:20:24,525 --> 00:20:27,694 +它叫做 +NSPreviewRepresentingActivityItem + +356 +00:20:27,728 --> 00:20:32,866 +您可以用它来绑定一个现有的 +共享项及其元数据 + +357 +00:20:32,900 --> 00:20:36,637 +您可以直接以 NSImage 的形式 +提供每个图像参数 + +358 +00:20:36,670 --> 00:20:40,474 +如果预先生成这些图像 +对性能要求太高 + +359 +00:20:40,507 --> 00:20:42,910 +您也可以使用 NSItemProvider + +360 +00:20:44,378 --> 00:20:47,381 +新的共享选择器非常适合 +从工具栏按钮之类的地方 + +361 +00:20:47,414 --> 00:20:48,949 +开始共享 + +362 +00:20:48,982 --> 00:20:51,385 +但有时您会想从菜单 + +363 +00:20:51,418 --> 00:20:57,491 +比如主菜单栏或 App 内 +选定视图的对应菜单开始共享 + +364 +00:20:57,524 --> 00:21:01,228 +以前 您可能会通过枚举共享服务 +然后为每个共享服务构建菜单项 + +365 +00:21:01,261 --> 00:21:06,433 +构建自己的菜单来处理这个问题 + +366 +00:21:06,466 --> 00:21:10,103 +虽然这确实有效 +但它绕过了标准选择器 + +367 +00:21:10,137 --> 00:21:13,674 +这样您就错过了所有这些新功能 + +368 +00:21:13,707 --> 00:21:16,543 +在 macOS Ventura 中 +NSSharingServicePicker + +369 +00:21:16,577 --> 00:21:20,247 +可以为您创建一个 +standard share menu item + +370 +00:21:20,280 --> 00:21:24,852 +您可以将标准项目添加到任何菜单 +轻松开始共享 + +371 +00:21:24,885 --> 00:21:28,589 +一旦被选中 +菜单项就会调用共享弹出窗口 + +372 +00:21:28,622 --> 00:21:31,792 +对于特定情景菜单 +它甚至会将弹出窗口 + +373 +00:21:31,825 --> 00:21:34,328 +固定到生成菜单的视图 + +374 +00:21:34,995 --> 00:21:39,333 +在 macOS Ventura 中 +有很多管理协作的新支持项 + +375 +00:21:40,000 --> 00:21:43,470 +通过一些额外的采用 +您的可分享项目也可以 + +376 +00:21:43,504 --> 00:21:45,506 +成为合作邀请 + +377 +00:21:45,539 --> 00:21:48,108 +用户可以通过共享选择器发起 + +378 +00:21:48,141 --> 00:21:52,346 +拖拽到 Messages 信息中 +甚至通过 FaceTime 通话做到这些 + +379 +00:21:52,379 --> 00:21:55,983 +您可以使用 CloudKit +或 iCloud Drive 来共享内容 + +380 +00:21:56,016 --> 00:22:00,787 +也可以将邀请流程 +与您自己的协作服务器连接 + +381 +00:22:00,821 --> 00:22:02,689 +这是一个牵涉很广的话题 + +382 +00:22:02,723 --> 00:22:06,560 +所以我们做了几个视频 +来更深入地解释它 + +383 +00:22:06,593 --> 00:22:09,363 +如果您的 App 支持协作 + +384 +00:22:09,396 --> 00:22:12,499 +或者您想开始添加协作 +一定要看看它们 + +385 +00:22:12,533 --> 00:22:15,502 +开始使用 macOS Ventura 时 + +386 +00:22:15,536 --> 00:22:19,873 +请确保您将窗口设置为 +与台前调度最适合的状态 + +387 +00:22:19,907 --> 00:22:24,077 +然后 考虑一下您的设计 +会如何从 NSComboButton + +388 +00:22:24,111 --> 00:22:27,881 +和 NSColorWell 这样的控件 +增强中受益 + +389 +00:22:27,915 --> 00:22:33,921 +使用 SF Symbols 的最新符号 +和功能改善您的图标 + +390 +00:22:33,954 --> 00:22:36,290 +最后 对于协作 + +391 +00:22:36,323 --> 00:22:39,126 +采用最新的 API 以便您最大限度地 + +392 +00:22:39,159 --> 00:22:42,796 +利用 macOS Ventura 的新共享体验 + +393 +00:22:43,797 --> 00:22:45,199 +感谢收看 + +394 +00:22:45,232 --> 00:22:48,869 +也感谢您 +持续开发好用的 Mac App + diff --git a/zho/2022 Session 10075 Use SwiftUI with AppKit.srt b/zho/2022 Session 10075 Use SwiftUI with AppKit.srt new file mode 100644 index 0000000..efdee5d --- /dev/null +++ b/zho/2022 Session 10075 Use SwiftUI with AppKit.srt @@ -0,0 +1,1592 @@ +1 +00:00:00,000 --> 00:00:03,036 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,036 --> 00:00:09,610 +♪ + +3 +00:00:09,610 --> 00:00:12,045 +欢迎收看 +“ SwiftUI 与 AppKit 组合使用方法” + +4 +00:00:12,045 --> 00:00:16,350 +我是 Ian 是快捷指令的工程师 + +5 +00:00:16,350 --> 00:00:20,120 +在 macOS Monterey 中 +上线了macOS版的快捷指令 App + +6 +00:00:20,120 --> 00:00:23,757 +快捷指令 App 在 Mac 上 +大量地采用 SwiftUI 来实现 + +7 +00:00:23,757 --> 00:00:26,760 +SwiftUI 有助于为平台定制体验 + +8 +00:00:26,760 --> 00:00:28,862 +同时在 iOS +和 watchOS 上 + +9 +00:00:28,862 --> 00:00:31,398 +与 App 共享常用视图 + +10 +00:00:31,398 --> 00:00:33,333 +本次视频 我将用 + +11 +00:00:33,333 --> 00:00:36,703 +快捷指令 App 的例子向大家展示 + +12 +00:00:36,703 --> 00:00:40,707 +在 Mac 的 App 中 +采用 SwiftUI 的方法 + +13 +00:00:40,707 --> 00:00:42,543 +首先 我将向您展示 + +14 +00:00:42,543 --> 00:00:45,512 +如何在 App 中 +托管 SwiftUI 视图 + +15 +00:00:45,512 --> 00:00:47,447 +然后为您讲解如何在 AppKit + +16 +00:00:47,447 --> 00:00:50,817 +和 SwiftUI 之间传输数据 + +17 +00:00:50,817 --> 00:00:53,086 +还有如何在集合或表格视图的 + +18 +00:00:53,086 --> 00:00:55,989 +单元格中 +引入 SwiftUI 视图 + +19 +00:00:55,989 --> 00:00:58,926 +当 SwiftUI 视图 +嵌入到 AppKit 中时 + +20 +00:00:58,926 --> 00:01:01,495 +如何处理视图的布局和大小 + +21 +00:01:01,495 --> 00:01:03,931 +如何将您的 +SwiftUI 视图加入到 + +22 +00:01:03,931 --> 00:01:07,000 +响应链中并获得焦点 + +23 +00:01:07,000 --> 00:01:12,439 +以及如何在 SwiftUI 中 +引入 AppKit 视图 + +24 +00:01:12,439 --> 00:01:16,877 +好 我先从在 AppKit 中 +引入 SwiftUI 开始 + +25 +00:01:16,877 --> 00:01:18,579 +在快捷指令 App 中 + +26 +00:01:18,579 --> 00:01:23,150 +主窗口包含一个 +AppKit 分割视图控制器 + +27 +00:01:23,150 --> 00:01:28,589 +左边的侧边栏 +是用 SwiftUI 编写的 + +28 +00:01:28,589 --> 00:01:32,326 +侧边栏视图 +就是一个 SwiftUI 列表 + +29 +00:01:32,326 --> 00:01:35,896 +列表中显示的各行可以 + +30 +00:01:35,896 --> 00:01:38,899 +导航至相应条目 + +31 +00:01:38,899 --> 00:01:42,302 +视图通过被选中的绑定条目 + +32 +00:01:42,302 --> 00:01:45,806 +来追踪所选中的条目 + +33 +00:01:45,806 --> 00:01:47,908 +可能选中的条目 + +34 +00:01:47,908 --> 00:01:53,113 +在 SidebarItem 类型中 +显示为案例 + +35 +00:01:53,113 --> 00:01:56,850 +在此情况下 +由于已经有了一个分割视图控制器 + +36 +00:01:56,850 --> 00:01:58,986 +要引入该侧边栏视图 + +37 +00:01:58,986 --> 00:02:03,891 +我们要用 SwiftUI 中一个名为 +NSHostingController 的类 + +38 +00:02:03,891 --> 00:02:06,727 +SwiftUI 侧边栏视图 + +39 +00:02:06,727 --> 00:02:10,898 +作为该主控制器的根视图被导入 + +40 +00:02:10,898 --> 00:02:12,633 +由于主控制器 + +41 +00:02:12,633 --> 00:02:14,801 +同任一视图控制器一样可被利用 + +42 +00:02:14,801 --> 00:02:19,072 +在这里 我们将其配置为 +splitViewItem + +43 +00:02:19,072 --> 00:02:23,076 +并添加到 splitViewController + +44 +00:02:23,076 --> 00:02:26,213 +现在分屏浏览引入了侧边栏 + +45 +00:02:26,213 --> 00:02:29,983 +但要让其在选项变化时发挥作用 + +46 +00:02:29,983 --> 00:02:35,522 +分割视图的右侧需要显示不同的页面 + +47 +00:02:35,522 --> 00:02:37,791 +现在 所选条目状态 + +48 +00:02:37,791 --> 00:02:40,527 +仅存在于 SwiftUI 中 + +49 +00:02:40,527 --> 00:02:43,864 +我们需要将其移动到分屏浏览和 + +50 +00:02:43,864 --> 00:02:47,234 +侧边栏均可共享的位置 + +51 +00:02:47,234 --> 00:02:50,704 +最好的办法是创建一个可以存储在 + +52 +00:02:50,704 --> 00:02:54,241 +SwiftUI 之外的模型对象 并包含 + +53 +00:02:54,241 --> 00:02:56,109 +需要共享的状态 + +54 +00:02:56,109 --> 00:02:59,479 +我将这个对象称为 SelectionModel + +55 +00:02:59,479 --> 00:03:02,583 +现在 +侧边栏仍可在 SelectionModel 中 + +56 +00:03:02,583 --> 00:03:05,285 +保持读写状态 + +57 +00:03:05,285 --> 00:03:08,989 +在代码中 +SelectionModel 是一个符合 + +58 +00:03:08,989 --> 00:03:11,425 +ObservableObject 的类 + +59 +00:03:11,425 --> 00:03:15,195 +作为可观察对象 +当模型中存储的状态发生变化时 + +60 +00:03:15,195 --> 00:03:18,799 +SwiftUI 就会重新加载视图 + +61 +00:03:18,799 --> 00:03:23,103 +它还存储了当前选中的侧边栏条目 + +62 +00:03:23,103 --> 00:03:27,241 +发布此属性 +可让 SwiftUI 侧边栏视图 + +63 +00:03:27,241 --> 00:03:31,211 +在所选条目更改时同步更新 + +64 +00:03:31,211 --> 00:03:34,314 +每次更改侧边栏中的选项时 + +65 +00:03:34,314 --> 00:03:39,119 +该模型就可在细节视图中显示新页面 + +66 +00:03:39,119 --> 00:03:42,856 +介绍完在 AppKit 中 +引入 SwiftUI 的方法 + +67 +00:03:42,856 --> 00:03:46,760 +接下来看集合和表格单元格 + +68 +00:03:46,760 --> 00:03:50,731 +将快捷指令 App +从其他平台带到 macOS 时 + +69 +00:03:50,731 --> 00:03:53,600 +就有一个标志性的 +SwiftUI 视图 + +70 +00:03:53,600 --> 00:03:57,137 +可在集合视图单元格 +或主屏幕小组件中 + +71 +00:03:57,137 --> 00:04:00,007 +显示快捷方式 + +72 +00:04:00,007 --> 00:04:03,777 +在 macOS 上 +这些相同的视图显示在 + +73 +00:04:03,777 --> 00:04:06,880 +NSCollectionView 的单元格中 + +74 +00:04:06,880 --> 00:04:10,317 +在包含大量条目的集合或表格视图中 + +75 +00:04:10,317 --> 00:04:13,654 +随着滚动 +每个单元格视图都会被回收 + +76 +00:04:13,654 --> 00:04:17,024 +显示不同的内容 + +77 +00:04:17,024 --> 00:04:20,027 +为保证单元重用良好运作 + +78 +00:04:20,027 --> 00:04:22,763 +您要避免在用户滚动时 + +79 +00:04:22,763 --> 00:04:26,800 +从单元格中添加和删除子视图 + +80 +00:04:26,800 --> 00:04:29,803 +在每个单元格中 +显示 SwiftUI 视图时 + +81 +00:04:29,803 --> 00:04:32,539 +要使用单个托管视图 并在 + +82 +00:04:32,539 --> 00:04:35,542 +单元格内容需要改变时 + +83 +00:04:35,542 --> 00:04:37,778 +用不同的根视图更新 + +84 +00:04:37,778 --> 00:04:40,280 +您需用以下方法构建集合视图单元 + +85 +00:04:40,280 --> 00:04:42,249 +以托管 SwiftUI + +86 +00:04:42,249 --> 00:04:43,684 +在这个例子中 + +87 +00:04:43,684 --> 00:04:47,688 +我正在构建 +显示快捷指令视图的单元格 + +88 +00:04:47,688 --> 00:04:52,359 +每个单元格都包含一个 +NSHostingView 来托管 SwiftUI + +89 +00:04:52,359 --> 00:04:54,094 +由于单元格创建于 + +90 +00:04:54,094 --> 00:04:56,663 +添加任何内容之前 + +91 +00:04:56,663 --> 00:04:58,565 +所以要从零开始 + +92 +00:04:58,565 --> 00:05:00,300 +并在第一次准备 + +93 +00:05:00,300 --> 00:05:03,504 +显示快捷指令时设置 + +94 +00:05:03,504 --> 00:05:06,773 +displayShortcut 方法在配置单元格 + +95 +00:05:06,773 --> 00:05:10,344 +以显示快捷方式时被数据源调用 + +96 +00:05:10,344 --> 00:05:14,615 +该方法创建了一个 +SwiftUI ShortcutView + +97 +00:05:14,615 --> 00:05:17,551 +那么 如果已经 +有一个 hostingView + +98 +00:05:17,551 --> 00:05:21,989 +其 rootView 就要 +设置为新视图 + +99 +00:05:21,989 --> 00:05:24,291 +否则 如果是第一次显示快捷指令 + +100 +00:05:24,291 --> 00:05:26,927 +就会创建一个 +newHostingView + +101 +00:05:26,927 --> 00:05:30,264 +作为单元格的子视图添加其中 + +102 +00:05:30,264 --> 00:05:34,001 +以下是一个主 +SwiftUI 单元格的生命周期 + +103 +00:05:34,001 --> 00:05:38,772 +首先 单元格被初始化 没有子视图 + +104 +00:05:38,772 --> 00:05:41,909 +因为此时还未显示快捷方式 + +105 +00:05:41,909 --> 00:05:44,711 +第一次调用 displayShortcut 时 + +106 +00:05:44,711 --> 00:05:49,683 +hostingView 就被创建 +shortcutView 也显示出来 + +107 +00:05:49,683 --> 00:05:52,319 +这会创建一个 +SwiftUI 视图层次结构 + +108 +00:05:52,319 --> 00:05:59,993 +包含一个 Vstack 视图 一个图像视图 +一个空格视图和两个文本视图 + +109 +00:05:59,993 --> 00:06:02,896 +如果该单元格滚动到屏幕外 + +110 +00:06:02,896 --> 00:06:05,566 +就可能会被系统从伫列中移除 + +111 +00:06:05,566 --> 00:06:08,268 +并且需要显示不同的快捷指令 + +112 +00:06:08,268 --> 00:06:12,072 +发生这种情况时 +一个新的 ShortcutView 会被创建 + +113 +00:06:12,072 --> 00:06:15,042 +并提供给 HostingView + +114 +00:06:15,042 --> 00:06:17,511 +由于 HostingView +已经显示出 + +115 +00:06:17,511 --> 00:06:19,313 +不同的快捷指令视图 + +116 +00:06:19,313 --> 00:06:22,549 +它将重用视图的整体结构 + +117 +00:06:22,549 --> 00:06:25,385 +包括 VStack 和空格视图 + +118 +00:06:25,385 --> 00:06:30,791 +并且只更新变化了的 +图像 文本和背景视图 + +119 +00:06:30,791 --> 00:06:35,596 +好 接下来 +我们讨论一下布局和尺寸 + +120 +00:06:35,596 --> 00:06:37,798 +主控制器和主视图的 + +121 +00:06:37,798 --> 00:06:39,900 +固定尺寸 + +122 +00:06:39,900 --> 00:06:43,604 +基于 SwiftUI 视图的 +理想宽度和高度 + +123 +00:06:43,604 --> 00:06:46,273 +SwiftUI 会自动创建和更新 + +124 +00:06:46,273 --> 00:06:49,843 +Auto Layout +约束 AppKit 布局系统 + +125 +00:06:49,843 --> 00:06:53,313 +会用其适当调整视图大小 + +126 +00:06:53,313 --> 00:06:56,350 +视图也很灵活 这意味着它们支持 + +127 +00:06:56,350 --> 00:07:00,854 +各种尺寸 可从小到大变化 + +128 +00:07:00,854 --> 00:07:05,359 +SwiftUI 也为以下这些 +创建约束 + +129 +00:07:05,359 --> 00:07:08,762 +在层次结构中 +嵌入 SwiftUI 主视图时 + +130 +00:07:08,762 --> 00:07:11,865 +您要将自己的 +Auto Layout 约束 + +131 +00:07:11,865 --> 00:07:15,936 +应用到超级视图或其他相邻视图 + +132 +00:07:15,936 --> 00:07:19,506 +使用框架修饰符 +或其他 SwiftUI 布局 + +133 +00:07:19,506 --> 00:07:23,377 +将更新所创建的约束 + +134 +00:07:23,377 --> 00:07:28,215 +例如将宽度覆盖为固定大小 + +135 +00:07:28,215 --> 00:07:31,185 +由于用户可以调整窗口大小 + +136 +00:07:31,185 --> 00:07:35,088 +窗口则可以最小化和最大化 + +137 +00:07:35,088 --> 00:07:36,723 +在设置 HostingViews + +138 +00:07:36,723 --> 00:07:39,793 +为一个窗口的顶层 +contentView 时 + +139 +00:07:39,793 --> 00:07:43,096 +SwiftUI +将基于显示内容自动更新 + +140 +00:07:43,096 --> 00:07:47,401 +该窗口的最小和最大尺寸 + +141 +00:07:47,401 --> 00:07:49,670 +这让窗口可按垂直或水平方向 + +142 +00:07:49,670 --> 00:07:52,673 +调整大小 也可两者都做调整 + +143 +00:07:52,673 --> 00:07:55,275 +取决于显示内容 + +144 +00:07:55,275 --> 00:07:58,412 +放置在托管控制器中的 +SwiftUI 视图 + +145 +00:07:58,412 --> 00:08:02,349 +在以模态形式呈现时 +也会根据内容调整大小 + +146 +00:08:02,349 --> 00:08:05,586 +例如 您可以 +轻松将 SwiftUI 视图 + +147 +00:08:05,586 --> 00:08:07,521 +放在 AppKit 弹出框中 + +148 +00:08:07,521 --> 00:08:09,556 +用 NSViewController 上的 + +149 +00:08:09,556 --> 00:08:13,260 +popover presentation API 呈现托管控制器 + +150 +00:08:13,260 --> 00:08:15,262 +如此处所示 + +151 +00:08:15,262 --> 00:08:18,031 +您还可以将 SwiftUI 视图 +呈现为工作表 + +152 +00:08:18,031 --> 00:08:20,968 +用 presentAsSheet 方法即可实现 + +153 +00:08:20,968 --> 00:08:23,570 +最后 对于模态窗口 + +154 +00:08:23,570 --> 00:08:26,607 +您可以使用 +presentAsModalWindow 方法 + +155 +00:08:26,607 --> 00:08:30,777 +呈现一个阻止交互的窗口 +关闭窗口即可结束阻止 + +156 +00:08:30,777 --> 00:08:34,615 +窗口的大小会根据内容调整 + +157 +00:08:34,615 --> 00:08:37,551 +macOS Ventura 中 +NSHostingView + +158 +00:08:37,551 --> 00:08:40,721 +和 NSHostingController 上 +新增了 API + +159 +00:08:40,721 --> 00:08:42,923 +可允许您自定义 + +160 +00:08:42,923 --> 00:08:45,459 +自动添加的约束 + +161 +00:08:45,459 --> 00:08:47,961 +默认情况下 托管控制器和视图 + +162 +00:08:47,961 --> 00:08:50,497 +会为最小尺寸 固定尺寸 + +163 +00:08:50,497 --> 00:08:53,867 +和最大尺寸创建约束 + +164 +00:08:53,867 --> 00:08:56,904 +出于性能原因 +您可能希望禁用其中一些约束 + +165 +00:08:56,904 --> 00:09:00,174 +比如您希望视图始终具有灵活尺寸 + +166 +00:09:00,174 --> 00:09:02,209 +或者您已 +为 AppKit 中的周围视图 + +167 +00:09:02,209 --> 00:09:05,345 +添加了约束 + +168 +00:09:05,345 --> 00:09:06,747 +对于托管控制器 + +169 +00:09:06,747 --> 00:09:08,682 +为让视图的理想尺寸 + +170 +00:09:08,682 --> 00:09:11,618 +确定首选的内容尺寸 + +171 +00:09:11,618 --> 00:09:15,622 +您可启用 +preferredContentSize 选项 + +172 +00:09:15,622 --> 00:09:18,825 +当您开始在 App 中 +添加 SwiftUI 视图时 + +173 +00:09:18,825 --> 00:09:21,595 +该视图像您 App 中的 +其他视图一样 + +174 +00:09:21,595 --> 00:09:26,200 +参与响应链和 +焦点系统就显得非常重要 + +175 +00:09:26,200 --> 00:09:29,303 +在快捷指令中 我们的编辑器以 + +176 +00:09:29,303 --> 00:09:32,039 +SwiftUI 视图实现 + +177 +00:09:32,039 --> 00:09:35,008 +但是编辑器需要处理主菜单中定义的 + +178 +00:09:35,008 --> 00:09:40,013 +菜单栏命令 +这也是在 AppKit 中实现 + +179 +00:09:40,013 --> 00:09:45,085 +该命令包括剪切 复制 粘贴等 + +180 +00:09:45,085 --> 00:09:49,089 +我们还实现了 +我们自己的自定义菜单项 + +181 +00:09:49,089 --> 00:09:52,526 +用于上下移动操作 + +182 +00:09:52,526 --> 00:09:56,230 +在 AppKit 中 +您的视图层次结构组成了一个 + +183 +00:09:56,230 --> 00:09:58,899 +称为“响应者链”的视图链 + +184 +00:09:58,899 --> 00:10:02,903 +焦点响应者称为第一响应者 + +185 +00:10:02,903 --> 00:10:04,838 +选择菜单项时 + +186 +00:10:04,838 --> 00:10:08,709 +该条目的选择器 +会被发送至第一响应者 + +187 +00:10:08,709 --> 00:10:10,210 +但若第一响应者 + +188 +00:10:10,210 --> 00:10:12,145 +未响应该选择器 + +189 +00:10:12,145 --> 00:10:15,215 +那选择器就会被 +依次发送至下一个响应者 + +190 +00:10:15,215 --> 00:10:17,651 +直到选择器被响应 + +191 +00:10:17,651 --> 00:10:20,654 +或者到达 App + +192 +00:10:20,654 --> 00:10:23,790 +SwiftUI 中 +相当于第一响应者的 + +193 +00:10:23,790 --> 00:10:26,994 +是焦点视图 + +194 +00:10:26,994 --> 00:10:31,098 +可聚焦的 SwiftUI 视图 +可以响应键盘输入 + +195 +00:10:31,098 --> 00:10:35,602 +并处理发送至响应链的选择器 + +196 +00:10:35,602 --> 00:10:40,207 +像文本字段 +这样的视图已经可以获得焦点 + +197 +00:10:40,207 --> 00:10:42,910 +但您可以使用可聚焦修饰符 + +198 +00:10:42,910 --> 00:10:46,313 +让其他视图也获得焦点 + +199 +00:10:46,313 --> 00:10:50,017 +SwiftUI +有处理常用命令的修饰符 + +200 +00:10:50,017 --> 00:10:52,886 +例如复制 剪切和粘贴等 + +201 +00:10:52,886 --> 00:10:55,556 +这些修饰符可将值传入 传出粘贴板 + +202 +00:10:55,556 --> 00:10:58,392 +是用户从您的 App +传入传出数据的 + +203 +00:10:58,392 --> 00:11:00,994 +简便方法 + +204 +00:11:00,994 --> 00:11:03,764 +快捷指令编辑器 +利用 onMoveCommand + +205 +00:11:03,764 --> 00:11:07,334 +和 onExit 命令修饰符 +来处理方向键 + +206 +00:11:07,334 --> 00:11:09,603 +和返回键 + +207 +00:11:09,603 --> 00:11:12,272 +onCommand 修饰符 +可用于处理 + +208 +00:11:12,272 --> 00:11:14,675 +AppKit +和您的 App 定义的 + +209 +00:11:14,675 --> 00:11:17,845 +自定义选择器中的任一常见选择器 + +210 +00:11:17,845 --> 00:11:21,748 +在此 我们可处理来自 +AppKit 的 selectAll 命令 + +211 +00:11:21,748 --> 00:11:25,686 +以及在快捷方式 App 中 +定义的 moveActionUp + +212 +00:11:25,686 --> 00:11:28,856 +和 moveActionDown 命令 + +213 +00:11:28,856 --> 00:11:32,092 +在您的 App 中 +测试焦点和键盘可导航性时 + +214 +00:11:32,092 --> 00:11:34,628 +一定要确保打开键盘系统设置 + +215 +00:11:34,628 --> 00:11:36,897 +并在全键盘导航开启和关闭的情况下 + +216 +00:11:36,897 --> 00:11:39,633 +进行测试 + +217 +00:11:39,633 --> 00:11:44,371 +因为许多控件仅在启用时才可聚焦 + +218 +00:11:44,371 --> 00:11:46,006 +还有很多方法可以 + +219 +00:11:46,006 --> 00:11:48,775 +让您的 App 与键盘完美配合 + +220 +00:11:48,775 --> 00:11:52,579 +比如 +FocusState 等 API + +221 +00:11:52,579 --> 00:11:54,314 +以及能让您用编程更改 + +222 +00:11:54,314 --> 00:11:58,218 +需要聚焦的视图的焦点修饰符 + +223 +00:11:58,218 --> 00:12:01,054 +要了解有关焦点和键盘的更多信息 + +224 +00:12:01,054 --> 00:12:02,222 +您可以观看 + +225 +00:12:02,222 --> 00:12:06,326 +“在 SwiftUI 中 +直接和间接获取焦点”视频 + +226 +00:12:06,326 --> 00:12:11,932 +最后 我们来讨论在 +SwiftUI 中托管 AppKit 视图的方法 + +227 +00:12:11,932 --> 00:12:13,267 +在某些情况下 + +228 +00:12:13,267 --> 00:12:15,602 +“快捷指令” +会在 SwiftUI 布局内 + +229 +00:12:15,602 --> 00:12:17,971 +托管 AppKit 视图 + +230 +00:12:17,971 --> 00:12:20,641 +当您在 App 中 +采用 SwiftUI 时 + +231 +00:12:20,641 --> 00:12:24,244 +也可能需要 +托管 AppKit 视图 + +232 +00:12:24,244 --> 00:12:29,483 +其中一种情况是在 +SwiftUI 快捷指令编辑器内部 + +233 +00:12:29,483 --> 00:12:32,052 +其中有一个嵌入式 +AppleScript 编辑器视图 + +234 +00:12:32,052 --> 00:12:33,921 +由一个 AppKit 控件 + +235 +00:12:33,921 --> 00:12:37,624 +和 macOS 上 +其他一些系统 App 共享 + +236 +00:12:37,624 --> 00:12:40,694 +SwiftUI 提供了两种 +representable 协议 + +237 +00:12:40,694 --> 00:12:43,363 +允许 AppKit 视图 +和视图控制器 + +238 +00:12:43,363 --> 00:12:48,402 +嵌入到 SwiftUI +视图层次结构中 + +239 +00:12:48,402 --> 00:12:50,337 +与 SwiftUI 视图一样 + +240 +00:12:50,337 --> 00:12:54,007 +Representable 协议 +描述了 AppKit 视图 + +241 +00:12:54,007 --> 00:12:57,311 +创建和更新的方式 + +242 +00:12:57,311 --> 00:13:01,481 +由于 AppKit 中的 +许多类都有委托 观察者 + +243 +00:13:01,481 --> 00:13:06,053 +或依赖 KVO 或通知来观察 + +244 +00:13:06,053 --> 00:13:09,823 +协议还包括一个可选的协调器对象 + +245 +00:13:09,823 --> 00:13:12,326 +您可利用其配合您的视图 + +246 +00:13:12,326 --> 00:13:15,662 +或视图控制器 + +247 +00:13:15,662 --> 00:13:18,232 +这是托管对象的生命周期 + +248 +00:13:18,232 --> 00:13:20,267 +及其协调器 + +249 +00:13:20,267 --> 00:13:23,604 +我们从初始化托管视图开始 + +250 +00:13:23,604 --> 00:13:26,139 +当视图即将首次显示时 + +251 +00:13:26,139 --> 00:13:28,609 +会发生以下情况 + +252 +00:13:28,609 --> 00:13:31,645 +SwiftUI 在初始化期间 +做的第一件事 + +253 +00:13:31,645 --> 00:13:33,447 +就是创建协调器 + +254 +00:13:33,447 --> 00:13:35,949 +这可自行选择 +但您可以定义自己的类型 + +255 +00:13:35,949 --> 00:13:37,951 +并从 makeCoordinator 返回 + +256 +00:13:37,951 --> 00:13:41,822 +如果您需要它来 +进行委派或状态管理的话 + +257 +00:13:41,822 --> 00:13:43,690 +协调器的单个实例 + +258 +00:13:43,690 --> 00:13:47,594 +将在视图的生命周期内一直存在 + +259 +00:13:47,594 --> 00:13:50,330 +其次 makeNSView 和 + +260 +00:13:50,330 --> 00:13:53,967 +makeNSViewController +方法会有一个被调用 + +261 +00:13:53,967 --> 00:13:56,203 +这是您向 SwiftUI 描述 + +262 +00:13:56,203 --> 00:14:00,407 +如何创建视图新实例的地方 + +263 +00:14:00,407 --> 00:14:03,810 +上下文包含了刚刚创建的协调器 + +264 +00:14:03,810 --> 00:14:07,447 +如果有的话 +这里就可将协调器分配为 + +265 +00:14:07,447 --> 00:14:13,387 +视图的委托或其他类型的观察者 + +266 +00:14:13,387 --> 00:14:15,355 +创建视图后 + +267 +00:14:15,355 --> 00:14:17,491 +每当 SwiftUI 状态或 + +268 +00:14:17,491 --> 00:14:22,129 +环境发生变化时 +就会调用更新视图方法 + +269 +00:14:22,129 --> 00:14:25,966 +在这里 您有义务更新 +存储在 AppKit 视图中的 + +270 +00:14:25,966 --> 00:14:28,836 +任何属性或状态 + +271 +00:14:28,836 --> 00:14:31,638 +使其与周围的 +SwiftUI 状态和环境 + +272 +00:14:31,638 --> 00:14:33,473 +保持同步 + +273 +00:14:33,473 --> 00:14:35,843 +更新方法可经常被调用 + +274 +00:14:35,843 --> 00:14:38,011 +所以您对视图应尽可能 + +275 +00:14:38,011 --> 00:14:40,747 +少做更改 + +276 +00:14:40,747 --> 00:14:42,749 +在进行更改时 + +277 +00:14:42,749 --> 00:14:45,185 +您应检查所做的更改 + +278 +00:14:45,185 --> 00:14:47,855 +只重新加载视图受影响的部分 + +279 +00:14:47,855 --> 00:14:50,691 +当 SwiftUI +完成显示托管视图时 + +280 +00:14:50,691 --> 00:14:53,093 +就会被清除 + +281 +00:14:53,093 --> 00:14:57,297 +托管视图和协调器都将被释放 + +282 +00:14:57,297 --> 00:15:00,634 +而被释放之前 +representable 协议 + +283 +00:15:00,634 --> 00:15:02,836 +会给您提供选择来操作 + +284 +00:15:02,836 --> 00:15:06,106 +如果需要 您可在其中清理状态 + +285 +00:15:06,106 --> 00:15:08,675 +好了 现在您了解了生命周期 + +286 +00:15:08,675 --> 00:15:12,112 +也熟悉了 +representable 协议 + +287 +00:15:12,112 --> 00:15:14,381 +我来向您展示 +“快捷指令”在 App 中 + +288 +00:15:14,381 --> 00:15:18,118 +托管自定义脚本编辑器视图的方法 + +289 +00:15:18,118 --> 00:15:22,990 +脚本编辑器是一个名为 +ScriptEditorView 的 NSView + +290 +00:15:22,990 --> 00:15:25,659 +编辑器中编写的代码可被访问 + +291 +00:15:25,659 --> 00:15:28,662 +并可通过 sourceCode +属性进行修改 + +292 +00:15:28,662 --> 00:15:30,364 +且视图可被禁用 + +293 +00:15:30,364 --> 00:15:33,000 +以防止进行更改 + +294 +00:15:33,000 --> 00:15:35,736 +脚本编辑器还有一个委托 + +295 +00:15:35,736 --> 00:15:38,372 +每当有人更改源代码时都会 + +296 +00:15:38,372 --> 00:15:40,774 +收到通知 + +297 +00:15:40,774 --> 00:15:42,976 +托管 AppKit 视图时 + +298 +00:15:42,976 --> 00:15:46,613 +首先思考一下 +视图在 SwiftUI 中的位置 + +299 +00:15:46,613 --> 00:15:50,450 +以及需要传入和传出的数据 + +300 +00:15:50,450 --> 00:15:54,154 +在快捷指令中 +该视图被放到编译按钮旁边的 + +301 +00:15:54,154 --> 00:15:57,291 +一个容器视图中 + +302 +00:15:57,291 --> 00:16:00,761 +编译按钮的处理程序需要访问 + +303 +00:16:00,761 --> 00:16:03,597 +输入到视图中的源代码 + +304 +00:16:03,597 --> 00:16:05,999 +源代码用 State 属性包装器 + +305 +00:16:05,999 --> 00:16:08,502 +存储在 SwiftUI 中 + +306 +00:16:08,502 --> 00:16:10,437 +representable 协议 +需要阅读 + +307 +00:16:10,437 --> 00:16:13,407 +并写入此状态 + +308 +00:16:13,407 --> 00:16:15,108 +为了构建 +representable 协议 + +309 +00:16:15,108 --> 00:16:19,213 +首先要创建一个符合 +NSViewRepresentable 的类型 + +310 +00:16:19,213 --> 00:16:22,916 +因为它要托管一个 NSView + +311 +00:16:22,916 --> 00:16:26,353 +为每个需要从 +SwiftUI 中配置的事物 + +312 +00:16:26,353 --> 00:16:28,155 +添加属性 + +313 +00:16:28,155 --> 00:16:31,058 +对于绑定源代码 + +314 +00:16:31,058 --> 00:16:36,129 +这会读取和写入 +存储在 SwiftUI 中的状态 + +315 +00:16:36,129 --> 00:16:40,167 +您需要操作的第一个方法 +是 makeNSView + +316 +00:16:40,167 --> 00:16:41,468 +这是您描述 + +317 +00:16:41,468 --> 00:16:44,004 +创建视图新实例 + +318 +00:16:44,004 --> 00:16:47,975 +以及进行一次性设置的地方 + +319 +00:16:47,975 --> 00:16:51,144 +在此 委托被设置为协调器 + +320 +00:16:51,144 --> 00:16:55,249 +稍后我将进一步介绍协调器 + +321 +00:16:55,249 --> 00:16:58,552 +接下来 +操作 updateNSView + +322 +00:16:58,552 --> 00:17:01,221 +这会在源代码更改时 + +323 +00:17:01,221 --> 00:17:05,092 +或在 SwiftUI 环境 +发生变化时调用 + +324 +00:17:05,092 --> 00:17:07,628 +由于脚本编辑器在设置 + +325 +00:17:07,628 --> 00:17:09,830 +sourceCode 属性时 +做了很多工作 + +326 +00:17:09,830 --> 00:17:12,199 +所以我们只比较视图中已经存在的值 + +327 +00:17:12,199 --> 00:17:15,035 +并且仅在更改时设置属性 + +328 +00:17:15,035 --> 00:17:17,938 +以避免不必要的工作 + +329 +00:17:17,938 --> 00:17:20,908 +传递给 updateNSView +的上下文 + +330 +00:17:20,908 --> 00:17:23,544 +包含 SwiftUI 环境 + +331 +00:17:23,544 --> 00:17:25,746 +isEnabled 环境键 + +332 +00:17:25,746 --> 00:17:30,017 +会被传递给 +脚本编辑器上的 isEditable 属性 + +333 +00:17:30,017 --> 00:17:31,718 +因此若 +SwiftUI 视图层次结构的 + +334 +00:17:31,718 --> 00:17:35,689 +其余部分被禁用 编辑也会被禁用 + +335 +00:17:35,689 --> 00:17:39,193 +每当有人修改视图中的源代码时 + +336 +00:17:39,193 --> 00:17:42,829 +源代码绑定就需要捕获新值 + +337 +00:17:42,829 --> 00:17:44,932 +为此 我们将构建一个 + +338 +00:17:44,932 --> 00:17:49,269 +符合 ScriptEditorViewDelegate 的协调器 + +339 +00:17:49,269 --> 00:17:52,206 +协调器将存储 +representable 值 + +340 +00:17:52,206 --> 00:17:56,243 +包含需要更新的源代码绑定 + +341 +00:17:56,243 --> 00:17:59,179 +在 sourceCodeDidChange 方法中 + +342 +00:17:59,179 --> 00:18:01,515 +绑定被设置为来自视图的 + +343 +00:18:01,515 --> 00:18:04,318 +新字符串值 + +344 +00:18:04,318 --> 00:18:07,554 +最后 我们要告知 +SwiftUI representable + +345 +00:18:07,554 --> 00:18:10,490 +构建和更新协调器的方法 + +346 +00:18:10,490 --> 00:18:14,094 +首先 您需要使用 +makeCoordinator 方法 + +347 +00:18:14,094 --> 00:18:17,297 +构建一个新协调器 + +348 +00:18:17,297 --> 00:18:21,068 +协调器与托管视图 +具有相同的生命周期 + +349 +00:18:21,068 --> 00:18:23,203 +和托管视图一样 + +350 +00:18:23,203 --> 00:18:25,305 +添加到协调器的属性 + +351 +00:18:25,305 --> 00:18:29,376 +随着 representable 的 +变化更新 + +352 +00:18:29,376 --> 00:18:31,545 +当存储在 +representable 的值 + +353 +00:18:31,545 --> 00:18:34,948 +发生变化时 由于 +updateNSView 被调用 + +354 +00:18:34,948 --> 00:18:40,320 +在这里 协调器上的 +representable 属性就被更新 + +355 +00:18:40,320 --> 00:18:43,624 +现在您已了解将 AppKit +添加到 SwiftUI + +356 +00:18:43,624 --> 00:18:46,727 +以及将 SwiftUI 添加到 +AppKit 中的方法 + +357 +00:18:46,727 --> 00:18:50,397 +您就可以将 SwiftUI +集成到 App 中了 + +358 +00:18:50,397 --> 00:18:52,766 +从侧边栏或表格 +和集合视图单元格开始 + +359 +00:18:52,766 --> 00:18:55,536 +将会是不错的选择 + +360 +00:18:55,536 --> 00:18:58,071 +可以确保您的视图尺寸合适 + +361 +00:18:58,071 --> 00:19:01,508 +能正常处理常见命令和焦点 + +362 +00:19:01,508 --> 00:19:02,509 +感谢收看 + +363 +00:19:02,509 --> 00:19:05,045 +期待您的成果 + +364 +00:19:05,045 --> 00:19:08,982 +♪ + diff --git a/zho/2022 Session 10076 Bring your iOS app to the Mac.srt b/zho/2022 Session 10076 Bring your iOS app to the Mac.srt new file mode 100644 index 0000000..47bedd1 --- /dev/null +++ b/zho/2022 Session 10076 Bring your iOS app to the Mac.srt @@ -0,0 +1,1519 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,576 --> 00:00:14,314 +Owen: 大家好 欢迎参加 +将 iOS app 带到 Mac 上 + +3 +00:00:14,348 --> 00:00:17,784 +我叫 Owen +是一名 Mac Catalyst 工程师 + +4 +00:00:19,286 --> 00:00:24,291 +无论您是在 M1 Mac 上 +原封不动地发布您的 iOS app + +5 +00:00:24,324 --> 00:00:28,395 +还是已经开始考虑用 +Mac Catalyst 更进一步 + +6 +00:00:28,428 --> 00:00:33,033 +或者已经发布 Catalyst app +并希望做得更好 + +7 +00:00:33,066 --> 00:00:36,203 +我都很高兴分享新的 API 和技术 + +8 +00:00:36,236 --> 00:00:39,773 +让您的 App 在 Mac 上做到最好 + +9 +00:00:39,806 --> 00:00:43,610 +但首先 我想通过一些 +由开发者完成的令人惊叹的工作 + +10 +00:00:43,644 --> 00:00:49,249 +展示 Mac Catalyst 的可能性 + +11 +00:00:49,283 --> 00:00:52,719 +Craft 是一款令人难以置信的 App + +12 +00:00:52,753 --> 00:00:56,023 +可以毫不费力地开始 +编写和制作漂亮的文档 + +13 +00:00:56,056 --> 00:01:00,327 +也入选了 App Store +2021 年度 Mac App + +14 +00:01:00,360 --> 00:01:01,995 +多亏了 Mac Catalyst + +15 +00:01:02,029 --> 00:01:05,933 +我们可以在各种设备上 +获得这种出色的体验 + +16 +00:01:05,966 --> 00:01:10,671 +当您的下一个想法出现时 +它随时准备就绪 + +17 +00:01:10,704 --> 00:01:15,909 +Darkroom 的智能 AI 编辑工具 +简化了您的摄影工作流程 + +18 +00:01:15,943 --> 00:01:20,080 +您可以在 iPhone 或 iPad 上 +开始现场编辑 + +19 +00:01:20,113 --> 00:01:23,851 +并在家里用他们的 +Mac Catalyst app 完成之后的编辑 + +20 +00:01:23,884 --> 00:01:27,421 +它因出色的设计 创新和独创性 + +21 +00:01:27,454 --> 00:01:30,023 +获得了 Apple 设计奖 + +22 +00:01:30,057 --> 00:01:34,761 +并自 2018 年以来一直是 +App Store 编辑推荐的 app + +23 +00:01:36,330 --> 00:01:42,035 +Night Sky 是直接从您的计算机 +探索宇宙的绝佳方式 + +24 +00:01:42,069 --> 00:01:44,204 +您可以了解星座 + +25 +00:01:44,238 --> 00:01:48,842 +并通过详细的 +月球 行星和卫星 3D 模型 + +26 +00:01:48,876 --> 00:01:51,712 +近距离观察这些星球 + +27 +00:01:51,745 --> 00:01:57,284 +它因其设计和令人惊叹的视觉效果 +赢得了多个威比奖和洛维奖 + +28 +00:01:59,319 --> 00:02:04,358 +狂野飙车 9 竞速传奇是是一款 +令人振奋的高辛烷值赛车模拟游戏 + +29 +00:02:04,391 --> 00:02:08,428 +也是唯一赢得 +Apple 设计奖的赛车游戏 + +30 +00:02:08,462 --> 00:02:11,532 +而在 Mac Catalyst 版本中 + +31 +00:02:11,565 --> 00:02:13,667 +大屏幕上的动作更令人兴奋 + +32 +00:02:15,135 --> 00:02:19,840 +现在 我将介绍可以在 Mac 上 +为您的 App 创建良好体验的 + +33 +00:02:19,873 --> 00:02:23,043 +所有方法 + +34 +00:02:23,076 --> 00:02:25,979 +我将从几个新选项开始 + +35 +00:02:26,013 --> 00:02:29,550 +来讲一下在 M1 上原生运行iOS app + +36 +00:02:29,583 --> 00:02:33,954 +这些是将现有 iOS app +发布到 Mac 上最简单的方法 + +37 +00:02:35,389 --> 00:02:40,527 +然后 我将介绍如何在 Xcode 中 +添加一个 Mac Catalyst 运行目标 + +38 +00:02:40,561 --> 00:02:42,763 +并介绍做出的更改 + +39 +00:02:44,031 --> 00:02:48,268 +我将展示当您采用新的 +桌面级 iPad API 时 + +40 +00:02:48,302 --> 00:02:52,039 +您的 Catalyst app +可以免费获得的新行为 + +41 +00:02:53,607 --> 00:02:56,376 +然后深入研究 Mac 特有的改进 + +42 +00:02:56,410 --> 00:02:59,980 +新的 Mac Catalyst API 使之成为可能 + +43 +00:03:01,849 --> 00:03:07,321 +我将从 M1 的 Mac 为原生 iOS app +提供的一些新选项开始 + +44 +00:03:09,323 --> 00:03:14,895 +您的 iOS app 已经可以在 M1 Mac 上的 +Mac App Store 中下载了 + +45 +00:03:14,928 --> 00:03:17,231 +只要您没有选择退出 + +46 +00:03:17,264 --> 00:03:22,870 +您的 App 就会在搜索中出现在 +iPhone and iPad Apps 标签下 + +47 +00:03:22,903 --> 00:03:25,439 +我们还增加了几个新功能 + +48 +00:03:25,472 --> 00:03:28,976 +可以改善您在 Mac 上的应用体验 + +49 +00:03:29,009 --> 00:03:33,080 +您可以将两个新的键值 +添加到您的 Info.plist 中 + +50 +00:03:33,113 --> 00:03:38,385 +这可以让您指定 iOS app +在 Mac 上的启动方式 + +51 +00:03:38,418 --> 00:03:41,688 +这些键值不绑定任何 SDK 版本 + +52 +00:03:41,722 --> 00:03:47,127 +在 iOS 和 macOS 12.1 之前的 +Mac 上都是被忽略的 + +53 +00:03:47,160 --> 00:03:50,330 +所以它们可以安全添加到 +任何会受益的 App 中 + +54 +00:03:51,865 --> 00:03:55,769 +第一个键值 +“UISupportsTrueScreenSizeOnMac” + +55 +00:03:55,802 --> 00:03:58,138 +表明您的 App 已经为 + +56 +00:03:58,172 --> 00:04:03,143 +它可能遇到的各种显示配置 +做好了准备 + +57 +00:04:03,177 --> 00:04:05,879 +通过这种方式 +您的 App 可以获得真实的屏幕尺寸 + +58 +00:04:05,913 --> 00:04:10,250 +和像素密度 +而不是兼容的 iPad 尺寸 + +59 +00:04:13,387 --> 00:04:18,025 +第二个键值 +“UILaunchToFullScreenByDefaultOnMac” + +60 +00:04:18,058 --> 00:04:21,695 +告诉系统您的 App 希望在启动后 + +61 +00:04:21,728 --> 00:04:23,997 +立即进入全屏模式 + +62 +00:04:24,031 --> 00:04:26,200 +这两个键值可以很好地协同工作 + +63 +00:04:26,233 --> 00:04:29,102 +特别是对于游戏和多媒体应用程序 + +64 +00:04:29,136 --> 00:04:34,007 +提供像素完美 无边框的全屏体验 + +65 +00:04:35,609 --> 00:04:36,977 +这些键值已被获奖的 + +66 +00:04:37,010 --> 00:04:40,314 +Sky: Children of the Light 采用 + +67 +00:04:40,347 --> 00:04:43,784 +可以立即提供沉浸的体验 + +68 +00:04:43,817 --> 00:04:47,855 +游戏一启动 +屏幕上就充满了丰富的细节 + +69 +00:04:47,888 --> 00:04:51,992 +把您拉进美丽的探索世界 + +70 +00:04:52,025 --> 00:04:57,130 +在 Mac 上改善应用体验的 +另一种方法是使用触控替代 + +71 +00:04:57,164 --> 00:05:01,869 +它可以自动将键盘 鼠标 +和触控板输入 + +72 +00:05:01,902 --> 00:05:07,074 +转换为 App 期望的 +iOS 多点触摸手势和设备运动 + +73 +00:05:08,008 --> 00:05:11,245 +我们已经为 app store 上 + +74 +00:05:11,278 --> 00:05:14,982 +许多流行的游戏添加了 +内置的触摸替代支持 + +75 +00:05:15,015 --> 00:05:18,418 +启动后 它们会自动显示一个教程 + +76 +00:05:18,452 --> 00:05:22,189 +解释其触摸控制如何转换为 +键盘 鼠标 + +77 +00:05:22,222 --> 00:05:24,157 +或触控板 + +78 +00:05:24,191 --> 00:05:28,295 +例如 箭头键可用于模拟从窗口中心 + +79 +00:05:28,328 --> 00:05:30,163 +进行的滑动 + +80 +00:05:30,197 --> 00:05:33,000 +空格键可用于执行轻触 + +81 +00:05:35,202 --> 00:05:38,138 +要选择自动开启触控替代 + +82 +00:05:38,172 --> 00:05:41,041 +请在您的 App 中创建一个名为 + +83 +00:05:41,074 --> 00:05:46,847 +com.apple.uikit.inputalternatives.plist 的 +新 plist 文件 + +84 +00:05:48,649 --> 00:05:52,186 +首先 添加一个名为 +defaultEnablement 的键值 + +85 +00:05:52,219 --> 00:05:54,454 +该键值的字符串值为 enabled + +86 +00:05:54,488 --> 00:05:58,992 +它告诉系统立即打开触摸替代 + +87 +00:06:01,028 --> 00:06:05,232 +在那下面 添加另一个名为 +requiredOnboarding 的键值 + +88 +00:06:05,265 --> 00:06:08,735 +这是一个数组 其中包含您认为 + +89 +00:06:08,769 --> 00:06:11,638 +最适合您的 App 的控制列表 + +90 +00:06:14,074 --> 00:06:16,109 +您可以选择展示 + +91 +00:06:16,143 --> 00:06:18,879 +五种不同的控制选项 + +92 +00:06:18,912 --> 00:06:23,183 +从触控板上点击 倾斜 拖动 滑动 + +93 +00:06:23,217 --> 00:06:25,953 +和来自触控板的直接触控输入 + +94 +00:06:27,454 --> 00:06:30,257 +请注意 +当启用触控替代时 + +95 +00:06:30,290 --> 00:06:32,659 +所有这些控制都将处于开启状态 + +96 +00:06:32,693 --> 00:06:36,430 +但您仍应决定哪些 +对您的 App 最有意义 + +97 +00:06:36,463 --> 00:06:41,802 +并且仅将您想要突出显示的控制方式 +添加到您的 onboarding plist + +98 +00:06:41,835 --> 00:06:44,705 +当您的 App 在 Mac 上运行时 +会检测到这一选项 + +99 +00:06:44,738 --> 00:06:50,744 +并且在首次启动时会显示引导页面 +突出显示这些控制方式 + +100 +00:06:50,777 --> 00:06:54,147 +在您的 App 设置中 +人们可以在显示 + +101 +00:06:54,181 --> 00:06:58,585 +plist 中指定的首选控制方式 +和所有控制方式之间 + +102 +00:06:58,619 --> 00:07:00,721 +进行切换 + +103 +00:07:02,289 --> 00:07:06,960 +当然 最好的选择是在您的 App 中 + +104 +00:07:06,994 --> 00:07:09,530 +直接实现键盘和光标支持 + +105 +00:07:09,563 --> 00:07:14,001 +通过该操作 您可以确保您的 App +在所有设备上都运行良好 + +106 +00:07:14,034 --> 00:07:18,572 +包括带有键盘的 iPad 和 Mac + +107 +00:07:19,973 --> 00:07:22,609 +若想了解更多有关信息 请观看视频 + +108 +00:07:22,643 --> 00:07:25,145 +“Support hardware keyboards +in your app” + +109 +00:07:25,179 --> 00:07:28,215 +和 “Handle trackpad +and mouse input” + +110 +00:07:28,248 --> 00:07:34,521 +现在我将快速介绍成为 +Mac Catalyst app 的过程 + +111 +00:07:35,556 --> 00:07:39,726 +通过在您的项目设置中 +添加 Mac Catalyst 目标 + +112 +00:07:39,760 --> 00:07:44,231 +您的 App 将自动转换为 +能够在每个 Mac 上运行的 + +113 +00:07:44,264 --> 00:07:46,667 +完整 Mac Catalyst app + +114 +00:07:46,700 --> 00:07:52,005 +并允许您使用 Mac Catalyst API +对其进行进一步自定义 + +115 +00:07:52,039 --> 00:07:56,043 +您还可以选择为 Mac 优化界面 + +116 +00:07:56,076 --> 00:07:59,279 +为您提供原生的 AppKit 样式控件 + +117 +00:07:59,313 --> 00:08:02,883 +并确保您的 App 内容 +以原生规模呈现 + +118 +00:08:04,918 --> 00:08:08,722 +我将使用 Markdown demo app + +119 +00:08:08,755 --> 00:08:11,525 +团队一直致力于突出其 iPad 的新功能 + +120 +00:08:11,558 --> 00:08:16,430 +当我第一次将它移植到 Mac 上时 +它是以 “Scaled to Match iPad” 模式运行的 + +121 +00:08:18,198 --> 00:08:20,734 +当我切换到 Optimize for Mac 时 + +122 +00:08:20,767 --> 00:08:23,437 +许多更改会自动发生 + +123 +00:08:25,239 --> 00:08:27,241 +并排比较时 + +124 +00:08:27,274 --> 00:08:29,877 +差异是显而易见的 + +125 +00:08:29,910 --> 00:08:32,012 +当该 App 针对 Mac 进行优化时 + +126 +00:08:32,045 --> 00:08:34,781 +UINavigationBar 被转换为 + +127 +00:08:34,815 --> 00:08:36,884 +丰富的 NSToolbar + +128 +00:08:36,917 --> 00:08:39,887 +提供原生 AppKit 控件 + +129 +00:08:39,920 --> 00:08:43,824 +其他控件也会发生这种转换 + +130 +00:08:43,857 --> 00:08:47,394 +文本大小也会随之调整 + +131 +00:08:47,427 --> 00:08:50,931 +iPad 惯用法中的文本 +以 iPad 大小呈现 + +132 +00:08:50,964 --> 00:08:56,303 +然后缩小到原始大小的 77% + +133 +00:08:56,336 --> 00:09:00,841 +Mac 惯用法中的文本 +通过本地 Mac 字体渲染来处理 + +134 +00:09:00,874 --> 00:09:04,244 +这种渲染以像素级进行 + +135 +00:09:04,278 --> 00:09:06,246 +这对我们的 App 来说很理想 + +136 +00:09:06,280 --> 00:09:10,484 +因为它能确保文本看起来总是清晰的 + +137 +00:09:10,517 --> 00:09:13,387 +当 App 选择加入 Mac Catalyst 后 + +138 +00:09:13,420 --> 00:09:15,956 +我想检查一下它的工作情况 + +139 +00:09:15,989 --> 00:09:19,960 +并深入了解由 iPadOS 16 的新 API + +140 +00:09:19,993 --> 00:09:24,231 +提供的新的自适配 Mac 行为 + +141 +00:09:24,264 --> 00:09:27,601 +如果您已经看过 +“Meet desktop-class iPad” + +142 +00:09:27,634 --> 00:09:30,370 +和 “Build a desktop-class +iPad app” + +143 +00:09:30,404 --> 00:09:32,639 +那您已经了解了许多 + +144 +00:09:32,673 --> 00:09:37,044 +使用 iPadOS 16 增强 App 的新工具 + +145 +00:09:37,077 --> 00:09:39,780 +这些新的 API 完美地转换成了 + +146 +00:09:39,813 --> 00:09:43,183 +原生 Mac 表现形式 + +147 +00:09:43,217 --> 00:09:45,552 +我将浏览一下 markdown app + +148 +00:09:45,586 --> 00:09:48,288 +并重点介绍其中的一些新行为 + +149 +00:09:49,623 --> 00:09:55,963 +控件和导航从 UINavigationBar +转换为 NSToolbar + +150 +00:09:55,996 --> 00:09:58,699 +如果您还没有创建工具栏 + +151 +00:09:58,732 --> 00:10:01,668 +我们会自动为您提供一个 + +152 +00:10:01,702 --> 00:10:05,105 +如果您已经在 Catalyst 中 +管理了自己的 NSToolbar + +153 +00:10:05,138 --> 00:10:07,207 +我们会为您保留原样 + +154 +00:10:09,009 --> 00:10:13,180 +中心项目控件变成 NSToolbarItem + +155 +00:10:15,082 --> 00:10:16,750 +对于基于文稿的应用程序 + +156 +00:10:16,783 --> 00:10:19,987 +您的窗口标题会显示文稿名称 + +157 +00:10:20,020 --> 00:10:25,058 +如果在辅助功能系统设置中 +启用了显示窗口标题图标 + +158 +00:10:25,092 --> 00:10:27,895 +那么文件代理图标也会显示出来 + +159 +00:10:27,928 --> 00:10:30,864 +就像您在 Mac 上看到的那样 + +160 +00:10:32,432 --> 00:10:35,202 +如果您使用导航控制器 + +161 +00:10:35,235 --> 00:10:38,105 +后退按钮和其他导航控件 + +162 +00:10:38,138 --> 00:10:42,142 +也会出现在工具栏中 + +163 +00:10:42,176 --> 00:10:45,579 +此外 您还可以在文件菜单中 +获得新的以文档为中心的 + +164 +00:10:45,612 --> 00:10:47,347 +菜单项 + +165 +00:10:47,381 --> 00:10:51,885 +复制 移到 重新命名 和 导出为 + +166 +00:10:53,887 --> 00:10:55,856 +要启用这些菜单项 + +167 +00:10:55,889 --> 00:11:01,862 +请确保响应链中的某个对象 +重载了 UIResponder 的 duplicate + +168 +00:11:01,895 --> 00:11:05,299 +move rename 和 export 这些函数 + +169 +00:11:07,067 --> 00:11:10,003 +如果您的 App +不需要这些文件菜单项 + +170 +00:11:10,037 --> 00:11:13,440 +可以用 UIMenuBuilder 把它们去掉 + +171 +00:11:13,473 --> 00:11:18,779 +在 App delegate 上实现 +buildMenu 方法来控制 App 菜单 + +172 +00:11:20,247 --> 00:11:26,887 +新文档菜单项的 UIMenuIdentifier +值为 .document + +173 +00:11:28,188 --> 00:11:30,257 +如果您的 App 包括搜索栏 + +174 +00:11:30,290 --> 00:11:34,461 +它也会被自动加入 NSToolbar + +175 +00:11:34,494 --> 00:11:38,298 +首先显示为一个搜索按钮 + +176 +00:11:38,332 --> 00:11:42,069 +单击会扩展为搜索栏 + +177 +00:11:42,102 --> 00:11:47,774 +支持它的 UISearchTextField +驻留在 NSToolbarItem 内部 + +178 +00:11:47,808 --> 00:11:51,545 +这也可用于自定义视图 + +179 +00:11:51,578 --> 00:11:54,781 +搜索建议菜单和搜索范围栏 + +180 +00:11:54,815 --> 00:11:58,285 +也被转换成原生 AppKit 控件 + +181 +00:12:00,153 --> 00:12:04,124 +除了通过采用桌面级 iPad 功能 + +182 +00:12:04,157 --> 00:12:07,394 +免费获得的所有新 Mac 行为 + +183 +00:12:07,427 --> 00:12:12,199 +我们还添加了 +几个新的 Catalyst-specific API + +184 +00:12:12,232 --> 00:12:15,903 +来改进多窗口和工具栏行为 + +185 +00:12:15,936 --> 00:12:19,306 +我将再次浏览我们的 Markdown app + +186 +00:12:19,339 --> 00:12:25,012 +并混合使用新旧 API 添加 +这些特定于 Mac 的功能 + +187 +00:12:25,045 --> 00:12:27,848 +从现有的 Mac Catalyst API 中 + +188 +00:12:27,881 --> 00:12:31,185 +我选择了几个真正能增强 +我们的 App 的 + +189 +00:12:33,187 --> 00:12:36,490 +我采用了 Mac 惯用法来获得 + +190 +00:12:36,523 --> 00:12:39,459 +原生控件和自动 NSToolbar + +191 +00:12:39,493 --> 00:12:43,897 +我添加了一个自定义指针 +因此当鼠标移动到 + +192 +00:12:43,931 --> 00:12:47,768 +自定义拆分视图中间的滑块柄上 +指针将切换为 + +193 +00:12:47,801 --> 00:12:50,070 +水平双箭头 + +194 +00:12:50,103 --> 00:12:52,706 +指示拆分可以调整大小 + +195 +00:12:53,841 --> 00:12:55,742 +我还用 +UIApplicationSupportsPrintCommand plist 键值 + +196 +00:12:55,776 --> 00:12:59,880 +添加了打印支持 + +197 +00:13:02,316 --> 00:13:04,251 +当考虑到您的 App 时 + +198 +00:13:04,284 --> 00:13:08,422 +不用觉得您需要添加 +这里面的每一项功能 + +199 +00:13:08,455 --> 00:13:11,725 +相反 请考虑您创建的 App 类型 + +200 +00:13:11,758 --> 00:13:14,361 +以及哪些功能最适合它 + +201 +00:13:14,394 --> 00:13:18,599 +查看 Mac 和 Mac Catalyst +Human Interface Guidelines + +202 +00:13:18,632 --> 00:13:22,135 +并在您使用的其他 App 中寻找灵感 + +203 +00:13:23,303 --> 00:13:25,339 +实现了这些功能后 + +204 +00:13:25,372 --> 00:13:28,642 +该 App 已经非常出色了 + +205 +00:13:28,675 --> 00:13:34,014 +现在有了一些新的 Mac Catalyst API +我可以做的更多 + +206 +00:13:34,047 --> 00:13:38,785 +我们添加了新的选项 +来定制 App 窗口框和控件 + +207 +00:13:38,819 --> 00:13:42,756 +在 NSToolbar 中显示 UIView 内容 + +208 +00:13:42,789 --> 00:13:46,527 +以及从工具栏项目中显示弹出窗口 + +209 +00:13:46,560 --> 00:13:52,699 +我将继续使用这些新的 API +在 Mac 上进一步改进我们的 App + +210 +00:13:52,733 --> 00:13:54,701 +从窗口开始 + +211 +00:13:56,436 --> 00:14:02,910 +Catalyst app 使用现有的 +UIWindowScene API 支持多个窗口 + +212 +00:14:02,943 --> 00:14:05,045 +在 macOS Ventura 中 + +213 +00:14:05,078 --> 00:14:09,716 +我们新增了 API 让您 +可以进一步自定义 App 窗口 + +214 +00:14:09,750 --> 00:14:13,187 +设置交通灯窗口控件的样式 + +215 +00:14:13,220 --> 00:14:17,124 +以编程方式调整窗口大小和位置 + +216 +00:14:17,157 --> 00:14:20,827 +以及针对特定窗口禁用全屏 + +217 +00:14:22,663 --> 00:14:25,899 +我将使用这些工具 +向 markdown app 添加一个功能 + +218 +00:14:25,933 --> 00:14:30,604 +通过一个有用的辅助面板 +显示markdown 语法 + +219 +00:14:30,637 --> 00:14:35,642 +使用新的几何属性请求 API +此面板将变小 + +220 +00:14:35,676 --> 00:14:39,246 +并禁用其最小化和缩放按钮 + +221 +00:14:41,782 --> 00:14:47,020 +在窗口创建时 在我的 Scene Delegate 的 +sceneWillConnectToSession 方法中 + +222 +00:14:47,054 --> 00:14:49,456 +我创建了我想要的 frame + +223 +00:14:49,489 --> 00:14:55,562 +最好总是从 effectiveGeometry +直接获取当前 frame 开始 + +224 +00:14:55,596 --> 00:15:00,267 +在创建窗口之前 +它被初始化为 CGRectNull + +225 +00:15:00,300 --> 00:15:05,639 +系统知道在初始窗口创建时 +要忽略它的值 + +226 +00:15:05,672 --> 00:15:09,643 +我修改了大小 +然后通过创建一个 + +227 +00:15:09,676 --> 00:15:13,814 +UIWindowScene +.macGeometryPreferences 对象 + +228 +00:15:13,847 --> 00:15:18,352 +通过 systemFrame 参数 +给窗口设置一个新的 frame + +229 +00:15:20,354 --> 00:15:25,859 +然后我使用 +scene.requestGeometryUpdate 方法提交更新 + +230 +00:15:25,893 --> 00:15:27,828 +因为这是一个请求 + +231 +00:15:27,861 --> 00:15:31,698 +系统保留拒绝新几何属性的权利 + +232 +00:15:31,732 --> 00:15:36,270 +在这种情况下 它将调用 +错误处理回调并提供详细信息 + +233 +00:15:36,303 --> 00:15:40,374 +在此处所示的窗口 +willConnectToSession 方法中完成时 + +234 +00:15:40,407 --> 00:15:43,911 +该请求将应用于 +您的 App 的首次启动 + +235 +00:15:43,944 --> 00:15:48,148 +但是会被系统在以后启动时 + +236 +00:15:48,182 --> 00:15:51,151 +执行的任何适用状态恢复所取代 + +237 +00:15:52,920 --> 00:15:55,589 +由于这是一个小的辅助面板 + +238 +00:15:55,622 --> 00:15:57,724 +我还从新的 windowScene +windowingBehaviors 对象中 + +239 +00:15:57,758 --> 00:16:01,395 +禁用了最小化按钮 + +240 +00:16:01,428 --> 00:16:04,398 +并从 sizeRestrictions 的新属性中 + +241 +00:16:04,431 --> 00:16:07,601 +禁用了全屏显示窗口的功能 + +242 +00:16:09,603 --> 00:16:12,372 +当这个新的 +Markdown Hints 窗口出现时 + +243 +00:16:12,406 --> 00:16:16,276 +它会以我们要求的大小出现 + +244 +00:16:16,310 --> 00:16:21,315 +黄色的最小化 +和绿色的缩放窗口控制按钮被禁用 + +245 +00:16:21,348 --> 00:16:23,951 +只留下红色的关闭按钮 + +246 +00:16:26,520 --> 00:16:30,524 +这些选项不仅仅是为窗口创建保留的 + +247 +00:16:30,557 --> 00:16:32,960 +在窗口生命周期中的任何时候 + +248 +00:16:32,993 --> 00:16:34,828 +您都可以从 + +249 +00:16:34,862 --> 00:16:38,131 +只读 resolvedGeometry 属性 +检查其当前 frame + +250 +00:16:38,165 --> 00:16:40,367 +根据需要进行修改 + +251 +00:16:40,400 --> 00:16:44,438 +并请求新的几何属性更新 + +252 +00:16:44,471 --> 00:16:48,675 +下面是另一个例子 +展示了如何修改窗口的原点 + +253 +00:16:48,709 --> 00:16:51,211 +保持其大小不变 + +254 +00:16:53,146 --> 00:16:57,751 +几何属性有两个重要方面需要记住 + +255 +00:16:57,784 --> 00:17:01,655 +首先 因为 systemFrame +决定了 Mac 桌面上 + +256 +00:17:01,688 --> 00:17:03,557 +窗口的 frame + +257 +00:17:03,590 --> 00:17:06,827 +所以 systemFrame 属性的 +一个点的大小 + +258 +00:17:06,860 --> 00:17:10,531 +始终是一个 AppKit 点的大小 + +259 +00:17:10,564 --> 00:17:13,200 +如果您的 App 针对 Mac 进行了优化 + +260 +00:17:13,233 --> 00:17:16,803 +那这与您的 UI 元素的比例相同 + +261 +00:17:16,837 --> 00:17:19,973 +然而 如果您的 App 按比例 +缩放到与 iPad 匹配 + +262 +00:17:20,007 --> 00:17:24,578 +则其比例因子将相差 77% + +263 +00:17:24,611 --> 00:17:27,481 +其次 坐标空间的原点 + +264 +00:17:27,514 --> 00:17:31,051 +是主显示器的左上角 + +265 +00:17:31,084 --> 00:17:33,187 +如果您有多台显示器 + +266 +00:17:33,220 --> 00:17:36,557 +主显示是在系统显示设置中 + +267 +00:17:36,590 --> 00:17:39,459 +显示菜单栏的那个 + +268 +00:17:41,128 --> 00:17:43,630 +使用新的 Mac Catalyst API + +269 +00:17:43,664 --> 00:17:45,599 +您可以控制三个窗口控制按钮中 + +270 +00:17:45,632 --> 00:17:48,702 +每个按钮的状态 + +271 +00:17:48,735 --> 00:17:53,907 +UIWindowScene 上新的 +windowingBehaviors 对象 + +272 +00:17:53,941 --> 00:17:56,677 +有 closable +和 miniaturizable 两个属性 + +273 +00:17:56,710 --> 00:17:59,680 +这两个属性 +将调整这些相应的窗口行为 + +274 +00:17:59,713 --> 00:18:03,450 +并启用或禁用红色 + +275 +00:18:03,483 --> 00:18:06,553 +和黄色窗口按钮 + +276 +00:18:07,521 --> 00:18:12,292 +绿色窗口按钮既可以 +在桌面上调整窗口大小 + +277 +00:18:12,326 --> 00:18:15,829 +也可以全屏显示窗口 + +278 +00:18:15,863 --> 00:18:19,700 +您可以使用 sizeRestrictions 上的 +新属性 allowsFullscreen + +279 +00:18:19,733 --> 00:18:22,936 +来禁用全屏 + +280 +00:18:22,970 --> 00:18:27,074 +或者通过使用大小限制 + +281 +00:18:27,107 --> 00:18:31,912 +并将最小和最大尺寸设置为 +相同的大小来禁用调整大小 + +282 +00:18:31,945 --> 00:18:37,284 +通过这两种方式 绿色按钮也被禁用 + +283 +00:18:38,919 --> 00:18:42,456 +您可以使用新的 isFullScreen 属性 + +284 +00:18:42,489 --> 00:18:46,426 +检查您的窗口当前是否是全屏的 + +285 +00:18:46,460 --> 00:18:50,764 +现在我将把重点放在 +改进 Mac 的工具栏上 + +286 +00:18:50,797 --> 00:18:54,168 +我们为自定义工具栏添加了新选项 + +287 +00:18:54,201 --> 00:18:58,438 +无论您是依赖 +UINavigationBar 的自动转换 + +288 +00:18:58,472 --> 00:19:02,142 +还是在 App 代码中管理 +自己的 NSToolbar 都可以用这些选项 + +289 +00:19:04,077 --> 00:19:05,579 +Mac Catalyst 中新增了 + +290 +00:19:05,612 --> 00:19:10,317 +可以将 UIView 作为项目 +添加到 NSToolbar 中 + +291 +00:19:10,350 --> 00:19:13,620 +我为我们的 App 设计了 +一个自定义 UIView + +292 +00:19:13,654 --> 00:19:16,156 +以显示当前的字数 + +293 +00:19:16,190 --> 00:19:19,059 +单击后 它会显示一个弹出窗口 + +294 +00:19:19,092 --> 00:19:22,930 +提供额外的详细信息 +如段落和章节数 + +295 +00:19:22,963 --> 00:19:26,300 +阅读时间和翻译 + +296 +00:19:26,333 --> 00:19:29,670 +由于我使用的是新的桌面级别 iPad API + +297 +00:19:29,703 --> 00:19:33,307 +我的 UIBarButton 项目上的 +customView 属性 + +298 +00:19:33,340 --> 00:19:36,977 +会被自动包装并添加到工具栏中 + +299 +00:19:37,010 --> 00:19:40,480 +但是如果您自行管理 NSToolbar + +300 +00:19:40,514 --> 00:19:44,051 +我们还添加了 +一个新的 NSToolbarItem 子类 + +301 +00:19:44,084 --> 00:19:47,454 +叫做 NSUIViewToolbarItem + +302 +00:19:48,222 --> 00:19:53,694 +您可以像使用任何 +其他 NSToolbarItem 一样 + +303 +00:19:53,727 --> 00:19:55,696 +使用 NSUIViewToolbarItem + +304 +00:19:55,729 --> 00:20:00,567 +从 NSToolbarDelegate 的 +itemForIdentifier 方法实例化工具栏项 + +305 +00:20:00,601 --> 00:20:03,504 +初始化通过打包一个 UIView + +306 +00:20:03,537 --> 00:20:06,673 +然后将其插入 NSToolbar + +307 +00:20:09,776 --> 00:20:13,580 +NSToolbar 要求 +在工具栏自定义模式下 + +308 +00:20:13,614 --> 00:20:16,383 +工具栏项实例都是唯一的 + +309 +00:20:16,416 --> 00:20:21,388 +如果您从 UINavigationBar +使用自动 NSToolbar 托管 + +310 +00:20:21,421 --> 00:20:26,660 +系统会自动克隆视图 +以进行工具栏自定义 + +311 +00:20:26,693 --> 00:20:29,897 +但是 如果您管理自己的 NSToolbar + +312 +00:20:29,930 --> 00:20:32,699 +那么您的代理就需要为 +每个 NSUIViewToolbarItem 实例 + +313 +00:20:32,733 --> 00:20:37,804 +创建唯一的 UIView 实例 + +314 +00:20:37,838 --> 00:20:41,842 +而不是重复使用相同的 UIView 实例 + +315 +00:20:43,744 --> 00:20:45,846 +使用工具栏中的新项目 + +316 +00:20:45,879 --> 00:20:48,549 +我将添加 popover 行为 + +317 +00:20:48,582 --> 00:20:50,651 +在工具栏项的操作中 + +318 +00:20:50,684 --> 00:20:53,187 +我创建了 popover 视图控制器 + +319 +00:20:53,220 --> 00:20:57,124 +并将其 sourceItem +设置为我的工具栏项 + +320 +00:20:57,157 --> 00:20:59,426 +然后我来展示 popover + +321 +00:21:01,595 --> 00:21:03,664 +有了 popover 代码后 + +322 +00:21:03,697 --> 00:21:06,800 +单击工具栏项会在 +锚定在工具栏项上的 + +323 +00:21:06,834 --> 00:21:11,104 +popover 展示中显示更多详细信息 + +324 +00:21:12,806 --> 00:21:15,142 +与 Mac Catalyst 中的其他控件一样 + +325 +00:21:15,175 --> 00:21:19,813 +您可以通过使用 +UINavigationBar 上的新属性 + +326 +00:21:19,847 --> 00:21:23,984 +preferredBehavioralStyle 来选择 +是否使用导航栏转换 + +327 +00:21:24,017 --> 00:21:28,088 +它的默认值是自动的 +但您可以将其设置为 .mac + +328 +00:21:28,121 --> 00:21:31,959 +以显式请求转换 + +329 +00:21:31,992 --> 00:21:33,760 +通过将其设置为 .pad + +330 +00:21:33,794 --> 00:21:37,731 +您的导航栏将不再自动转换 + +331 +00:21:39,833 --> 00:21:43,770 +使用这些选项 +您可以向 App 的工具栏 + +332 +00:21:43,804 --> 00:21:45,639 +添加新的自定义层 + +333 +00:21:46,974 --> 00:21:50,844 +我们会很高兴看到您使用这些新工具 + +334 +00:21:50,878 --> 00:21:53,881 +使您的 App 变得更好 + +335 +00:21:53,914 --> 00:21:57,684 +当您的 iPad app 自动出现 +在 Mac app store 中 + +336 +00:21:57,718 --> 00:22:00,954 +它可供全新的受众使用 + +337 +00:22:00,988 --> 00:22:03,123 +当您上传您的 iPad app 时 + +338 +00:22:03,156 --> 00:22:06,426 +请在 Mac 上运行它并亲自尝试 + +339 +00:22:06,460 --> 00:22:11,298 +或者通过转成 Mac Catalyst app +将其提升到新的水平 + +340 +00:22:11,331 --> 00:22:16,103 +并使用 iOS 16 和 +macOS Ventura 中的新 API + +341 +00:22:16,136 --> 00:22:18,205 +使您的 App 达到最佳状态 + +342 +00:22:19,339 --> 00:22:22,075 +将您的 App 带到 Mac 上很容易 + +343 +00:22:22,109 --> 00:22:24,311 +我们很愿意展示您的辛勤工作 + +344 +00:22:24,344 --> 00:22:28,282 +并迫不及待地想要尝试 +您接下来要构建的内容了 + +345 +00:22:28,315 --> 00:22:30,217 +谢谢大家 + diff --git a/zho/2022 Session 10078 Reduce networking delays for a more responsive app.srt b/zho/2022 Session 10078 Reduce networking delays for a more responsive app.srt new file mode 100644 index 0000000..3fee817 --- /dev/null +++ b/zho/2022 Session 10078 Reduce networking delays for a more responsive app.srt @@ -0,0 +1,1189 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:10,143 +♪ + +3 +00:00:10,143 --> 00:00:14,348 +嗨 我是 Vidhi Goel +在这个视频中 + +4 +00:00:14,348 --> 00:00:19,052 +我将为您介绍降低 +App 网络延迟的方法 + +5 +00:00:19,052 --> 00:00:21,722 +使其更快做出响应 + +6 +00:00:21,722 --> 00:00:25,959 +首先 我会解释为什么降低延迟 + +7 +00:00:25,959 --> 00:00:29,563 +对 App 的快速响应至关重要 + +8 +00:00:29,563 --> 00:00:31,832 +其次 我将介绍 + +9 +00:00:31,832 --> 00:00:34,902 +您在 App 和服务器中 + +10 +00:00:34,902 --> 00:00:40,240 +为消除不必要的延迟 +可以做的一系列工作 + +11 +00:00:40,240 --> 00:00:44,178 +最后 我将向您展示为降低延迟 + +12 +00:00:44,178 --> 00:00:47,948 +可在网络上执行的操作 + +13 +00:00:47,948 --> 00:00:51,451 +网络延迟是数据从一个端点到达 + +14 +00:00:51,451 --> 00:00:55,055 +另一个端点所需的时间 + +15 +00:00:55,055 --> 00:00:58,725 +它决定了内容传递到 + +16 +00:00:58,725 --> 00:01:01,028 +您 App 的速度 + +17 +00:01:01,028 --> 00:01:04,531 +所有使用网络的 App +都可能受到 + +18 +00:01:04,531 --> 00:01:06,767 +缓慢网络事务的影响 + +19 +00:01:06,767 --> 00:01:11,138 +从而导致 App 体验不佳 + +20 +00:01:11,138 --> 00:01:15,676 +例如 视频通话有时会卡顿 + +21 +00:01:15,676 --> 00:01:20,380 +或反应迟钝 导致会议中断 + +22 +00:01:20,380 --> 00:01:23,550 +为解决该问题 人们经常致电 + +23 +00:01:23,550 --> 00:01:27,421 +服务供应商要求升级带宽 + +24 +00:01:27,421 --> 00:01:31,792 +但问题依然存在 + +25 +00:01:31,792 --> 00:01:34,595 +为找出问题的根本 + +26 +00:01:34,595 --> 00:01:38,265 +您需了解 App 中的数据包 + +27 +00:01:38,265 --> 00:01:40,767 +在网络中的传输方式 + +28 +00:01:40,767 --> 00:01:44,805 +当您的 App 或框架 +从服务器请求数据时 + +29 +00:01:44,805 --> 00:01:48,675 +数据包由网络栈发出 + +30 +00:01:48,675 --> 00:01:52,079 +通常认为数据包直接发送至 + +31 +00:01:52,079 --> 00:01:56,216 +服务器 在网络中没有延迟 + +32 +00:01:56,216 --> 00:01:59,920 +但实际上 网络中最慢的链路 + +33 +00:01:59,920 --> 00:02:05,592 +通常有很长的数据包队列需要处理 + +34 +00:02:05,592 --> 00:02:07,561 +因此 来自您 App 的数据包 + +35 +00:02:07,561 --> 00:02:10,864 +实际上也排在这个长队列后面 + +36 +00:02:10,864 --> 00:02:16,036 +要等到前面的数据包处理完毕 + +37 +00:02:16,036 --> 00:02:19,840 +在最慢链路上排队增加了数据包在 + +38 +00:02:19,840 --> 00:02:24,745 +您的 App 和服务器之间 +每次往返的时间 + +39 +00:02:24,745 --> 00:02:29,917 +当需要多次往返才能首次响应 + +40 +00:02:29,917 --> 00:02:34,855 +您 App 发出的请求时 +该问题会更加严重 + +41 +00:02:34,855 --> 00:02:39,159 +例如 在 TCP 上 +使用 TLS 1.2 时 + +42 +00:02:39,159 --> 00:02:43,830 +得到第一个响应包的时间 + +43 +00:02:43,830 --> 00:02:46,400 +是每次往返时间 + +44 +00:02:46,400 --> 00:02:50,871 +乘以四 + +45 +00:02:50,871 --> 00:02:54,541 +由于在网络中排队 + +46 +00:02:54,541 --> 00:02:56,810 +单次往返时间已经增加 + +47 +00:02:56,810 --> 00:03:02,216 +最终总耗时只能更长 + +48 +00:03:02,216 --> 00:03:05,152 +有两个因素共同决定了 + +49 +00:03:05,152 --> 00:03:09,156 +您 App 的响应能力 + +50 +00:03:09,156 --> 00:03:15,128 +即每次往返的时间和往返次数 + +51 +00:03:15,128 --> 00:03:18,866 +减少这两个因素 +可降低您 App 的延迟 + +52 +00:03:18,866 --> 00:03:24,071 +提高其响应能力 + +53 +00:03:24,071 --> 00:03:26,607 +有一项研究测试了 + +54 +00:03:26,607 --> 00:03:30,677 +增加带宽速度与降低延迟 + +55 +00:03:30,677 --> 00:03:33,680 +对页面加载时间的影响 + +56 +00:03:33,680 --> 00:03:37,484 +在第一个测试中 延迟固定不变 + +57 +00:03:37,484 --> 00:03:44,224 +带宽速度从 1 +增加到 10Mb/s + +58 +00:03:44,224 --> 00:03:49,129 +首先 将带宽速度 +从 1 增加到 2Mb/s + +59 +00:03:49,129 --> 00:03:53,767 +页面加载时间减少近 40% + +60 +00:03:53,767 --> 00:03:56,036 +效果显著 + +61 +00:03:56,036 --> 00:04:01,441 +但宽带速度增至 4Mb/s 后 +每次增速 + +62 +00:04:01,441 --> 00:04:07,181 +对页面加载时间的影响几乎为零 + +63 +00:04:07,181 --> 00:04:11,618 +这就是为什么即使升级到千兆互联网 + +64 +00:04:11,618 --> 00:04:14,188 +App 运行仍然会慢 + +65 +00:04:14,188 --> 00:04:19,226 +第二个延迟测试的结果显示 + +66 +00:04:19,226 --> 00:04:24,097 +延迟每减少 20 毫秒 + +67 +00:04:24,097 --> 00:04:28,869 +页面加载时间随之线性递减 + +68 +00:04:28,869 --> 00:04:33,473 +以上结果适用于您 App 中的 + +69 +00:04:33,473 --> 00:04:35,642 +所有网络活动 + +70 +00:04:35,642 --> 00:04:40,414 +现在 我来为您介绍 +可采取哪些简单操作 + +71 +00:04:40,414 --> 00:04:45,285 +来减少延迟 +使您的 App 更快响应 + +72 +00:04:45,285 --> 00:04:48,222 +您可采用新版协议显著降低 + +73 +00:04:48,222 --> 00:04:50,624 +App 的延迟 + +74 +00:04:50,624 --> 00:04:57,097 +例如 IPv6 TLS 1.3 +和 HTTP/3 + +75 +00:04:57,097 --> 00:05:01,068 +您只需在 App 中的使用 + +76 +00:05:01,068 --> 00:05:04,371 +URLSession和 +Network.framework API + +77 +00:05:04,371 --> 00:05:07,741 +一旦上述协议在您的服务器上被启用 + +78 +00:05:07,741 --> 00:05:12,880 +就能自动被使用 + +79 +00:05:12,880 --> 00:05:17,351 +自协议推出以来 +我们看到 HTTP/3 的使用量 + +80 +00:05:17,351 --> 00:05:22,356 +不断增加 短短一年 + +81 +00:05:22,356 --> 00:05:28,262 +20% 的网络流量 +都在使用 HTTP/3 协议 + +82 +00:05:28,262 --> 00:05:32,499 +且数据仍在增长 + +83 +00:05:32,499 --> 00:05:37,604 +对比不同 HTTP 版本的 +Safari 浏览器流量 + +84 +00:05:37,604 --> 00:05:42,876 +HTTP/3 的速度最快 + +85 +00:05:42,876 --> 00:05:47,848 +在将请求完成时间的中位数看做是 + +86 +00:05:47,848 --> 00:05:50,551 +往返时间的倍数时 + +87 +00:05:50,551 --> 00:05:53,720 +HTTP/3 请求所花费的 +时间只有 HTTP/1 的 + +88 +00:05:53,720 --> 00:05:57,558 +一半多一点 + +89 +00:05:57,558 --> 00:06:03,664 +这意味着您 App +发送的请求会更快得到响应 + +90 +00:06:03,664 --> 00:06:07,100 +当设备从 Wi-Fi +移动到蜂窝网络时 + +91 +00:06:07,100 --> 00:06:11,071 +需要花时间重新建立新连接 + +92 +00:06:11,071 --> 00:06:15,275 +这可能会 +使您的 App 处于卡顿状态 + +93 +00:06:15,275 --> 00:06:20,614 +使用连接迁移可消除卡顿 + +94 +00:06:20,614 --> 00:06:24,685 +要选择接入 +请在您的 URLSession 或 + +95 +00:06:24,685 --> 00:06:28,889 +NWParameters 上 +将 multipathServiceType 属性 + +96 +00:06:28,889 --> 00:06:32,326 +设置为 .handover + +97 +00:06:32,326 --> 00:06:39,233 +启用此选项 +并确保其适用您的 App + +98 +00:06:39,233 --> 00:06:44,338 +如果您直接 +用 UDP 设计自己的协议 + +99 +00:06:44,338 --> 00:06:49,810 +iOS 16 和 macOS Ventura +引进了更好的方法 + +100 +00:06:49,810 --> 00:06:52,446 +来发送数据报文 + +101 +00:06:52,446 --> 00:06:57,584 +QUIC 数据报文 +比普通 UDP 优点更多 + +102 +00:06:57,584 --> 00:07:00,787 +最重要的是 QUIC 数据报文 + +103 +00:07:00,787 --> 00:07:03,023 +可对网络拥堵做出反应 + +104 +00:07:03,023 --> 00:07:07,895 +进而维持较低往返时间 +并减少数据包损失 + +105 +00:07:07,895 --> 00:07:10,030 +要选择接入客户端 + +106 +00:07:10,030 --> 00:07:13,734 +需在您的 QUIC 选项上 +将 isDatagram 设置为 true + +107 +00:07:13,734 --> 00:07:19,606 +并设置您要使用的 +maxDatagramFrameSize + +108 +00:07:19,606 --> 00:07:22,409 +创建数据报文流后 + +109 +00:07:22,409 --> 00:07:27,714 +您可像任何其它 QUIC 流 +一样在上面发送和接收 + +110 +00:07:27,714 --> 00:07:30,217 +现在您知道了在 App 中 + +111 +00:07:30,217 --> 00:07:32,519 +降低延迟的方法 + +112 +00:07:32,519 --> 00:07:36,156 +接下来我将解释服务器如何影响 + +113 +00:07:36,156 --> 00:07:39,393 +您 App 的响应能力 + +114 +00:07:39,393 --> 00:07:42,763 +尽管常在顶级硬件上运行 + +115 +00:07:42,763 --> 00:07:46,667 +您的服务器仍然可能 + +116 +00:07:46,667 --> 00:07:49,303 +拖慢您的 App + +117 +00:07:49,303 --> 00:07:54,308 +我们在 macOS Monterey 中 +引进了网络质量工具 + +118 +00:07:54,308 --> 00:07:56,443 +您可利用该工具 + +119 +00:07:56,443 --> 00:08:00,480 +在您的服务供应商网络以及服务器上 + +120 +00:08:00,480 --> 00:08:03,183 +测试缓冲区膨胀情况 + +121 +00:08:03,183 --> 00:08:06,887 +您需配置您的服务器为 + +122 +00:08:06,887 --> 00:08:09,623 +网络质量工具的目标 + +123 +00:08:09,623 --> 00:08:14,394 +配置完成后 +运行 networkQuality 工具 + +124 +00:08:14,394 --> 00:08:17,598 +首先针对 +Apple 的默认服务器 + +125 +00:08:17,598 --> 00:08:22,569 +然后针对您自己配置的服务器 + +126 +00:08:22,569 --> 00:08:26,406 +如果该工具在默认服务器上得分良好 + +127 +00:08:26,406 --> 00:08:30,544 +但在您自己的服务器上得分较差 + +128 +00:08:30,544 --> 00:08:33,580 +那可能您的服务器响应能力 + +129 +00:08:33,580 --> 00:08:35,949 +有待提高 + +130 +00:08:35,949 --> 00:08:40,888 +现在 我来向您展示 +我们如何利用该技术 + +131 +00:08:40,888 --> 00:08:45,792 +改进现在大家都在做的事情 + +132 +00:08:45,792 --> 00:08:48,695 +流媒体视频 + +133 +00:08:50,397 --> 00:08:52,399 +您可能有过这样的经历 + +134 +00:08:52,399 --> 00:08:55,869 +您想将视频向前跳到某一位置 + +135 +00:08:55,869 --> 00:09:01,808 +却要花很长时间等待缓冲 + +136 +00:09:01,808 --> 00:09:05,512 +于是 我们在随机访问中调查了 + +137 +00:09:05,512 --> 00:09:08,282 +缓冲较慢的原因 + +138 +00:09:08,282 --> 00:09:10,584 +我们利用网络质量工具 + +139 +00:09:10,584 --> 00:09:13,820 +测试流媒体服务器 + +140 +00:09:13,820 --> 00:09:18,759 +发现其响应能力得分很差 + +141 +00:09:18,759 --> 00:09:23,897 +我在右侧 +播放了一个 WWDC 视频 + +142 +00:09:23,897 --> 00:09:26,900 +然后 前跳该视频 + +143 +00:09:26,900 --> 00:09:28,836 +视频在缓冲时 + +144 +00:09:28,836 --> 00:09:32,206 +屏幕未显示任何画面 + +145 +00:09:32,206 --> 00:09:36,310 +几秒钟后 画面才出现 + +146 +00:09:36,310 --> 00:09:38,679 +借助 macOS 上 + +147 +00:09:38,679 --> 00:09:41,949 +网络质量工具的输出详解 + +148 +00:09:41,949 --> 00:09:46,920 +我们发现服务器上的队列很长 + +149 +00:09:46,920 --> 00:09:52,226 +所以我们看了一下服务器配置 + +150 +00:09:52,226 --> 00:09:58,866 +具体来说 我们查看了 +TCP TLS 和 HTTP 缓冲区大小 + +151 +00:09:58,866 --> 00:10:09,142 +配置分别为 +4MB 256K 和 4MB + +152 +00:10:09,142 --> 00:10:14,014 +因为 RAM 充足 +所以缓冲区很大 + +153 +00:10:14,014 --> 00:10:17,451 +但缓冲有用 + +154 +00:10:17,451 --> 00:10:22,155 +并不代表缓冲越多越好 + +155 +00:10:22,155 --> 00:10:27,427 +响应能力测试突出了实际的问题 + +156 +00:10:27,427 --> 00:10:32,065 +即在较大的缓冲区中 +新生成的数据包 + +157 +00:10:32,065 --> 00:10:34,168 +会排在旧数据后面 + +158 +00:10:34,168 --> 00:10:37,237 +导致在传输最新数据包时 + +159 +00:10:37,237 --> 00:10:41,241 +造成了很多额外延迟 + +160 +00:10:41,241 --> 00:10:47,981 +因此 我们将 +HTTP 缓冲区大小减至 256K + +161 +00:10:47,981 --> 00:10:54,855 +TLS 减至 16K +TCP 减至 128K + +162 +00:10:57,691 --> 00:11:01,328 +这是 Apache Traffic Server 的配置文件 + +163 +00:11:01,328 --> 00:11:05,399 +显示的是已配置的选项 + +164 +00:11:05,399 --> 00:11:10,871 +TCP 未发送低水位标记 +设置为 128K + +165 +00:11:10,871 --> 00:11:16,977 +同时启用其他选项以降低缓冲 + +166 +00:11:16,977 --> 00:11:21,748 +对于 TLS +我们启用了动态记录大小 + +167 +00:11:21,748 --> 00:11:26,753 +对于 HTTP/2 +我们降低了低水位标记 + +168 +00:11:26,753 --> 00:11:28,789 +和缓冲区块大小 + +169 +00:11:28,789 --> 00:11:31,725 +我们建议 +您的 Apache Traffic Server + +170 +00:11:31,725 --> 00:11:34,628 +也使用相同配置 + +171 +00:11:34,628 --> 00:11:38,031 +如果您使用的是其他网络服务器 + +172 +00:11:38,031 --> 00:11:41,301 +请寻找等效选项 + +173 +00:11:41,301 --> 00:11:43,737 +配置完成后 + +174 +00:11:43,737 --> 00:11:47,541 +再次运行网络质量工具 + +175 +00:11:47,541 --> 00:11:52,646 +这次获得了较高的 RPM 分数! + +176 +00:11:52,646 --> 00:11:56,250 +我在右侧播放相同视频 + +177 +00:11:56,250 --> 00:11:58,919 +但这次前跳视频时 + +178 +00:11:58,919 --> 00:12:03,590 +视频立即开始继续播放 + +179 +00:12:03,590 --> 00:12:07,594 +消除了服务器上不必要的排队 + +180 +00:12:07,594 --> 00:12:11,698 +随机访问响应就更快 + +181 +00:12:11,698 --> 00:12:15,869 +无论您的 App 如何使用网络 + +182 +00:12:15,869 --> 00:12:20,841 +在服务器上更改上述配置 +都可让您的 App 更快响应 + +183 +00:12:20,841 --> 00:12:24,878 +提供更好的用户体验 + +184 +00:12:24,878 --> 00:12:29,917 +以上就是改进您的 App +并更新服务器的方法 + +185 +00:12:29,917 --> 00:12:34,855 +还有第三个因素会极大影响响应能力 + +186 +00:12:34,855 --> 00:12:37,224 +即网络本身 + +187 +00:12:37,224 --> 00:12:41,528 +Apple 在 iOS 15 +和 macOS Monterey 中 + +188 +00:12:41,528 --> 00:12:44,364 +引进网络质量工具后 + +189 +00:12:44,364 --> 00:12:48,402 +也有其他使用相同的方法 + +190 +00:12:48,402 --> 00:12:52,973 +开展网络质量测试的 + +191 +00:12:52,973 --> 00:12:56,977 +Waveform 发布了 +Bufferbloat 测试 + +192 +00:12:56,977 --> 00:12:59,246 +Go 编写了开源的 + +193 +00:12:59,246 --> 00:13:03,984 +响应能力测试 + +194 +00:13:03,984 --> 00:13:07,855 +Ookla 也在 +其 Speedtest App 中 + +195 +00:13:07,855 --> 00:13:11,525 +添加了响应测试 + +196 +00:13:11,525 --> 00:13:15,395 +Ookla 的 App +以毫秒为单位显示往返时间 + +197 +00:13:15,395 --> 00:13:18,966 +如果用 60000 除以往返时间 + +198 +00:13:18,966 --> 00:13:24,104 +就会得到 +每分钟的往返次数 或 RPM + +199 +00:13:24,104 --> 00:13:26,673 +您可以利用以上工具来测试 + +200 +00:13:26,673 --> 00:13:30,944 +自己的网络性能 + +201 +00:13:30,944 --> 00:13:34,114 +了解网络延迟的最佳方法 + +202 +00:13:34,114 --> 00:13:37,751 +就是使用延迟敏感的 App + +203 +00:13:37,751 --> 00:13:41,054 +所以 我将向您展示 +在远程计算机上的 + +204 +00:13:41,054 --> 00:13:43,824 +屏幕共享的体验 + +205 +00:13:43,824 --> 00:13:45,559 +我设置了网络条件 + +206 +00:13:45,559 --> 00:13:48,829 +用于模仿一个有代表性的接入网络 + +207 +00:13:48,829 --> 00:13:54,234 +并有来自其他设备的流量共享该网络 + +208 +00:13:54,234 --> 00:13:59,106 +在此 我使用屏幕共享 +登录到我的远程计算机 + +209 +00:14:01,175 --> 00:14:04,378 +我点击了不同的访达菜单 + +210 +00:14:04,378 --> 00:14:09,149 +但每个菜单显示得都比较迟钝 + +211 +00:14:09,149 --> 00:14:12,553 +为了检查这种 +互动行为的网络延迟情况 + +212 +00:14:12,553 --> 00:14:16,823 +我在本地计算 +启动了一个显示时间的 App + +213 +00:14:16,823 --> 00:14:21,361 +并在远程计算机上 +启动了相同的 App + +214 +00:14:21,361 --> 00:14:25,832 +即便两台计算机的时间同步 + +215 +00:14:25,832 --> 00:14:29,703 +但远程屏幕并未按时更新 + +216 +00:14:29,703 --> 00:14:34,908 +显示的时间延迟了几秒钟 + +217 +00:14:34,908 --> 00:14:37,344 +延迟更新的原因 + +218 +00:14:37,344 --> 00:14:39,980 +是在网络最慢的链路上 + +219 +00:14:39,980 --> 00:14:42,783 +有一个较长的队列 + +220 +00:14:42,783 --> 00:14:45,485 +来自屏幕共享 App 的数据包 + +221 +00:14:45,485 --> 00:14:48,822 +卡在了该队列中 + +222 +00:14:50,824 --> 00:14:53,260 +为解决该队列问题 + +223 +00:14:53,260 --> 00:14:56,029 +Apple 正与网络社区合作 + +224 +00:14:56,029 --> 00:14:59,900 +共同开发 +一项名为 L4S 的新技术 + +225 +00:14:59,900 --> 00:15:06,773 +该技术将在 iOS 16 +和 macOS Ventura 中以 Beta 版提供 + +226 +00:15:06,773 --> 00:15:10,110 +L4S 可显著降低排队延迟 + +227 +00:15:10,110 --> 00:15:14,748 +还可实现零拥堵损失 + +228 +00:15:14,748 --> 00:15:17,551 +为维持较短排队时间 + +229 +00:15:17,551 --> 00:15:20,420 +网络会明确发出拥堵信号 + +230 +00:15:20,420 --> 00:15:22,623 +而不是丢弃数据包 + +231 +00:15:22,623 --> 00:15:25,492 +发送器会根据网络拥堵反馈 + +232 +00:15:25,492 --> 00:15:29,530 +调整发送速率 + +233 +00:15:29,530 --> 00:15:34,134 +这就可以在网络中 +维持非常短的排队时间 + +234 +00:15:34,134 --> 00:15:37,070 +而不丢失数据包 + +235 +00:15:37,070 --> 00:15:41,875 +进而让您的 App 快速响应 + +236 +00:15:41,875 --> 00:15:48,282 +现在 我们来看看 +L4S 如何改进屏幕共享 + +237 +00:15:48,282 --> 00:15:52,586 +这里我用了相同的计算机和网络 + +238 +00:15:52,586 --> 00:15:57,558 +不同的是 我启用了 L4S + +239 +00:15:57,558 --> 00:16:00,360 +我在点击各个访达菜单时 + +240 +00:16:00,360 --> 00:16:02,896 +都可立即打开 + +241 +00:16:02,896 --> 00:16:06,900 +我在两台计算机上 +都启动了 Time App + +242 +00:16:06,900 --> 00:16:09,770 +现在 远程屏幕上的时间 + +243 +00:16:09,770 --> 00:16:16,944 +和本地计算机上的几乎完全同步 + +244 +00:16:16,944 --> 00:16:21,381 +L4S 技术不仅改进了屏幕共享 + +245 +00:16:21,381 --> 00:16:25,485 +还改进了现今所有的 App + +246 +00:16:25,485 --> 00:16:28,121 +并为未来更加先进的 App + +247 +00:16:28,121 --> 00:16:31,959 +开放了大门 + +248 +00:16:31,959 --> 00:16:36,230 +这张表绘制的是监控下 + +249 +00:16:36,230 --> 00:16:39,166 +屏幕共享 App 数据包的 +平均往返时间 + +250 +00:16:39,166 --> 00:16:41,535 +该 App 与同一网络下的 + +251 +00:16:41,535 --> 00:16:46,006 +其他设备同时消耗流量 + +252 +00:16:46,006 --> 00:16:49,510 +对比常规排队与 L4S 排队 + +253 +00:16:49,510 --> 00:16:52,713 +可看出启用 L4S 后 + +254 +00:16:52,713 --> 00:16:56,416 +往返时间大大减少 + +255 +00:16:56,416 --> 00:17:00,387 +这是屏幕共享体验显著改善的 + +256 +00:17:00,387 --> 00:17:05,158 +主要原因 + +257 +00:17:05,158 --> 00:17:11,131 +要用您的 App 在 HTTP/3 或 QUIC +上测试 L4S + +258 +00:17:11,131 --> 00:17:16,970 +您可在 iOS 16 中的 +开发者设置中启用 L4S + +259 +00:17:16,970 --> 00:17:22,809 +或在 macOS Ventura 上 +通过 defaults write 来启用 L4S + +260 +00:17:22,809 --> 00:17:25,612 +要用 Linux 服务器进行测试 + +261 +00:17:25,612 --> 00:17:30,083 +您的 QUIC 实现 +需要支持 Accurate ECN + +262 +00:17:30,083 --> 00:17:34,521 +和可扩展的拥堵控制算法 + +263 +00:17:34,521 --> 00:17:36,623 +在部署支持 L4S 的网络时 + +264 +00:17:36,623 --> 00:17:40,227 +要确保您已做好准备 + +265 +00:17:40,227 --> 00:17:44,264 +测试您的 App 与 L4S 的兼容性 + +266 +00:17:44,264 --> 00:17:50,504 +并就可能遇到的任何问题提供反馈 + +267 +00:17:50,504 --> 00:17:54,441 +您已了解了降低延迟是 + +268 +00:17:54,441 --> 00:17:58,045 +提高您 App 响应能力的关键 + +269 +00:17:58,045 --> 00:18:02,382 +因此 采用 HTTP/3 和 QUIC + +270 +00:18:02,382 --> 00:18:04,718 +来减少往返次数 + +271 +00:18:04,718 --> 00:18:09,823 +并将内容更快速地 +传输到您的 App + +272 +00:18:09,823 --> 00:18:13,460 +消除服务器上不必要的排队 + +273 +00:18:13,460 --> 00:18:17,364 +可提高交互时的响应能力 + +274 +00:18:17,364 --> 00:18:21,702 +通过在开发者设置中启用 L4S + +275 +00:18:21,702 --> 00:18:25,939 +可测试您的 App 与 +L4S 的兼容性并提供反馈 + +276 +00:18:25,939 --> 00:18:29,042 +最后 再和您的 +服务器供应商谈论一下 + +277 +00:18:29,042 --> 00:18:32,880 +启用 L4S 的支持问题即可 + +278 +00:18:32,880 --> 00:18:34,748 +感谢收看! + +279 +00:18:34,748 --> 00:18:39,119 +♪ + diff --git a/zho/2022 Session 10079 Improve DNS security for apps and servers.srt b/zho/2022 Session 10079 Improve DNS security for apps and servers.srt new file mode 100644 index 0000000..b76e0da --- /dev/null +++ b/zho/2022 Session 10079 Improve DNS security for apps and servers.srt @@ -0,0 +1,1011 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,810 --> 00:00:11,078 +Qiaoyu Deng: 大家好 + +3 +00:00:11,111 --> 00:00:17,384 +欢迎收看讲座“提高 App 和 +服务器的 DNS 安全性” + +4 +00:00:17,417 --> 00:00:20,687 +我叫 Qiaoyu Deng + +5 +00:00:20,721 --> 00:00:27,694 +在这段视频中 我们将讨论 +为什么 DNS 通常会不安全 + +6 +00:00:27,728 --> 00:00:32,332 +以及如何使用 DNSSEC + +7 +00:00:32,366 --> 00:00:37,171 +和带 DDR 的加密 DNS +对其进行保护 + +8 +00:00:37,204 --> 00:00:43,210 +首先 我们来谈一下为什么 DNS 不安全 + +9 +00:00:44,912 --> 00:00:49,917 +DNS 是互联网的电话簿 + +10 +00:00:49,950 --> 00:00:53,120 +它将人类可读且容易记忆的 + +11 +00:00:53,153 --> 00:00:57,124 +域名翻译成 IP 地址 + +12 +00:00:57,157 --> 00:01:02,262 +而 IP 地址是为机器设计的 + +13 +00:01:02,296 --> 00:01:04,798 +其他互联网协议 + +14 +00:01:04,831 --> 00:01:09,469 +如 TCP TLS 和 QUIC + +15 +00:01:09,503 --> 00:01:12,973 +依赖于 IP 地址 + +16 +00:01:13,006 --> 00:01:17,110 +所以一切都从 DNS 开始 + +17 +00:01:17,144 --> 00:01:20,948 +目前 TLS 协议被广泛应用于 + +18 +00:01:20,981 --> 00:01:24,551 +网络通信的安全保障 + +19 +00:01:24,585 --> 00:01:29,556 +这很好 但是基础层 DNS + +20 +00:01:29,590 --> 00:01:31,592 +存在一些安全问题 + +21 +00:01:31,625 --> 00:01:35,696 +历史上 DNS 是不安全的 + +22 +00:01:35,729 --> 00:01:41,902 +它是在 1983 年设计的 +几乎没有考虑安全问题 + +23 +00:01:41,935 --> 00:01:46,840 +在那以后的几年里 +已经发生了许多 DNS 攻击事件 + +24 +00:01:46,874 --> 00:01:52,112 +一个例子是 DNS 缓存中毒 + +25 +00:01:52,145 --> 00:01:57,117 +攻击者利用 DNS 解析器的缺陷 + +26 +00:01:57,150 --> 00:02:01,488 +让它们缓存不正确的 IP 地址 + +27 +00:02:01,522 --> 00:02:05,526 +导致客户端连接到恶意主机 + +28 +00:02:05,559 --> 00:02:09,963 +这暴露了 DNS 的一个漏洞 + +29 +00:02:09,997 --> 00:02:12,866 +没有经过身份验证 + +30 +00:02:12,900 --> 00:02:17,971 +如今传统的 DNS 客户端 +无法验证答案 + +31 +00:02:18,005 --> 00:02:21,375 +因此很容易被欺骗 + +32 +00:02:21,408 --> 00:02:25,479 +另一种常见的攻击是 DNS 嗅探 + +33 +00:02:25,512 --> 00:02:32,252 +攻击者监视客户端和 DNS 服务器 +之间的 DNS 流量 + +34 +00:02:32,286 --> 00:02:35,455 +收集客户端的历史记录 + +35 +00:02:35,489 --> 00:02:39,860 +这是一个严重的用户隐私问题 + +36 +00:02:39,893 --> 00:02:43,230 +这种攻击可能的原因是 + +37 +00:02:43,263 --> 00:02:49,336 +DNS 流量最初是未加密的 + +38 +00:02:49,369 --> 00:02:55,909 +为了成为构建在它顶部的协议的 +安全起点 + +39 +00:02:55,943 --> 00:03:01,882 +DNS 需要经过身份验证和加密 + +40 +00:03:01,915 --> 00:03:05,886 +当我们使用 DNSSEC +签署 DNS 响应时 + +41 +00:03:05,919 --> 00:03:09,289 +它会提供身份验证 + +42 +00:03:09,323 --> 00:03:15,395 +当我们使用 TLS 和 HTTPS +来加密 DNS 解析时 + +43 +00:03:15,429 --> 00:03:18,365 +它保证了隐私 + +44 +00:03:18,398 --> 00:03:23,203 +接下来 让我们谈谈 DNSSEC + +45 +00:03:23,237 --> 00:03:27,608 +DNSSEC 是由 IETF 创建的 + +46 +00:03:27,641 --> 00:03:30,577 +一套扩展规范 + +47 +00:03:30,611 --> 00:03:35,082 +许多 DNS 服务提供商 +已经可以支持它的使用 + +48 +00:03:35,115 --> 00:03:38,986 +但另一方面 +客户端支持仍在增加 + +49 +00:03:39,019 --> 00:03:42,422 +iOS 16 和 macOS Ventura + +50 +00:03:42,456 --> 00:03:47,828 +现在支持客户端 DNSSEC 验证 + +51 +00:03:47,861 --> 00:03:53,967 +DNSSEC 通过添加数字签名 +来保证数据的身份验证 + +52 +00:03:54,001 --> 00:03:57,337 +它能保护数据的完整性 + +53 +00:03:57,371 --> 00:04:00,541 +当答案不存在时 + +54 +00:04:00,574 --> 00:04:03,977 +它能验证其真实性 + +55 +00:04:04,011 --> 00:04:09,316 +它还提供加密身份验证 + +56 +00:04:09,349 --> 00:04:12,920 +DNSSEC 通过在响应中 + +57 +00:04:12,953 --> 00:04:17,024 +附加签名来保护数据完整性 + +58 +00:04:17,057 --> 00:04:20,294 +如果响应被攻击者更改 + +59 +00:04:20,327 --> 00:04:26,567 +更改数据的签名将与原始数据不匹配 + +60 +00:04:26,600 --> 00:04:33,507 +在这种情况下 客户端可以检测到 +更改的响应并将其丢弃 + +61 +00:04:33,540 --> 00:04:37,277 +DNSSEC 还通过 + +62 +00:04:37,311 --> 00:04:40,848 +使用特殊类型的 DNS 记录 + +63 +00:04:40,881 --> 00:04:44,051 +如 NSEC 记录 来明确判断区域中 + +64 +00:04:44,084 --> 00:04:47,921 +记录的存在和不存在 + +65 +00:04:47,955 --> 00:04:52,826 +NSEC 记录会按字母顺序安全地告诉你 + +66 +00:04:52,860 --> 00:04:56,663 +下一个记录名称 + +67 +00:04:56,697 --> 00:05:01,401 +它列出的是存在的名称 + +68 +00:05:01,435 --> 00:05:06,273 +任何未列出的名称都不存在 + +69 +00:05:06,306 --> 00:05:10,777 +例如 我们这里有三条 NSEC 记录 + +70 +00:05:10,811 --> 00:05:17,184 +记录集显示 +zone org 只有三个记录名称 + +71 +00:05:17,217 --> 00:05:20,687 +A.org C.org 和 E.org + +72 +00:05:20,721 --> 00:05:27,728 +现在 如果有攻击者声称 A.org 不存在 + +73 +00:05:27,761 --> 00:05:31,164 +那客户端可以检测到这种攻击 + +74 +00:05:31,198 --> 00:05:33,834 +A.org 确实存在 + +75 +00:05:33,867 --> 00:05:39,873 +因为它被列在第一个 NSEC 记录中 + +76 +00:05:39,907 --> 00:05:45,946 +同样 如果攻击者说 D.org 存在 + +77 +00:05:45,979 --> 00:05:49,449 +客户端也可以检测到 + +78 +00:05:49,483 --> 00:05:53,220 +因为根据第二个 NSEC 记录 + +79 +00:05:53,253 --> 00:05:57,824 +D.org 在 C.org 和 E.org 之间 + +80 +00:05:57,858 --> 00:06:03,030 +这两个名字之间不应该有名字 + +81 +00:06:03,063 --> 00:06:09,369 +DNSSEC 通过建立信任链来认证记录 + +82 +00:06:09,403 --> 00:06:12,339 +这里有一个例子 + +83 +00:06:12,372 --> 00:06:17,344 +设备希望在 +启用 DNSSEC 验证的情况下 + +84 +00:06:17,377 --> 00:06:21,515 +解析 www.example.org + +85 +00:06:21,548 --> 00:06:25,085 +它发送查询请求 IP 地址 + +86 +00:06:25,118 --> 00:06:28,288 +签名和密钥 + +87 +00:06:28,322 --> 00:06:32,893 +通过响应 可以从 IP 地址 + +88 +00:06:32,926 --> 00:06:37,197 +到密钥 1 建立信任关系 + +89 +00:06:37,231 --> 00:06:42,436 +然后客户端向父区域 org 发送查询 + +90 +00:06:42,469 --> 00:06:47,774 +请求可以用来验证密钥 1 的记录 + +91 +00:06:47,808 --> 00:06:53,680 +这样它就可以建立 +从密钥 1 到密钥 2 的信任关系 + +92 +00:06:53,714 --> 00:06:58,418 +因此设备递归地重复这个过程 + +93 +00:06:58,452 --> 00:07:01,355 +直到它到达根节点 + +94 +00:07:01,388 --> 00:07:06,627 +现在如果根密钥 (图中的密钥 3) +可以被信任 + +95 +00:07:06,660 --> 00:07:12,466 +那么从 IP 地址 +到密钥 3 的信任关系 + +96 +00:07:12,499 --> 00:07:16,370 +就可以被验证 + +97 +00:07:16,403 --> 00:07:21,875 +根密钥的哈希值总是安全地 +存储在设备中 + +98 +00:07:21,909 --> 00:07:26,380 +在 DNSSEC 中 它被称为根信任锚 + +99 +00:07:26,413 --> 00:07:31,952 +如果 密钥 3 的哈希值 +与预安装的锚匹配 + +100 +00:07:31,985 --> 00:07:35,822 +则可以安全地建立信任链 + +101 +00:07:35,856 --> 00:07:37,658 +有了信任链 + +102 +00:07:37,691 --> 00:07:44,698 +www.example.org 的 IP 地址 +现在得到了验证 + +103 +00:07:45,432 --> 00:07:50,504 +如果你想在 App 中 +要求 DNSSEC 验证 + +104 +00:07:50,537 --> 00:07:54,274 +请执行以下操作 + +105 +00:07:54,308 --> 00:07:58,245 +支持 IPv6 为你的域名 + +106 +00:07:58,278 --> 00:08:04,618 +在纯 IPv6 环境中 纯 IPv4 地址 + +107 +00:08:04,651 --> 00:08:08,455 +被转换为合成 IPv6 地址 + +108 +00:08:08,488 --> 00:08:12,326 +如果域已签名 + +109 +00:08:12,359 --> 00:08:16,330 +则合成地址无法通过 DNSSEC 验证 + +110 +00:08:16,363 --> 00:08:20,934 +启用 DNSSEC 后 它们将无法访问 + +111 +00:08:20,968 --> 00:08:26,373 +因此 请确保你的域支持 IPv6 + +112 +00:08:26,406 --> 00:08:33,180 +确保你的 DNS 服务提供商 +用 DNSSEC 为你的域签名 + +113 +00:08:33,213 --> 00:08:38,385 +如果你在 App 中启用了 DNSSEC +而没有对你的域进行签名 + +114 +00:08:38,418 --> 00:08:40,587 +你将不会获得任何好处 + +115 +00:08:40,621 --> 00:08:46,627 +但你将获得额外的 DNS 流量 +和延长的解析时间 + +116 +00:08:46,660 --> 00:08:51,632 +来尝试对你未签名的域进行身份验证 + +117 +00:08:51,665 --> 00:08:55,035 +一旦你获得了相应的基础架构支持 + +118 +00:08:55,068 --> 00:09:01,341 +下面是为你的 App +采用 DNSSEC 所需的代码 + +119 +00:09:01,375 --> 00:09:04,845 +如果你是 NSURLSession 客户端 + +120 +00:09:04,878 --> 00:09:10,551 +则可以要求对 URL 请求 +进行 DNSSEC 验证 + +121 +00:09:10,584 --> 00:09:13,420 +这里是一个例子 + +122 +00:09:13,453 --> 00:09:17,858 +你将首先创建默认会话配置 + +123 +00:09:17,891 --> 00:09:23,263 +然后需要 DNSSEC 验证 + +124 +00:09:23,297 --> 00:09:28,969 +接下来 你将使用修改后的配置 +来创建会话 + +125 +00:09:29,002 --> 00:09:33,841 +为此会话创建的所有 URL + +126 +00:09:33,874 --> 00:09:37,544 +请求启用 DNSSEC + +127 +00:09:37,578 --> 00:09:42,716 +如果不想在整个会话中启用 DNSSEC + +128 +00:09:42,749 --> 00:09:46,653 +也可以在请求级别执行此操作 + +129 +00:09:46,687 --> 00:09:50,557 +首先 使用禁用 DNSSEC 验证的 + +130 +00:09:50,591 --> 00:09:54,728 +默认配置创建会话 + +131 +00:09:54,761 --> 00:09:57,297 +然后在请求中启用它 + +132 +00:09:57,331 --> 00:10:01,401 +现在 只有在完成 DNSSEC 验证后 + +133 +00:10:01,435 --> 00:10:06,640 +才会启动此会话任务 + +134 +00:10:06,673 --> 00:10:10,010 +如果你是 +Network.framework 客户端 + +135 +00:10:10,043 --> 00:10:15,816 +你还可以要求 +对你的连接进行 DNSSEC 验证 + +136 +00:10:15,849 --> 00:10:20,287 +首先 当你创建一个参数对象时 + +137 +00:10:20,320 --> 00:10:24,291 +需要 DNSSEC 验证 + +138 +00:10:24,324 --> 00:10:30,364 +然后用参数对象创建 NWConnection + +139 +00:10:30,397 --> 00:10:36,003 +现在 当你启动连接时 +只有在 DNSSEC 验证已完成 + +140 +00:10:36,036 --> 00:10:39,540 +并且建立与已验证 IP 地址的 + +141 +00:10:39,573 --> 00:10:46,113 +连接时 它才会进入就绪状态 + +142 +00:10:46,146 --> 00:10:48,916 +启用 DNSSEC 后 + +143 +00:10:48,949 --> 00:10:55,222 +只有经过验证的地址 +才会用于建立连接 + +144 +00:10:55,255 --> 00:11:01,195 +在 HTTPS 中 错误是通过 API 报告的 + +145 +00:11:01,228 --> 00:11:06,700 +在 DNSSEC 验证失败不会返回错误 + +146 +00:11:06,733 --> 00:11:13,540 +收到验证失败的响应 +等于没有收到任何响应 + +147 +00:11:13,574 --> 00:11:18,245 +如果有 DNS 提供商篡改响应 + +148 +00:11:18,278 --> 00:11:22,616 +地址将无法通过身份验证检查 + +149 +00:11:22,649 --> 00:11:25,652 +因此它们将被直接丢弃 + +150 +00:11:25,686 --> 00:11:30,324 +当设备加入 DNS 提供商 + +151 +00:11:30,357 --> 00:11:33,026 +未篡改响应的新网络时 + +152 +00:11:33,060 --> 00:11:36,230 +验证将再次进行 + +153 +00:11:36,263 --> 00:11:40,534 +解析将自动恢复正常 + +154 +00:11:41,602 --> 00:11:47,841 +以下是一些可能导致 +DNSSEC 故障的情况 + +155 +00:11:47,875 --> 00:11:51,411 +更改原始 DNS 响应时 + +156 +00:11:51,445 --> 00:11:57,184 +不匹配的签名 +将无法通过 DNSSEC 检查 + +157 +00:11:57,217 --> 00:12:00,254 +从而导致验证失败 + +158 +00:12:00,287 --> 00:12:05,626 +当设备不能到达 +任何预先安装的信任锚 + +159 +00:12:05,659 --> 00:12:11,098 +并且不能从中建立信任链时 + +160 +00:12:11,131 --> 00:12:13,934 +当网络不支持 + +161 +00:12:13,967 --> 00:12:18,739 +DNSSEC 要求的必要协议时 + +162 +00:12:18,772 --> 00:12:24,811 +如 TCP 上的 DNS 和 EDNS0 选项 + +163 +00:12:24,845 --> 00:12:30,284 +会携带 DNSSEC 启用位 + +164 +00:12:30,317 --> 00:12:35,389 +当签名域不支持 IPv6 时 + +165 +00:12:35,422 --> 00:12:38,759 +由互联网服务提供商提供的 + +166 +00:12:38,792 --> 00:12:45,098 +合成 IPv6 地址将无法通过验证 + +167 +00:12:45,132 --> 00:12:52,139 +这就是如何使用 DNSSEC +对 DNS 响应进行身份验证 + +168 +00:12:52,172 --> 00:12:55,576 +但如果它们仍然未加密 + +169 +00:12:55,609 --> 00:12:59,413 +那网络上的任何人都可以看到它们 + +170 +00:12:59,446 --> 00:13:02,416 +接下来 我们将谈一谈 + +171 +00:13:02,449 --> 00:13:07,788 +如何用 DDR 自动启用 DNS 加密 + +172 +00:13:09,122 --> 00:13:12,926 +在 iOS 14 和 macOS Big Sur 中 + +173 +00:13:12,960 --> 00:13:19,533 +我们引入了加密 DNS +来帮助保护隐私 + +174 +00:13:19,566 --> 00:13:24,137 +你可以使用 App 中的 +NEDNSSettingsManager + +175 +00:13:24,171 --> 00:13:27,708 +或配置文件中的 DNSSettings + +176 +00:13:27,741 --> 00:13:32,779 +手动配置系统范围内的加密 DNS + +177 +00:13:32,813 --> 00:13:36,250 +你还可以使用 NWParameters 上的 + +178 +00:13:36,283 --> 00:13:41,455 +PrivacyContext 为你的 App +选择加密 DNS + +179 +00:13:41,488 --> 00:13:47,661 +更多有关信息 请观看 +“启用加密的 DNS” + +180 +00:13:47,694 --> 00:13:51,932 +iOS 16 和 macOS Ventura 中 +新增了可以自动使用的 + +181 +00:13:51,965 --> 00:13:56,103 +加密 DNS + +182 +00:13:56,136 --> 00:14:03,143 +如果你的网络支持指定解析器的发现 +也称为 DDR + +183 +00:14:03,177 --> 00:14:09,983 +DNS 查询将自动使用 TLS 或 HTTPS + +184 +00:14:10,017 --> 00:14:12,819 +要使用加密 DNS + +185 +00:14:12,853 --> 00:14:15,289 +你的设备就需要知道 + +186 +00:14:15,322 --> 00:14:21,662 +解析器支持 TLS 或 HTTPS + +187 +00:14:21,695 --> 00:14:28,669 +并且可能还需要 +了解端口或 URL 路径 + +188 +00:14:28,702 --> 00:14:35,409 +常见的机制 +如 DHCP 或路由器广告 + +189 +00:14:35,442 --> 00:14:40,180 +只提供普通的 IP 地址 + +190 +00:14:40,214 --> 00:14:46,053 +DDR 是由 Apple +和其他行业合作伙伴 + +191 +00:14:46,086 --> 00:14:49,556 +在 IETF 中开发的新协议 + +192 +00:14:49,590 --> 00:14:55,662 +它为 DNS 客户端提供了一种 + +193 +00:14:55,696 --> 00:14:59,399 +通过使用特殊的 DNS 查询 +来了解这些必要信息的方法 + +194 +00:14:59,433 --> 00:15:02,970 +当你的设备加入一个新的网络时 + +195 +00:15:03,003 --> 00:15:05,839 +它会发出一个 _dns.resolver.arpa 的 + +196 +00:15:05,873 --> 00:15:10,777 +服务绑定查询 + +197 +00:15:10,811 --> 00:15:13,914 +如果 DNS 服务器支持 DDR + +198 +00:15:13,947 --> 00:15:18,218 +它将回复一个或多个配置 + +199 +00:15:18,252 --> 00:15:22,122 +然后 设备使用此信息 + +200 +00:15:22,155 --> 00:15:28,028 +建立到指定解析器的加密连接 + +201 +00:15:28,061 --> 00:15:33,300 +它验证未加密解析程序的 IP 地址 + +202 +00:15:33,333 --> 00:15:38,639 +是否包含在 +指定解析程序的 TLS 证书中 + +203 +00:15:38,672 --> 00:15:43,410 +这样做是为了确保未加密的解析器 + +204 +00:15:43,443 --> 00:15:47,581 +和加密的解析器属于同一个实体 + +205 +00:15:47,614 --> 00:15:54,087 +如果一切正常 +设备现在默认使用加密 DNS + +206 +00:15:55,088 --> 00:15:59,693 +DDR 一次只适用于单个网络 + +207 +00:15:59,726 --> 00:16:04,665 +只有在当前网络支持的情况下 + +208 +00:16:04,698 --> 00:16:09,369 +你的设备才会自动使用加密 DNS + +209 +00:16:09,403 --> 00:16:14,441 +同样重要的是要注意 +如果你的 DNS 服务器的 IP 地址 + +210 +00:16:14,474 --> 00:16:20,013 +是私有 IP 地址 那么 DDR 将不起作用 + +211 +00:16:20,047 --> 00:16:23,383 +这是因为 TLS 证书中 + +212 +00:16:23,417 --> 00:16:27,521 +不允许此类 IP 地址 + +213 +00:16:27,554 --> 00:16:32,125 +因为无法验证它们的所有权 + +214 +00:16:32,159 --> 00:16:36,330 +在 iOS 16 和 macOS Ventura 中 + +215 +00:16:36,363 --> 00:16:41,869 +我们还支持在使用 +加密 DNS 进行配置设置时 + +216 +00:16:41,902 --> 00:16:45,939 +使用 NEDNSSettingsManager +或 DNSSettings 配置文件 + +217 +00:16:45,973 --> 00:16:52,179 +来指定客户端验证的能力 + +218 +00:16:53,180 --> 00:16:58,085 +客户端身份验证允许在企业环境中 +使用加密 DNS 服务器 + +219 +00:16:58,118 --> 00:17:00,587 +在这种环境中 + +220 +00:17:00,621 --> 00:17:06,960 +服务器需要在允许访问之前 +验证客户端 + +221 +00:17:06,994 --> 00:17:10,430 +现在你可以使用 NEDNSSettings 的 + +222 +00:17:10,464 --> 00:17:16,003 +identityReference 属性 +来配置客户端证书 + +223 +00:17:16,036 --> 00:17:22,676 +这就像 VPN 的客户端证书一样 + +224 +00:17:22,709 --> 00:17:26,647 +这些规定适用于 TLS 上的 DNS + +225 +00:17:26,680 --> 00:17:30,617 +和 HTTPS 上的 DNS + +226 +00:17:30,651 --> 00:17:35,489 +这是保护 DNS 的路径 + +227 +00:17:35,522 --> 00:17:38,859 +使用 DNSSEC 对你的域进行签名 + +228 +00:17:38,892 --> 00:17:43,297 +并要求在你的 App 中 +进行 DNSSEC 验证 + +229 +00:17:43,330 --> 00:17:47,234 +以验证你的 IP 地址 + +230 +00:17:47,267 --> 00:17:50,237 +在网络上启用 DDR + +231 +00:17:50,270 --> 00:17:55,876 +以便客户端可以自动切换到 +加密 DNS + +232 +00:17:55,909 --> 00:17:58,879 +以此更好地保护用户隐私 + +233 +00:17:58,912 --> 00:18:02,749 +在需要更好地访问控制的企业中 + +234 +00:18:02,783 --> 00:18:06,687 +采用客户端身份验证 + +235 +00:18:06,720 --> 00:18:10,824 +我期待将来能有一个 +由你帮忙建立的 + +236 +00:18:10,858 --> 00:18:14,828 +更安全的 DNS 基础 + +237 +00:18:14,862 --> 00:18:16,263 +感谢收看 + +238 +00:18:16,296 --> 00:18:20,300 +[欢快的音乐] + diff --git a/zho/2022 Session 10082 Track down hangs with Xcode and on-device detection.srt b/zho/2022 Session 10082 Track down hangs with Xcode and on-device detection.srt new file mode 100644 index 0000000..ea5f2ec --- /dev/null +++ b/zho/2022 Session 10082 Track down hangs with Xcode and on-device detection.srt @@ -0,0 +1,1508 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,376 +♪ + +3 +00:00:09,376 --> 00:00:12,079 +大家好 +我是 John Crowson + +4 +00:00:12,079 --> 00:00:14,414 +我是 Apple 性能工具团队的 + +5 +00:00:14,414 --> 00:00:15,682 +软件工程师 + +6 +00:00:15,682 --> 00:00:17,451 +在本次讲座中 +我将向您介绍几个新工具 + +7 +00:00:17,451 --> 00:00:20,554 +它们可以用 Xcode +和设备上的卡顿检测 + +8 +00:00:20,554 --> 00:00:24,258 +来跟踪 App 中的卡顿 + +9 +00:00:24,258 --> 00:00:26,360 +我将作为您的向导 带领您参观 +App 开发过程的不同阶段 + +10 +00:00:26,360 --> 00:00:29,363 +并考虑在每个阶段 + +11 +00:00:29,363 --> 00:00:32,266 +最适合提供帮助的工具是什么 + +12 +00:00:32,266 --> 00:00:35,235 +本次讲座分为四个部分 + +13 +00:00:35,235 --> 00:00:38,405 +首先 我将介绍 什么是卡顿 + +14 +00:00:38,405 --> 00:00:40,774 +然后 我将介绍一些工具 帮助您在 + +15 +00:00:40,774 --> 00:00:44,912 +开发 App + +16 +00:00:44,912 --> 00:00:49,716 +测试 App 时以及发布 App 后 +发现和诊断卡顿 + +17 +00:00:49,716 --> 00:00:52,619 +让我们现在开始吧 + +18 +00:00:52,619 --> 00:00:55,455 +我想分享我团队 +正在开发的一个新 App + +19 +00:00:55,455 --> 00:00:58,025 +“食品车”它将有助于管理 + +20 +00:00:58,025 --> 00:01:00,694 +专门销售甜甜圈的食品车 + +21 +00:01:00,694 --> 00:01:04,398 +来看看我创建的甜甜圈类型 + +22 +00:01:07,868 --> 00:01:09,837 +滚动浏览我的甜甜圈列表 + +23 +00:01:09,837 --> 00:01:11,839 +确实要花不少时间 + +24 +00:01:11,839 --> 00:01:15,809 +该 App 运行缓慢 +没有响应我的任何触碰 + +25 +00:01:15,809 --> 00:01:20,047 +在 Apple 我们将这段 +无响应的时间称为“卡顿” + +26 +00:01:20,047 --> 00:01:22,616 +App 的主线程负责处理 + +27 +00:01:22,616 --> 00:01:26,119 +用户交互和更新视图内容 + +28 +00:01:26,119 --> 00:01:29,556 +当主线程忙于工作 + +29 +00:01:29,556 --> 00:01:32,759 +或等待另一个线程或系统资源 + +30 +00:01:32,759 --> 00:01:35,295 +导致更新视图内容 + +31 +00:01:35,295 --> 00:01:39,233 +至少延迟 250 毫秒时 +会报告卡顿 + +32 +00:01:39,233 --> 00:01:41,068 +在卡顿解决之前 + +33 +00:01:41,068 --> 00:01:46,006 +主线程也无法处理新的用户交互 + +34 +00:01:46,006 --> 00:01:51,378 +在用户看来 +App 看上去完全卡死了 + +35 +00:01:51,378 --> 00:01:52,880 +创建响应灵敏的 App + +36 +00:01:52,880 --> 00:01:56,717 +对于提高用户体验至关重要 + +37 +00:01:56,717 --> 00:01:59,520 +持续无响应的 App +可能会导致用户 + +38 +00:01:59,520 --> 00:02:03,123 +强制退出 App +切换到其他 App + +39 +00:02:03,123 --> 00:02:05,559 +在某些情况下 +甚至删除您的 App + +40 +00:02:05,559 --> 00:02:08,061 +并写负面评价 + +41 +00:02:08,061 --> 00:02:10,697 +因此 跟踪您的 App 中的卡顿 + +42 +00:02:10,697 --> 00:02:15,202 +对于积累和维护您的用户群体 +至关重要 + +43 +00:02:15,202 --> 00:02:17,504 +提供即时响应的体验可让用户 + +44 +00:02:17,504 --> 00:02:19,973 +会更愿意使用您的 App + +45 +00:02:21,975 --> 00:02:24,778 +有关卡顿及其原因的更多信息 + +46 +00:02:24,778 --> 00:02:27,514 +以及从代码中消除它们的方法 + +47 +00:02:27,514 --> 00:02:30,217 +请查看 WWDC 2021 + +48 +00:02:30,217 --> 00:02:32,819 +“理解和消除 App 中的卡顿” + +49 +00:02:32,819 --> 00:02:34,087 +App 的开发过程 + +50 +00:02:34,087 --> 00:02:36,723 +可以分为三个阶段 + +51 +00:02:36,723 --> 00:02:41,395 +首先 使用 Xcode 在桌面上 +开发最新的 App 版本 + +52 +00:02:41,395 --> 00:02:43,997 +然后 在没有 Xcode 的 +测试环境中 + +53 +00:02:43,997 --> 00:02:46,967 +测试 App 并收集反馈 + +54 +00:02:46,967 --> 00:02:48,836 +例如 您可能有一个 App 版本 + +55 +00:02:48,836 --> 00:02:50,971 +是在您的设备上开发的 或是通过 + +56 +00:02:50,971 --> 00:02:53,540 +TestFlight 分发的 + +57 +00:02:53,540 --> 00:02:57,678 +最后 在 App Store 上 +发布最新的 App 版本 + +58 +00:02:57,678 --> 00:02:59,913 +即使对于最积极主动的开发者 + +59 +00:02:59,913 --> 00:03:02,583 +新的卡顿问题也可能 +会出现在任何情况下 + +60 +00:03:02,583 --> 00:03:05,085 +所以知道在各个阶段 +帮助定位卡顿的工具 + +61 +00:03:05,085 --> 00:03:07,120 +是非常重要的 + +62 +00:03:07,120 --> 00:03:09,857 +在 iOS 16 和 +Xcode 14 之前 + +63 +00:03:09,857 --> 00:03:12,626 +我们提供了两种帮助发现和诊断 + +64 +00:03:12,626 --> 00:03:14,995 +App 中卡顿的工具 + +65 +00:03:14,995 --> 00:03:17,698 +MetricKit +是一个支持收集卡顿率指标 + +66 +00:03:17,698 --> 00:03:21,201 +和反馈诊断报告的框架 + +67 +00:03:21,201 --> 00:03:26,106 +可用于您的 Beta 版 +或公开发布的 App + +68 +00:03:26,106 --> 00:03:29,776 +Xcode Organizer +会收集用户在使用 + +69 +00:03:29,776 --> 00:03:32,946 +您公开发布的 App 时 +产生的卡顿率数据 + +70 +00:03:32,946 --> 00:03:35,782 +这里存在一些差距 + +71 +00:03:35,782 --> 00:03:39,052 +特别是在开发 App 或试图理解 + +72 +00:03:39,052 --> 00:03:43,657 +什么源代码 +导致公开发布卡顿率指标上升时 + +73 +00:03:43,657 --> 00:03:46,226 +在 iOS 16 和 +Xcode 14 中 + +74 +00:03:46,226 --> 00:03:50,697 +我们致力于引入新工具来提供帮助 + +75 +00:03:50,697 --> 00:03:52,799 +在我们更详细介绍这些工具之前 + +76 +00:03:52,799 --> 00:03:55,669 +让我先简要地概述一下 + +77 +00:03:55,669 --> 00:03:57,938 +在调试 App 时 +Xcode 中的线程性能检查器 + +78 +00:03:57,938 --> 00:04:00,407 +会在没有主动跟踪的情况下 + +79 +00:04:00,407 --> 00:04:04,578 +提醒您引起线程卡顿的问题 + +80 +00:04:04,578 --> 00:04:07,915 +Xcode 中的 Instruments +在跟踪您的 + +81 +00:04:07,915 --> 00:04:10,484 +App 时可以检测并标注卡顿 + +82 +00:04:10,484 --> 00:04:13,420 +设备上的卡顿检测 +可以提供卡顿检测 + +83 +00:04:13,420 --> 00:04:16,256 +而无需 Xcode 和跟踪 + +84 +00:04:16,256 --> 00:04:18,458 +提供实时卡顿通知 + +85 +00:04:18,458 --> 00:04:20,827 +并在使用您开发签名或 + +86 +00:04:20,827 --> 00:04:24,164 +TestFlight App 时 +支持诊断 + +87 +00:04:24,164 --> 00:04:26,400 +最后 Xcode 中的 Organizer + +88 +00:04:26,400 --> 00:04:29,036 +现在支持卡顿报告 它将提供 + +89 +00:04:29,036 --> 00:04:33,373 +用户在实际使用中汇总的卡顿率数据 + +90 +00:04:33,373 --> 00:04:35,108 +现在您知道什么是卡顿 + +91 +00:04:35,108 --> 00:04:37,077 +以及它们可能出现的不同阶段 + +92 +00:04:37,077 --> 00:04:39,313 +接下来我将介绍在使用 Xcode + +93 +00:04:39,313 --> 00:04:43,350 +开发 App 时如何追踪卡顿 + +94 +00:04:43,350 --> 00:04:46,620 +在 Xcode 14 中 +当新的线程性能检查工具检测到 + +95 +00:04:46,620 --> 00:04:49,823 +您的 App 主线程中存在 +优先级反转和非 UI 工作时 + +96 +00:04:49,823 --> 00:04:52,426 +它会在 Xcode 问题导航器中 + +97 +00:04:52,426 --> 00:04:54,328 +通知您 + +98 +00:04:54,328 --> 00:04:58,298 +这两种情况都是导致卡顿的常见原因 + +99 +00:04:58,298 --> 00:04:59,633 +我现在已经回到 Xcode + +100 +00:04:59,633 --> 00:05:03,036 +来诊断我之前滚动浏览甜甜圈列表时 + +101 +00:05:03,036 --> 00:05:06,607 +发现的食品车 App 卡顿问题 + +102 +00:05:06,607 --> 00:05:08,375 +当我构建并运行 App + +103 +00:05:08,375 --> 00:05:10,577 +并重复用户交互时 + +104 +00:05:10,577 --> 00:05:13,714 +线程性能检查器工具提醒我 + +105 +00:05:13,714 --> 00:05:16,984 +由优先级反转引起的卡顿风险 + +106 +00:05:16,984 --> 00:05:19,586 +这意味着更高优先级的线程正在尝试 + +107 +00:05:19,586 --> 00:05:22,556 +与较低优先级的线程同步 + +108 +00:05:22,556 --> 00:05:24,791 +这可能表明我们注意到的卡顿 + +109 +00:05:24,791 --> 00:05:27,861 +是由主线程 + +110 +00:05:27,861 --> 00:05:30,063 +在等待不同的低优先级线程引起的 + +111 +00:05:30,063 --> 00:05:32,599 +为了检测您的 App 主线程上的 + +112 +00:05:32,599 --> 00:05:34,134 +优先级反转和非 UI 工作 + +113 +00:05:34,134 --> 00:05:36,370 +从相应 scheme 的 Diagnostics 部分 + +114 +00:05:36,370 --> 00:05:40,607 +启用Thread Performance Checker 工具 + +115 +00:05:40,607 --> 00:05:43,243 +线程性能检查器警报能帮助我发现 + +116 +00:05:43,243 --> 00:05:45,746 +卡顿潜在的罪魁祸首 + +117 +00:05:45,746 --> 00:05:48,115 +但为了进一步分析 我想知道 + +118 +00:05:48,115 --> 00:05:51,552 +在卡顿期间另一个线程在做什么 + +119 +00:05:51,552 --> 00:05:56,456 +让我们使用另一个工具 +进行更深入的研究 + +120 +00:05:56,456 --> 00:05:58,992 +Time Profiler 工具 +通过提供调用堆栈 + +121 +00:05:58,992 --> 00:06:01,828 +让您能够知道 App 中的 + +122 +00:06:01,828 --> 00:06:04,264 +每个线程在一段时间内做了什么 + +123 +00:06:04,264 --> 00:06:08,235 +Xcode 14 中提供了新功能 +Time Profiler + +124 +00:06:08,235 --> 00:06:12,239 +还可以检测卡顿 +并直接在相应的流程轨迹中进行标注 + +125 +00:06:12,239 --> 00:06:14,741 +在食品车 App 中 我将使用 +Time Profiler + +126 +00:06:14,741 --> 00:06:16,610 +来确认在滚动浏览甜甜圈列表时 + +127 +00:06:16,610 --> 00:06:18,445 +发生卡顿 + +128 +00:06:18,445 --> 00:06:21,682 +卡顿是由于 +主线程上的优先级反转引起的 + +129 +00:06:21,682 --> 00:06:23,784 +我也将找出低优先级线程 + +130 +00:06:23,784 --> 00:06:28,255 +正在忙于做什么导致主线程等待 + +131 +00:06:28,255 --> 00:06:31,325 +打开 Xcode 中的 +Product Profile + +132 +00:06:31,325 --> 00:06:33,327 +这将构建发行版的 App + +133 +00:06:33,327 --> 00:06:37,464 +并启动为目标 App 配置 +好的 Instruments + +134 +00:06:37,464 --> 00:06:40,234 +我启动 Time Profiler 模板 + +135 +00:06:40,234 --> 00:06:43,437 +并开始记录食品车 App 中 + +136 +00:06:43,437 --> 00:06:45,572 +有问题的用户交互 + +137 +00:06:49,543 --> 00:06:51,411 +我看到这里检测到卡顿 + +138 +00:06:51,411 --> 00:06:53,213 +并在时间轴上标注 + +139 +00:06:53,213 --> 00:06:55,115 +卡顿持续时间也会标出 + +140 +00:06:55,115 --> 00:06:58,719 +来帮助评估问题的严重性 + +141 +00:06:58,719 --> 00:07:01,588 +接下来 我可以三击卡顿间隔 + +142 +00:07:01,588 --> 00:07:04,391 +为卡顿的持续时间创建时间过滤器 + +143 +00:07:04,391 --> 00:07:06,793 +并将底部的详细视图中的信息筛选为 + +144 +00:07:06,793 --> 00:07:09,296 +仅在选定的时间间隔内 + +145 +00:07:09,296 --> 00:07:11,431 +发生的事件 + +146 +00:07:11,431 --> 00:07:14,034 +它还可以更轻松地查看 + +147 +00:07:14,034 --> 00:07:17,738 +在此期间其他轨道正在发生的事情 + +148 +00:07:17,738 --> 00:07:19,840 +我首先注意到的是主线程 +在卡顿间隔期 + +149 +00:07:19,840 --> 00:07:23,510 +几乎没有任何 CPU 使用率 + +150 +00:07:23,510 --> 00:07:25,913 +这表示主线程没有响应 + +151 +00:07:25,913 --> 00:07:27,981 +因为它正在等待另一个线程 + +152 +00:07:27,981 --> 00:07:31,285 +而不是因为它本身工作过载 + +153 +00:07:31,285 --> 00:07:33,954 +这与之前线程性能检查器的 + +154 +00:07:33,954 --> 00:07:37,424 +优先级反转警报反馈一致 + +155 +00:07:37,424 --> 00:07:39,159 +然后 我看到一个在卡顿期间 + +156 +00:07:39,159 --> 00:07:42,296 +有很多 CPU 使用率的工作线程 + +157 +00:07:42,296 --> 00:07:46,567 +这可能就是主线程正在等待的线程 + +158 +00:07:46,567 --> 00:07:48,101 +下一步将是检查 + +159 +00:07:48,101 --> 00:07:50,737 +工作线程在卡顿期间在做什么 + +160 +00:07:50,737 --> 00:07:53,640 +并解决优先级反转问题 + +161 +00:07:53,640 --> 00:07:55,442 +Instruments 中的 +卡顿检测和标记 + +162 +00:07:55,442 --> 00:07:58,345 +以很好的方法显示出 + +163 +00:07:58,345 --> 00:08:00,347 +在分析 App 时遇到的任何卡顿 + +164 +00:08:00,347 --> 00:08:02,816 +它在 Time Profiler + +165 +00:08:02,816 --> 00:08:06,019 +和 CPU Profiler 中默认可用 + +166 +00:08:06,019 --> 00:08:09,256 +还有一个新的独立卡顿跟踪工具 + +167 +00:08:09,256 --> 00:08:11,525 +您可以将其添加到任何跟踪文件中 + +168 +00:08:11,525 --> 00:08:15,495 +以便与其他工具结合检测卡顿 + +169 +00:08:15,495 --> 00:08:17,898 +除了卡顿检测和标记 + +170 +00:08:17,898 --> 00:08:20,901 +它还让您配置卡顿持续时间阈值 + +171 +00:08:20,901 --> 00:08:24,838 +找出特定的无响应时期 + +172 +00:08:24,838 --> 00:08:26,773 +您现在已经学会了 +如何使用 Xcode + +173 +00:08:26,773 --> 00:08:30,043 +来发现和诊断卡顿 + +174 +00:08:30,043 --> 00:08:32,846 +即使在开发过程中有很好的测试覆盖 + +175 +00:08:32,846 --> 00:08:35,182 +Beta 版和 +公开发布环境也很可能 + +176 +00:08:35,182 --> 00:08:39,586 +发现您忽略了的 +代码路径中的卡顿 + +177 +00:08:39,586 --> 00:08:42,256 +接下来 我将介绍 一旦 +App 部署在 Beta 环境中 + +178 +00:08:42,256 --> 00:08:45,526 +该如何跟踪卡顿 + +179 +00:08:45,526 --> 00:08:48,161 +我现在已通过 +App Store Connect + +180 +00:08:48,161 --> 00:08:50,430 +将食品车 App 的内部版本 +部署至 TestFlight + +181 +00:08:50,430 --> 00:08:53,400 +也将它下载至我的个人设备上 + +182 +00:08:53,400 --> 00:08:56,303 +我会在城镇售卖甜甜圈时 +测试这个 App + +183 +00:08:56,303 --> 00:08:58,505 +包括在网络连接较弱 + +184 +00:08:58,505 --> 00:09:00,507 +的地方测试 + +185 +00:09:00,507 --> 00:09:03,343 +但如果我的设备 +没有连接到 Xcode + +186 +00:09:03,343 --> 00:09:08,315 +我该如何发现和诊断卡顿呢 + +187 +00:09:08,315 --> 00:09:11,318 +要在这些情况下继续监视卡顿 + +188 +00:09:11,318 --> 00:09:16,123 +iOS 16 在开发者设置中 +引入了设备内卡顿检测 + +189 +00:09:16,123 --> 00:09:18,759 +提供实时卡顿通知 + +190 +00:09:18,759 --> 00:09:21,461 +以及支持诊断 + +191 +00:09:21,461 --> 00:09:23,363 +这可用于开发签名 + +192 +00:09:23,363 --> 00:09:25,766 +或 TestFlight App + +193 +00:09:25,766 --> 00:09:28,435 +是时候开始销售了 + +194 +00:09:28,435 --> 00:09:30,704 +当我尝试打开当前订单时 + +195 +00:09:30,704 --> 00:09:33,473 +我收到设备上卡顿检测通知 + +196 +00:09:33,473 --> 00:09:35,108 +这表示我的 App 卡顿了 + +197 +00:09:35,108 --> 00:09:38,312 +这次卡顿持续了三秒多 + +198 +00:09:38,312 --> 00:09:40,147 +我想知道 +在我使用 Xcode 进行开发时 + +199 +00:09:40,147 --> 00:09:42,749 +为什么我没有注意到这个卡顿 + +200 +00:09:42,749 --> 00:09:45,052 +于是我将需要使用 + +201 +00:09:45,052 --> 00:09:49,389 +设备上卡顿检测工具提供的诊断信息 +以了解更多 + +202 +00:09:49,389 --> 00:09:51,325 +只要你的 App 是为开发而设置的 + +203 +00:09:51,325 --> 00:09:52,993 +该功能可以通过打开 + +204 +00:09:52,993 --> 00:09:55,729 +设置 开发者 卡顿检测 + +205 +00:09:55,729 --> 00:09:58,799 +并切换开关来启用 + +206 +00:09:58,799 --> 00:10:00,634 +卡顿阈值可设置 + +207 +00:10:00,634 --> 00:10:03,303 +要检测的卡顿的最短持续时间 + +208 +00:10:03,303 --> 00:10:06,540 +最短卡顿阈值为 250 毫秒 + +209 +00:10:06,540 --> 00:10:10,010 +并且可提高到 500 毫秒或更高 + +210 +00:10:10,010 --> 00:10:12,813 +长时间卡顿往往会对用户 +产生更大的影响 + +211 +00:10:12,813 --> 00:10:15,849 +但即便是更短时间的卡顿 +也可能会破坏用户使用体验 + +212 +00:10:15,849 --> 00:10:17,518 +这取决于上下文 + +213 +00:10:17,518 --> 00:10:20,287 +特别是当它们连续发生时 + +214 +00:10:20,287 --> 00:10:21,622 +安装您的 App 后 + +215 +00:10:21,622 --> 00:10:24,725 +它将出现在监控 App 列表 + +216 +00:10:24,725 --> 00:10:27,294 +最后一部分为您已收到警告的 + +217 +00:10:27,294 --> 00:10:30,764 +按时间顺序排列的卡顿列表 + +218 +00:10:30,764 --> 00:10:33,200 +请注意 这些诊断是尽力而为的 + +219 +00:10:33,200 --> 00:10:36,036 +并在后台以低优先级处理 + +220 +00:10:36,036 --> 00:10:39,072 +以最小化性能开销 + +221 +00:10:39,072 --> 00:10:41,241 +这意味着处理可能需要更长的时间 + +222 +00:10:41,241 --> 00:10:44,378 +特别是在系统繁忙的情况下 + +223 +00:10:44,378 --> 00:10:47,047 +幸运的是 当新的诊断可用时 + +224 +00:10:47,047 --> 00:10:50,284 +被动通知会被显示 + +225 +00:10:50,284 --> 00:10:53,620 +让我们来查看一下 + +226 +00:10:53,620 --> 00:10:55,589 +当我在镇上卖甜甜圈时 + +227 +00:10:55,589 --> 00:10:58,592 +在 App 中打开订单 +检测到的卡顿诊断 + +228 +00:10:58,592 --> 00:11:00,761 +我得到了基于文本的卡顿日志 + +229 +00:11:00,761 --> 00:11:03,597 +和用于检测卡顿的 tailspin + +230 +00:11:03,597 --> 00:11:06,066 +基于文本的卡顿日志信息较少 + +231 +00:11:06,066 --> 00:11:08,202 +但可以让我们一眼 + +232 +00:11:08,202 --> 00:11:10,070 +就了解到卡顿 + +233 +00:11:10,070 --> 00:11:12,606 +要进行更深入的研究 +打开 Instruments 中的 tailspin + +234 +00:11:12,606 --> 00:11:15,642 +查看进程中的线程交互 + +235 +00:11:15,642 --> 00:11:19,413 +或识别系统资源的使用情况 + +236 +00:11:19,413 --> 00:11:21,381 +之类的内容 + +237 +00:11:21,381 --> 00:11:23,217 +首先 我将使用“分享”按钮 + +238 +00:11:23,217 --> 00:11:25,652 +将基于文本的卡顿日志 +发送到 Mac + +239 +00:11:25,652 --> 00:11:30,424 +以便我符号化和在更大的屏幕上查看 + +240 +00:11:30,424 --> 00:11:33,126 +从查看我转移和标记的 +基于文本的卡顿日志摘录 + +241 +00:11:33,126 --> 00:11:36,396 +可以看到在卡顿期间 + +242 +00:11:36,396 --> 00:11:38,532 +我在主线程上调用一个方法 + +243 +00:11:38,532 --> 00:11:42,736 +我知道该方法执行对网络的同步请求 + +244 +00:11:42,736 --> 00:11:44,805 +当我在桌面上和 +网络连接良好的环境下 + +245 +00:11:44,805 --> 00:11:47,674 +使用 Xcode 测试 App 时 + +246 +00:11:47,674 --> 00:11:49,076 +从网络请求数据 + +247 +00:11:49,076 --> 00:11:51,645 +可能不会有任何延迟 + +248 +00:11:51,645 --> 00:11:53,881 +但是 在某些网络连接受限的地方 + +249 +00:11:53,881 --> 00:11:55,849 +测试 App 时 + +250 +00:11:55,849 --> 00:12:00,087 +该请求需要更长的时间并会导致卡顿 + +251 +00:12:00,087 --> 00:12:02,256 +在这些不同的真实条件下 + +252 +00:12:02,256 --> 00:12:04,625 +测试 App 的 Beta 版很重要 + +253 +00:12:04,625 --> 00:12:07,761 +且设备上卡顿检测仅允许 + +254 +00:12:07,761 --> 00:12:10,664 +您使用自己的设备来监控卡顿 + +255 +00:12:10,664 --> 00:12:13,500 +至此 我已经使用开发和测试阶段 + +256 +00:12:13,500 --> 00:12:16,870 +可用的工具来发现并诊断出卡顿 + +257 +00:12:16,870 --> 00:12:19,306 +我已准备将食品车 App + +258 +00:12:19,306 --> 00:12:22,075 +上线至 App Store + +259 +00:12:22,075 --> 00:12:24,711 +我现在将介绍当您的 App + +260 +00:12:24,711 --> 00:12:26,513 +上线后 该如何跟踪卡顿 + +261 +00:12:26,513 --> 00:12:28,048 +在不同的操作系统版本 + +262 +00:12:28,048 --> 00:12:30,584 +设备和其他现实环境中 + +263 +00:12:30,584 --> 00:12:35,856 +您可能无法在之前的测试中复现 + +264 +00:12:35,856 --> 00:12:38,892 +Xcode 14 中的新功能 +Xcode Organizer + +265 +00:12:38,892 --> 00:12:42,763 +能够从用户设备收集卡顿数据 + +266 +00:12:42,763 --> 00:12:46,333 +并展示卡顿报告和诊断 + +267 +00:12:46,333 --> 00:12:49,036 +收集的数据来自已同意 + +268 +00:12:49,036 --> 00:12:51,839 +共享 App 分析的用户设备 + +269 +00:12:51,839 --> 00:12:57,377 +数据包含导致卡顿的 +主线程堆栈跟踪信息 + +270 +00:12:57,377 --> 00:13:00,614 +可在 Xcode Organizer + +271 +00:13:00,614 --> 00:13:03,750 +的左侧导航器中查看卡顿报告 + +272 +00:13:03,750 --> 00:13:05,786 +当收集到类似的堆栈跟踪时 + +273 +00:13:05,786 --> 00:13:09,556 +将它们组合在一起形成单个签名 + +274 +00:13:09,556 --> 00:13:11,925 +在列表中 + +275 +00:13:11,925 --> 00:13:14,428 +签名是根据用户影响排序的 + +276 +00:13:14,428 --> 00:13:18,031 +对于每个签名 +您可以找到一些示例卡顿日志 + +277 +00:13:18,031 --> 00:13:20,934 +每个卡顿日志都包含主线程堆栈跟踪 + +278 +00:13:20,934 --> 00:13:24,872 +其中包含导致卡顿的代码 +卡顿持续时间 + +279 +00:13:24,872 --> 00:13:28,642 +以及生成日志的设备和操作系统版本 + +280 +00:13:28,642 --> 00:13:32,145 +每个签名还提供关于签名 + +281 +00:13:32,145 --> 00:13:35,449 +相关的卡顿日志数量的 +汇总统计信息 + +282 +00:13:35,449 --> 00:13:39,386 +并按操作系统版本和设备 +细分这些日志 + +283 +00:13:39,386 --> 00:13:42,289 +要确定对您的用户影响最大的卡顿 + +284 +00:13:42,289 --> 00:13:45,692 +请密切留意您的排名靠前的签名 + +285 +00:13:45,692 --> 00:13:49,663 +在本例中 顶部签名 + +286 +00:13:49,663 --> 00:13:53,267 +占用该版本中 21% 的卡顿时间 + +287 +00:13:53,267 --> 00:13:55,169 +由于我已向 App Store +提交了带有符号信息的 App + +288 +00:13:55,169 --> 00:13:58,005 +卡顿报告显示了所有函数的名称 + +289 +00:13:58,005 --> 00:14:02,342 +就像它们在源代码中一样 + +290 +00:14:02,342 --> 00:14:05,812 +通过检查 +这个主线程调用堆栈中的函数 + +291 +00:14:05,812 --> 00:14:08,882 +我可以推断这个卡顿 +是由于在主线程上 + +292 +00:14:08,882 --> 00:14:11,618 +从磁盘同步读取文件引起的 + +293 +00:14:11,618 --> 00:14:15,956 +我们知道这会阻塞主线程很长时间 + +294 +00:14:15,956 --> 00:14:18,091 +解决对用户影响最大的性能问题 + +295 +00:14:18,091 --> 00:14:20,093 +至关重要 + +296 +00:14:20,093 --> 00:14:23,664 +Organizer 是定位这种问题的好工具 + +297 +00:14:23,664 --> 00:14:25,899 +在每个 App 发布后 +检查这些数据 + +298 +00:14:25,899 --> 00:14:28,635 +以确认之前的卡顿问题已被解决 + +299 +00:14:28,635 --> 00:14:31,738 +并处理可能出现的新卡顿问题 + +300 +00:14:33,740 --> 00:14:36,109 +您还可以通过 +App Store Connect REST API + +301 +00:14:36,109 --> 00:14:39,146 +检索相同的卡顿报告数据 + +302 +00:14:39,146 --> 00:14:41,148 +这可以帮助您将性能数据 + +303 +00:14:41,148 --> 00:14:45,118 +与您自己的系统集成 +或运行其他分析 + +304 +00:14:45,118 --> 00:14:46,887 +我强烈建议您查看 + +305 +00:14:46,887 --> 00:14:50,224 +“Identify trends with the +Power and Performance API” 讲座 + +306 +00:14:50,224 --> 00:14:54,394 +了解更多有关使用 +Power and Performance API 的信息 + +307 +00:14:54,394 --> 00:14:58,465 +从 Xcode 13.2 起 + +308 +00:14:58,465 --> 00:15:02,536 +当您在 App 中监控功耗 +和性能指标时 可接收通知 + +309 +00:15:02,536 --> 00:15:04,571 +建议从 Xcode Organizer + +310 +00:15:04,571 --> 00:15:07,307 +的 Regression 视图 + +311 +00:15:07,307 --> 00:15:10,511 +点击右上角的通知按钮启用通知 + +312 +00:15:10,511 --> 00:15:14,515 +这将提醒您注意 +App 卡顿率的突然上升 + +313 +00:15:14,515 --> 00:15:16,650 +可在 2021 年的 + +314 +00:15:16,650 --> 00:15:19,653 +“诊断 App 中的功耗 +和性能回归”讲座 + +315 +00:15:19,653 --> 00:15:21,755 +了解更多信息 + +316 +00:15:21,755 --> 00:15:24,424 +为了改善您的 +Xcode Organizer 使用体验 + +317 +00:15:24,424 --> 00:15:27,461 +我强烈建议您构建并提交 App + +318 +00:15:27,461 --> 00:15:30,564 +到 App Store 时包含符号信息 + +319 +00:15:30,564 --> 00:15:33,333 +此符号信息用于将 App 中的 +函数名添加到 + +320 +00:15:33,333 --> 00:15:36,570 +Xcode Organizer +的报告中 + +321 +00:15:36,570 --> 00:15:37,804 +这大大方便了 + +322 +00:15:37,804 --> 00:15:40,374 +理解堆栈跟踪 + +323 +00:15:40,374 --> 00:15:42,743 +它还支持从堆栈跟踪中的函数名 + +324 +00:15:42,743 --> 00:15:44,478 +到 Xcode 源代码编辑器中 + +325 +00:15:44,478 --> 00:15:47,881 +函数定义的一键式导航 + +326 +00:15:47,881 --> 00:15:49,449 +提取的信息 + +327 +00:15:49,449 --> 00:15:51,585 +仅限于函数和方法 + +328 +00:15:51,585 --> 00:15:53,687 +源代码文件的名称和路径 + +329 +00:15:53,687 --> 00:15:55,656 +以及行号信息 + +330 +00:15:55,656 --> 00:15:58,492 +需要注意的是 有限的符号信息 + +331 +00:15:58,492 --> 00:16:02,296 +将被安全存储并且永远不会被共享 + +332 +00:16:02,296 --> 00:16:03,830 +很好 + +333 +00:16:03,830 --> 00:16:06,033 +您现在知道在开发过程的每个阶段 + +334 +00:16:06,033 --> 00:16:09,603 +如何发现和诊断卡顿 + +335 +00:16:09,603 --> 00:16:11,839 +运行 发现 诊断 + +336 +00:16:11,839 --> 00:16:14,241 +在开发过程的最早阶段 + +337 +00:16:14,241 --> 00:16:16,076 +发现并修复卡顿 + +338 +00:16:16,076 --> 00:16:18,212 +使用可用的工具提供帮助 + +339 +00:16:18,212 --> 00:16:22,816 +包括使用 Instruments +主动分析新功能 + +340 +00:16:22,816 --> 00:16:25,285 +确保启用线程性能检查器 + +341 +00:16:25,285 --> 00:16:28,288 +和设备上卡顿检测 + +342 +00:16:28,288 --> 00:16:31,158 +在每个版本发布后 使用 +Xcode Organizer + +343 +00:16:31,158 --> 00:16:33,827 +来解决最影响用户的卡顿问题 + +344 +00:16:33,827 --> 00:16:36,363 +并验证之前 App 版本的 + +345 +00:16:36,363 --> 00:16:38,565 +卡顿问题是否已经解决 + +346 +00:16:38,565 --> 00:16:41,735 +启用退化通知 + +347 +00:16:41,735 --> 00:16:43,804 +主动提醒性能指标的退化 + +348 +00:16:43,804 --> 00:16:48,008 +这可能是耗电和 +性能问题的第一个迹象 + +349 +00:16:48,008 --> 00:16:50,978 +最后 构建带有符号信息的 App + +350 +00:16:50,978 --> 00:16:52,479 +并提交至 App Store + +351 +00:16:52,479 --> 00:16:55,816 +以提高 +Xcode Organizer 的实用性 + +352 +00:16:55,816 --> 00:16:57,251 +按照这些步骤 + +353 +00:16:57,251 --> 00:16:59,353 +您的 App 将会有更好的性能 + +354 +00:16:59,353 --> 00:17:02,122 +提供最佳的用户体验 + +355 +00:17:02,122 --> 00:17:05,592 +感谢您参加 WWDC + +356 +00:17:05,592 --> 00:17:09,029 +♪ + diff --git a/zho/2022 Session 10083 Power down - Improve battery consumption.srt b/zho/2022 Session 10083 Power down - Improve battery consumption.srt new file mode 100644 index 0000000..dfcd3ee --- /dev/null +++ b/zho/2022 Session 10083 Power down - Improve battery consumption.srt @@ -0,0 +1,1366 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,645 +Vaibhav Gautam: 大家好 +我是 Vaibhav Gautam + +3 +00:00:11,678 --> 00:00:15,482 +我是 Software Power 团队的 +工程师 + +4 +00:00:15,516 --> 00:00:17,251 +App 为人们的日常生活 + +5 +00:00:17,284 --> 00:00:22,222 +提供了多种多样的重要功能 +让生活更丰富多彩 + +6 +00:00:22,256 --> 00:00:26,293 +但这些功能需要付出一定代价 +即电量消耗 + +7 +00:00:26,326 --> 00:00:30,230 +因此 如何改进 App 的 +耗电量 + +8 +00:00:30,264 --> 00:00:32,432 +让用户有更长的时间 +使用设备和您的 App + +9 +00:00:32,466 --> 00:00:37,437 +是需要格外关注的问题 + +10 +00:00:37,471 --> 00:00:39,573 +我们深入研究了不同的系统组件 + +11 +00:00:39,606 --> 00:00:41,775 +了解电量消耗的问题 + +12 +00:00:41,808 --> 00:00:45,245 +有四个关键行动 + +13 +00:00:45,279 --> 00:00:47,281 +可以大大改善您 App 的耗电量 + +14 +00:00:47,314 --> 00:00:51,185 +在本次讲座中 +我们将与大家逐一分享 + +15 +00:00:51,218 --> 00:00:54,454 +其中包括 App 的深色模式 + +16 +00:00:54,488 --> 00:00:56,823 +审计帧率 + +17 +00:00:56,857 --> 00:01:00,060 +限制后台时间 + +18 +00:01:00,093 --> 00:01:02,196 +以及推迟 App 的任务 + +19 +00:01:03,797 --> 00:01:05,899 +首先 我们先看下深色模式 + +20 +00:01:06,834 --> 00:01:09,703 +深色模式在 iOS 13 中 +首次推出 + +21 +00:01:09,736 --> 00:01:14,942 +用户可将设备配置为 +深颜色的显示方式 + +22 +00:01:14,975 --> 00:01:18,946 +深色模式的个性化显示 +您应该不陌生 + +23 +00:01:18,979 --> 00:01:22,649 +但这对耗电量同样有 +极大的影响 + +24 +00:01:24,051 --> 00:01:27,888 +这是因为在使用 +OLED 显示屏的设备中 + +25 +00:01:27,921 --> 00:01:31,191 +如 iPhone 13 和 13 Pro + +26 +00:01:31,225 --> 00:01:35,762 +深色内容比浅色内容 +耗电量更低 + +27 +00:01:35,796 --> 00:01:40,434 +在 OLED 显示屏中 +每个像素都需要单独的能耗 + +28 +00:01:40,467 --> 00:01:45,539 +而深色模式下 点亮像素所需的 +能耗较少 + +29 +00:01:45,572 --> 00:01:48,609 +系统的所有组件中 + +30 +00:01:48,642 --> 00:01:52,779 +显示屏是耗电最多的 + +31 +00:01:52,813 --> 00:01:58,051 +实际上 在典型用例中 +显示屏是电池损耗的 + +32 +00:01:58,085 --> 00:02:00,554 +主要来源 + +33 +00:02:00,587 --> 00:02:04,725 +您可以改变显示屏的电池损耗 + +34 +00:02:04,758 --> 00:02:07,961 +其中一个方法就是应用深色模式 + +35 +00:02:08,896 --> 00:02:12,933 +我以我们团队正在开发的 + +36 +00:02:12,966 --> 00:02:14,801 +Food Truck App 为例 + +37 +00:02:14,835 --> 00:02:18,071 +这一 App 的背景颜色很显眼 + +38 +00:02:18,105 --> 00:02:21,008 +占据了显示屏的大部分 + +39 +00:02:21,041 --> 00:02:22,910 +使用深色模式时 + +40 +00:02:22,943 --> 00:02:27,047 +背景颜色比浅色模式下的深 + +41 +00:02:27,080 --> 00:02:29,583 +大大减少了电池损耗 + +42 +00:02:29,616 --> 00:02:34,254 +事实上 在这种案例中 我们预期 + +43 +00:02:34,288 --> 00:02:38,759 +电池损耗能减少 70% 以上 + +44 +00:02:38,792 --> 00:02:41,495 +这是非常惊人的比例 + +45 +00:02:41,528 --> 00:02:43,897 +屏幕亮度高 + +46 +00:02:43,931 --> 00:02:46,667 +电池电量节省更多 + +47 +00:02:46,700 --> 00:02:49,603 +对喜欢用深色模式的用户来说 + +48 +00:02:49,636 --> 00:02:53,607 +这是减少耗电的绝佳机会 + +49 +00:02:53,640 --> 00:02:56,009 +同时也可以减少热负荷 + +50 +00:02:56,844 --> 00:03:01,215 +要应用深色模式 首先要看下 +您的 App 当前在 + +51 +00:03:01,248 --> 00:03:03,884 +深色模式下是如何显示的 + +52 +00:03:03,917 --> 00:03:07,154 +想想如果要适应系统 UI + +53 +00:03:07,187 --> 00:03:10,257 +需要更新您 App 中哪些组件 + +54 +00:03:10,290 --> 00:03:16,930 +而 Xcode 构建 App 时使用外观功能 +让这一过程更简便 + +55 +00:03:18,165 --> 00:03:23,971 +您的 App 如果仅支持浅色模式 +可能会使用硬编码颜色 + +56 +00:03:24,004 --> 00:03:28,275 +在 Xcode 中使用动态颜色 +以支持浅色和深色模式中的 + +57 +00:03:28,308 --> 00:03:32,713 +背景颜色 图像和文本 + +58 +00:03:32,746 --> 00:03:36,350 +系统会自动应用正确的色值 + +59 +00:03:36,383 --> 00:03:38,919 +根据模式改变进行更新 + +60 +00:03:40,587 --> 00:03:44,558 +您的 App 应同样支持 +浅色和深色模式中的 + +61 +00:03:44,591 --> 00:03:46,593 +替代图像 + +62 +00:03:46,627 --> 00:03:50,063 +您可查看 WWDC 2019 中的 +“Implementing Dark Mode on iOS” + +63 +00:03:50,097 --> 00:03:55,469 +以了解更多关于自定义 App +深色模式的信息 + +64 +00:03:57,004 --> 00:04:00,507 +现在您知道如何在 App 中 +应用深色模式了 + +65 +00:04:00,541 --> 00:04:06,113 +网页内容中如何应用深色模式 +同样也是需要考虑的 + +66 +00:04:06,146 --> 00:04:09,049 +Safari 不会自动加深 +网页内容颜色 + +67 +00:04:09,082 --> 00:04:13,320 +因此要确保您的网页内容 +也能适应深色模式 + +68 +00:04:14,321 --> 00:04:19,293 +要在您网站的样式表中 +实现配色方案属性 + +69 +00:04:20,894 --> 00:04:25,399 +在网页中启用默认文本及背景颜色 + +70 +00:04:25,432 --> 00:04:27,768 +从而匹配当前系统外观 + +71 +00:04:27,801 --> 00:04:31,405 +标准表单控件和滚动条 + +72 +00:04:31,438 --> 00:04:34,374 +其它指定的系统颜色 +会改变外观 + +73 +00:04:34,408 --> 00:04:38,011 +在浅色和深色模式之间转换 + +74 +00:04:38,045 --> 00:04:40,414 +无论颜色在样式表中 +哪个位置被引用 + +75 +00:04:40,447 --> 00:04:44,418 +都请使用样式表变量 + +76 +00:04:44,451 --> 00:04:47,821 +这让您的网页内容 +可以随着设备在浅色模式 + +77 +00:04:47,855 --> 00:04:51,925 +和深色模式之间的切换 +更新其颜色 + +78 +00:04:51,959 --> 00:04:56,997 +将同样的逻辑应用到 +网页的图像及其它媒体 assets 中 + +79 +00:04:57,030 --> 00:05:00,501 +为不同模式套用不同变体 + +80 +00:05:00,534 --> 00:05:04,371 +您可查看 WWDC 2019 中的 +“Supporting Dark Mode in Your Web Content” + +81 +00:05:04,404 --> 00:05:07,574 +以了解更多关于在网页内容中 + +82 +00:05:07,608 --> 00:05:11,211 +应用深色模式的内容 + +83 +00:05:11,245 --> 00:05:17,184 +另一个减少 App 电池损耗的方法 +是审计帧率 + +84 +00:05:17,217 --> 00:05:19,953 +在使用 ProMotion 显示屏的设备中 + +85 +00:05:19,987 --> 00:05:23,257 +刷新率会影响电池损耗 + +86 +00:05:23,290 --> 00:05:26,760 +高刷新率则需要高能耗 + +87 +00:05:26,793 --> 00:05:29,696 +您 App 中的动画帧率 + +88 +00:05:29,730 --> 00:05:32,499 +决定了显示屏的刷新率 + +89 +00:05:32,533 --> 00:05:35,669 +想想 App 的主要内容 + +90 +00:05:35,702 --> 00:05:37,971 +以及需求的帧率 + +91 +00:05:38,005 --> 00:05:42,176 +不一定 App 中的所有内容 +都需要高帧率 + +92 +00:05:42,209 --> 00:05:45,712 +显示屏的刷新率是由您 App 中 + +93 +00:05:45,746 --> 00:05:48,448 +最高帧率的动画决定的 + +94 +00:05:48,482 --> 00:05:52,619 +您的 App 可能有次要元素的 +刷新率 + +95 +00:05:52,653 --> 00:05:54,454 +高于必要水平 + +96 +00:05:54,488 --> 00:05:58,792 +导致 App 整体消耗比预期 +更多的电量 + +97 +00:06:00,427 --> 00:06:03,797 +我们再以 food truck App 为例 + +98 +00:06:03,830 --> 00:06:08,836 +顶部主要的卡车场景 +是以每秒 30 帧的速率渲染的 + +99 +00:06:08,869 --> 00:06:12,439 +在卡车下面 有一个文字蒙版 +“Food Truck” + +100 +00:06:12,472 --> 00:06:15,142 +以水平方向滚动 + +101 +00:06:15,175 --> 00:06:19,613 +这种次要文本是以 +每秒 60 帧的速率渲染的 + +102 +00:06:19,646 --> 00:06:24,351 +结果是 整个屏幕现在均以 +每秒 60 帧的刷新率渲染 + +103 +00:06:24,384 --> 00:06:27,588 +如果我们将文本动画 +改为 30fps + +104 +00:06:27,621 --> 00:06:30,691 +整个屏幕就以 30fps 来渲染 + +105 +00:06:30,724 --> 00:06:33,961 +我们可以减少高达 20% 的 +电池损耗 + +106 +00:06:33,994 --> 00:06:35,462 +太神奇了 + +107 +00:06:36,230 --> 00:06:40,701 +要调试和获取更多关于 +您 App 帧率的信息 + +108 +00:06:40,734 --> 00:06:42,636 +就使用 Instruments 吧 + +109 +00:06:42,669 --> 00:06:45,572 +使用 instrument 中的 +CoreAnimation FPS + +110 +00:06:45,606 --> 00:06:51,178 +可以查看您 App 随着时间推移的 +帧率时间线 + +111 +00:06:51,211 --> 00:06:54,414 +首先审计主要用户场景 + +112 +00:06:54,448 --> 00:06:59,052 +确定帧是否以预期的帧率渲染 + +113 +00:06:59,086 --> 00:07:01,955 +确定屏幕上的次要元素帧率 + +114 +00:07:01,989 --> 00:07:05,626 +是否高于主要内容的帧率 + +115 +00:07:06,693 --> 00:07:12,766 +您的 App 可能使用 iOS 中的 +CoreAnimation 所提供的 CADisplayLink + +116 +00:07:12,799 --> 00:07:16,603 +来驱动自定义动画 +以及自定义渲染循环 + +117 +00:07:16,637 --> 00:07:21,542 +CADisplayLink 是一个定时器 +与显示屏刷新率同步 + +118 +00:07:21,575 --> 00:07:25,145 +它为您 App 提供了 +必要的计时信息 + +119 +00:07:25,179 --> 00:07:30,384 +这样您的自定义绘图 +能意识到刷新率 + +120 +00:07:30,417 --> 00:07:34,288 +您的 App 可提示 +CADisplayLink 对象 + +121 +00:07:34,321 --> 00:07:37,758 +期望的屏幕刷新率是什么 + +122 +00:07:37,791 --> 00:07:41,461 +设置 CADisplayLink 的 +preferredFrameRateRange + +123 +00:07:41,495 --> 00:07:46,466 +指定您最小 最大和偏好帧率 + +124 +00:07:47,868 --> 00:07:51,305 +Display link 随后根据 +系统能处理的范围 + +125 +00:07:51,338 --> 00:07:55,676 +选择可用帧率中 +与您偏好帧率最接近的数值 + +126 +00:07:55,709 --> 00:07:57,978 +如果无法提供该数值 + +127 +00:07:58,011 --> 00:08:02,382 +则会尝试保留在您指定的范围内 + +128 +00:08:02,416 --> 00:08:04,384 +要配置您的 display link + +129 +00:08:04,418 --> 00:08:07,888 +用 target 和 selector 初始化 + +130 +00:08:07,921 --> 00:08:11,825 +提供的 selector 用于 +运行自定义动画 + +131 +00:08:11,859 --> 00:08:16,163 +计算下一次显示的视频帧 + +132 +00:08:16,196 --> 00:08:18,298 +初始化 display link 后 + +133 +00:08:18,332 --> 00:08:20,667 +设置偏好帧率范围 + +134 +00:08:20,701 --> 00:08:24,404 +在这一例子中 偏好帧率为 30 + +135 +00:08:24,438 --> 00:08:29,076 +但范围可在 10 至 60 之间 + +136 +00:08:29,109 --> 00:08:32,746 +最后 在当前运行循环中 +添加 display link + +137 +00:08:34,882 --> 00:08:39,820 +当考虑 App 的电池损耗时 +要紧记刷新率 + +138 +00:08:39,853 --> 00:08:43,891 +这对于使用 ProMotion 显示屏 +支持高动态刷新率的 + +139 +00:08:43,924 --> 00:08:47,361 +设备来说尤为重要 + +140 +00:08:47,394 --> 00:08:50,831 +使用 Instruments 监测 +您 App 的帧率 + +141 +00:08:50,864 --> 00:08:55,536 +在发布 App 前先发现问题 + +142 +00:08:55,569 --> 00:09:00,240 +最后 将信息提供给系统 +用 CADisplayLink + +143 +00:09:00,274 --> 00:09:03,810 +限制 App 内容的刷新率 + +144 +00:09:05,279 --> 00:09:08,215 +您可查看 WWDC 2021 的 + +145 +00:09:08,248 --> 00:09:11,852 +“Optimize for variable +refresh rate displays” 以了解更多 + +146 +00:09:11,885 --> 00:09:15,455 +关于帧率优化的信息 + +147 +00:09:15,489 --> 00:09:19,193 +现在 我们来说下 +App 后台运行时 + +148 +00:09:19,226 --> 00:09:21,295 +如何减少电池损耗 + +149 +00:09:21,328 --> 00:09:25,365 +当有人将您的 App +切换到另一个 App 时 + +150 +00:09:25,399 --> 00:09:28,902 +您的 App 可能会需要使用 +后台执行 APIs + +151 +00:09:28,936 --> 00:09:31,438 +来保证在后台持续运行 + +152 +00:09:31,471 --> 00:09:33,106 +在后台运行时 + +153 +00:09:33,140 --> 00:09:39,112 +您的 App 可能会继续使用 +常用服务 如定位和音频 + +154 +00:09:39,146 --> 00:09:43,550 +长时间运行这些服务 +将会导致电池损耗 + +155 +00:09:43,584 --> 00:09:46,887 +因此 当您的 App 在后台 +使用这些服务时 + +156 +00:09:46,920 --> 00:09:49,723 +您需要尤为小心 + +157 +00:09:49,756 --> 00:09:56,029 +我们来说下使用这些模式时 +如何避免过多的电池损耗 + +158 +00:09:56,063 --> 00:09:58,866 +定位服务保证设备处于唤醒状态 + +159 +00:09:58,899 --> 00:10:01,201 +从而持续定位 + +160 +00:10:01,235 --> 00:10:04,304 +即使对于用户来说 +App 并不可见 + +161 +00:10:04,338 --> 00:10:07,741 +也可能在后台持续进行 +定位的流式传输 + +162 +00:10:07,774 --> 00:10:10,277 +导致电池损耗过多 + +163 +00:10:10,310 --> 00:10:15,616 +很重要的是 要确保您清楚了解 +您 App 后台定位 session 的 + +164 +00:10:15,649 --> 00:10:17,718 +运行时间 + +165 +00:10:17,751 --> 00:10:19,853 +当您不需要该 session 时 + +166 +00:10:19,887 --> 00:10:23,323 +确保 App +调用 stopUpdatingLocation() + +167 +00:10:23,357 --> 00:10:25,559 +从而停止该 session + +168 +00:10:25,592 --> 00:10:28,161 +在 App 开发的不同阶段 + +169 +00:10:28,195 --> 00:10:31,765 +您可以用不同的工具 +来查看后台定位使用 + +170 +00:10:31,798 --> 00:10:34,168 +可能会超乎您所料 + +171 +00:10:34,201 --> 00:10:36,403 +在构建和测试 App 时 + +172 +00:10:36,436 --> 00:10:40,541 +Xcode gauges 可用于 +查看系统能耗 + +173 +00:10:40,574 --> 00:10:43,210 +以及后台定位使用 + +174 +00:10:43,243 --> 00:10:46,079 +发布前测试 App 时 + +175 +00:10:46,113 --> 00:10:51,685 +您可以使用 MetricKit 来收集 +一天内使用情况的诊断信息 + +176 +00:10:51,718 --> 00:10:57,558 +iOS 16 中新增了 +在 Control Center 显示定位使用 + +177 +00:10:57,591 --> 00:11:00,594 +Xcode gauges 提供关于 +系统使用的信息 + +178 +00:11:00,627 --> 00:11:05,265 +如 CPU 网络 定位使用 + +179 +00:11:05,299 --> 00:11:09,069 +Xcode gauges 会展示 +您 App 的定位使用 + +180 +00:11:09,102 --> 00:11:11,772 +以及能量损耗时间线 + +181 +00:11:11,805 --> 00:11:15,442 +这一时间线视图可验证您的 +定位运行时间是否在您 + +182 +00:11:15,475 --> 00:11:19,446 +预期的时间停止 +这是一个绝佳的方法 + +183 +00:11:20,314 --> 00:11:24,818 +另一个工具是在测试 App 时 +使用 MetricKit + +184 +00:11:24,852 --> 00:11:28,055 +使用 +cumulativeBackgroundLocationTime 属性 + +185 +00:11:28,088 --> 00:11:33,727 +查看您 App 在后台 +使用定位服务的活跃时间 + +186 +00:11:34,995 --> 00:11:38,365 +在 iOS 16 的更新中 +用户可以通过 + +187 +00:11:38,398 --> 00:11:43,070 +浏览 Control Center +监测当前使用定位服务的 App + +188 +00:11:43,103 --> 00:11:45,906 +用户可以点击顶部的文本 + +189 +00:11:45,939 --> 00:11:49,276 +查看使用定位的 App 的详细视图 + +190 +00:11:49,309 --> 00:11:52,112 +用这种方式可以发现那些 +不在前台运行 + +191 +00:11:52,145 --> 00:11:54,548 +却仍然在使用定位系统的情况 + +192 +00:11:54,581 --> 00:11:57,885 +如果您的 App 毫无征兆地 +在这里显示 + +193 +00:11:57,918 --> 00:12:03,090 +就是您 App +有活跃定位流 session 的指标 + +194 +00:12:03,123 --> 00:12:07,027 +我们可以将同样的原则 +应用到音频 sessions + +195 +00:12:07,060 --> 00:12:11,331 +假设我们有一个音乐 App +使用音频播放器 + +196 +00:12:11,365 --> 00:12:15,102 +来回放一些文件 +而用户停止了回放 + +197 +00:12:15,936 --> 00:12:18,739 +App 不仅应暂停或停止音频 + +198 +00:12:18,772 --> 00:12:22,042 +而且应暂停或停止 Audio Engine + +199 +00:12:22,075 --> 00:12:25,979 +从而阻止其空运转 + +200 +00:12:26,013 --> 00:12:28,448 +我们推荐使用自动关闭模式 + +201 +00:12:28,482 --> 00:12:32,619 +该模式可通过设置 +AVAudioEngine 类的 + +202 +00:12:32,653 --> 00:12:35,556 +autoShutdownEnabled 来启用 + +203 +00:12:35,589 --> 00:12:39,726 +在这一模式下 audio engine +继续监控及探测 + +204 +00:12:39,760 --> 00:12:42,496 +在一定期间内是否空运转 + +205 +00:12:42,529 --> 00:12:47,000 +如在空运转 引擎将关闭音频硬件 + +206 +00:12:47,034 --> 00:12:51,205 +随后 如果有任何软件源 +再次活跃运行 + +207 +00:12:51,238 --> 00:12:54,341 +将会动态开启音频硬件 + +208 +00:12:54,374 --> 00:12:57,611 +这些都是在后台运行的 + +209 +00:12:57,644 --> 00:13:02,249 +watchOS 的自动关闭模式是 +强制执行的行为 + +210 +00:13:02,282 --> 00:13:05,385 +确保在 Audio Engine 未使用时 +将其停止 + +211 +00:13:05,419 --> 00:13:07,654 +从而减少能耗 + +212 +00:13:07,688 --> 00:13:09,923 +限制后台运行时间的关键在于 + +213 +00:13:09,957 --> 00:13:13,894 +要记得提示系统您完成的时间 + +214 +00:13:13,927 --> 00:13:18,532 +最后一个改善耗电量的动作 +是延迟工作 + +215 +00:13:18,565 --> 00:13:20,467 +在一天的使用中 + +216 +00:13:20,501 --> 00:13:24,838 +您的 App 可能要处理 +许多不同的任务和数据 + +217 +00:13:24,872 --> 00:13:28,876 +有些是需要在服务用户操作时 +立即进行的 + +218 +00:13:28,909 --> 00:13:32,412 +如屏幕上的渲染内容 + +219 +00:13:32,446 --> 00:13:35,282 +或用户点击时播放音频或视频 + +220 +00:13:37,584 --> 00:13:39,853 +其它运行工作如机器学习任务 + +221 +00:13:39,887 --> 00:13:45,292 +上传分析或备份 +时间敏感性并不高 + +222 +00:13:45,325 --> 00:13:49,129 +如果我们将这些非时间敏感性的工作 +延迟到其它更合适的时间 + +223 +00:13:49,162 --> 00:13:51,031 +在设备充电时 + +224 +00:13:51,064 --> 00:13:52,299 +我们可以节省电池损耗 + +225 +00:13:52,332 --> 00:13:56,537 +避免与用户主动触发的 +及交互性工作发生冲突 + +226 +00:13:56,570 --> 00:14:01,008 +我们来看下您可以用来完成 +该行为的三个 APIs + +227 +00:14:01,041 --> 00:14:07,648 +BGProcessingTask 是延迟 +长时间运行工作的绝佳选择 + +228 +00:14:07,681 --> 00:14:10,617 +授权系统支配的 URLSession +是规划可延迟网络连接的 + +229 +00:14:10,651 --> 00:14:13,053 +完美选择 + +230 +00:14:13,086 --> 00:14:16,456 +利用正确的推送优先级 +可帮助服务器 + +231 +00:14:16,490 --> 00:14:19,059 +在适宜的时间传递推送 + +232 +00:14:19,092 --> 00:14:21,995 +我们逐一详细了解下 + +233 +00:14:22,029 --> 00:14:24,798 +首先是 BGProcessingTask + +234 +00:14:24,831 --> 00:14:29,269 +BGProcessingTask 可让您 +将长时间运行的处理任务 + +235 +00:14:29,303 --> 00:14:34,241 +延迟到其它更适宜的时间 +如设备充电时 + +236 +00:14:34,274 --> 00:14:37,010 +这对如数据库清理 + +237 +00:14:37,044 --> 00:14:41,415 +创建备份 运行机器学习训练 +诸如此类的任务非常适合 + +238 +00:14:41,448 --> 00:14:47,754 +您只需通过使用 +BGProcessingTaskRequest API 创建请求 + +239 +00:14:47,788 --> 00:14:50,891 +提供一个应用标识符 + +240 +00:14:50,924 --> 00:14:52,359 +然后提供更多信息 + +241 +00:14:52,392 --> 00:14:57,497 +如您的任务是否需要 +外接电源或网络 + +242 +00:14:57,531 --> 00:15:01,335 +提供更多信息可帮助系统 +在更好的时间窗口内 + +243 +00:15:01,368 --> 00:15:03,537 +规划该任务 + +244 +00:15:03,570 --> 00:15:08,242 +系统会在合适的时间 +后台启动您的 App + +245 +00:15:08,275 --> 00:15:12,613 +保证数分钟的运行时间 +从而完成可延迟工作 + +246 +00:15:12,646 --> 00:15:16,116 +接下来是 +discretionary URLSession + +247 +00:15:16,149 --> 00:15:20,254 +您的 App 可能已经在普通网络连接中 + +248 +00:15:20,287 --> 00:15:22,055 +使用了 Background URLSessions + +249 +00:15:22,089 --> 00:15:28,195 +在您使用 discretionary 标记时 +Background URLSessions 将更为理想 + +250 +00:15:28,228 --> 00:15:32,833 +有 discretionary 标记的 URLSessions + +251 +00:15:32,866 --> 00:15:35,335 +将完全由系统决定 + +252 +00:15:35,369 --> 00:15:38,605 +在更优时间运行网络连接任务 + +253 +00:15:38,639 --> 00:15:42,743 +如当设备接通电源 +和连接至 Wi-Fi 时 + +254 +00:15:42,776 --> 00:15:46,547 +discretionary 标记非常适用于 +非用户触发的 + +255 +00:15:46,580 --> 00:15:50,784 +长时间运行的网络 +如远端信息收集 + +256 +00:15:50,817 --> 00:15:54,454 +或下载电视剧集的下一集 + +257 +00:15:54,488 --> 00:15:57,090 +由于网络任务是全权交给系统的 + +258 +00:15:57,124 --> 00:15:59,927 +意味着您的 App 不需要 + +259 +00:15:59,960 --> 00:16:02,362 +在网络事务完成时运行 + +260 +00:16:03,230 --> 00:16:05,866 +要使用 discretionary URL sessions + +261 +00:16:05,899 --> 00:16:09,970 +您只需设置一个 +background URL session + +262 +00:16:10,003 --> 00:16:14,074 +将 isDiscretionary 设置为 true + +263 +00:16:14,107 --> 00:16:16,276 +您可提供额外信息 + +264 +00:16:16,310 --> 00:16:20,480 +帮助系统在合适的时间计划下载 + +265 +00:16:20,514 --> 00:16:24,451 +设置超时间隔 +这样系统不会一直尝试下载 + +266 +00:16:24,484 --> 00:16:27,120 +从而导致电池损耗 + +267 +00:16:28,722 --> 00:16:31,291 +如果您未来一段时间内 + +268 +00:16:31,325 --> 00:16:33,694 +不想上传或下载数据 + +269 +00:16:33,727 --> 00:16:36,864 +可以设置最早开始的时间 + +270 +00:16:36,897 --> 00:16:40,033 +最后 设置预期的工作量大小 + +271 +00:16:40,067 --> 00:16:43,270 +这样系统可智能地 + +272 +00:16:43,303 --> 00:16:45,873 +在您多个下载任务中 +保持负载平衡 + +273 +00:16:48,175 --> 00:16:52,913 +与您用 BGProcessingTask +和 discretionary URL sessions + +274 +00:16:52,946 --> 00:16:57,417 +控制某些操作的即时性类似 + +275 +00:16:57,451 --> 00:17:00,554 +您可以通过使用 +不同的推送优先级 + +276 +00:17:00,587 --> 00:17:03,123 +影响推动的即时性 + +277 +00:17:03,156 --> 00:17:07,327 +推送优先级决定了一个通知 +推送到设备的 + +278 +00:17:07,361 --> 00:17:08,529 +紧急性 + +279 +00:17:08,562 --> 00:17:10,197 +对于高优先级的推送 + +280 +00:17:10,230 --> 00:17:13,867 +服务器会将其立即推送到设备 + +281 +00:17:13,901 --> 00:17:18,071 +潜在地唤醒设备 导致电池损耗 + +282 +00:17:18,105 --> 00:17:19,806 +对于低优先级的推送 + +283 +00:17:19,840 --> 00:17:24,011 +服务器会将其延迟 +直至更为恰当的时机再予以推送 + +284 +00:17:24,044 --> 00:17:26,446 +如设备唤醒时 + +285 +00:17:26,480 --> 00:17:29,449 +或者有高优先级推送出现时 + +286 +00:17:29,483 --> 00:17:34,855 +高优先级推送是如重大天气预警 +这种紧急信息的最好选择 + +287 +00:17:34,888 --> 00:17:39,059 +低优先级推送适用于 +更被动的通知 + +288 +00:17:39,092 --> 00:17:42,496 +不紧急且可以被延迟的 + +289 +00:17:42,529 --> 00:17:46,667 +利用低优先级推送 +推迟可延迟信息的推送 + +290 +00:17:46,700 --> 00:17:52,840 +将减少电池损耗 因为设备 +不会频繁地从休眠中被唤醒 + +291 +00:17:52,873 --> 00:17:55,108 +要配置低优先级推送 + +292 +00:17:55,142 --> 00:17:59,780 +只要在推送负载中 +将 apns-priority 设置到 5 + +293 +00:17:59,813 --> 00:18:01,782 +服务器会处理余下的部分 + +294 +00:18:01,815 --> 00:18:05,686 +您的用户会为电量节省而满意 + +295 +00:18:06,553 --> 00:18:10,324 +我们来总结下最后的想法 +和接下来的步骤 + +296 +00:18:10,357 --> 00:18:13,427 +在你的 App 中 +提供深色模式的选项 + +297 +00:18:13,460 --> 00:18:18,799 +如果用户选择深色模式 +尊重其选择可减少电池损耗 + +298 +00:18:18,832 --> 00:18:20,634 +查看您的动画 + +299 +00:18:20,667 --> 00:18:25,172 +寻找机会在必要时降低帧率 + +300 +00:18:25,205 --> 00:18:28,709 +一个小动画都可能带来大改变 + +301 +00:18:28,742 --> 00:18:31,478 +让系统知道您已完成动作 + +302 +00:18:31,512 --> 00:18:34,715 +时刻关注您的后台运行时间 + +303 +00:18:34,748 --> 00:18:38,585 +最后 考虑延迟 +长时间运行的后台工作 + +304 +00:18:38,619 --> 00:18:42,756 +至其它更好的时机 +如设备连接电源时 + +305 +00:18:42,789 --> 00:18:44,691 +如果您完成了这些操作 + +306 +00:18:44,725 --> 00:18:47,594 +就会真正降低您 App 的能耗 + +307 +00:18:47,628 --> 00:18:49,463 +感谢大家 + diff --git a/zho/2022 Session 10089 What's new in PDFKit.srt b/zho/2022 Session 10089 What's new in PDFKit.srt new file mode 100644 index 0000000..9a6b69d --- /dev/null +++ b/zho/2022 Session 10089 What's new in PDFKit.srt @@ -0,0 +1,1114 @@ +1 +00:00:01,468 --> 00:00:07,474 +[古怪的音乐] + +2 +00:00:09,877 --> 00:00:11,912 +Conrad: 我是 Conrad 今天 + +3 +00:00:11,945 --> 00:00:14,481 +我将为大家介绍 +PDFKit 更新的内容 + +4 +00:00:14,515 --> 00:00:15,883 +以下是我们的议程 + +5 +00:00:15,916 --> 00:00:19,520 +我们首先快速回顾下 PDFKit + +6 +00:00:19,553 --> 00:00:21,455 +然后 了解更新的内容 + +7 +00:00:21,488 --> 00:00:24,558 +包括实时文本和表单 + +8 +00:00:24,591 --> 00:00:27,628 +将 PDF 页面转为图片的新方式 + +9 +00:00:27,661 --> 00:00:30,831 +最后 overlay views (覆盖视图) + +10 +00:00:30,864 --> 00:00:33,567 +首先 我们先快速回顾下 +PDFKit 是如何运行的 + +11 +00:00:34,501 --> 00:00:38,539 +PDFKit 是一个全功能框架 +能帮助您的 App 查看 + +12 +00:00:38,572 --> 00:00:41,041 +编辑和编写 PDF 文件 + +13 +00:00:41,074 --> 00:00:44,978 +在 iOS macOS +和 Mac Catalyst 中均适用 + +14 +00:00:45,012 --> 00:00:49,616 +也可以通过可将 UI 视图 +整合到您 APP 中的 + +15 +00:00:49,650 --> 00:00:54,888 +封装 UIViewRepresentable +在 SwiftUI 中使用 PDFKit + +16 +00:00:54,922 --> 00:00:58,592 +PDFKit 包含四个核心类 +覆盖您 App 中 + +17 +00:00:58,625 --> 00:01:00,694 +所需的大部分功能 + +18 +00:01:00,727 --> 00:01:03,430 +PDFView 是您使用 SwiftUI +或 Interface Builder + +19 +00:01:03,463 --> 00:01:05,966 +加入到布局中的小组件 + +20 +00:01:05,999 --> 00:01:09,670 +可展示 PDF 文档的内容 +允许用户导航 + +21 +00:01:09,703 --> 00:01:12,372 +设置缩放比例 +及将文本复制到剪贴板 + +22 +00:01:13,507 --> 00:01:16,710 +PDFDocument 代表 +一个 PDF 文件 + +23 +00:01:16,743 --> 00:01:20,681 +这对 PDFDocument 子类来说 +并不常见 但您总是会用到 + +24 +00:01:20,714 --> 00:01:24,518 +它是 PDF 对象图的根源 +是树之躯干 + +25 +00:01:24,551 --> 00:01:26,720 +无枝不成树 + +26 +00:01:28,455 --> 00:01:32,192 +每个文档都包含一个或多个 +PDFPage 对象 + +27 +00:01:32,226 --> 00:01:36,263 +页面渲染内容和存储资源 +如字体和图像 + +28 +00:01:36,296 --> 00:01:37,631 +对页面来说都是独特的 + +29 +00:01:38,799 --> 00:01:41,969 +我们对象图的绿叶 +是 PDFAnnotations + +30 +00:01:42,002 --> 00:01:43,537 +这些是可选的 + +31 +00:01:43,570 --> 00:01:46,306 +然而 PDFPage的内容 +并不是用于编辑 + +32 +00:01:46,340 --> 00:01:49,610 +annotations 则具有交互特性 +通常是可编辑的 + +33 +00:01:50,177 --> 00:01:53,947 +这些对象在我们今天的内容中 +都扮演了对应的角色 + +34 +00:01:53,981 --> 00:01:55,949 +您可通过下方链接中 +关于“Introducing PDFKit”的精彩内容 + +35 +00:01:55,983 --> 00:01:59,953 +来了解更多 PDFKit 的基本原理 + +36 +00:02:01,989 --> 00:02:07,160 +现在 我们来看下在 iOS 16 和 +macOS Ventura 中推出的新功能 + +37 +00:02:08,228 --> 00:02:11,131 +PDFKit 当前已支持实时文本 + +38 +00:02:11,164 --> 00:02:13,000 +在照片 App 中 文本通常 + +39 +00:02:13,033 --> 00:02:16,703 +占少数 您可以直接点击复制 + +40 +00:02:16,737 --> 00:02:21,275 +而在 PDF 中 如果您看到的是文本 +则普遍都是文本 + +41 +00:02:21,308 --> 00:02:25,312 +人们也希望其发挥文本的功能 +别无他用 + +42 +00:02:25,345 --> 00:02:27,614 +而现在 使用实时文本 +您可以在 PDF 文档中 + +43 +00:02:27,648 --> 00:02:30,517 +选择和搜索文本 如这一示例 + +44 +00:02:30,551 --> 00:02:32,886 +这只是一个扫描的位图 +完全没有文本 + +45 +00:02:34,188 --> 00:02:36,890 +当然 PDFs 有很多页面 + +46 +00:02:36,924 --> 00:02:40,594 +您打开文档时 不会想对一个 +PDF 文档的每个页面 + +47 +00:02:40,627 --> 00:02:41,895 +都费力进行 OCR + +48 +00:02:41,929 --> 00:02:45,566 +因此 在您与每个页面发生 +交互动作时 + +49 +00:02:45,599 --> 00:02:47,534 +PDFKit 应需启用 + +50 +00:02:47,568 --> 00:02:51,605 +OCR 即时完成 无需生成 +文档副本 + +51 +00:02:52,472 --> 00:02:55,209 +如果您选择保存整份文档的文本 + +52 +00:02:55,242 --> 00:02:56,877 +保存时也可以选择对应的选项 + +53 +00:02:58,478 --> 00:03:02,783 +除实况文本以外 PDFKit的 +表单处理也进行了改进 + +54 +00:03:02,816 --> 00:03:05,719 +即使没有内置文本区域 + +55 +00:03:05,752 --> 00:03:08,522 +也能自动识别 +包含表单区域的文档 + +56 +00:03:08,555 --> 00:03:11,191 +您可以点击这些文本区域 +输入文本 + +57 +00:03:11,225 --> 00:03:12,526 +正如您所想的那样 + +58 +00:03:14,394 --> 00:03:18,365 +接下来 我们说下从图片 +创建 PDF 页面的新 API + +59 +00:03:20,567 --> 00:03:24,605 +在 iOS 16 和 macOS Ventura 中 +有一个全新的 灵活的 API + +60 +00:03:24,638 --> 00:03:28,041 +可以让您的 App 用图片 +作为输入 创建 PDF 页面 + +61 +00:03:28,809 --> 00:03:32,012 +您的 App 用 CGImageRef +提供图片 + +62 +00:03:32,045 --> 00:03:35,549 +PDFKit 使用您提供的 +CGImageRef 并将其用高质量的 + +63 +00:03:35,582 --> 00:03:37,518 +JPEG 解码进行压缩 + +64 +00:03:38,285 --> 00:03:41,455 +由于 CGImageRef +是 CoreGraphics 中的原生数据类型 + +65 +00:03:41,488 --> 00:03:43,657 +所以无需额外转换 + +66 +00:03:44,725 --> 00:03:48,161 +有多个选项可供您处理 +最常见的情况 + +67 +00:03:49,463 --> 00:03:52,599 +MediaBox 指定页面大小 + +68 +00:03:52,633 --> 00:03:56,937 +您可以选择适合图片的大小 +或选择纸张尺寸 如 Letter + +69 +00:03:58,372 --> 00:04:02,009 +Rotation 可供您指定纵向或横向 + +70 +00:04:03,210 --> 00:04:04,444 +还有 UpscaleIfSmaller + +71 +00:04:04,478 --> 00:04:07,080 +如果图片大于 MediaBox + +72 +00:04:07,114 --> 00:04:09,216 +则默认将图片缩小到适应比例 + +73 +00:04:09,249 --> 00:04:12,452 +如果 UpscaleIfSmaller 已被指定 +该规则仍有效 + +74 +00:04:12,486 --> 00:04:16,456 +但如果图片较小 +则会增加尺寸以适合页面 + +75 +00:04:18,292 --> 00:04:21,562 +现在 我们来回答下 +大家都在问的问题 + +76 +00:04:21,595 --> 00:04:24,865 +“我怎么能用 PencilKit +在 PDF 页面上绘图呢” + +77 +00:04:24,898 --> 00:04:27,301 +答案就是使用覆盖视图 + +78 +00:04:28,535 --> 00:04:31,538 +过去 在 PDFs 上绘图的 +唯一方法 + +79 +00:04:31,572 --> 00:04:34,842 +就是将 PDFPage 编入子类 +覆写绘图方法 + +80 +00:04:34,875 --> 00:04:37,678 +或使用 +自定义 PDF annotations + +81 +00:04:37,711 --> 00:04:41,615 +但从 iOS 16 和 macOS Ventura +开始 现在可以 + +82 +00:04:41,648 --> 00:04:44,952 +在每个 PDF 页面上 +覆盖您自己的视图 + +83 +00:04:44,985 --> 00:04:47,988 +让您的 App 创建实时 +具有强交互性的视图 + +84 +00:04:48,021 --> 00:04:49,756 +显示在 PDF 页面上层 + +85 +00:04:50,557 --> 00:04:53,961 +关于覆盖视图 你需要知道 +以下三点 + +86 +00:04:54,695 --> 00:04:58,265 +首先 您要使用一个新代理 +在 PDF 页面中 + +87 +00:04:58,298 --> 00:04:59,733 +安装您的覆盖视图 + +88 +00:05:00,934 --> 00:05:05,339 +到了需要保存的时候 +您需要将内容并入 PDF + +89 +00:05:06,306 --> 00:05:09,576 +说到保存 我们会分享一些 +保存 PDF 文档的 + +90 +00:05:09,610 --> 00:05:11,311 +最优方法 + +91 +00:05:13,280 --> 00:05:17,885 +在 PDF 页面上安装覆盖视图 +很简单 + +92 +00:05:17,918 --> 00:05:21,121 +因为 PDFs 可以包含 +成百上千的页面 + +93 +00:05:21,154 --> 00:05:25,792 +打开 PDF 时 您不会想为这些 +所有页面创建视图 + +94 +00:05:25,826 --> 00:05:28,562 +但如果用户快速前后滚动呢 + +95 +00:05:28,595 --> 00:05:30,464 +您如何知道何时创建视图 + +96 +00:05:31,732 --> 00:05:35,869 +幸运的是 PDFKit 已经设计好 +在用户滚动至所需位置前 + +97 +00:05:35,903 --> 00:05:38,238 +就能智能准备内容 + +98 +00:05:38,272 --> 00:05:41,341 +它知道何时请求覆盖视图 + +99 +00:05:41,375 --> 00:05:43,777 +您的 App 只需要响应它 + +100 +00:05:43,810 --> 00:05:45,546 +通过新代理发出的请求 + +101 +00:05:47,881 --> 00:05:51,685 +PDFPageOverlayViewProvider +是新代理 + +102 +00:05:51,718 --> 00:05:56,924 +对了 PDFKitPlatformView +只是 UIView 或 NSView 的定义 + +103 +00:05:56,957 --> 00:05:59,593 +取决于平台 + +104 +00:05:59,626 --> 00:06:03,730 +你需要运行的最重要方法 +是 overlayViewForPage + +105 +00:06:04,398 --> 00:06:07,835 +只需要提供您的视图实例 +PDFKit 就会应用适当的边界 + +106 +00:06:07,868 --> 00:06:10,070 +重设其尺寸 + +107 +00:06:10,103 --> 00:06:13,173 +如果页面有非零旋转 +它会执行旋转 + +108 +00:06:14,641 --> 00:06:16,643 +接下来两个方法是可选的 + +109 +00:06:16,677 --> 00:06:20,414 +willDisplayOverlayView 可用于 +安装您自己的动作处理程序 + +110 +00:06:20,447 --> 00:06:23,917 +或与 PDFKit 的动作处理程序 +建立失败关系 + +111 +00:06:25,619 --> 00:06:30,224 +在 PDFKit 完成您的视图时 会调用 +willEndDisplayingOverlayView + +112 +00:06:30,257 --> 00:06:32,559 +可能是因为页面已滚动到 +视图之外 + +113 +00:06:32,593 --> 00:06:37,431 +您可在这里发布您的视图 +但这一方法还有另一个重要用途 + +114 +00:06:37,464 --> 00:06:40,968 +假如您的视图有一些 +展示其正在绘制内容的数据 + +115 +00:06:41,001 --> 00:06:44,671 +您可以用该方法获取数据 +并将其放置一边 + +116 +00:06:44,705 --> 00:06:47,474 +我们会用 PencilKit 进行示例 + +117 +00:06:47,508 --> 00:06:49,977 +但如果您的视图数据 +被搁置在别处 + +118 +00:06:50,010 --> 00:06:51,612 +则无需执行此操作 + +119 +00:06:53,380 --> 00:06:57,150 +在示例中 这是我们用于 +提供程序的类 + +120 +00:06:57,184 --> 00:07:01,154 +它执行 +PDFPageOverlayViewProvider 代理 + +121 +00:07:01,188 --> 00:07:05,392 +这是 iOS 所以 +PDFKitPlatformView 是一个 UIView + +122 +00:07:05,425 --> 00:07:09,029 +使用地图从 PDFPage +到 UIView + +123 +00:07:09,930 --> 00:07:12,132 +这是占位符代理方法 + +124 +00:07:12,165 --> 00:07:15,169 +接下来 我们看下实现 + +125 +00:07:15,202 --> 00:07:18,238 +overlayViewForPage 检查 +其 pageToView 地图 + +126 +00:07:18,272 --> 00:07:20,908 +看是否对指定页面建立了视图 + +127 +00:07:20,941 --> 00:07:23,010 +如果没有 则创建一个新视图 + +128 +00:07:23,043 --> 00:07:25,679 +不管哪种情况 我们都能从页面 +获取绘图 + +129 +00:07:25,712 --> 00:07:28,182 +并将其放置于画布视图 + +130 +00:07:28,215 --> 00:07:32,252 +在这些示例中 我使用的是 +PDFPage 的子类 + +131 +00:07:32,286 --> 00:07:34,521 +其作用是添加“绘制”属性 + +132 +00:07:37,691 --> 00:07:42,196 +现在 我们来看下一个方法 +即 WillEndDisplayingOverlay + +133 +00:07:44,264 --> 00:07:46,466 +willEndDisplayingOverlayView +很简单 + +134 +00:07:46,500 --> 00:07:51,939 +它从视图中获取绘图 +并将其存储于我们自定义页面类 + +135 +00:07:51,972 --> 00:07:54,408 +现在我们已经完成了 +那就来看下实际的实施吧 + +136 +00:07:56,076 --> 00:07:59,713 +通常 每年大约这个时候 +我会在缅因州钓鱼 + +137 +00:07:59,746 --> 00:08:01,982 +然而现在 我却在 WWDC 现场 + +138 +00:08:02,015 --> 00:08:04,618 +因此 有另一个人代替我去旅行 + +139 +00:08:04,651 --> 00:08:07,521 +我将会给他看下 +一些我最喜欢的地点 + +140 +00:08:07,554 --> 00:08:09,723 +并且会用这一 App 来完成 + +141 +00:08:09,756 --> 00:08:12,159 +在覆盖视图中 +使用 PencilKit + +142 +00:08:12,793 --> 00:08:16,129 +这一 App 包含我们刚刚 +看到的代码 仅此而已 + +143 +00:08:16,163 --> 00:08:21,001 +获取屏幕上的覆盖视图的 +完整代码仅约 30 行 + +144 +00:08:21,034 --> 00:08:24,972 +因此 Grand Lake Stream +这是大坝池 + +145 +00:08:25,005 --> 00:08:28,675 +有很多鱼 大部分动作 +都是在这里进行的 + +146 +00:08:28,709 --> 00:08:30,811 +您沿着这条小路一直走 +经过树林 + +147 +00:08:30,844 --> 00:08:33,647 +就能到达大坝池 然后钓鱼 + +148 +00:08:33,680 --> 00:08:35,449 +您可以钓各种鱼 + +149 +00:08:35,482 --> 00:08:40,053 +或者也可以走这条路 越过大坝 + +150 +00:08:40,087 --> 00:08:41,522 +从这里往下走 + +151 +00:08:41,555 --> 00:08:43,857 +您可以从那里钓鱼 一直到这里 + +152 +00:08:43,891 --> 00:08:46,326 +环岛一圈 下来这里 + +153 +00:08:46,360 --> 00:08:49,763 +但不管你做什么 不要越过这里 + +154 +00:08:49,796 --> 00:08:52,599 +这里的水流又深又急 + +155 +00:08:52,633 --> 00:08:56,670 +避开这个地方 下来这里 + +156 +00:08:56,703 --> 00:08:58,572 +到孵化场 + +157 +00:08:58,605 --> 00:09:02,009 +沿着孵化场旁一直走 + +158 +00:09:02,042 --> 00:09:04,578 +进入这个池塘 + +159 +00:09:04,611 --> 00:09:06,580 +您可以在这里抛钓丝 + +160 +00:09:06,613 --> 00:09:09,283 +这是很好的地方 +我经常在这里钓鱼 + +161 +00:09:10,317 --> 00:09:14,588 +好了 现在我们在这个页面 +做了一些标记 + +162 +00:09:14,621 --> 00:09:16,423 +我们演示下缩放和滚动 + +163 +00:09:17,891 --> 00:09:19,059 +看它响应速度多快 + +164 +00:09:25,299 --> 00:09:26,233 +这就好了 + +165 +00:09:26,266 --> 00:09:28,235 +PDFKit 的覆盖视图 + +166 +00:09:28,268 --> 00:09:31,738 +现在 您已经有了这些草图 +那要怎么保存呢 + +167 +00:09:31,772 --> 00:09:34,441 +我们可以用 PDFAnnotation 类 +来完成 + +168 +00:09:34,474 --> 00:09:37,144 +保存时 我们希望能实现两点 + +169 +00:09:37,177 --> 00:09:39,379 +我们希望在高保真的前提下 + +170 +00:09:39,413 --> 00:09:40,848 +匹配屏幕显示 + +171 +00:09:40,881 --> 00:09:43,217 +并且我们希望做一些往返编辑 + +172 +00:09:43,250 --> 00:09:47,554 +PDF annotations 有一些功能 +可以实现这些要求 + +173 +00:09:47,588 --> 00:09:49,590 +PDF annotations 有一个 +“appearance stream” + +174 +00:09:49,623 --> 00:09:52,526 +是 PDF 绘制指令流 + +175 +00:09:52,559 --> 00:09:55,195 +基本上所有您能用 Quartz2D +绘制的东西 + +176 +00:09:55,229 --> 00:09:57,731 +appearance stream 都能记录下来 + +177 +00:09:57,764 --> 00:10:02,102 +只要能渲染成图片的都能记录 + +178 +00:10:02,135 --> 00:10:03,904 +如果我们使用 Metal +用的就是这个方法 + +179 +00:10:04,771 --> 00:10:07,074 +而且 由于是作为 PDF 绘图 +来记录的 + +180 +00:10:07,107 --> 00:10:10,043 +看起来和在 Adobe Reader +Chrome 等的显示都一样 + +181 +00:10:11,378 --> 00:10:14,915 +在 PDF 文档中 PDF annotations +是以字典的形式来存储的 + +182 +00:10:14,948 --> 00:10:18,685 +这意味着我们也可以在 +私人密钥/值对中存储自定义数据 + +183 +00:10:19,653 --> 00:10:22,756 +那我们来看看代码是什么样的 + +184 +00:10:22,789 --> 00:10:26,360 +首先创建 PDFAnnotation 的子类 + +185 +00:10:26,393 --> 00:10:28,795 +这一步是为了覆写 +draw() 方法 + +186 +00:10:29,596 --> 00:10:32,766 +PDFKit 在保存我上一张幻灯片中 +讲的appearance stream 时 + +187 +00:10:32,799 --> 00:10:34,434 +会调用此方法 + +188 +00:10:36,336 --> 00:10:39,640 +要保存文档 我们要 +覆写 UIDocument 的 contents() + +189 +00:10:39,673 --> 00:10:43,610 +这是该函数的概览 +对应稍后的上下文 + +190 +00:10:43,644 --> 00:10:47,147 +我们依次通过 +PDFDocument 的各页面 + +191 +00:10:47,181 --> 00:10:49,316 +下一步再来充实循环 + +192 +00:10:51,084 --> 00:10:53,253 +每个页面我们都进行以下操作 + +193 +00:10:53,287 --> 00:10:57,090 +创建我们自定义类的 annotation + +194 +00:10:57,124 --> 00:11:00,527 +将我们的绘图编码至数据 + +195 +00:11:00,561 --> 00:11:02,129 +将数据添加至 annotation + +196 +00:11:02,162 --> 00:11:06,300 +我们下次打开该文档时 +就可以使用 value:forAnnotationKey + +197 +00:11:06,333 --> 00:11:08,235 +来回读存储的绘图数据 + +198 +00:11:08,268 --> 00:11:10,003 +并将其放置到我们的覆盖视图中 + +199 +00:11:11,238 --> 00:11:14,174 +最后 将 annotation +添加到页面 + +200 +00:11:15,075 --> 00:11:16,944 +回到我们的 contents() 覆写 + +201 +00:11:16,977 --> 00:11:20,881 +现在我们页面上 +已经添加了 annotations + +202 +00:11:20,914 --> 00:11:25,018 +我们用 PDFDocument 的 +dataRepresentation() 返回结果 + +203 +00:11:26,153 --> 00:11:28,589 +当您的内容被存为 annotation 时 + +204 +00:11:28,622 --> 00:11:31,892 +文档接收者可对其进行移动 +重设大小或删除 + +205 +00:11:31,925 --> 00:11:33,260 +通常来说 那正是您想要的 + +206 +00:11:33,293 --> 00:11:38,232 +但有时 您会希望您的 annotations +作为页面的一部分烧录 + +207 +00:11:38,265 --> 00:11:42,970 +在 iOS 16 和 macOS Ventura 中 +有一个新的 PDFDocumentWriteOption + +208 +00:11:43,003 --> 00:11:44,404 +可以简化该操作 + +209 +00:11:44,438 --> 00:11:47,274 +只要添加 +burnInAnnotationsOption = true + +210 +00:11:47,307 --> 00:11:49,142 +到保存选项 即可完成 + +211 +00:11:50,544 --> 00:11:52,779 +说到 PDF 编写选项 有一些 + +212 +00:11:52,813 --> 00:11:56,717 +在 iOS 16 和 macOS Ventura 中 +已可用 + +213 +00:11:56,750 --> 00:11:58,418 +我们来看看 + +214 +00:11:58,452 --> 00:12:01,488 +CoreGraphics 一直致力于 +让 PDFs 中保存的图片 + +215 +00:12:01,522 --> 00:12:03,423 +维持最高保真度 + +216 +00:12:03,457 --> 00:12:07,294 +因此图片都以无损压缩 +全解析度保存 + +217 +00:12:07,327 --> 00:12:10,898 +如果 PDF 在大幅面打印机中 +打印出来 那堪称完美 + +218 +00:12:10,931 --> 00:12:13,634 +但是更有可能的是 +图片是在屏幕上显示的 + +219 +00:12:13,667 --> 00:12:18,005 +这些高保真度的图片数据 +带来的结果就是文件尺寸超大 + +220 +00:12:18,038 --> 00:12:20,807 +为了应对这一问题 我向大家介绍 +以下两个选项 + +221 +00:12:21,942 --> 00:12:25,379 +saveAllImagesAsJPEG 可完成 +刚刚所说的操作 + +222 +00:12:25,412 --> 00:12:28,015 +不管图片是如何创建的 +都可以通过 JPEG 保存 + +223 +00:12:28,048 --> 00:12:30,150 +解码入 PDF + +224 +00:12:31,351 --> 00:12:34,154 +optimizeImagesForScreen 可对 +图片进行下采样 + +225 +00:12:34,188 --> 00:12:37,057 +直至 HiDPI 屏幕分辨率的最大值 + +226 +00:12:37,090 --> 00:12:39,159 +这两个选项可以同时使用 + +227 +00:12:41,428 --> 00:12:44,665 +createLinearizedPDF 创建 +一种特殊类型的 PDF + +228 +00:12:44,698 --> 00:12:46,600 +针对网络进行优化 + +229 +00:12:46,633 --> 00:12:50,971 +PDF 格式 最初在互联网出现前 +就已设计为 + +230 +00:12:51,004 --> 00:12:53,207 +从文件末尾读取 + +231 +00:12:53,240 --> 00:12:55,876 +这意味着它要提前下载 + +232 +00:12:55,909 --> 00:12:57,911 +所需的只是展示 + +233 +00:12:57,945 --> 00:13:01,415 +一个线性化 PDF 有了展示文件 +开始的第一页 + +234 +00:13:01,448 --> 00:13:03,450 +所需的所有内容 + +235 +00:13:03,483 --> 00:13:05,419 +因此网页浏览器可先显示该内容 + +236 +00:13:05,452 --> 00:13:06,920 +并同时加载剩余部分 + +237 +00:13:08,722 --> 00:13:12,059 +您可以将这些选项传送到 +PDFDocument 的 dataRepresentation + +238 +00:13:12,092 --> 00:13:14,394 +或 writeToURL 方法 + +239 +00:13:14,428 --> 00:13:18,131 +正是如此 PDFKit 强大 简便 + +240 +00:13:18,165 --> 00:13:21,902 +今天在 iOS 和 macOS 以及有新功能的 +iOS 16 和 macOS Ventura 中 + +241 +00:13:21,935 --> 00:13:25,239 +许多 App 都在使用 + +242 +00:13:25,272 --> 00:13:27,307 +我已经迫不及待要看看 +您的成果了 + +243 +00:13:28,642 --> 00:13:30,511 +请查看下方的讲座 + +244 +00:13:30,544 --> 00:13:32,012 +了解更多信息 + +245 +00:13:32,045 --> 00:13:33,146 +感谢大家的观看 + +246 +00:13:33,180 --> 00:13:36,183 +[古怪的音乐] + diff --git a/zho/2022 Session 10090 What's new in TextKit and text views.srt b/zho/2022 Session 10090 What's new in TextKit and text views.srt new file mode 100644 index 0000000..7cbaa79 --- /dev/null +++ b/zho/2022 Session 10090 What's new in TextKit and text views.srt @@ -0,0 +1,1567 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:13,714 +大家好 欢迎收看 +“TextKit 和文本视图的新功能” + +3 +00:00:14,681 --> 00:00:17,384 +我叫 Donna Tom +是一名 TextKit 工程师 + +4 +00:00:18,752 --> 00:00:23,924 +在 iOS 15 和 macOS Monterey 中 +我们引入了 TextKit 2 + +5 +00:00:23,957 --> 00:00:27,094 +这是一个功能强大的新文本引擎 +具有更高的性能 + +6 +00:00:27,127 --> 00:00:29,263 +正确性和安全性 + +7 +00:00:30,264 --> 00:00:33,100 +TextKit 2 基于视口的布局架构 + +8 +00:00:33,133 --> 00:00:35,469 +提供了高性能的文本布局 + +9 +00:00:35,502 --> 00:00:38,705 +尤其是对于包含大量内容的文档 + +10 +00:00:40,174 --> 00:00:44,711 +TextKit 2 通过消除使用字形 +不必要的复杂性 + +11 +00:00:44,745 --> 00:00:49,049 +为全球的用户提供了 +更好的文本体验 + +12 +00:00:49,082 --> 00:00:52,219 +并且它完全支持 OpenType + +13 +00:00:52,252 --> 00:00:54,621 +和可变字体等现代字体技术 + +14 +00:00:56,356 --> 00:00:59,359 +TextKit 2 专注于使用更高级的对象 + +15 +00:00:59,393 --> 00:01:01,261 +来控制文本布局 + +16 +00:01:01,295 --> 00:01:04,665 +使您可以更轻松地自定义文本的布局 + +17 +00:01:04,698 --> 00:01:07,768 +从而可以用更少的代码 +来构建更酷的东西 + +18 +00:01:10,504 --> 00:01:12,773 +接下来 TextKit 2 引擎构成了 + +19 +00:01:12,806 --> 00:01:18,145 +所有 Apple 平台上 +文本布局和渲染的基础 + +20 +00:01:19,713 --> 00:01:24,051 +未来的性能增强 更新和改进 + +21 +00:01:24,084 --> 00:01:27,387 +都将集中在 TextKit 2 引擎上 + +22 +00:01:28,188 --> 00:01:31,258 +更新到 TextKit 2 后 +您的 App 将可以 + +23 +00:01:31,291 --> 00:01:33,560 +在我们推出这些改进后 +从中受益 + +24 +00:01:34,394 --> 00:01:36,563 +有关 TextKit2 的深入介绍 + +25 +00:01:36,597 --> 00:01:39,900 +请观看 Meet TextKit2 视频 + +26 +00:01:39,933 --> 00:01:42,669 +该视频涵盖了基础知识 + +27 +00:01:42,703 --> 00:01:46,807 +以及如何使用 TextKit 2 +构建自己的文本布局组件 + +28 +00:01:47,641 --> 00:01:52,579 +另一方面 本视频则会介绍 +TextKit 2 的最新进展 + +29 +00:01:52,613 --> 00:01:56,683 +以及如何充分利用 +TextKit 2 支持的多个文本视图 + +30 +00:01:56,717 --> 00:02:02,155 +没错 我说的是多个文本视图 复数形式 + +31 +00:02:02,189 --> 00:02:05,626 +因为现在 +截至 iOS 16 和 macOS Ventura + +32 +00:02:05,659 --> 00:02:09,963 +UIKit 和 AppKit 中的 +所有文本控件都使用 TextKit 2 + +33 +00:02:09,997 --> 00:02:12,766 +包括 UITextView + +34 +00:02:12,799 --> 00:02:17,938 +所以我们在整个系统中使用 TextKit 2 +进行布局和渲染 + +35 +00:02:17,971 --> 00:02:22,876 +让所有 App 尽快过渡到 TextKit 2 +非常重要 + +36 +00:02:22,910 --> 00:02:27,481 +我们添加了许多工具 +来帮您更轻松地过渡 + +37 +00:02:27,514 --> 00:02:31,251 +对于许多 App 来说 +这可能是零代码转换 + +38 +00:02:31,285 --> 00:02:33,153 +我们预计 对于那些没有对文本视图 + +39 +00:02:33,187 --> 00:02:36,890 +进行任何特殊修改的 App 来说 +情况也是如此 + +40 +00:02:36,924 --> 00:02:39,092 +稍后我会告诉您更多这方面的信息 + +41 +00:02:40,294 --> 00:02:44,031 +但首先 我将介绍 +TextKit 2 中的新增功能 + +42 +00:02:44,064 --> 00:02:46,700 +包括我刚才提到的一些工具 + +43 +00:02:48,001 --> 00:02:50,270 +之后 我将深入讲解文本视图的 + +44 +00:02:50,304 --> 00:02:53,774 +TextKit 1 兼容模式的细节 + +45 +00:02:54,942 --> 00:02:58,979 +然后我将讨论在准备将代码 + +46 +00:02:59,012 --> 00:03:02,182 +转换到 TextKit 2 时 +可以使用的现代化策略 + +47 +00:03:03,550 --> 00:03:07,187 +首先是 TextKit 2 中的新功能 + +48 +00:03:08,322 --> 00:03:12,059 +TextKit 2 最早出现在 +iOS 15 中的 UIKit + +49 +00:03:12,092 --> 00:03:14,928 +为了使用 TextKit 2 +UITextField 进行了升级 + +50 +00:03:15,529 --> 00:03:20,234 +在 iOS 16 中 +UIKit 向 TextKit 2 的过渡已经完成 + +51 +00:03:20,267 --> 00:03:26,340 +所有文本控件默认使用 TextKit 2 +包括 UITextView + +52 +00:03:26,373 --> 00:03:30,010 +大多数文本视图 +将自动选择加入 TextKit 2 + +53 +00:03:30,043 --> 00:03:32,846 +而无需您的任何操作 + +54 +00:03:32,880 --> 00:03:36,884 +只有少数情况下 +文本视图可能无法选择 + +55 +00:03:36,917 --> 00:03:40,521 +我将在本视频的兼容性部分进行介绍 + +56 +00:03:42,155 --> 00:03:44,458 +AppKit 也有类似的情况 + +57 +00:03:44,491 --> 00:03:49,329 +TextKit 2 最早出现在 +macOS Big Sur 中的 AppKit + +58 +00:03:49,363 --> 00:03:53,867 +在 macOS Monterey 中 +NSTextField 已升级为默认使用它 + +59 +00:03:53,901 --> 00:03:57,671 +通过选择加入 +它可用于 NSTextView + +60 +00:03:58,939 --> 00:04:03,944 +在 macOS Ventura 中 +所有文本控件默认使用 TextKit 2 + +61 +00:04:03,977 --> 00:04:09,583 +就像 UITextView 大多数 NSTextViews +自动选择加入TextKit 2 + +62 +00:04:09,616 --> 00:04:11,985 +而不需要您的任何操作 + +63 +00:04:14,221 --> 00:04:17,858 +TextEdit 是 NSTextView 的 +一个薄包装器 + +64 +00:04:17,891 --> 00:04:22,029 +它在 macOS Ventura 的任何地方 +都使用 TextKit 2 + +65 +00:04:22,062 --> 00:04:27,768 +自 macOS Big Sur 以来 TextEdit +一直在纯文本模式下使用 TextKit 2 + +66 +00:04:27,801 --> 00:04:32,272 +在 macOS Ventura 中 +富文本模式也使用 TextKit 2 + +67 +00:04:34,708 --> 00:04:37,277 +由于 TextKit 2 是新标准 + +68 +00:04:37,311 --> 00:04:42,683 +我们为 UITextView 和 NSTextView +添加了一些方便的构造函数 + +69 +00:04:42,716 --> 00:04:46,453 +使用这些新的构造函数在初始化时 + +70 +00:04:46,486 --> 00:04:48,689 +选择使用哪个文本引擎 + +71 +00:04:49,957 --> 00:04:52,326 +要创建使用 TextKit 2 的文本视图 + +72 +00:04:52,359 --> 00:04:55,095 +请使用新的构造函数 + +73 +00:04:55,128 --> 00:04:58,332 +并为 UsingTextLayoutManager +参数传递 true + +74 +00:04:58,365 --> 00:05:04,371 +如果文本视图需要使用 TextKit 1 +以实现兼容性 则改为传递 false + +75 +00:05:07,207 --> 00:05:12,045 +在 Interface Builder 中创建的 +文本视图有一个新的文本布局选项 + +76 +00:05:12,079 --> 00:05:16,149 +通过此新选项 +您可以控制在每个实例上 + +77 +00:05:16,183 --> 00:05:18,519 +使用哪种布局系统 + +78 +00:05:18,552 --> 00:05:22,756 +默认设置是系统默认值 即 TextKit 2 + +79 +00:05:23,757 --> 00:05:28,762 +还可以选择显式使用 +TextKit 2 或 TextKit 1 + +80 +00:05:30,664 --> 00:05:34,468 +TextKit 2 现在支持非简单文本容器 + +81 +00:05:34,501 --> 00:05:39,606 +非简单文本容器中可能有漏洞或缺口 + +82 +00:05:39,640 --> 00:05:43,810 +这允许文本环绕图像或其他内联内容 + +83 +00:05:45,145 --> 00:05:47,414 +若要创建非简单文本容器 + +84 +00:05:47,447 --> 00:05:51,552 +请使用 NSTextContainer 上的 + +85 +00:05:51,585 --> 00:05:55,656 +exclusionPaths 属性来定义 +不应放置文本的区域 + +86 +00:05:55,689 --> 00:06:00,460 +关于如何做到这一点的示例 +请查看与此视频相关的参考资料中的 + +87 +00:06:00,494 --> 00:06:03,497 +TextKitAndTextView 示例代码 + +88 +00:06:03,530 --> 00:06:07,534 +您可以在排除路径选项卡上 +找到相关示例 + +89 +00:06:10,137 --> 00:06:13,207 +我们增强了 TextKit 2 中的 +换行符引擎 + +90 +00:06:13,240 --> 00:06:17,477 +为两端对齐的段落选择 +更均匀的换行符 + +91 +00:06:17,511 --> 00:06:22,382 +这是一个微妙的变化 +在较长的文本段落中更容易注意到 + +92 +00:06:23,684 --> 00:06:27,688 +在这里我们有两个版本的同一文本 +放在同一个区域 + +93 +00:06:28,689 --> 00:06:32,526 +请注意 使用传统的换行符时 + +94 +00:06:32,559 --> 00:06:34,528 +线条会拉伸 字间距也会变大 + +95 +00:06:36,029 --> 00:06:37,698 +在新的偶数换行中 + +96 +00:06:37,731 --> 00:06:40,033 +这种情况要少得多 + +97 +00:06:40,067 --> 00:06:42,503 +这使得文本更容易阅读 + +98 +00:06:42,536 --> 00:06:45,272 +并且您可以通过 TextKit 2 免费获得 + +99 +00:06:45,305 --> 00:06:47,107 +无需采用 + +100 +00:06:48,642 --> 00:06:53,680 +最后 我们在 TextKit 2 中 +为所有平台添加了文本列表支持 + +101 +00:06:53,714 --> 00:06:56,750 +使用文本列表 您可以通过编程方式 + +102 +00:06:56,783 --> 00:07:00,387 +创建编号或项目符号列表 +以便在文本视图中显示 + +103 +00:07:00,420 --> 00:07:06,994 +TextKit 2 使用 NSTextList +来表示文本列表 就像 TextKit 1 一样 + +104 +00:07:07,027 --> 00:07:10,197 +NSTextList 过去仅在 AppKit 中可用 + +105 +00:07:10,230 --> 00:07:13,767 +但在iOS 16 中 它在 UIKit 中也可用 + +106 +00:07:15,669 --> 00:07:20,774 +将 NSTextList 与 +NSmutableParagraphStyle 一起使用 + +107 +00:07:20,807 --> 00:07:25,712 +可以指定文本存储中的段落 +格式化为列表以供显示 + +108 +00:07:25,746 --> 00:07:29,283 +文本视图负责从文本存储中 +提取这些属性 + +109 +00:07:29,316 --> 00:07:34,221 +并将段落内容重新格式化为列表 + +110 +00:07:35,856 --> 00:07:41,795 +虽然 NSTextList 本身并不是新的 +但有一些新增的 TextKit 2 + +111 +00:07:41,828 --> 00:07:44,164 +由于列表有嵌套项 + +112 +00:07:44,198 --> 00:07:47,267 +所以很自然地将它们表示为树结构 + +113 +00:07:47,301 --> 00:07:52,973 +在 TextKit 2 中 +我们增强了 NSTextElement + +114 +00:07:53,006 --> 00:07:56,443 +以支持将它们结构化为具有 +访问子元素和父元素属性的树 + +115 +00:07:58,011 --> 00:08:02,616 +我们还添加了一个新的 +元素子类 叫做NSTextListElement + +116 +00:08:02,649 --> 00:08:07,487 +当内容管理器在文本内容中 +遇到 NSTextList 时 + +117 +00:08:07,521 --> 00:08:12,192 +它将生成 NSTextListElements +来表示列表中的项目 + +118 +00:08:14,394 --> 00:08:18,565 +要更深入地了解 +如何创建文本列表和添加项目 + +119 +00:08:18,599 --> 00:08:22,302 +请参阅 +TextKitAndTextView 示例代码 + +120 +00:08:22,336 --> 00:08:25,205 +您可以在列表选项卡上找到相关示例 + +121 +00:08:27,474 --> 00:08:29,443 +在探索示例代码时 + +122 +00:08:29,476 --> 00:08:31,879 +请不要错过文本附件示例 + +123 +00:08:31,912 --> 00:08:37,084 +该示例演示了如何使用 TextKit 2 中的 +文本附件视图提供程序 API + +124 +00:08:38,852 --> 00:08:43,223 +这些 API 允许您使用 +UI 或 NSView 作为文本附件 + +125 +00:08:43,257 --> 00:08:47,294 +并且事件可以由附件视图直接处理 + +126 +00:08:47,327 --> 00:08:50,998 +因此使用文本附件处理事件 +就变得更加容易了 + +127 +00:08:51,031 --> 00:08:54,268 +而且只有使用 TextKit 2 +才有可能做到这点 + +128 +00:08:54,301 --> 00:08:57,838 +好了 这就是 TextKit 2 中新增的功能 + +129 +00:08:57,871 --> 00:09:03,443 +接下来 我将详细介绍 +TextKit 1 兼容性模式 + +130 +00:09:03,477 --> 00:09:08,015 +由于 TextKit 2 与 TextKit 1 的设计 +截然不同 + +131 +00:09:08,048 --> 00:09:12,553 +我们理解 对于大量投资于 +TextKit 1 架构的 App 来说 + +132 +00:09:12,586 --> 00:09:17,157 +全面采用 TextKit 2 +可能需要一些时间 + +133 +00:09:17,191 --> 00:09:21,662 +我们希望这些 App 能够继续工作 +直到实现过渡 + +134 +00:09:21,695 --> 00:09:25,399 +这就是为什么我们为 +UITextView 和 NSTextView + +135 +00:09:25,432 --> 00:09:28,468 +添加了一个特殊的 TextKit 1 +兼容模式 + +136 +00:09:28,502 --> 00:09:32,172 +当您显式调用 +NSLayoutManager API 时 + +137 +00:09:32,206 --> 00:09:35,943 +文本视图将用 NSTextLayoutManager +替换其 NSLayoutManager + +138 +00:09:35,976 --> 00:09:41,215 +并将自身重新配置为使用 TextKit 1 + +139 +00:09:41,248 --> 00:09:45,052 +如果文本视图遇到 TextKit 2 +尚不支持的属性 + +140 +00:09:45,085 --> 00:09:50,557 +例如表格 或者在打印时 +也会发生这种情况 + +141 +00:09:52,826 --> 00:09:57,865 +如果在 UITextView 中 +遇到意外运行时回退到 TextKit 1 + +142 +00:09:57,898 --> 00:10:01,802 +请检查日志中有关开关的警告消息 + +143 +00:10:01,835 --> 00:10:07,274 +在符号下划线上设置断点 + +144 +00:10:07,307 --> 00:10:11,044 +以捕获堆栈跟踪 +和其他有用的调试信息 + +145 +00:10:13,046 --> 00:10:15,549 +对于 NSTextView +您可以通过订阅 willSwitch + +146 +00:10:15,582 --> 00:10:19,953 +或 didSwitchToNSLayoutManager 通知 + +147 +00:10:19,987 --> 00:10:23,223 +来获取有关意外运行时回退的 +更多信息 + +148 +00:10:25,292 --> 00:10:27,694 +如果您必须退回到 TextKit 1 + +149 +00:10:27,728 --> 00:10:31,064 +最好在初始化时退出 + +150 +00:10:31,098 --> 00:10:34,501 +以编程方式初始化的文本视图 + +151 +00:10:34,535 --> 00:10:39,039 +通过使用自己的文本容器和 +TextKit 1 布局管理器来实现这一点 + +152 +00:10:40,707 --> 00:10:43,610 +另一种选择是使用新的便利构造函数 + +153 +00:10:43,644 --> 00:10:49,316 +来初始化 TextKit 1 文本视图 +并将 false 作为参数传递 + +154 +00:10:49,349 --> 00:10:52,152 +这将使您的文本视图使用 TextKit 1 + +155 +00:10:54,354 --> 00:10:57,057 +第三个选项是使用 Interface Builder + +156 +00:10:57,090 --> 00:11:01,862 +并在文本视图中 +将新的文本布局选项设置为 TextKit 1 + +157 +00:11:03,230 --> 00:11:05,432 +这里有一点是需要注意的 + +158 +00:11:05,465 --> 00:11:08,836 +如果要在初始化期间或之后 + +159 +00:11:08,869 --> 00:11:11,672 +调出文本容器的布局管理器 + +160 +00:11:11,705 --> 00:11:16,643 +则文本视图将返回到设计的 TextKit 1 + +161 +00:11:16,677 --> 00:11:21,381 +在初始化期间创建 +所有的 TextKit 2 对象 + +162 +00:11:21,415 --> 00:11:24,351 +稍后将其丢弃 这是非常低效的 + +163 +00:11:24,384 --> 00:11:28,922 +根据时间的不同 +还有潜在的用户副作用 + +164 +00:11:28,956 --> 00:11:32,559 +如果它发生在键入过程中 +文本视图可能会失去焦点 + +165 +00:11:32,593 --> 00:11:38,899 +并中断输入 +需要再次选择文本视图才能恢复 + +166 +00:11:38,932 --> 00:11:44,705 +可以通过在初始化时选择文本视图 +来避免这种情况 + +167 +00:11:44,738 --> 00:11:47,708 +既然您已经了解了所有的兼容性模式 + +168 +00:11:47,741 --> 00:11:52,212 +现在是时候谈谈如何通过更新 App +和采用 TextKit 2 + +169 +00:11:52,246 --> 00:11:54,281 +来完全避免它了 + +170 +00:11:54,314 --> 00:11:57,718 +我想让您记住一件非常重要的事 + +171 +00:11:59,553 --> 00:12:03,023 +每个文本视图只能有一个布局管理器 + +172 +00:12:03,056 --> 00:12:06,393 +文本视图不能 +同时拥有 NSTextLayoutManager + +173 +00:12:06,426 --> 00:12:10,030 +和 NSLayoutManager + +174 +00:12:11,698 --> 00:12:17,004 +一旦文本视图切换到 TextKit 1 +就无法自动返回 + +175 +00:12:17,037 --> 00:12:20,073 +切换布局系统的过程代价很高 + +176 +00:12:20,107 --> 00:12:25,345 +并且您会丢失切换时 +存在的任何 UI 状态 + +177 +00:12:25,379 --> 00:12:28,348 +因此为了优化性能和可用性 + +178 +00:12:28,382 --> 00:12:33,554 +系统不会将文本视图 +从 TextKit 1 切换回 TextKit 2 + +179 +00:12:33,587 --> 00:12:35,389 +这是单向操作 + +180 +00:12:36,790 --> 00:12:42,429 +这意味着避免兼容模式非常重要 + +181 +00:12:42,462 --> 00:12:46,934 +文本视图进入兼容模式 +有几个不同的原因 + +182 +00:12:46,967 --> 00:12:50,838 +文本视图进入兼容模式的第一个原因 + +183 +00:12:50,871 --> 00:12:55,342 +是访问文本视图的 +layoutManager 属性 + +184 +00:12:55,375 --> 00:12:57,778 +其他原因则不太常见 + +185 +00:12:59,746 --> 00:13:01,181 +因此一个重要的策略是 + +186 +00:13:01,215 --> 00:13:05,219 +避免访问文本视图的布局管理器属性 + +187 +00:13:05,252 --> 00:13:10,991 +还应避免通过文本视图的 +文本容器访问布局管理器 + +188 +00:13:11,024 --> 00:13:14,194 +检查代码中这些属性的使用情况 + +189 +00:13:14,228 --> 00:13:18,432 +并将其删除或替换为 +与 TextKit 2 等效的属性 + +190 +00:13:20,334 --> 00:13:24,705 +如果您将 App 部署到 +没有 TextKit 2 的旧操作系统版本 + +191 +00:13:24,738 --> 00:13:28,809 +您可能无法 +完全删除 layoutManager 代码 + +192 +00:13:29,977 --> 00:13:35,048 +在这种情况下 应首先检查 +文本视图的 NSTextLayoutManager + +193 +00:13:36,216 --> 00:13:39,086 +将 TextKit 2 代码放在 if 子句中 + +194 +00:13:39,119 --> 00:13:42,389 +将 TextKit 1 代码放在 else 子句中 + +195 +00:13:42,422 --> 00:13:45,392 +包括 layoutManager 访问权限 + +196 +00:13:45,425 --> 00:13:50,531 +这样 TextKit 1 代码 +仅在 TextKit 2 不可用时运行 + +197 +00:13:50,564 --> 00:13:55,469 +并且 layoutManager 查询不会导致 +意外回退到 TextKit 1 + +198 +00:13:57,771 --> 00:14:00,641 +如果您遵循了所有这些建议 +但仍然遇到了 + +199 +00:14:00,674 --> 00:14:04,411 +来自系统的 +对 TextKit 1 的意外回退 + +200 +00:14:04,444 --> 00:14:09,483 +那就是我们的问题了 +请向“反馈助手”报告此问题 + +201 +00:14:09,516 --> 00:14:12,519 +在回退时包含堆栈跟踪的捕获 + +202 +00:14:12,553 --> 00:14:13,921 +您可以通过在 UIKit 中的下划线 + +203 +00:14:13,954 --> 00:14:17,791 +UITextViewEnableingCompatibilityMode 上 +断开获取 + +204 +00:14:17,824 --> 00:14:22,229 +也可以通过 AppKit 中的 + +205 +00:14:22,262 --> 00:14:24,231 +willSwitchToNSLayoutManagerNotification +来获取 + +206 +00:14:25,632 --> 00:14:29,336 +好的 现在我将从 +NSLayoutManager 开始 + +207 +00:14:29,369 --> 00:14:33,974 +详细介绍与 TextKit 1 类型 +相关的更新代码 + +208 +00:14:34,007 --> 00:14:37,444 +审核了 NSLayoutManager +查询的代码后 + +209 +00:14:37,477 --> 00:14:41,982 +您需要找出与 NSTextLayoutManager +等价的 TextKit 2 + +210 +00:14:44,418 --> 00:14:49,122 +一些布局管理器 API +在 TextKit 1 和 2 之间有相似的名称 + +211 +00:14:49,156 --> 00:14:51,892 +替换很简单 + +212 +00:14:51,925 --> 00:14:53,894 +这里有几个例子 + +213 +00:14:53,927 --> 00:14:59,032 +在 TextKit 1 中 +在 NSLayoutManager 上调用 + +214 +00:14:59,066 --> 00:15:04,805 +usedRect (for: textContainer) +来获取文本容器内文本的边框 + +215 +00:15:04,838 --> 00:15:09,643 +在 TextKit 2 中 您可以从 +NSTextLayoutManager 上的 + +216 +00:15:09,676 --> 00:15:11,712 +usageBoundsForTextContainer +属性中获得此信息 + +217 +00:15:12,779 --> 00:15:16,316 +在 TextKit 1 中 我们使用临时属性 + +218 +00:15:16,350 --> 00:15:21,455 +来表示只影响渲染 +而不影响布局的属性 + +219 +00:15:21,488 --> 00:15:25,792 +在 TextKit 2 中 +我们更准确地将这些称为渲染属性 + +220 +00:15:27,861 --> 00:15:30,030 +但是有一些 TextKit 1 API + +221 +00:15:30,063 --> 00:15:33,634 +在 TextKit 2 中没有直接的对应 API + +222 +00:15:33,667 --> 00:15:36,436 +要了解原因 您需要了解 + +223 +00:15:36,470 --> 00:15:39,640 +印度文 (如卡纳达语) 脚本中 +有些单词没有 + +224 +00:15:39,673 --> 00:15:42,743 +正确的字符来进行字形映射 + +225 +00:15:43,644 --> 00:15:46,079 +在这些脚本中 字形可以被分割 + +226 +00:15:46,113 --> 00:15:49,349 +重新排序 重组 甚至删除 + +227 +00:15:50,751 --> 00:15:53,787 +NSLayoutManager 上 +基于字形的 API + +228 +00:15:53,820 --> 00:15:58,392 +假设您可以直接 +将连续的字符范围 + +229 +00:15:58,425 --> 00:16:03,630 +与连续的字形范围相关联 +但这并不适用于所有脚本 + +230 +00:16:03,664 --> 00:16:07,134 +使用这些 API 可能会导致 +用卡纳达语等脚本编写的 + +231 +00:16:07,167 --> 00:16:09,937 +文本的布局和呈现中断 + +232 +00:16:09,970 --> 00:16:14,508 +这就是为什么 TextKit 2 中的 +字形 API 为零的原因 + +233 +00:16:14,541 --> 00:16:19,413 +您不能仅仅用单个 TextKit 2 API +替换 TextKit 1 glyph API + +234 +00:16:19,446 --> 00:16:23,016 +替换这些 API 需要不同的方法 + +235 +00:16:24,818 --> 00:16:28,422 +这里是如何更新基于字形的代码 + +236 +00:16:28,455 --> 00:16:33,060 +第一步是识别您正在使用的字形 API + +237 +00:16:33,093 --> 00:16:36,597 +接下来 看看您要如何使用这些 API + +238 +00:16:36,630 --> 00:16:40,701 +并从高级别上定义您想做什么 + +239 +00:16:40,734 --> 00:16:44,171 +基于字形的代码是非常低级的 + +240 +00:16:44,204 --> 00:16:47,107 +并且有许多细节与您的高级任务无关 + +241 +00:16:48,342 --> 00:16:50,110 +定义了高级任务后 + +242 +00:16:50,143 --> 00:16:54,448 +请检查 TextKit 2 中可用的结构 + +243 +00:16:54,481 --> 00:16:58,952 +例如布局片段 行片段和文本选择 + +244 +00:16:58,986 --> 00:17:02,155 +这些可以帮助您完成任务 + +245 +00:17:02,189 --> 00:17:06,126 +例如 考虑下面的 TextKit 1 代码 + +246 +00:17:06,159 --> 00:17:09,296 +这里使用了两个字形 API + +247 +00:17:09,329 --> 00:17:10,964 +numberOfGlyphs + +248 +00:17:10,998 --> 00:17:15,836 +和 lineFragmentRect +(for glyphat:index) + +249 +00:17:15,869 --> 00:17:19,973 +这段 TextKit 1 代码 +历遍了文档中的所有字形 + +250 +00:17:20,007 --> 00:17:22,743 +并计算行片段的长度 + +251 +00:17:22,776 --> 00:17:27,581 +高级任务是计算文本视图中 + +252 +00:17:27,614 --> 00:17:29,816 +已包装文本的行数 + +253 +00:17:29,850 --> 00:17:32,953 +由于此代码使用的是行片段 rect + +254 +00:17:32,986 --> 00:17:37,124 +因此要使用的 TextKit 2 结构 +是 NSTextLineFragment + +255 +00:17:37,157 --> 00:17:39,693 +和 NSTextLayoutFragment + +256 +00:17:40,594 --> 00:17:43,964 +这是为使用 TextKit 2 而重写的代码 + +257 +00:17:43,997 --> 00:17:46,400 +它没有历遍字形 + +258 +00:17:46,433 --> 00:17:49,837 +而是枚举文档中的文本布局片段 + +259 +00:17:49,870 --> 00:17:53,740 +并提供一个闭包来计算 + +260 +00:17:53,774 --> 00:17:55,909 +每个布局片段中的所有文本行片段 + +261 +00:17:57,578 --> 00:18:01,648 +在为 TextKit 2 更新自己的代码时 +请记住这个示例 + +262 +00:18:01,682 --> 00:18:06,587 +现在我将换个方向 +讨论如何更新基于 NSRange 的代码 + +263 +00:18:09,756 --> 00:18:14,561 +TextKit 1 使用 NSRange +索引文本内容 + +264 +00:18:14,595 --> 00:18:19,099 +NSRange 是字符串的线性索引 + +265 +00:18:19,132 --> 00:18:22,703 +对于文本 Hello TextKit 2! +感叹号表示 + +266 +00:18:22,736 --> 00:18:27,674 +代表“TextKit 2 exclamation point” 的 +NSRange 的 + +267 +00:18:27,708 --> 00:18:31,278 +位置是 6 长度是 10 + +268 +00:18:31,311 --> 00:18:36,016 +因为它从第 6 个字符开始 +长度是 10 个字符 + +269 +00:18:36,049 --> 00:18:38,785 +这种线性模型很容易理解 + +270 +00:18:38,819 --> 00:18:41,755 +对于字符串的索引非常有效 + +271 +00:18:43,557 --> 00:18:47,394 +但是线性模型不适用于索引 + +272 +00:18:47,427 --> 00:18:50,297 +任何比字符串更具结构的内容 + +273 +00:18:50,330 --> 00:18:52,833 +举一个例子 + +274 +00:18:52,866 --> 00:18:56,336 +HTML 文档被表示为一个树形结构 + +275 +00:18:56,370 --> 00:18:58,872 +其中每个标签是树中的一个节点 + +276 +00:18:58,906 --> 00:19:01,341 +如果我们的 Hello TextKit 2!文本 + +277 +00:19:01,375 --> 00:19:03,710 +是 HTML 文档的一部分 + +278 +00:19:03,744 --> 00:19:08,215 +我们的 NSRange 无法告诉我们 +文本在 span 标签内 + +279 +00:19:08,248 --> 00:19:10,851 +嵌套了 3 层 + +280 +00:19:10,884 --> 00:19:14,488 +线性模型的表达能力 +不足以存储该信息 + +281 +00:19:14,521 --> 00:19:19,426 +所以我们不能用它来索引 +像这样的嵌套结构 + +282 +00:19:19,459 --> 00:19:26,466 +这就是为什么 TextKit 2 添加了 +新类型来表示文本内容中的范围 + +283 +00:19:26,500 --> 00:19:31,271 +NSTextLocation 是一个 +能够表示文本内容中 + +284 +00:19:31,305 --> 00:19:33,574 +单个位置的对象 + +285 +00:19:33,607 --> 00:19:38,245 +NSTextRange 由开始和结束位置组成 + +286 +00:19:38,278 --> 00:19:42,449 +结束位置不在该范围内 + +287 +00:19:42,482 --> 00:19:46,954 +这些新类型可以通过 +将位置定义为 DOM 节点 + +288 +00:19:46,987 --> 00:19:52,426 +加上字符偏移量 +来表示这个 HTML 文档的嵌套结构 + +289 +00:19:53,594 --> 00:19:58,532 +既然 NSTextLocation 是一个协议 +那任何自定义对象都可以是一个位置 + +290 +00:19:58,565 --> 00:20:03,437 +只要它实现了 +NSTextLocation 协议方法 + +291 +00:20:03,470 --> 00:20:07,407 +这对于处理不同类型的支持模型中 +结构化数据的后备存储来说 + +292 +00:20:07,441 --> 00:20:10,344 +是至关重要的基础设施 + +293 +00:20:11,912 --> 00:20:15,983 +但是文本视图是建立在 +没有这种结构的 + +294 +00:20:16,016 --> 00:20:19,019 +NSAttributedString 后台存储上的 +我们无法在不破坏 + +295 +00:20:19,052 --> 00:20:23,123 +许多 App 的情况下改变这一点 +包括您的 App + +296 +00:20:23,156 --> 00:20:26,994 +因此 在使用 selectedRange +或 scrollRangeToVisible 等 + +297 +00:20:27,027 --> 00:20:30,731 +文本视图 API 时 您将继续使用 +NSRange 布局管理器或内容管理器 + +298 +00:20:30,764 --> 00:20:34,968 +当与 TextKit 2 通信时 + +299 +00:20:35,002 --> 00:20:39,473 +您需要在 NSRange +和 NSTextRange 之间进行转换 + +300 +00:20:40,941 --> 00:20:44,778 +要将文本视图的 NSRange +转换为 NSTextRange + +301 +00:20:44,811 --> 00:20:49,716 +请将位置定义为 +属性化字符串的整数索引 + +302 +00:20:50,851 --> 00:20:55,589 +使用 NSRange 位置 +作为 NSTextRange 的起始位置 + +303 +00:20:56,790 --> 00:21:02,596 +使用 NSRange 位置加上长度 +作为 NSTextRange 的结束位置 + +304 +00:21:02,629 --> 00:21:07,234 +从概念上讲 这就是从 NSRange +映射到 NSTextRange 的方法 + +305 +00:21:09,069 --> 00:21:11,705 +实际上 代码看起来有点不同 + +306 +00:21:11,738 --> 00:21:15,442 +因为 NSTextLocations 必须是对象 + +307 +00:21:17,110 --> 00:21:20,547 +您需要通过内容管理器来计算位置 + +308 +00:21:21,815 --> 00:21:24,785 +对于开始位置 +请向内容管理员询问 + +309 +00:21:24,818 --> 00:21:27,354 +文档开始的位置 + +310 +00:21:27,387 --> 00:21:31,091 +然后根据 NSRange 的位置 +对其进行偏移 + +311 +00:21:31,124 --> 00:21:36,530 +然后将起始位置偏移 +NSRange 的长度以获得结束位置 + +312 +00:21:38,899 --> 00:21:42,369 +要朝另一个方向发展 +请使用文本内容管理器 + +313 +00:21:42,402 --> 00:21:44,204 +以获取两个不同的偏移量 + +314 +00:21:45,772 --> 00:21:49,676 +NSRange 的位置是文档开头 + +315 +00:21:49,710 --> 00:21:53,347 +和 NSTextRange 位置之间的偏移量 + +316 +00:21:53,380 --> 00:21:57,651 +NSRange 的长度是 NSTextRange 的 +开始和结束位置 + +317 +00:21:57,684 --> 00:21:59,686 +之间的偏移量 + +318 +00:22:01,455 --> 00:22:06,193 +UITextViews 和 UITextFields +符合 UITextInput 协议 + +319 +00:22:06,226 --> 00:22:09,963 +该协议使用 UITextPosition 和 range + +320 +00:22:09,997 --> 00:22:12,399 +大多数时候 在使用 + +321 +00:22:12,432 --> 00:22:16,003 +UITextView 或 UITextField 时 + +322 +00:22:16,036 --> 00:22:19,540 +您不需要将 UITextRange +直接转换为 NSTextRange + +323 +00:22:19,573 --> 00:22:22,009 +如果您想这样做 使用整数偏移量 + +324 +00:22:22,042 --> 00:22:24,611 +作为两个范围类型之间的媒介 + +325 +00:22:26,713 --> 00:22:30,851 +另一方面 如果您使用 +带有 UITextInput 的自定义视图 + +326 +00:22:30,884 --> 00:22:34,288 +您可以直接控制视图中 + +327 +00:22:34,321 --> 00:22:38,592 +使用的 UITextPosition +和 UITextRange 子类 + +328 +00:22:38,625 --> 00:22:41,495 +您可以使您的 UITextPosition 子类 + +329 +00:22:41,528 --> 00:22:45,399 +符合 NSTextLocation 实现所需的方法 + +330 +00:22:45,432 --> 00:22:49,703 +并使用您的子类直接创建 +NSTextRanges + +331 +00:22:51,138 --> 00:22:56,076 +最后 这里提醒您避免 +跨不同视图重用 + +332 +00:22:56,109 --> 00:23:02,416 +UITextPosition 对象 +即使两个视图中的内容相似 + +333 +00:23:02,449 --> 00:23:07,721 +UITextPosition 仅对 +用于创建它的视图有效 + +334 +00:23:09,223 --> 00:23:12,526 +好了 现在您已经有了很多 + +335 +00:23:12,559 --> 00:23:14,561 +让代码现代化的策略 + +336 +00:23:14,595 --> 00:23:17,297 +应用这些策略 您的 App 就可以 + +337 +00:23:17,331 --> 00:23:19,666 +享受到 TextKit 2 的好处 + +338 +00:23:21,568 --> 00:23:24,805 +这就是 TextKit 和文本视图的 +新增功能 + +339 +00:23:24,838 --> 00:23:27,875 +我介绍了 TextKit 2 中的 +许多重大改进 + +340 +00:23:27,908 --> 00:23:30,344 +并分享了一些更新 App 的策略 + +341 +00:23:30,377 --> 00:23:33,814 +同时保持与旧操作系统版本的兼容性 + +342 +00:23:33,847 --> 00:23:39,052 +今天就在您的 App 中使用 TextKit 2 +充分利用新的改进吧 + +343 +00:23:39,086 --> 00:23:40,954 +检查您的文本视图 以确保 + +344 +00:23:40,988 --> 00:23:44,391 +它们不会无意中退回到 TextKit 1 + +345 +00:23:44,424 --> 00:23:47,127 +最后 采用现代化策略 + +346 +00:23:47,160 --> 00:23:50,464 +让您的 App 在 TextKit 2 上运行 + +347 +00:23:50,497 --> 00:23:55,169 +我们迫不及待地想阅读您使用 +TextKit 2 和文本视图创建的内容了 + +348 +00:23:55,202 --> 00:23:57,171 +感谢收看 + diff --git a/zho/2022 Session 10092 Meet passkeys.srt b/zho/2022 Session 10092 Meet passkeys.srt new file mode 100644 index 0000000..61472a5 --- /dev/null +++ b/zho/2022 Session 10092 Meet passkeys.srt @@ -0,0 +1,2596 @@ +1 +00:00:00,067 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,776 +♪ + +3 +00:00:09,776 --> 00:00:11,912 +嗨 我是 Garrett + +4 +00:00:11,912 --> 00:00:15,148 +身份验证体验团队的工程师 + +5 +00:00:15,148 --> 00:00:19,386 +在这个视频中 +我很高兴能和大家聊聊通行密钥 + +6 +00:00:19,386 --> 00:00:23,490 +通行密钥是新一代的验证技术 + +7 +00:00:23,490 --> 00:00:25,359 +但首先 我需要谈谈 + +8 +00:00:25,359 --> 00:00:28,896 +当今的身份验证技术:密码 + +9 +00:00:28,896 --> 00:00:30,397 +您可能已经习惯用密码登录 + +10 +00:00:30,397 --> 00:00:33,600 +几乎所有的 App 和网站 + +11 +00:00:33,600 --> 00:00:37,137 +密码真的很难安全地使用 + +12 +00:00:37,137 --> 00:00:39,940 +我们都知道每个帐户都应该创建 + +13 +00:00:39,940 --> 00:00:42,709 +强大 独特的密码 + +14 +00:00:42,709 --> 00:00:45,779 +但实际上没有多少人会这么做 + +15 +00:00:45,779 --> 00:00:48,782 +在设计 App 和网站时 + +16 +00:00:48,782 --> 00:00:52,019 +在保持帐户安全与设计良好体验之间 + +17 +00:00:52,019 --> 00:00:55,322 +需要不断地权衡 + +18 +00:00:55,322 --> 00:00:59,760 +即使您的 App 和网站一切正常 + +19 +00:00:59,760 --> 00:01:02,996 +网络钓鱼和密码重用等问题 + +20 +00:01:02,996 --> 00:01:06,433 +仍然可能导致帐户泄露 + +21 +00:01:06,433 --> 00:01:09,436 +在 macOS Monterey +和 iOS 15 中 + +22 +00:01:09,436 --> 00:01:12,606 +我们宣布了这个解决方案的 +开发者预览版 + +23 +00:01:12,606 --> 00:01:16,310 +也就是通行密钥 +并获得了很多很棒的反馈 + +24 +00:01:16,310 --> 00:01:19,313 +在 macOS Ventura +和 iOS 16 中 + +25 +00:01:19,313 --> 00:01:23,083 +我们很高兴通行密钥将向所有人提供 + +26 +00:01:23,083 --> 00:01:26,086 +现在是采用通行密钥的时候了 + +27 +00:01:26,086 --> 00:01:27,387 +使用通行密钥 + +28 +00:01:27,387 --> 00:01:31,358 +不仅能提供比密码更好的用户体验 + +29 +00:01:31,358 --> 00:01:35,329 +而且整个类别的安全问题 + +30 +00:01:35,329 --> 00:01:37,564 +如弱密码和重用密码凭据 + +31 +00:01:37,564 --> 00:01:42,769 +密码凭据泄露和网络钓鱼 +都不复存在了 + +32 +00:01:42,769 --> 00:01:45,272 +而且通行密钥非常易于使用 + +33 +00:01:45,272 --> 00:01:47,975 +让我来给您展示 + +34 +00:01:47,975 --> 00:01:51,378 +从我们最爱的 +演示 App Shiny 开始 + +35 +00:01:51,378 --> 00:01:54,781 +这个 App 每天会 +为我展示一张可爱的照片 + +36 +00:01:54,781 --> 00:01:59,386 +并具有典型的基于密码的登录流程 + +37 +00:01:59,386 --> 00:02:01,755 +我可以点击用户名字段 + +38 +00:02:01,755 --> 00:02:04,958 +看到我的帐户的自动填充建议 + +39 +00:02:04,958 --> 00:02:08,428 +选择填充建议 登录 + +40 +00:02:08,428 --> 00:02:10,664 +然后 填写密码 + +41 +00:02:12,933 --> 00:02:14,968 +然后 我稍等片刻 + +42 +00:02:14,968 --> 00:02:18,005 +直到短信传来一次性验证码 + +43 +00:02:20,374 --> 00:02:22,142 +收到了 + +44 +00:02:22,142 --> 00:02:25,212 +最后 登录上了 + +45 +00:02:25,212 --> 00:02:28,348 +花了几个步骤 但在自动填充 + +46 +00:02:28,348 --> 00:02:31,051 +和密码管理器的帮助下 +我成功登录了 + +47 +00:02:33,320 --> 00:02:37,524 +现在登录上了 我将向帐户添加通行密钥 + +48 +00:02:37,524 --> 00:02:41,228 +帐户管理 添加通行密钥 + +49 +00:02:41,228 --> 00:02:45,332 +这里是用于创建通行密钥的系统表 + +50 +00:02:45,332 --> 00:02:47,000 +继续 + +51 +00:02:47,000 --> 00:02:48,802 +完毕! + +52 +00:02:48,802 --> 00:02:52,172 +只需几下按键 我的设备就为帐户 + +53 +00:02:52,172 --> 00:02:56,109 +生成了一个独特的 +加密性强的通行密钥对 + +54 +00:02:56,109 --> 00:02:58,879 +并存储在 iCloud 钥匙串中 + +55 +00:02:58,879 --> 00:03:02,049 +从而让通行密钥在我的所有运行 + +56 +00:03:02,049 --> 00:03:04,585 +macOS Ventura 和 iOS 16 的 +设备上同步和工作 + +57 +00:03:06,987 --> 00:03:08,689 +现在有了通行密钥 + +58 +00:03:08,689 --> 00:03:11,458 +让我来展示一下通行密钥多么容易使用 + +59 +00:03:11,458 --> 00:03:13,627 +我先退出登录 + +60 +00:03:13,627 --> 00:03:18,398 +又回到了之前用过的登录表单 + +61 +00:03:18,398 --> 00:03:21,902 +像之前一样 点击用户名字段 + +62 +00:03:21,902 --> 00:03:25,572 +现在我已经为帐户保存了一个通行密钥 + +63 +00:03:25,572 --> 00:03:28,208 +通行密钥会显示在 QuickType 栏中 + +64 +00:03:28,208 --> 00:03:31,979 +只要点击它 就能登录了 + +65 +00:03:31,979 --> 00:03:34,248 +一步就能完成 + +66 +00:03:34,248 --> 00:03:35,883 +保存通行密钥时 + +67 +00:03:35,883 --> 00:03:38,652 +我不需要设置新密码 + +68 +00:03:38,652 --> 00:03:42,689 +也不需要满足密码复杂度要求 + +69 +00:03:42,689 --> 00:03:45,926 +每个通行密钥由系统生成 + +70 +00:03:45,926 --> 00:03:49,663 +并保证通行密钥强度大 + +71 +00:03:49,663 --> 00:03:52,332 +且只用于一个帐户 + +72 +00:03:52,332 --> 00:03:54,968 +当我用通行密钥登录时 它可以显示 + +73 +00:03:54,968 --> 00:03:57,938 +在我习惯的现有登录流程中 + +74 +00:03:57,938 --> 00:04:00,774 +而且只需轻轻一点就可以使用 + +75 +00:04:00,774 --> 00:04:04,511 +而且系统会让我仅在 + +76 +00:04:04,511 --> 00:04:07,014 +正确的 App 或网站上使用通行密钥 + +77 +00:04:07,014 --> 00:04:10,784 +内置了强大的防钓鱼功能 + +78 +00:04:10,784 --> 00:04:14,354 +当然 通行密钥也可以在网络页面上使用 + +79 +00:04:14,354 --> 00:04:17,925 +我在 Safari 浏览器上 +浏览 Shiny 网站 + +80 +00:04:17,925 --> 00:04:21,828 +就像在我的手机上 +我点击用户名字段 + +81 +00:04:21,828 --> 00:04:25,299 +多亏了 iCloud 钥匙串 + +82 +00:04:25,299 --> 00:04:27,334 +通行密钥已经可以使用了 + +83 +00:04:27,334 --> 00:04:30,838 +只需要触控 ID 就能登录 + +84 +00:04:30,838 --> 00:04:32,973 +就这么容易 + +85 +00:04:32,973 --> 00:04:37,010 +Apple 的通行密钥实现 +是建立在开放标准之上 + +86 +00:04:37,010 --> 00:04:39,279 +我们一直在与 FIDO 联盟内的 + +87 +00:04:39,279 --> 00:04:42,182 +其他平台供应商合作 + +88 +00:04:42,182 --> 00:04:45,886 +以确保通行密钥实现兼容跨平台 + +89 +00:04:45,886 --> 00:04:49,923 +并能在尽可能多的设备上工作 + +90 +00:04:49,923 --> 00:04:52,893 +把我的帐户升级为使用通行密钥后 + +91 +00:04:52,893 --> 00:04:57,297 +我仍然可以在我朋友的电脑上登录 + +92 +00:04:57,297 --> 00:05:00,601 +当然 我朋友的电脑 +没有本地储存通行密钥 + +93 +00:05:00,601 --> 00:05:05,806 +但我仍然可以在这里输入我的用户名 + +94 +00:05:05,806 --> 00:05:07,307 +我点击登录时 + +95 +00:05:07,307 --> 00:05:11,078 +收到一张允许我使用手机的表单 + +96 +00:05:11,078 --> 00:05:14,581 +然后我收到一个二维码 +我来扫描一下 + +97 +00:05:16,884 --> 00:05:19,419 +我的手机识别出此二维码 + +98 +00:05:19,419 --> 00:05:22,656 +是用通行密钥登录的 + +99 +00:05:22,656 --> 00:05:24,458 +当我选择这个选项时 + +100 +00:05:24,458 --> 00:05:29,062 +我的手机和浏览器 +就安全地连接在一起了 + +101 +00:05:29,062 --> 00:05:34,668 +接下来点击继续 就能登录上了 + +102 +00:05:34,668 --> 00:05:37,271 +这种跨平台的登录体验 + +103 +00:05:37,271 --> 00:05:39,973 +是一流的系统功能 + +104 +00:05:39,973 --> 00:05:43,177 +是通行密钥背后标准的一部分 + +105 +00:05:43,177 --> 00:05:46,680 +表面上 它看起来非常简单 + +106 +00:05:46,680 --> 00:05:49,516 +但这不仅仅是一个二维码 + +107 +00:05:49,516 --> 00:05:50,684 +在后台 + +108 +00:05:50,684 --> 00:05:53,587 +设备正在执行本地通行密钥协议 + +109 +00:05:53,587 --> 00:05:55,289 +证明接近性 + +110 +00:05:55,289 --> 00:05:59,259 +建立一个端到端加密通信通道 + +111 +00:05:59,259 --> 00:06:02,796 +这些都是为了简化登录方式 + +112 +00:06:02,796 --> 00:06:07,034 +但又能保持通行密钥强大的对抗钓鱼能力 + +113 +00:06:07,034 --> 00:06:10,137 +它可以让我在任何设备上 + +114 +00:06:10,137 --> 00:06:14,541 +安全地登录我的帐户 + +115 +00:06:14,541 --> 00:06:17,878 +密码替换的另一个重要功能 + +116 +00:06:17,878 --> 00:06:22,382 +是可以在两人或多人之间共享帐户 + +117 +00:06:22,382 --> 00:06:24,551 +要与其他人共享通行密钥 + +118 +00:06:24,551 --> 00:06:26,386 +我可以使用 AirDrop + +119 +00:06:28,522 --> 00:06:32,626 +我和我的伙伴也有一个 +共享的 Shiny 帐户 + +120 +00:06:32,626 --> 00:06:35,963 +我已经将帐户升级为使用通行密钥 + +121 +00:06:35,963 --> 00:06:39,833 +有了通行密钥 我就无需输入密码凭证 + +122 +00:06:39,833 --> 00:06:43,170 +但我仍然可以与我信任的人分享通行密钥 + +123 +00:06:43,170 --> 00:06:46,006 +在我的手机上 我打开帐户详细信息 + +124 +00:06:48,942 --> 00:06:50,644 +这是我所有使用 + +125 +00:06:50,644 --> 00:06:54,648 +密码和通行密钥的帐户 + +126 +00:06:54,648 --> 00:06:58,852 +我可以点击我们的共享帐户 +调出更多细节 + +127 +00:06:58,852 --> 00:07:02,456 +在这里 我可以看到 +关于我保存的通行密钥的信息 + +128 +00:07:02,456 --> 00:07:04,825 +或向此帐户添加备注 + +129 +00:07:04,825 --> 00:07:08,428 +我也可以分享我的通行密钥 + +130 +00:07:08,428 --> 00:07:09,997 +这是我伙伴的手机 + +131 +00:07:09,997 --> 00:07:11,698 +我来选择它 + +132 +00:07:14,868 --> 00:07:17,604 +现在我的伙伴也有了通行密钥 + +133 +00:07:19,840 --> 00:07:25,512 +可以看出来 +到处都能用通行密钥 多么容易 + +134 +00:07:25,512 --> 00:07:29,316 +我刚刚介绍了使用通行密钥的体验 + +135 +00:07:29,316 --> 00:07:32,119 +接下来说说什么是通行密钥 + +136 +00:07:32,119 --> 00:07:36,323 +以及使用通行密钥时的一些界面指南 + +137 +00:07:36,323 --> 00:07:39,359 +然后 我将向您展示 +如何利用自动填充 + +138 +00:07:39,359 --> 00:07:42,930 +将通行密钥集成到您的 App + +139 +00:07:42,930 --> 00:07:45,832 +和网站中现有的登录流程中 + +140 +00:07:45,832 --> 00:07:48,202 +然后是一些额外的选项 + +141 +00:07:48,202 --> 00:07:52,539 +可以进一步简化您的登录过程 + +142 +00:07:52,539 --> 00:07:55,475 +接下来 我将详细介绍 + +143 +00:07:55,475 --> 00:07:58,278 +密匙的工作原理 + +144 +00:07:58,278 --> 00:08:04,284 +最后 讨论密匙和多因素身份验证 + +145 +00:08:04,284 --> 00:08:07,921 +首先 通行密钥的设计 + +146 +00:08:07,921 --> 00:08:10,490 +说到通行密钥 + +147 +00:08:10,490 --> 00:08:15,863 +首先也是最重要的是 +通行密钥是密码的替代品 + +148 +00:08:15,863 --> 00:08:19,399 +登录速度更快 使用起来更容易 + +149 +00:08:19,399 --> 00:08:23,370 +也更安全 + +150 +00:08:23,370 --> 00:08:26,473 +以下是有关如何 +在您的 App 和网站中 + +151 +00:08:26,473 --> 00:08:29,343 +使用通行密钥的指导方针 + +152 +00:08:29,343 --> 00:08:33,247 +“Passkey” (通行密钥) 是一个通用的 +用户可见的术语 + +153 +00:08:33,247 --> 00:08:37,217 +本视频重点介绍 Apple 的实施 + +154 +00:08:37,217 --> 00:08:40,220 +但正如我刚才向开发者展示的 +其他主要平台 + +155 +00:08:40,220 --> 00:08:45,092 +已经开始建立自己对通行密钥的支持 + +156 +00:08:45,092 --> 00:08:49,196 +“Passkey” (通行密钥) 也是个普通名词 +就像“密码”一样 + +157 +00:08:49,196 --> 00:08:51,965 +在英语中 这个词是小写的 + +158 +00:08:51,965 --> 00:08:54,968 +并能像“密码”一样变成复数 + +159 +00:08:54,968 --> 00:08:59,439 +我的帐户有通行密钥 可以去“设置” + +160 +00:08:59,439 --> 00:09:03,610 +查看我所有的帐户的通行密钥 + +161 +00:09:03,610 --> 00:09:07,581 +在 Apple 平台上 +您还可以使用 SF Symbol + +162 +00:09:07,581 --> 00:09:11,485 +person.key.badge 和 .fill 变体 + +163 +00:09:11,485 --> 00:09:15,722 +来提供与系统一致的图标 + +164 +00:09:15,722 --> 00:09:18,125 +在您的 App 和网站中 +提供通行密钥时 + +165 +00:09:18,125 --> 00:09:24,031 +您不需要设计全新的界面 + +166 +00:09:24,031 --> 00:09:27,534 +用户名字段是目前大多数 App + +167 +00:09:27,534 --> 00:09:30,137 +和网站登录的中心点 + +168 +00:09:30,137 --> 00:09:32,639 +几乎每个人都知道如何使用 + +169 +00:09:32,639 --> 00:09:36,376 +许多 App 和网站已经利用通行密钥 + +170 +00:09:36,376 --> 00:09:40,614 +来定制每个帐户的登录体验 + +171 +00:09:40,614 --> 00:09:45,085 +现在用户名字段还有另一个大特点 + +172 +00:09:45,085 --> 00:09:47,554 +虽然通行密钥为登录工作带来了新的范式 + +173 +00:09:47,554 --> 00:09:51,859 +但摆脱密码的过渡 + +174 +00:09:51,859 --> 00:09:55,062 +也需要平稳和简单 + +175 +00:09:55,062 --> 00:09:58,532 +您现在可以使用自动填充 + +176 +00:09:58,532 --> 00:10:01,902 +作为一级特性来提供通行密钥 + +177 +00:10:01,902 --> 00:10:05,239 +让您可以将通行密钥 +直接放入现有的登录流中 + +178 +00:10:05,239 --> 00:10:10,277 +在熟悉且人们知道如何使用的界面中 + +179 +00:10:10,277 --> 00:10:12,145 +使用自动填充提供通行密钥 + +180 +00:10:12,145 --> 00:10:15,282 +是使用通行密钥的主要方式 + +181 +00:10:15,282 --> 00:10:18,285 +不过 对于更高级的用户 + +182 +00:10:18,285 --> 00:10:21,922 +Apple 平台也有 +很多额外的 UI 选项 + +183 +00:10:21,922 --> 00:10:25,359 +可以使用通行密钥登录 + +184 +00:10:25,359 --> 00:10:27,661 +接下来看一下如何开始使用通行密钥 + +185 +00:10:27,661 --> 00:10:30,531 +并使用自动填充显示通行密钥 + +186 +00:10:30,531 --> 00:10:33,100 +通行密钥是基于 +WebAuthentication 构建的 + +187 +00:10:33,100 --> 00:10:37,671 +其又名 WebAuthn 标准 +并使用公钥加密 + +188 +00:10:37,671 --> 00:10:41,508 +每个帐户生成唯一的加密通行密钥对 + +189 +00:10:41,508 --> 00:10:46,680 +而不是使用可键入的字或字符串 + +190 +00:10:46,680 --> 00:10:49,950 +您需要在服务器后端采用 WebAuthn + +191 +00:10:49,950 --> 00:10:52,953 +来执行通行密钥登录 + +192 +00:10:52,953 --> 00:10:55,956 +任何标准的 WebAuthn 服务器实现 + +193 +00:10:55,956 --> 00:10:59,860 +应该使用通行密钥 + +194 +00:10:59,860 --> 00:11:01,862 +在 Apple 平台上的 App 中 + +195 +00:11:01,862 --> 00:11:05,599 +通行密钥是 +AuthenticationServices 框架中的 + +196 +00:11:05,599 --> 00:11:08,468 +ASAuthorization API 系列的一部分 + +197 +00:11:08,468 --> 00:11:11,004 +这是我们的 API 用于处理 + +198 +00:11:11,004 --> 00:11:14,141 +各种不同的凭证 包括密码 + +199 +00:11:14,141 --> 00:11:17,744 +安全通行密钥和使用 Apple 登录 + +200 +00:11:17,744 --> 00:11:20,514 +我们还添加了一些 +您可以使用的新方法 + +201 +00:11:20,514 --> 00:11:25,319 +像自动填充支持 +使这个 API 更加灵活 + +202 +00:11:25,319 --> 00:11:30,424 +并让您无缝地将它 +融入到现有的登录流中 + +203 +00:11:30,424 --> 00:11:33,727 +要开始在 +您的 App 中使用通行密钥 + +204 +00:11:33,727 --> 00:11:36,496 +首先 您需要 +使用 webcredentials 服务 + +205 +00:11:36,496 --> 00:11:39,166 +设置相关的域 + +206 +00:11:39,166 --> 00:11:41,301 +您可以在 “Introducing Password +AutoFill for Apps”(App 密码自动填充介绍) + +207 +00:11:41,301 --> 00:11:44,238 +和“通用链接中的新功能” +(What's new in Universal Links) 视频中 + +208 +00:11:44,238 --> 00:11:47,608 +了解更多细节 + +209 +00:11:47,608 --> 00:11:51,278 +在您的 App 界面中 +请确保您的用户名字段 + +210 +00:11:51,278 --> 00:11:54,915 +使用的是用户名 textContentTtype + +211 +00:11:54,915 --> 00:11:59,586 +这让系统知道在哪里提供通行密钥建议 + +212 +00:11:59,586 --> 00:12:02,089 +配置完成后 下面是启动自动填充 + +213 +00:12:02,089 --> 00:12:05,592 +辅助通行密钥请求所需的代码 + +214 +00:12:05,592 --> 00:12:09,530 +分解时只需几个简单的步骤 + +215 +00:12:09,530 --> 00:12:12,666 +与任何 WebAuthn 请求 +一样 您首先需要 + +216 +00:12:12,666 --> 00:12:16,103 +从服务器获取一个质询 + +217 +00:12:16,103 --> 00:12:19,473 +然后创建提供者和请求 + +218 +00:12:19,473 --> 00:12:23,143 +ASAuthorizationPlatformPublicKeyCredentialProvider + +219 +00:12:23,143 --> 00:12:25,179 +是 ASAuthorizationProvider + +220 +00:12:25,179 --> 00:12:28,248 +用于处理通行密钥请求 + +221 +00:12:28,248 --> 00:12:32,452 +在 WebAuthn 术语中 +登录时使用断言 + +222 +00:12:32,452 --> 00:12:35,055 +所以在这里 我创建一个断言 + +223 +00:12:35,055 --> 00:12:38,192 +请求来使用现有的通行密钥进行登录 + +224 +00:12:38,192 --> 00:12:39,993 +ASAuthorizationController + +225 +00:12:39,993 --> 00:12:42,696 +是实际处理请求的内容 + +226 +00:12:42,696 --> 00:12:45,365 +使用通行密钥请求创建实例 + +227 +00:12:45,365 --> 00:12:50,537 +并配置它的委托 +和 presentationContextProvider + +228 +00:12:50,537 --> 00:12:54,274 +最后 调用 +performAutoFillAssistedRequests + +229 +00:12:54,274 --> 00:12:56,510 +开始请求 + +230 +00:12:56,510 --> 00:12:59,046 +当这个请求在 App 中运行时 + +231 +00:12:59,046 --> 00:13:01,715 +每当点击一个用户名字段时 + +232 +00:13:01,715 --> 00:13:05,919 +系统将在 QuickType 栏中 +提供可用的通行密钥 + +233 +00:13:05,919 --> 00:13:09,756 +确保在视图生命周期的早期 + +234 +00:13:09,756 --> 00:13:11,859 +在点击用户名字段之前启动这个请求 + +235 +00:13:11,859 --> 00:13:15,629 +这样当键盘出现时 通行密钥就准备好了 + +236 +00:13:15,629 --> 00:13:18,465 +当 QuickType 栏中的 +一个项目被选中时 + +237 +00:13:18,465 --> 00:13:21,468 +面容 ID 被调用 然后您会收到 + +238 +00:13:21,468 --> 00:13:24,471 +一个 ASAuthorizationController +委托回调 + +239 +00:13:24,471 --> 00:13:26,473 +来完成登录 + +240 +00:13:26,473 --> 00:13:29,576 +文本框中实际上不会填充内容 + +241 +00:13:29,576 --> 00:13:32,913 +当对任何凭据类型的授权成功时 + +242 +00:13:32,913 --> 00:13:35,048 +您将获得 +didCompleteWithAuthorization + +243 +00:13:35,048 --> 00:13:37,217 +回调 + +244 +00:13:37,217 --> 00:13:38,785 +您首先应该 + +245 +00:13:38,785 --> 00:13:41,822 +检查您获得的凭证的类型 + +246 +00:13:41,822 --> 00:13:44,658 +在使用通行密钥登录的情况下 它将是 + +247 +00:13:44,658 --> 00:13:50,030 +ASAuthorizationPlatformPublicKeyCredentialAssertion + +248 +00:13:50,030 --> 00:13:52,466 +断言对象将包含在后端验证登录 + +249 +00:13:52,466 --> 00:13:55,369 +所需的字段 + +250 +00:13:55,369 --> 00:13:59,006 +您应该读这些值 用服务器验证它们 + +251 +00:13:59,006 --> 00:14:01,141 +然后完成登录 + +252 +00:14:01,141 --> 00:14:04,978 +自动填充辅助通行密钥请求功能强大 + +253 +00:14:04,978 --> 00:14:06,813 +通过这个小小的代码更改 + +254 +00:14:06,813 --> 00:14:11,285 +您的 App 的登录流程 +现在有了很大的灵活性 + +255 +00:14:11,285 --> 00:14:14,154 +当然 主要的情况是从 + +256 +00:14:14,154 --> 00:14:16,823 +QuickType 栏中选择通行密钥建议 + +257 +00:14:16,823 --> 00:14:19,960 +以便使用通行密钥快速登录 + +258 +00:14:19,960 --> 00:14:24,031 +这是应该是最经常发生的情况 + +259 +00:14:24,031 --> 00:14:26,500 +不过 还有其他选择 + +260 +00:14:26,500 --> 00:14:29,770 +我刚才向您展示的代码还允许 +从附近的设备 + +261 +00:14:29,770 --> 00:14:33,440 +进行通行密钥登录 无需进行额外的更改 + +262 +00:14:33,440 --> 00:14:36,176 +您可以点击钥匙图标以调出视图 + +263 +00:14:36,176 --> 00:14:40,080 +列出所有可用的通行密钥和密码 + +264 +00:14:40,080 --> 00:14:43,684 +并点击使用附近设备登录的选项 + +265 +00:14:43,684 --> 00:14:47,688 +然后可以执行跨设备通行密钥登录 + +266 +00:14:47,688 --> 00:14:50,724 +在这两种情况下 如果使用通行密钥 + +267 +00:14:50,724 --> 00:14:52,025 +您会收到相同的 + +268 +00:14:52,025 --> 00:14:55,062 +ASAuthorizationController +委托回调 + +269 +00:14:55,062 --> 00:14:59,166 +要支持这个功能 +您不需要做什么特别的操作 + +270 +00:14:59,166 --> 00:15:01,869 +如果用户还没有通行密钥 + +271 +00:15:01,869 --> 00:15:05,772 +他们可以照旧使用您的登录表单 + +272 +00:15:05,772 --> 00:15:09,142 +他们将在 QuickType 栏中 +获得密码建议 + +273 +00:15:09,142 --> 00:15:11,979 +或直接在输入栏中输入密码 + +274 +00:15:11,979 --> 00:15:14,348 +如果选择了密码项 + +275 +00:15:14,348 --> 00:15:17,751 +则仍然会将凭据填写到文本字段中 + +276 +00:15:17,751 --> 00:15:21,154 +您可以取消正在运行的请求 + +277 +00:15:21,154 --> 00:15:23,290 +我们设计这个 API 是为了让您 + +278 +00:15:23,290 --> 00:15:25,993 +把它直接放到您现有的登录流中 + +279 +00:15:25,993 --> 00:15:30,631 +这对您的用户来说非常容易 + +280 +00:15:30,631 --> 00:15:34,234 +如果用户已经升级到使用通行密钥 + +281 +00:15:34,234 --> 00:15:36,870 +还是决定输入他们的用户名 + +282 +00:15:36,870 --> 00:15:39,306 +而不是使用自动填充建议 + +283 +00:15:39,306 --> 00:15:41,208 +您应该取消自动填充请求 + +284 +00:15:41,208 --> 00:15:43,343 +并使用 ASAuthorizationController + +285 +00:15:43,343 --> 00:15:46,280 +来呈现模式通行密钥登录表 + +286 +00:15:46,280 --> 00:15:48,815 +这里 依旧只需要轻点一下 + +287 +00:15:48,815 --> 00:15:50,317 +您会收到相同的 + +288 +00:15:50,317 --> 00:15:53,921 +ASAuthorizationController 委托回调 + +289 +00:15:53,921 --> 00:15:56,123 +这是之前的代码 + +290 +00:15:56,123 --> 00:15:59,793 +要从自动填充请求切换到模态请求 + +291 +00:15:59,793 --> 00:16:03,230 +只需将 +performAutoFillAssistedRequests 方法调用 + +292 +00:16:03,230 --> 00:16:07,601 +与 performRequests() 调用交换 + +293 +00:16:07,601 --> 00:16:11,572 +这将显示一个 +包含所有可用通行密钥的模式表 + +294 +00:16:11,572 --> 00:16:16,009 +以及使用附近设备的通行密钥的选项 + +295 +00:16:16,009 --> 00:16:19,279 +这些是您需要在 App 中 + +296 +00:16:19,279 --> 00:16:22,082 +支持通行密钥的唯一代码更改 + +297 +00:16:22,082 --> 00:16:25,619 +网页平台还支持自动填充辅助 + +298 +00:16:25,619 --> 00:16:28,288 +和模态通行密钥请求 + +299 +00:16:28,288 --> 00:16:33,293 +在网页上 通行密钥是通过标准的 +WebAuthn API 使用的 + +300 +00:16:33,293 --> 00:16:36,697 +这个 API 也用于安全通行密钥 + +301 +00:16:36,697 --> 00:16:40,334 +就像在 App 中一样 +采用自动填充辅助请求功能 + +302 +00:16:40,334 --> 00:16:43,804 +只需触控 ID 即可快速登录 + +303 +00:16:43,804 --> 00:16:47,674 +获取所有可用的通行密钥和密码 + +304 +00:16:47,674 --> 00:16:50,878 +或者使用附近设备的通行密钥 + +305 +00:16:50,878 --> 00:16:54,081 +这些都只需要很少的代码 + +306 +00:16:54,081 --> 00:16:57,885 +首先 确保在您的网页上 + +307 +00:16:57,885 --> 00:17:01,021 +以用户名和 webauthn +自动完成细节标记 + +308 +00:17:01,021 --> 00:17:04,658 +注释您的用户名字段 + +309 +00:17:04,658 --> 00:17:07,861 +以便在正确的位置 + +310 +00:17:07,861 --> 00:17:10,130 +显示密码和通行密钥建议 + +311 +00:17:10,130 --> 00:17:13,667 +完成后 +这是一个在 JavaScript 中 + +312 +00:17:13,667 --> 00:17:16,303 +典型的 WebAuthn 登录 + +313 +00:17:16,303 --> 00:17:19,473 +在 WebAuthn 中 +使用条件中介调用 + +314 +00:17:19,473 --> 00:17:22,976 +自动填充样式的请求 + +315 +00:17:22,976 --> 00:17:24,211 +您应该首先使用 + +316 +00:17:24,211 --> 00:17:26,547 +标准 JavaScript 特性检测 + +317 +00:17:26,547 --> 00:17:29,249 +来检查它是否可用 + +318 +00:17:29,249 --> 00:17:33,320 +如果可用 您可以继续提出您的请求 + +319 +00:17:33,320 --> 00:17:37,057 +就像使用原生 API 一样 +首先使用 + +320 +00:17:37,057 --> 00:17:40,694 +从服务器获取的质询发起请求 + +321 +00:17:40,694 --> 00:17:42,863 +要使它成为自动填充辅助请求 + +322 +00:17:42,863 --> 00:17:47,901 +将 mediation: "conditional" +参数添加到选项中 + +323 +00:17:47,901 --> 00:17:53,407 +然后 使用 +navigator.credentials.get 启动请求 + +324 +00:17:53,407 --> 00:17:56,276 +.get 调用返回一个承诺 + +325 +00:17:56,276 --> 00:17:59,847 +如果解析成功 +您将收到一个断言对象 + +326 +00:17:59,847 --> 00:18:02,683 +您可以将对象发送回服务器进行验证 + +327 +00:18:02,683 --> 00:18:04,852 +然后完成登录 + +328 +00:18:04,852 --> 00:18:08,355 +就像在 App 中 +如果有人手动输入一个 + +329 +00:18:08,355 --> 00:18:12,059 +带有通行密钥的帐户的用户名 +您应该使用 API + +330 +00:18:12,059 --> 00:18:15,062 +来呈现一个模态登录表 + +331 +00:18:15,062 --> 00:18:19,132 +要切换到模态请求 +您需要做的就是删除 + +332 +00:18:19,132 --> 00:18:22,669 +mediation: "conditional" 参数 + +333 +00:18:22,669 --> 00:18:24,838 +使用 WebAuthn 时要注意的一件事 + +334 +00:18:24,838 --> 00:18:29,810 +是 Apple 平台如何处理 +用户验证 简称 UV + +335 +00:18:29,810 --> 00:18:33,547 +UV 是 WebAuthn 响应中的 +布尔字段 + +336 +00:18:33,547 --> 00:18:35,582 +表示验证者是否 + +337 +00:18:35,582 --> 00:18:37,885 +试图验证当前用户 + +338 +00:18:37,885 --> 00:18:39,953 +是设备的所有者 + +339 +00:18:39,953 --> 00:18:44,558 +在 Apple 设备上 +值 1 表示生物识别技术 + +340 +00:18:44,558 --> 00:18:47,494 +或使用的密码 + +341 +00:18:47,494 --> 00:18:50,964 +当生物识别技术可用时 + +342 +00:18:50,964 --> 00:18:52,933 +Apple 平台 +将始终需要 UV 用于通行密钥 + +343 +00:18:52,933 --> 00:18:55,769 +所以您不必担心这一点 + +344 +00:18:55,769 --> 00:18:57,771 +当提出 WebAuthn 请求时 + +345 +00:18:57,771 --> 00:19:02,109 +有一个选项可以指定用户验证要求 + +346 +00:19:02,109 --> 00:19:06,146 +默认值为 +userVerification: "preferred" + +347 +00:19:06,146 --> 00:19:10,484 +请始终使用默认值 +以避免在没有生物识别的设备上 + +348 +00:19:10,484 --> 00:19:14,288 +造成不良体验 + +349 +00:19:14,288 --> 00:19:18,559 +以下是在网页上 +使用通行密钥的一些附加说明 + +350 +00:19:18,559 --> 00:19:20,961 +当您提出自动填充辅助请求时 + +351 +00:19:20,961 --> 00:19:23,397 +您应该在页面生命周期的早期进行 + +352 +00:19:23,397 --> 00:19:25,732 +就像在 App 中一样 + +353 +00:19:25,732 --> 00:19:28,769 +对于模态 WebAuthn 请求 +您应该从用户手势事件 + +354 +00:19:28,769 --> 00:19:32,906 +比如点击按钮 来触发它们 + +355 +00:19:32,906 --> 00:19:36,109 +模态请求可以在用户手势事件之外的 + +356 +00:19:36,109 --> 00:19:40,013 +每次页面加载触发一次 +但如果您这样做 + +357 +00:19:40,013 --> 00:19:44,084 +WebKit 可能会 +限制页面的后续调用 + +358 +00:19:44,084 --> 00:19:46,720 +自动填充请求不是模态的 + +359 +00:19:46,720 --> 00:19:49,089 +所以它们不需要用户手势 + +360 +00:19:49,089 --> 00:19:52,359 +并且有更长的超时时间 + +361 +00:19:52,359 --> 00:19:55,996 +最后 通行密钥正在 +取代 Safari 浏览器的 + +362 +00:19:55,996 --> 00:19:58,398 +传统平台验证器 + +363 +00:19:58,398 --> 00:20:01,034 +现有凭证仍然有效 + +364 +00:20:01,034 --> 00:20:04,271 +并且仍然绑定到创建它们的设备上 + +365 +00:20:04,271 --> 00:20:08,842 +但新的平台凭据将被创建为通行密钥 + +366 +00:20:08,842 --> 00:20:11,311 +在注册期间可以将它们 + +367 +00:20:11,311 --> 00:20:12,913 +与遗留凭证区分开来 + +368 +00:20:12,913 --> 00:20:17,317 +因为通行密钥不会提供认证声明 + +369 +00:20:17,317 --> 00:20:19,987 +以上是通行密钥和自动填充 + +370 +00:20:19,987 --> 00:20:23,390 +接下来 我将介绍一些其他平台功能 + +371 +00:20:23,390 --> 00:20:26,894 +这可以进一步简化登录体验 + +372 +00:20:26,894 --> 00:20:29,696 +除了自动填充辅助的登录 + +373 +00:20:29,696 --> 00:20:31,632 +ASAuthorization API + +374 +00:20:31,632 --> 00:20:34,468 +还提供了许多更有用的功能 + +375 +00:20:34,468 --> 00:20:37,571 +我将介绍 +这个 API 的三个附加功能 + +376 +00:20:37,571 --> 00:20:39,773 +以及何时需要使用它们 + +377 +00:20:39,773 --> 00:20:43,076 +首先来说说通行密钥允许列表 + +378 +00:20:43,076 --> 00:20:45,479 +当用户名输入后 + +379 +00:20:45,479 --> 00:20:47,514 +显示模态通行密钥表时 + +380 +00:20:47,514 --> 00:20:50,617 +设备上可能保存了 + +381 +00:20:50,617 --> 00:20:52,186 +多个帐户的通行密钥 + +382 +00:20:52,186 --> 00:20:56,356 +默认情况下 所有可用的通行密钥 +都将显示在表单中 + +383 +00:20:56,356 --> 00:20:58,492 +您可以使用一个通行密钥允许列表 + +384 +00:20:58,492 --> 00:21:01,662 +来限制哪些通行密钥显示在工作表中 + +385 +00:21:01,662 --> 00:21:05,132 +以便只提供匹配的帐户 + +386 +00:21:05,132 --> 00:21:07,935 +要向模态请求添加允许列表 + +387 +00:21:07,935 --> 00:21:10,604 +首先需要用户名 + +388 +00:21:10,604 --> 00:21:13,040 +您可以使用该用户名获取 + +389 +00:21:13,040 --> 00:21:17,778 +匹配凭据 ID 的列表 +并将它转换为允许列表 + +390 +00:21:17,778 --> 00:21:22,015 +凭证 ID 是通行密钥的唯一标识符 + +391 +00:21:22,015 --> 00:21:25,719 +Webauthn 服务器应该 +有一种方法来查找 + +392 +00:21:25,719 --> 00:21:28,155 +给定用户名的凭证 ID + +393 +00:21:28,155 --> 00:21:32,659 +接下来 像以前一样继续您的请求 + +394 +00:21:32,659 --> 00:21:35,963 +现在 设备上有三个 +使用通行密钥的 Shiny 帐户 + +395 +00:21:35,963 --> 00:21:38,932 +表单只提供了 + +396 +00:21:38,932 --> 00:21:42,135 +我想要使用的一个帐户 + +397 +00:21:42,135 --> 00:21:45,572 +发出模态请求时 当您有关于用户 + +398 +00:21:45,572 --> 00:21:48,509 +试图用哪个帐户登录的附加场景时 + +399 +00:21:48,509 --> 00:21:50,811 +您应该使用允许列表 + +400 +00:21:50,811 --> 00:21:54,214 +例如用户是否 +已经输入了他们的用户名 + +401 +00:21:54,214 --> 00:21:58,552 +接下来 我将介绍 +在当前设备上没有保存通行密钥的情况下 + +402 +00:21:58,552 --> 00:22:02,556 +发出模态通行密钥请求会发生什么 + +403 +00:22:02,556 --> 00:22:05,225 +这同样适用于 +当您使用允许列表 + +404 +00:22:05,225 --> 00:22:08,562 +而所保存的通行密钥 +与该列表不匹配的情况 + +405 +00:22:08,562 --> 00:22:12,366 +默认情况下 +当您发出模态通行密钥请求时 + +406 +00:22:12,366 --> 00:22:14,735 +如果没有匹配的可用通行密钥 + +407 +00:22:14,735 --> 00:22:17,070 +将显示模态表 + +408 +00:22:17,070 --> 00:22:19,406 +并会立即显示二维码 + +409 +00:22:19,406 --> 00:22:23,110 +用于从附近的设备使用通行密钥登录 + +410 +00:22:23,110 --> 00:22:26,747 +这在登录时提供了最大的灵活性 + +411 +00:22:26,747 --> 00:22:30,317 +并且当您知道正在使用通行密钥时 +这是最好的选择 + +412 +00:22:30,317 --> 00:22:34,021 +但 API 中有一个新选项 +可以优先选择 + +413 +00:22:34,021 --> 00:22:37,257 +可以选择立即可用的凭证 + +414 +00:22:37,257 --> 00:22:39,927 +并在没有凭证时 +使用委托回调静默回退 + +415 +00:22:39,927 --> 00:22:43,030 +这可以用于在可能的情况下 + +416 +00:22:43,030 --> 00:22:44,364 +甚至在显示传统的登录表单之前 + +417 +00:22:44,364 --> 00:22:47,701 +如果当前设备上没有匹配的通行密钥 + +418 +00:22:47,701 --> 00:22:50,571 +使用默认选项的模态请求 + +419 +00:22:50,571 --> 00:22:52,906 +将退回到显示二维码 + +420 +00:22:52,906 --> 00:22:56,743 +如果当前设备上没有匹配的通行密钥 + +421 +00:22:56,743 --> 00:23:00,881 +如果您使用 +preferImmediatelyAvailableCredentials 选项 + +422 +00:23:00,881 --> 00:23:02,916 +您将获得一个带有错误的 + +423 +00:23:02,916 --> 00:23:07,454 +委托回调函数 而不是二维码 + +424 +00:23:07,454 --> 00:23:10,157 +如果您收到 ASAuthorizationError + +425 +00:23:10,157 --> 00:23:12,693 +代码为 canceled 这意味着 + +426 +00:23:12,693 --> 00:23:16,730 +要么用户看到了这个表并手动取消了 + +427 +00:23:16,730 --> 00:23:20,634 +要么您传递了 +preferImmediatelyAvailableCredentials + +428 +00:23:20,634 --> 00:23:23,937 +而没有立即可用的凭证 + +429 +00:23:23,937 --> 00:23:26,406 +要怎么做 取决于 + +430 +00:23:26,406 --> 00:23:28,709 +您调用它的场景 + +431 +00:23:28,709 --> 00:23:31,445 +例如 如果您使用此选项 + +432 +00:23:31,445 --> 00:23:33,881 +作为在显示正常登录表单之前 + +433 +00:23:33,881 --> 00:23:36,650 +测试本地凭据的一种方法 + +434 +00:23:36,650 --> 00:23:40,220 +那么这就是触发显示表单的地方 + +435 +00:23:40,220 --> 00:23:43,457 +如果设备上至少有一个匹配的凭据 + +436 +00:23:43,457 --> 00:23:45,959 +则将显示完整的模态表 + +437 +00:23:45,959 --> 00:23:48,896 +无论使用什么选项 + +438 +00:23:48,896 --> 00:23:50,864 +确保您也在使用 + +439 +00:23:50,864 --> 00:23:54,701 +自动填充辅助请求或模态请求 + +440 +00:23:54,701 --> 00:23:57,938 +在您的 App 中有默认的回退 + +441 +00:23:57,938 --> 00:24:00,807 +因此 如果当前设备上没有通行密钥 + +442 +00:24:00,807 --> 00:24:03,544 +仍然可以使用 +通过手边的设备 + +443 +00:24:03,544 --> 00:24:06,213 +来登录的选项 + +444 +00:24:06,213 --> 00:24:09,149 +我要介绍 +ASAuthorization API 的 + +445 +00:24:09,149 --> 00:24:13,387 +最后一个功能是发出组合凭证请求 + +446 +00:24:13,387 --> 00:24:16,256 +在本例中 + +447 +00:24:16,256 --> 00:24:21,195 +App 提交了通行密钥、密码 +以及通过 Apple 登录的请求 + +448 +00:24:21,195 --> 00:24:24,264 +我的设备恰好保存了 + +449 +00:24:24,264 --> 00:24:26,300 +三个不同帐户的三个不同凭证 + +450 +00:24:26,300 --> 00:24:29,102 +都在表单里 + +451 +00:24:29,102 --> 00:24:30,737 +但更有可能的情况是 + +452 +00:24:30,737 --> 00:24:34,007 +用户只有一个帐户 + +453 +00:24:34,007 --> 00:24:37,578 +在这种情况下 同样的组合凭证请求 + +454 +00:24:37,578 --> 00:24:40,914 +将只提供工作表中的一个帐户 + +455 +00:24:40,914 --> 00:24:42,950 +向现有的 ASAuthorization 请求 + +456 +00:24:42,950 --> 00:24:47,855 +添加额外的凭证类型非常容易 + +457 +00:24:47,855 --> 00:24:50,691 +您只需要为额外的请求类型 + +458 +00:24:50,691 --> 00:24:52,492 +创建提供程序和请求 + +459 +00:24:52,492 --> 00:24:56,063 +然后将这些新请求传递给控制器 + +460 +00:24:56,063 --> 00:24:58,799 +现在 模态表将提供任何凭据 + +461 +00:24:58,799 --> 00:25:02,936 +从这些凭证类型中获得的任何凭证 + +462 +00:25:02,936 --> 00:25:04,571 +无论使用哪种凭据类型 + +463 +00:25:04,571 --> 00:25:07,941 +您都将获得相同的委托回调 + +464 +00:25:07,941 --> 00:25:10,978 +您应该检查接收到的凭据类型 + +465 +00:25:10,978 --> 00:25:13,080 +并根据该凭据类型 + +466 +00:25:13,080 --> 00:25:15,315 +完成登录 + +467 +00:25:15,315 --> 00:25:18,018 +这就涵盖了 +ASAuthorization API 系列的 + +468 +00:25:18,018 --> 00:25:21,388 +一些更高级的特性 + +469 +00:25:21,388 --> 00:25:24,057 +现在 我将深入探讨一些技术细节 + +470 +00:25:24,057 --> 00:25:29,029 +通行密钥工作原理 +以及通行密钥为何如此安全 + +471 +00:25:29,029 --> 00:25:31,765 +现在 当您使用密码登录时 + +472 +00:25:31,765 --> 00:25:34,234 +通常情况下 + +473 +00:25:34,234 --> 00:25:36,537 +在您输入密码之后 + +474 +00:25:36,537 --> 00:25:40,841 +会被 hash 和 salt +以及由此产生的混淆值 + +475 +00:25:40,841 --> 00:25:44,077 +被发送到服务器得以储存 + +476 +00:25:44,077 --> 00:25:48,715 +稍后 如果您可以生成 +相同的哈希加盐值 + +477 +00:25:48,715 --> 00:25:51,185 +则允许您进入帐户 + +478 +00:25:51,185 --> 00:25:53,854 +这意味着服务器负责 + +479 +00:25:53,854 --> 00:25:56,924 +存储您的密码来源 + +480 +00:25:56,924 --> 00:25:59,860 +这对攻击者非常有价值 + +481 +00:25:59,860 --> 00:26:02,529 +如果攻击者能获得 +他们就有可能知道 + +482 +00:26:02,529 --> 00:26:06,500 +您的密码是什么并访问您的帐户 + +483 +00:26:06,500 --> 00:26:10,270 +但是 通行密钥的工作原理非常不同 + +484 +00:26:10,270 --> 00:26:13,207 +通行密钥不是单独的可输入字符串 + +485 +00:26:13,207 --> 00:26:16,577 +而是一对相关的通行密钥 + +486 +00:26:16,577 --> 00:26:19,413 +这些通行密钥由您的设备生成 + +487 +00:26:19,413 --> 00:26:23,550 +安全而唯一 为每个帐户服务 + +488 +00:26:23,550 --> 00:26:27,588 +一个是公开的 存储在服务器上 + +489 +00:26:27,588 --> 00:26:31,491 +另一个是私人的 即使在登录时 + +490 +00:26:31,491 --> 00:26:33,727 +也会保留在您的设备上 + +491 +00:26:33,727 --> 00:26:36,730 +公钥不是私密的 + +492 +00:26:36,730 --> 00:26:40,434 +就像您的用户名一样公开 + +493 +00:26:40,434 --> 00:26:44,171 +私钥是实际登录所需要的 + +494 +00:26:44,171 --> 00:26:47,341 +服务器永远不会知道您的私钥是什么 + +495 +00:26:47,341 --> 00:26:50,978 +您的设备会保护它的安全 + +496 +00:26:50,978 --> 00:26:54,448 +当您登录时 服务器会向您的设备 + +497 +00:26:54,448 --> 00:26:57,184 +发送一个一次性的质询 + +498 +00:26:57,184 --> 00:27:01,388 +WebAuthn 会允许 +许多不同的质询-响应算法 + +499 +00:27:01,388 --> 00:27:07,327 +但 Apple 平台上的通行密钥 +使用标准 ES256 + +500 +00:27:07,327 --> 00:27:10,464 +只有您的私钥才能 + +501 +00:27:10,464 --> 00:27:14,935 +为您的帐户质询产生有效的解决方案 + +502 +00:27:14,935 --> 00:27:17,104 +您的设备在本地生成这个解决方案 + +503 +00:27:17,104 --> 00:27:19,873 +叫做签名 + +504 +00:27:19,873 --> 00:27:23,744 +并且只将解决方案发送回服务器 + +505 +00:27:23,744 --> 00:27:28,949 +您的私钥是保密的 +并且只保存在您的设备上 + +506 +00:27:28,949 --> 00:27:34,154 +然后 服务器 +使用您的公钥验证解决方案 + +507 +00:27:34,154 --> 00:27:37,024 +如果您的设备提供的解决方案有效 + +508 +00:27:37,024 --> 00:27:39,326 +您就登录了! + +509 +00:27:39,326 --> 00:27:43,830 +公钥可用于检查解决方案是否有效 + +510 +00:27:43,830 --> 00:27:47,568 +但不能产生解决方案本身 + +511 +00:27:47,568 --> 00:27:49,803 +这意味着服务器可以确定 + +512 +00:27:49,803 --> 00:27:51,972 +您拥有正确的私钥 + +513 +00:27:51,972 --> 00:27:55,976 +而不需要知道私钥是什么 + +514 +00:27:55,976 --> 00:27:59,513 +而且由于服务器不知道任何私钥 + +515 +00:27:59,513 --> 00:28:02,015 +因此对攻击者来说 +这是一个价值较低的目标 + +516 +00:28:02,015 --> 00:28:06,086 +因为没有用户凭证可以泄露 + +517 +00:28:06,086 --> 00:28:08,755 +这些加密和通行密钥保护都是完全透明的 + +518 +00:28:08,755 --> 00:28:13,193 +并由设备执行 + +519 +00:28:13,193 --> 00:28:17,297 +您的客户不需要知道或思考通行密钥 + +520 +00:28:17,297 --> 00:28:20,567 +从他们的角度来看 通行密钥超级简单 + +521 +00:28:20,567 --> 00:28:23,570 +可以随时随地使用 + +522 +00:28:23,570 --> 00:28:27,641 +通行密钥也可用于跨设备登录 + +523 +00:28:27,641 --> 00:28:30,711 +以安全、防网络钓鱼的方式登录 + +524 +00:28:30,711 --> 00:28:33,013 +工作原理如下 + +525 +00:28:33,013 --> 00:28:34,815 +这里有两个设备 + +526 +00:28:34,815 --> 00:28:37,651 +客户端 也就是我登录的设备 +或网页浏览器 + +527 +00:28:37,651 --> 00:28:40,621 +以及身份验证器 + +528 +00:28:40,621 --> 00:28:44,291 +也就是拥有我的通行密钥的设备 + +529 +00:28:44,291 --> 00:28:46,894 +首先 客户端显示一个二维码 + +530 +00:28:46,894 --> 00:28:49,296 +身份验证器扫描二维码 + +531 +00:28:49,296 --> 00:28:51,798 +此二维码包含一个 URL + +532 +00:28:51,798 --> 00:28:56,470 +这个 URL 编码了 +一对一次性使用的加密通行密钥 + +533 +00:28:56,470 --> 00:29:00,240 +然后 身份认证器生成一个包含 + +534 +00:29:00,240 --> 00:29:04,444 +网络中继服务器路由信息的蓝牙广告 + +535 +00:29:04,444 --> 00:29:07,181 +这种本地交换 + +536 +00:29:07,181 --> 00:29:09,216 +允许选择服务器和共享路由信息 + +537 +00:29:09,216 --> 00:29:13,086 +但也有两个额外的功能 + +538 +00:29:13,086 --> 00:29:15,622 +它执行一个服务器看不到的 + +539 +00:29:15,622 --> 00:29:18,859 +带外通行密钥协议 因此网络上的 + +540 +00:29:18,859 --> 00:29:21,962 +所有内容都是端到端加密的 + +541 +00:29:21,962 --> 00:29:25,165 +服务器无法读取任何内容 + +542 +00:29:25,165 --> 00:29:27,701 +它还有力地证明了 + +543 +00:29:27,701 --> 00:29:31,538 +这两种设备在物理上是接近的 + +544 +00:29:31,538 --> 00:29:35,275 +这意味着通过电子邮件发送的二维码 + +545 +00:29:35,275 --> 00:29:39,513 +或在虚假网站上生成的二维码 +将无法工作 + +546 +00:29:39,513 --> 00:29:42,716 +因为远程攻击者将无法接收到 + +547 +00:29:42,716 --> 00:29:47,054 +蓝牙广告并完成本地交换 + +548 +00:29:47,054 --> 00:29:49,122 +以上就是本地部分 + +549 +00:29:49,122 --> 00:29:52,459 +一旦本地交换和通行密钥协议发生 + +550 +00:29:52,459 --> 00:29:54,995 +两台设备连接到由手机选择的 + +551 +00:29:54,995 --> 00:29:57,030 +中继服务器 + +552 +00:29:57,030 --> 00:30:01,468 +然后 执行一个标准的 +FIDO CTAP 操作 + +553 +00:30:01,468 --> 00:30:04,204 +这是使用前面的通行密钥加密的 + +554 +00:30:04,204 --> 00:30:07,541 +所以中继服务器 +看不到任何进行中的过程 + +555 +00:30:09,409 --> 00:30:12,446 +整个过程是由设备 + +556 +00:30:12,446 --> 00:30:14,181 +和网页浏览器执行的 + +557 +00:30:14,181 --> 00:30:17,417 +网站在任何时候都不涉及 + +558 +00:30:17,417 --> 00:30:19,620 +跨设备通信的过程 + +559 +00:30:19,620 --> 00:30:23,657 +跨设备跨平台登录是系统功能 + +560 +00:30:23,657 --> 00:30:28,262 +它可以在任何 +能够使用通行密钥的平台工作 + +561 +00:30:28,262 --> 00:30:31,665 +以上我们更专业地了解了 +通行密钥的工作原理 + +562 +00:30:31,665 --> 00:30:35,035 +通行密钥如何提供如此强大的安全保证 + +563 +00:30:35,035 --> 00:30:37,104 +甚至为何跨设备使用都如此安全 + +564 +00:30:37,104 --> 00:30:40,707 +接下来是多因素身份验证 + +565 +00:30:40,707 --> 00:30:44,044 +目前 考虑身份验证的一种常见方法 + +566 +00:30:44,044 --> 00:30:46,413 +是使用因素 + +567 +00:30:46,413 --> 00:30:48,715 +不同的因素 + +568 +00:30:48,715 --> 00:30:51,084 +对不同类型的攻击有强弱之分 + +569 +00:30:51,084 --> 00:30:52,519 +结合因素 + +570 +00:30:52,519 --> 00:30:55,355 +可以提供更好的集体覆盖率 + +571 +00:30:55,355 --> 00:30:59,927 +但是有了通行密钥 +您就不需要这么考虑了 + +572 +00:30:59,927 --> 00:31:02,029 +以下是目前最常用的一些 + +573 +00:31:02,029 --> 00:31:04,264 +登录方法 + +574 +00:31:04,264 --> 00:31:05,632 +您光凭记忆设置的密码 + +575 +00:31:05,632 --> 00:31:08,468 +是很不可靠的 + +576 +00:31:08,468 --> 00:31:09,803 +密码管理器 + +577 +00:31:09,803 --> 00:31:14,107 +擅长生成独特的、高熵的字符串 + +578 +00:31:14,107 --> 00:31:17,044 +可能具有本地保护措施 +防止设备被盗 + +579 +00:31:17,044 --> 00:31:20,781 +并提供一些关于网络钓鱼的提示 + +580 +00:31:20,781 --> 00:31:23,717 +添加短信或实时验证码 + +581 +00:31:23,717 --> 00:31:27,154 +在某些情况下 +可以帮助防止盗窃或网络钓鱼 + +582 +00:31:27,154 --> 00:31:29,790 +但并不能真正解决这两个问题 + +583 +00:31:29,790 --> 00:31:31,225 +而有了通行密钥 + +584 +00:31:31,225 --> 00:31:36,163 +每个通行密钥都是唯一的 +由设备生成的通行密钥对 + +585 +00:31:36,163 --> 00:31:39,700 +在 Apple 设备上 +通行密钥是在本地设备保护的 + +586 +00:31:39,700 --> 00:31:42,469 +强大基础上设立的 + +587 +00:31:42,469 --> 00:31:45,772 +通行密钥还完全消除了 + +588 +00:31:45,772 --> 00:31:48,075 +网络钓鱼的人为因素 + +589 +00:31:48,075 --> 00:31:51,445 +并且通行密钥不会 +被 App 或网站服务器泄露 + +590 +00:31:51,445 --> 00:31:55,449 +因为服务器没有私钥 + +591 +00:31:55,449 --> 00:31:58,619 +在基于密码的登录流程中 +添加因素是有意义的 + +592 +00:31:58,619 --> 00:32:01,655 +因为与单独使用密码相比 + +593 +00:32:01,655 --> 00:32:05,225 +结合在一起可以抵御更多类型的攻击 + +594 +00:32:05,225 --> 00:32:08,829 +但单凭通行密钥就能抵御的东西太多了 + +595 +00:32:08,829 --> 00:32:12,466 +不需要额外的因素 + +596 +00:32:12,466 --> 00:32:16,570 +我很期待一个 +不再需要密码的未来 + +597 +00:32:16,570 --> 00:32:20,707 +以下是您可以 +开始实现这一目标的方法 + +598 +00:32:20,707 --> 00:32:24,244 +首先 如果还没有采用 WebAuthn + +599 +00:32:24,244 --> 00:32:26,713 +您需要在服务器上采用它 + +600 +00:32:26,713 --> 00:32:27,981 +通行密钥应该可以用于 + +601 +00:32:27,981 --> 00:32:32,519 +任何标准的 +WebAuthn 服务器的实施 + +602 +00:32:32,519 --> 00:32:34,454 +服务器准备就绪后 + +603 +00:32:34,454 --> 00:32:38,225 +在您的 App +和网站中采用我们的新 API + +604 +00:32:38,225 --> 00:32:41,195 +自动填充辅助通行密钥请求可以 + +605 +00:32:41,195 --> 00:32:44,531 +直接放到您现有的登录流程中 + +606 +00:32:44,531 --> 00:32:48,001 +此外 如果您需要 我们还有一系列 + +607 +00:32:48,001 --> 00:32:50,237 +更高级的 UI 选项 + +608 +00:32:50,237 --> 00:32:56,176 +最后 帮助您的用户 +从密码转移到通行密钥 + +609 +00:32:56,176 --> 00:32:59,513 +通行密钥是行业标准的解决方案 + +610 +00:32:59,513 --> 00:33:01,715 +它能解决安全登录 App 和 + +611 +00:33:01,715 --> 00:33:05,786 +网站的便利性和安全性等问题 + +612 +00:33:05,786 --> 00:33:08,488 +通过引导您的用户 +使用通行密钥来替代密码 + +613 +00:33:08,488 --> 00:33:11,458 +您可以给用户带来 + +614 +00:33:11,458 --> 00:33:15,329 +非常快速和方便的登录体验 + +615 +00:33:15,329 --> 00:33:18,498 +同时为大家提高安全标准 + +616 +00:33:18,498 --> 00:33:19,466 +谢谢 + +617 +00:33:19,466 --> 00:33:23,303 +♪ + diff --git a/zho/2022 Session 10093 Integrate your custom collaboration app with Messages.srt b/zho/2022 Session 10093 Integrate your custom collaboration app with Messages.srt new file mode 100644 index 0000000..892e96c --- /dev/null +++ b/zho/2022 Session 10093 Integrate your custom collaboration app with Messages.srt @@ -0,0 +1,2283 @@ +1 +00:00:00,167 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,977 +♪ + +3 +00:00:09,977 --> 00:00:14,281 +Devin Clary:嗨 我是 +Messages 团队的工程师 Devin + +4 +00:00:14,281 --> 00:00:17,017 +Lance Parker:我是 Lance +也是 Messages 团队工程师 + +5 +00:00:17,017 --> 00:00:20,053 +Devin:欢迎收看 +“集成使用您的自定义协作 App + +6 +00:00:20,053 --> 00:00:22,222 +与 Messages ” + +7 +00:00:22,222 --> 00:00:24,625 +协作以会话为起点 + +8 +00:00:24,625 --> 00:00:27,227 +在 iOS 16 和 macOS Ventura 中 + +9 +00:00:27,227 --> 00:00:29,897 +您可将您 App 的自定义协作体验 + +10 +00:00:29,897 --> 00:00:32,466 +直接带入会话结构 + +11 +00:00:32,466 --> 00:00:36,870 +本次视频 我们首先 +为您介绍协作的生命周期 + +12 +00:00:36,870 --> 00:00:38,438 +其次 我们将向您展示如何准备 + +13 +00:00:38,438 --> 00:00:42,809 +通过 Messages 共享 +App 的协作内容 + +14 +00:00:42,809 --> 00:00:45,879 +再次 我们将为您详细讲解如何 + +15 +00:00:45,879 --> 00:00:49,650 +及时验证接收者的访问 +以及响应参与者的变化 + +16 +00:00:49,650 --> 00:00:52,619 +以上所有均不涉及隐私问题 + +17 +00:00:52,619 --> 00:00:55,355 +最后 我们将 +向您展示您的 App 如何 + +18 +00:00:55,355 --> 00:00:59,293 +在 Message 会话中 +直接发布有关内容的通知 + +19 +00:00:59,293 --> 00:01:00,928 +假设您的 App + +20 +00:01:00,928 --> 00:01:03,263 +已具备协作基础设施 + +21 +00:01:03,263 --> 00:01:06,066 +并且已经采用了通用链接 + +22 +00:01:06,066 --> 00:01:08,268 +我们将以“将 SharedWithYou +添加到您的 App 中” + +23 +00:01:08,268 --> 00:01:09,870 +和“利用 Messages +增强协作体验”中 + +24 +00:01:09,870 --> 00:01:14,575 +介绍的某些概念为基础 + +25 +00:01:14,575 --> 00:01:16,677 +首先 我来介绍一下 + +26 +00:01:16,677 --> 00:01:18,979 +自定义协作消息的生命周期 + +27 +00:01:18,979 --> 00:01:21,515 +说明该 API 如何让您的用户 + +28 +00:01:21,515 --> 00:01:24,818 +更加快速地开始协作 + +29 +00:01:24,818 --> 00:01:26,987 +当用户决定通过 Messages + +30 +00:01:26,987 --> 00:01:29,756 +在您的 App 中共享协作时 + +31 +00:01:29,756 --> 00:01:33,427 +您首先应创建表达内容的元数据 + +32 +00:01:33,427 --> 00:01:36,463 +元数据包括用户在发送消息前 + +33 +00:01:36,463 --> 00:01:37,965 +可配置的共享选项 + +34 +00:01:37,965 --> 00:01:41,301 +以及可由您定义的其他属性 + +35 +00:01:41,301 --> 00:01:43,971 +接下来 您将元数据提供给共享表 + +36 +00:01:43,971 --> 00:01:46,039 +或拖放 + +37 +00:01:46,039 --> 00:01:48,375 +这可让内容草稿暂存 + +38 +00:01:48,375 --> 00:01:51,144 +在 Messages 撰写字段中 + +39 +00:01:51,144 --> 00:01:55,215 +协作需要由通用链接表示 + +40 +00:01:55,215 --> 00:01:57,918 +可立即创建 但最好推迟到 + +41 +00:01:57,918 --> 00:02:00,721 +消息发送之前再创建 + +42 +00:02:00,721 --> 00:02:02,422 +您 App 的链接创建 +由所选的共享选项或接收者决定 + +43 +00:02:02,422 --> 00:02:05,325 +如在 Messages +撰写字段中配置的那样 + +44 +00:02:05,325 --> 00:02:08,395 +则该条件适合用 + +45 +00:02:08,395 --> 00:02:11,365 +用户选择接收者和分享选项 + +46 +00:02:11,365 --> 00:02:14,201 +并点击发送按钮 + +47 +00:02:14,201 --> 00:02:15,569 +在发送消息前 + +48 +00:02:15,569 --> 00:02:17,971 +Messages 要求 +您的 App 提供通用链接 + +49 +00:02:17,971 --> 00:02:21,575 +以及独立于设备的内容标识符 + +50 +00:02:21,575 --> 00:02:23,877 +利用该标识符 +Messages 提供了一组 + +51 +00:02:23,877 --> 00:02:26,747 +代表该特定协作消息 + +52 +00:02:26,747 --> 00:02:29,917 +接收者的加密身份 + +53 +00:02:29,917 --> 00:02:31,685 +您的 App 稍后会利用这组身份 + +54 +00:02:31,685 --> 00:02:34,087 +允许接收者在其任意设备上 + +55 +00:02:34,087 --> 00:02:38,725 +立即打开链接 + +56 +00:02:38,725 --> 00:02:41,261 +您的 App 还会将 +这组身份存储在服务器上 + +57 +00:02:41,261 --> 00:02:44,364 +并将其与共享内容相关联 + +58 +00:02:44,364 --> 00:02:46,033 +一旦您的 App 完成该步骤 + +59 +00:02:46,033 --> 00:02:50,470 +消息就会被发送给接收者 + +60 +00:02:50,470 --> 00:02:53,440 +现在 接收设备上会发生以下情况 + +61 +00:02:53,440 --> 00:02:56,009 +我们的目的是立即验证访问权限 + +62 +00:02:56,009 --> 00:02:59,913 +将接收者身份 +与您服务器上的帐户配对 + +63 +00:02:59,913 --> 00:03:01,682 +当接收者打开链接时 + +64 +00:03:01,682 --> 00:03:04,351 +您的 App 会收到 +打开 URL 的调用 + +65 +00:03:04,351 --> 00:03:08,388 +收到其他链接也是如此 + +66 +00:03:08,388 --> 00:03:10,090 +当您的 App 检测到某个用户帐户 + +67 +00:03:10,090 --> 00:03:12,326 +无权访问该文档时 + +68 +00:03:12,326 --> 00:03:15,262 +它就会查询系统 获取 + +69 +00:03:15,262 --> 00:03:18,866 +由接收设备加密签名的用户身份证明 + +70 +00:03:18,866 --> 00:03:20,901 +您的 App 会发送 +签名后的身份证明 + +71 +00:03:20,901 --> 00:03:23,871 +至您的服务器进行验证 + +72 +00:03:23,871 --> 00:03:26,373 +如果签名有效 服务器会对该证明 + +73 +00:03:26,373 --> 00:03:28,308 +与发送设备先前提供的身份证明 + +74 +00:03:28,308 --> 00:03:30,310 +做比较 + +75 +00:03:30,310 --> 00:03:33,213 +如果匹配 +您的服务器就会授予该用户帐户 + +76 +00:03:33,213 --> 00:03:35,215 +访问权限 + +77 +00:03:35,215 --> 00:03:36,717 +这样一来 接收者就可 + +78 +00:03:36,717 --> 00:03:39,419 +即时安全地访问内容 + +79 +00:03:39,419 --> 00:03:42,022 +无需交换帐户信息! + +80 +00:03:42,022 --> 00:03:45,826 +这就是协作消息的生命周期! + +81 +00:03:45,826 --> 00:03:47,561 +下面我们来进一步了解 + +82 +00:03:47,561 --> 00:03:51,198 +用于启动协作的 API + +83 +00:03:51,198 --> 00:03:55,169 +系统需要某些关于协作的元数据 + +84 +00:03:55,169 --> 00:03:56,970 +为此 您要在 +SharedWithYou 框架中 + +85 +00:03:56,970 --> 00:04:01,575 +使用一个名为 +SWCollaborationMetadata 的新类 + +86 +00:04:01,575 --> 00:04:05,012 +您需为该类配置属性 + +87 +00:04:05,012 --> 00:04:08,148 +如内容标题 即本地标识符 + +88 +00:04:08,148 --> 00:04:10,851 +用于在内容共享前参考 + +89 +00:04:10,851 --> 00:04:13,220 +又如发起者名称和帐户句柄 + +90 +00:04:13,220 --> 00:04:14,788 +用于为用户正在共享的账户 + +91 +00:04:14,788 --> 00:04:16,890 +增加透明度 + +92 +00:04:16,890 --> 00:04:21,528 +以及默认共享选项 供用户配置 + +93 +00:04:21,528 --> 00:04:23,330 +以下是创建元数据对象 + +94 +00:04:23,330 --> 00:04:27,034 +及配置其属性的方法 + +95 +00:04:27,034 --> 00:04:31,104 +利用以字符串初始化的 +SWLocalCollaborationIdentifier + +96 +00:04:31,104 --> 00:04:33,874 +创建本地标识符 + +97 +00:04:33,874 --> 00:04:36,143 +该字符串只需供您的 App + +98 +00:04:36,143 --> 00:04:41,114 +在本地识别内容 无需跨设备识别 + +99 +00:04:41,114 --> 00:04:43,183 +使用本地标识符初始化一个 + +100 +00:04:43,183 --> 00:04:47,020 +新的元数据实例 + +101 +00:04:47,020 --> 00:04:52,025 +使用基础框架中的 +PersonNameComponents + +102 +00:04:52,025 --> 00:04:54,628 +设置内容标题 发起者账号句柄 + +103 +00:04:54,628 --> 00:04:57,164 +及其名称 + +104 +00:04:57,164 --> 00:04:59,566 +句柄和名称仅在本地显示 + +105 +00:04:59,566 --> 00:05:04,371 +这样用户就可以确认其共享帐户 + +106 +00:05:04,371 --> 00:05:07,474 +接下来 +设置 defaultShareOptions + +107 +00:05:07,474 --> 00:05:08,942 +展示具体操作之前 + +108 +00:05:08,942 --> 00:05:12,012 +我先讲一下选项工作的方式 + +109 +00:05:12,012 --> 00:05:14,548 +共享选项是用户在 Messages 协作 + +110 +00:05:14,548 --> 00:05:18,252 +或共享表上配置的设置 + +111 +00:05:18,252 --> 00:05:20,621 +用户选择的选项将在发送消息之前 + +112 +00:05:20,621 --> 00:05:23,323 +提供给您 + +113 +00:05:23,323 --> 00:05:25,325 +共享选项可能包含的设置有 + +114 +00:05:25,325 --> 00:05:27,694 +谁可对协作进行编辑 + +115 +00:05:27,694 --> 00:05:32,199 +或谁有权访问内容 + +116 +00:05:32,199 --> 00:05:34,768 +您可用一些类来定义选项 + +117 +00:05:34,768 --> 00:05:38,238 +比如从 SWCollaborationOption 开始 + +118 +00:05:38,238 --> 00:05:39,640 +选项取决于分组方式 + +119 +00:05:39,640 --> 00:05:42,209 +它代表单个开关 + +120 +00:05:42,209 --> 00:05:46,280 +或某个设置的互斥值 + +121 +00:05:46,280 --> 00:05:48,715 +选项有一个标题和一个标识符 + +122 +00:05:48,715 --> 00:05:53,921 +两者要么选中要么不选 + +123 +00:05:53,921 --> 00:05:58,091 +有两个类来表示一组选项 + +124 +00:05:58,091 --> 00:06:00,060 +即 SWCollaborationOptionsGroup + +125 +00:06:00,060 --> 00:06:04,198 +和 SWCollaborationOptionsPickerGroup + +126 +00:06:04,198 --> 00:06:06,767 +您可用 +SWCollaborationOptionsGroup + +127 +00:06:06,767 --> 00:06:09,269 +表示开关的集合 + +128 +00:06:09,269 --> 00:06:11,905 +同时用 +SWCollaborationOptionsPickerGroup + +129 +00:06:11,905 --> 00:06:16,610 +表示设置的互斥值 + +130 +00:06:16,610 --> 00:06:19,246 +最后 SWCollaborationShareOptions + +131 +00:06:19,246 --> 00:06:21,682 +定义了全套选项组 + +132 +00:06:21,682 --> 00:06:25,252 +可在元数据的 +defaultShareOptions 属性上设置 + +133 +00:06:25,252 --> 00:06:29,489 +您还可以提供摘要字符串来描述选项 + +134 +00:06:29,489 --> 00:06:31,658 +描述完选项类 + +135 +00:06:31,658 --> 00:06:34,661 +我再来向您展示使用方法 + +136 +00:06:34,661 --> 00:06:38,765 +这个代码定义了两个选项组 + +137 +00:06:38,765 --> 00:06:41,368 +第一组用标识符和 + +138 +00:06:41,368 --> 00:06:43,937 +两个可能的选项初始化 + +139 +00:06:43,937 --> 00:06:45,973 +标识符是任意字符串 + +140 +00:06:45,973 --> 00:06:50,711 +稍后可用于识别用户选择了哪个选项 + +141 +00:06:50,711 --> 00:06:52,145 +由于是选择器组合 + +142 +00:06:52,145 --> 00:06:54,915 +因此各个选项互斥 + +143 +00:06:54,915 --> 00:06:56,884 +该组代表内容权限设置 + +144 +00:06:56,884 --> 00:07:00,787 +即读写或只读 + +145 +00:07:00,787 --> 00:07:06,093 +然后 默认选择该组的第一个选项 + +146 +00:07:06,093 --> 00:07:11,231 +标题设置为描述该组的字符串 + +147 +00:07:11,231 --> 00:07:13,667 +第二个选项组以同样的方式初始化 + +148 +00:07:13,667 --> 00:07:16,203 +也包含两个选项 + +149 +00:07:16,203 --> 00:07:18,305 +但因该选项组为通用选项组 + +150 +00:07:18,305 --> 00:07:19,673 +用户可以配置 + +151 +00:07:19,673 --> 00:07:23,710 +是否独立允许提及和评论 + +152 +00:07:23,710 --> 00:07:26,547 +最后 这两个选项组可用于初始化 + +153 +00:07:26,547 --> 00:07:30,184 +SWCollaborationShareOptions 实例 + +154 +00:07:30,184 --> 00:07:34,454 +随后在元数据上设置该实例 + +155 +00:07:34,454 --> 00:07:37,090 +接下来 根据用户分享内容的方式 + +156 +00:07:37,090 --> 00:07:39,626 +将元数据提供给共享表 + +157 +00:07:39,626 --> 00:07:42,362 +或拖放 + +158 +00:07:42,362 --> 00:07:46,033 +如果您的 App 用的是 SwiftUI +SWCollaborationMetadata + +159 +00:07:46,033 --> 00:07:49,536 +就可与新的 ShareLink API 兼容 + +160 +00:07:49,536 --> 00:07:52,105 +观看“Meet Transferable” +和“SwiftUI 的新功能” + +161 +00:07:52,105 --> 00:07:58,245 +即可了解有关 +Transferable 和 ShareLink 的更多信息 + +162 +00:07:58,245 --> 00:08:00,814 +我们来看 +在 SwiftUI 的代理模式上 + +163 +00:08:00,814 --> 00:08:05,552 +支持协作有多么简单! + +164 +00:08:05,552 --> 00:08:08,288 +从 Transferable 模型对象中 +设置一个 + +165 +00:08:08,288 --> 00:08:10,090 +ProxyRepresentation + +166 +00:08:10,090 --> 00:08:15,395 +来返回协作元数据实例 + +167 +00:08:15,395 --> 00:08:16,630 +然后从一个视图中 + +168 +00:08:16,630 --> 00:08:22,836 +使用该模型对象初始化 ShareLink + +169 +00:08:22,836 --> 00:08:26,673 +对于 UIKit 和 AppKit App +您可使用 NSItemProvider + +170 +00:08:26,673 --> 00:08:28,408 +支持分享 + +171 +00:08:28,408 --> 00:08:31,011 +且 SWCollaborationMetadata 符合 + +172 +00:08:31,011 --> 00:08:33,780 +NSItemProviderReading 和 Writing + +173 +00:08:33,780 --> 00:08:36,216 +所以您只需用 itemProvider + +174 +00:08:36,216 --> 00:08:39,853 +注册一个元数据实例 以支持协作 + +175 +00:08:39,853 --> 00:08:41,255 +还有个好方法是 + +176 +00:08:41,255 --> 00:08:43,757 +注册多个内容表示 + +177 +00:08:43,757 --> 00:08:47,528 +便于支持多个渠道分享 + +178 +00:08:47,528 --> 00:08:49,596 +例如 如果您提供了文件表示 + +179 +00:08:49,596 --> 00:08:52,232 +Messages 会自动 +提供将内容以副本发送 + +180 +00:08:52,232 --> 00:08:55,969 +这个选项 + +181 +00:08:55,969 --> 00:08:58,672 +您可将 NSItemProvider API 与 + +182 +00:08:58,672 --> 00:09:03,477 +iOS 和 iPadOS 上的 +UIActivityViewController 和 UIDragItem + +183 +00:09:03,477 --> 00:09:08,282 +以及 macOS 上的 +NSSharingServicePicker 结合使用 + +184 +00:09:08,282 --> 00:09:12,519 +以下是在 iOS 上 +使用共享表进行设置的方法 + +185 +00:09:12,519 --> 00:09:16,190 +创建一个 NSItemProvider 实例 + +186 +00:09:16,190 --> 00:09:18,091 +注册此前提到的 + +187 +00:09:18,091 --> 00:09:19,826 +协作元数据 + +188 +00:09:19,826 --> 00:09:25,032 +将可见性设置为系统上的所有进程 + +189 +00:09:25,032 --> 00:09:27,734 +用 itemProvider 初始化 + +190 +00:09:27,734 --> 00:09:30,604 +UIActivityItemsConfiguration + +191 +00:09:30,604 --> 00:09:32,973 +然后用同样的配置初始化 + +192 +00:09:32,973 --> 00:09:36,043 +UIActivityViewController + +193 +00:09:36,043 --> 00:09:40,948 +最后 展示视图控制器 + +194 +00:09:40,948 --> 00:09:44,918 +支持拖放也同样简单 + +195 +00:09:44,918 --> 00:09:46,186 +初始化 NSItemProvider + +196 +00:09:46,186 --> 00:09:50,591 +并以相同方式注册元数据 + +197 +00:09:50,591 --> 00:09:53,360 +然后使用 itemProvider 创建一个 + +198 +00:09:53,360 --> 00:09:58,565 +UIDragItem 以便 +与拖放 API 一起使用 + +199 +00:09:58,565 --> 00:10:03,237 +API 与 macOS 上的 +共享弹出框类似 + +200 +00:10:03,237 --> 00:10:06,573 +再次设置 itemProvider + +201 +00:10:06,573 --> 00:10:08,242 +这一次 需用它来初始化 + +202 +00:10:08,242 --> 00:10:11,879 +NSSharingServicePicker + +203 +00:10:11,879 --> 00:10:17,184 +然后显示涉及目标视图的选择器 + +204 +00:10:17,184 --> 00:10:20,621 +macOS 上的拖放 +可利用的是 NSPasteboardItem + +205 +00:10:20,621 --> 00:10:22,823 +而非 NSItemProvider + +206 +00:10:22,823 --> 00:10:24,625 +为提供支持 SharedWithYou + +207 +00:10:24,625 --> 00:10:29,329 +要导出一个 NSPasteboardItem 扩展 + +208 +00:10:29,329 --> 00:10:31,865 +使用该扩展 直接在一个新的 + +209 +00:10:31,865 --> 00:10:34,835 +NSPasteboardItem +实例上设置协作元数据 + +210 +00:10:34,835 --> 00:10:39,106 +以支持拖放 + +211 +00:10:39,106 --> 00:10:40,641 +以上就是在 Messages 中 + +212 +00:10:40,641 --> 00:10:45,746 +设置您的协作内容草稿的全部操作! + +213 +00:10:45,746 --> 00:10:47,981 +接下来 当用户点击发送按钮时 + +214 +00:10:47,981 --> 00:10:52,553 +系统会协调您的 App 以设置共享 + +215 +00:10:52,553 --> 00:10:54,388 +该操作通过一个名为 + +216 +00:10:54,388 --> 00:10:57,391 +SWCollaborationCoordinator +的新类实现 + +217 +00:10:57,391 --> 00:11:00,194 +SWCollaborationCoordinator +是一个单例模式 + +218 +00:11:00,194 --> 00:11:03,230 +意味着有一个全局共享实例 + +219 +00:11:03,230 --> 00:11:05,499 +该共享实例通过您定义的名为 + +220 +00:11:05,499 --> 00:11:09,336 +actionHandler 的委托来协调协作 + +221 +00:11:09,336 --> 00:11:11,138 +为确保您的 App 始终可用于 + +222 +00:11:11,138 --> 00:11:12,806 +协调合作 + +223 +00:11:12,806 --> 00:11:15,175 +它会适时在后台启动 + +224 +00:11:15,175 --> 00:11:17,678 +所以您应在启动后尽快注册委托 + +225 +00:11:17,678 --> 00:11:22,182 +并立即处理操作 避免超时 + +226 +00:11:22,182 --> 00:11:24,251 +以下是在您的 App 完成启动后 + +227 +00:11:24,251 --> 00:11:28,021 +设置协作协调器的方法 + +228 +00:11:28,021 --> 00:11:30,257 +通过共享属性访问 + +229 +00:11:30,257 --> 00:11:33,594 +单例模式协调器实例 + +230 +00:11:33,594 --> 00:11:34,828 +然后 在 App 委托的 + +231 +00:11:34,828 --> 00:11:36,964 +didFinishLaunchingWithOptions 方法中 + +232 +00:11:36,964 --> 00:11:38,265 +将 actionHandler 属性 + +233 +00:11:38,265 --> 00:11:39,800 +设置为符合 + +234 +00:11:39,800 --> 00:11:44,371 +SWCollaborationActionHandler +协议的对象 + +235 +00:11:44,371 --> 00:11:46,874 +操作处理程序协议使用了一个 + +236 +00:11:46,874 --> 00:11:49,176 +名为 SWAction 的新类 + +237 +00:11:49,176 --> 00:11:53,814 +SWActions 代表 +您的 App 需要执行的操作 + +238 +00:11:53,814 --> 00:11:56,116 +操作完成后会标记为完成 + +239 +00:11:56,116 --> 00:11:59,019 +否则会标记为失败 + +240 +00:11:59,019 --> 00:12:01,088 +您的 App 需要处理的第一个操作 + +241 +00:12:01,088 --> 00:12:03,924 +就是启动协作 + +242 +00:12:03,924 --> 00:12:05,559 +SWStartCollaborationAction + +243 +00:12:05,559 --> 00:12:08,595 +包含您此前设置的协作元数据 + +244 +00:12:08,595 --> 00:12:12,299 +元数据由用户 +选择的共享选项进行更新 + +245 +00:12:12,299 --> 00:12:14,234 +完成必要设置后 + +246 +00:12:14,234 --> 00:12:17,037 +您可使用通用链接和 + +247 +00:12:17,037 --> 00:12:18,972 +一个独立于设备的标识符 + +248 +00:12:18,972 --> 00:12:20,974 +完成协作启动操作 + +249 +00:12:20,974 --> 00:12:23,277 +如果您启动操作失败 + +250 +00:12:23,277 --> 00:12:26,013 +消息就会取消发送 + +251 +00:12:26,013 --> 00:12:28,282 +以下是使用示例服务器请求 + +252 +00:12:28,282 --> 00:12:32,219 +处理启动操作的方法 + +253 +00:12:32,219 --> 00:12:34,288 +首先 检索本地标识符 + +254 +00:12:34,288 --> 00:12:36,023 +和来自操作元数据属性的 + +255 +00:12:36,023 --> 00:12:40,227 +用户所选的共享选项 + +256 +00:12:40,227 --> 00:12:42,796 +使用标识符和选项设置服务器请求 + +257 +00:12:42,796 --> 00:12:47,334 +以准备协作 + +258 +00:12:47,334 --> 00:12:50,170 +然后 将请求发送到服务器 + +259 +00:12:50,170 --> 00:12:54,508 +此示例使用了异步等待功能 + +260 +00:12:54,508 --> 00:12:56,977 +最后用通用链接以及响应中的 + +261 +00:12:56,977 --> 00:13:01,715 +设备独立标识符来完成操作 + +262 +00:13:01,715 --> 00:13:03,116 +如若出现错误 + +263 +00:13:03,116 --> 00:13:05,953 +则消息取消发送 操作失败 + +264 +00:13:05,953 --> 00:13:07,955 +如果启动操作成功 + +265 +00:13:07,955 --> 00:13:10,224 +系统会向您的 App +发送第二个操作 + +266 +00:13:10,224 --> 00:13:13,093 +用于更新协作参与者 + +267 +00:13:13,093 --> 00:13:15,462 +SWUpdateCollaborationParticipantsAction + +268 +00:13:15,462 --> 00:13:17,664 +包含参与者的 + +269 +00:13:17,664 --> 00:13:19,867 +加密身份 + +270 +00:13:19,867 --> 00:13:22,469 +该身份来自上一步启动操作完成后 + +271 +00:13:22,469 --> 00:13:26,840 +得到的协作标识符 + +272 +00:13:26,840 --> 00:13:28,475 +请将与内容相关的身份 + +273 +00:13:28,475 --> 00:13:30,878 +存储在您的服务器上 + +274 +00:13:30,878 --> 00:13:32,880 +您将使用这些数据在接收设备上 + +275 +00:13:32,880 --> 00:13:35,382 +验证访问权限 + +276 +00:13:35,382 --> 00:13:36,950 +最后 操作完成后 + +277 +00:13:36,950 --> 00:13:40,587 +会在 Messages 中发送通用链接 + +278 +00:13:40,587 --> 00:13:42,089 +这个例子展示了 + +279 +00:13:42,089 --> 00:13:45,025 +如何处理更新参与者操作 + +280 +00:13:45,025 --> 00:13:46,593 +检索来自操作元数据的 + +281 +00:13:46,593 --> 00:13:49,162 +协作标识符所使用的方法 + +282 +00:13:49,162 --> 00:13:50,731 +在处理启动操作时 + +283 +00:13:50,731 --> 00:13:54,001 +就得到了您填写的标识符 + +284 +00:13:54,001 --> 00:13:57,204 +接下来 利用该操作的 +addedIdentities 属性 + +285 +00:13:57,204 --> 00:14:01,074 +可检索参与者数据 +并将其存储在您的服务器上 + +286 +00:14:01,074 --> 00:14:05,112 +每个身份都有一个 +称为根哈希的 Data 属性 + +287 +00:14:05,112 --> 00:14:06,713 +这是您应存储在服务器上的数据 + +288 +00:14:06,713 --> 00:14:09,316 +稍后会用到 + +289 +00:14:09,316 --> 00:14:10,784 +Lance 将为您详细介绍 + +290 +00:14:10,784 --> 00:14:16,190 +Verifying Access +部分中有关此属性的内容 + +291 +00:14:16,190 --> 00:14:18,425 +设置另一个服务器请求 这次是将 + +292 +00:14:18,425 --> 00:14:20,394 +参与者添加到具有 + +293 +00:14:20,394 --> 00:14:23,931 +目标标识符的协作中 + +294 +00:14:23,931 --> 00:14:26,667 +和之前一样 +将请求发送到您的服务器 + +295 +00:14:26,667 --> 00:14:29,503 +要么操作完成 要么操作失败 + +296 +00:14:29,503 --> 00:14:34,474 +这次 操作失败后不会有任何参数 + +297 +00:14:34,474 --> 00:14:36,443 +既然您已经设置好协作 + +298 +00:14:36,443 --> 00:14:39,546 +您的 App 就已万事俱备 +可授予信息接收者 + +299 +00:14:39,546 --> 00:14:42,049 +即时访问权限 + +300 +00:14:42,049 --> 00:14:44,818 +接下来就由 Lance +为您介绍具体操作方法! + +301 +00:14:44,818 --> 00:14:47,254 +Lance:谢谢 Devin 在这个部分 + +302 +00:14:47,254 --> 00:14:49,690 +我将展示如何利用 + +303 +00:14:49,690 --> 00:14:52,125 +您上一步存储在服务器上的身份数据 + +304 +00:14:52,125 --> 00:14:56,330 +向接收者提供即时访问 + +305 +00:14:56,330 --> 00:14:58,999 +SWPersonIdentity 上的 +rootHash 属性 + +306 +00:14:58,999 --> 00:15:02,135 +通常用来做此验证 + +307 +00:15:02,135 --> 00:15:05,939 +rootHash 是唯一用于识别 + +308 +00:15:05,939 --> 00:15:08,942 +参与者设备的安全值 + +309 +00:15:08,942 --> 00:15:11,044 +为进行验证 + +310 +00:15:11,044 --> 00:15:14,214 +您需要了解如何计算根哈希值 + +311 +00:15:14,214 --> 00:15:16,884 +我来为您一一解释 + +312 +00:15:16,884 --> 00:15:18,952 +发送协作消息时 + +313 +00:15:18,952 --> 00:15:24,591 +实际上是单独发送到每个人的设备 + +314 +00:15:24,591 --> 00:15:26,493 +Messages 利用加密公钥 + +315 +00:15:26,493 --> 00:15:29,563 +识别每个设备 + +316 +00:15:29,563 --> 00:15:31,465 +由于只允许 + +317 +00:15:31,465 --> 00:15:35,135 +在这组设备上进行访问 才会从 + +318 +00:15:35,135 --> 00:15:39,973 +每个接收者注册的 +一组公钥中得到根哈希值 + +319 +00:15:39,973 --> 00:15:42,576 +根哈希值是一个数据结构的根节点 + +320 +00:15:42,576 --> 00:15:45,078 +该结构叫做梅克尔树 + +321 +00:15:45,078 --> 00:15:47,581 +梅克尔树是一棵二叉树 + +322 +00:15:47,581 --> 00:15:51,785 +通过执行一系列散列操作建造而成 + +323 +00:15:51,785 --> 00:15:54,621 +为了根据用户公钥推导出其身份 + +324 +00:15:54,621 --> 00:15:59,459 +这些公钥就被视为梅克尔树的叶子 + +325 +00:15:59,459 --> 00:16:02,629 +梅克尔树中使用的散列算法确保 + +326 +00:16:02,629 --> 00:16:07,901 +根节点只能从这组公钥中计算出来 + +327 +00:16:07,901 --> 00:16:11,839 +本示例中 该用户有三台设备 + +328 +00:16:11,839 --> 00:16:15,175 +三个公钥 + +329 +00:16:15,175 --> 00:16:18,278 +对您的 App 所提供的 +每个协作标识符来说 + +330 +00:16:18,278 --> 00:16:19,847 +以上公钥都是唯一的 + +331 +00:16:19,847 --> 00:16:24,318 +用的都是一个称为密钥多样化的程序 + +332 +00:16:24,318 --> 00:16:28,055 +为了防止追踪用户注册的设备数量 + +333 +00:16:28,055 --> 00:16:31,959 +这组公钥用随机密钥填充至一定大小 + +334 +00:16:31,959 --> 00:16:34,628 +梅克尔树的叶节点由散列 + +335 +00:16:34,628 --> 00:16:38,432 +填充的一组多样化密钥集合创建 + +336 +00:16:38,432 --> 00:16:41,969 +SHA256 算法用于该树的 + +337 +00:16:41,969 --> 00:16:44,171 +散列操作 + +338 +00:16:44,171 --> 00:16:47,407 +然后 将每对叶节点连接起来 + +339 +00:16:47,407 --> 00:16:51,945 +散列运算得出其父节点 + +340 +00:16:51,945 --> 00:16:56,049 +在父节点上重复此过程 + +341 +00:16:56,049 --> 00:17:00,654 +并再次重复至仅剩一个根节点 + +342 +00:17:00,654 --> 00:17:03,790 +这个根哈希值仅用于表示 + +343 +00:17:03,790 --> 00:17:09,897 +该接收者在其设备上的身份 + +344 +00:17:09,897 --> 00:17:12,566 +请注意 根哈希值可用 + +345 +00:17:12,566 --> 00:17:17,204 +一棵完整梅克尔树 +上的节点子集合生成 + +346 +00:17:17,204 --> 00:17:20,741 +这棵树中的根哈希值只需用 + +347 +00:17:20,741 --> 00:17:25,145 +哈希值 H4 7 和 11 + +348 +00:17:25,145 --> 00:17:29,316 +以及多样化的公钥 P3 即可再现 + +349 +00:17:29,316 --> 00:17:35,689 +首先 对公钥进行散列运算 +得到缺失的叶节点 H3 + +350 +00:17:35,689 --> 00:17:39,893 +使用 H3 和 H4 生成 H8 + +351 +00:17:39,893 --> 00:17:44,698 +使用给定的 +H7 节点和 H8 生成 H10 + +352 +00:17:44,698 --> 00:17:49,970 +最后 H10 +和 H11 生成根哈希值 + +353 +00:17:49,970 --> 00:17:53,207 +需要注意的是 +无需重建整棵梅克尔树 + +354 +00:17:53,207 --> 00:17:55,776 +您就可证明公钥 P3 可用于生成 + +355 +00:17:55,776 --> 00:17:59,646 +给定的根哈希值 + +356 +00:17:59,646 --> 00:18:01,782 +执行此操作所需的节点子集称为 + +357 +00:18:01,782 --> 00:18:05,352 +proof of inclusion + +358 +00:18:05,352 --> 00:18:08,255 +您的 App 打开通用链接后 + +359 +00:18:08,255 --> 00:18:10,490 +验证就开始了 + +360 +00:18:10,490 --> 00:18:12,092 +为此 您首先需要检查 + +361 +00:18:12,092 --> 00:18:15,028 +该链接为可协作状态 + +362 +00:18:15,028 --> 00:18:18,498 +SWCollaborationHighlight +表示协作链接 + +363 +00:18:18,498 --> 00:18:22,503 +可在 SWHighlightCenter 中检索 + +364 +00:18:22,503 --> 00:18:24,071 +使用该链接 + +365 +00:18:24,071 --> 00:18:28,742 +生成 proof of inclusion + +366 +00:18:28,742 --> 00:18:31,311 +为了表示 proof of inclusion + +367 +00:18:31,311 --> 00:18:35,349 +可使用一个名为 +SWPersonIdentityProof 的类 + +368 +00:18:35,349 --> 00:18:37,551 +为执行验证 您首先要生成 + +369 +00:18:37,551 --> 00:18:40,554 +该对象以及加密签名 + +370 +00:18:40,554 --> 00:18:43,090 +发送到您的服务器 + +371 +00:18:43,090 --> 00:18:46,326 +使用 getSignedIdentityProof 方法 + +372 +00:18:46,326 --> 00:18:48,862 +在 SWHighlightCenter 上检索证明 + +373 +00:18:48,862 --> 00:18:51,732 +这需要一个 +SWCollaborationHighlight + +374 +00:18:51,732 --> 00:18:57,404 +以及一些要由设备签名的任意数据 + +375 +00:18:57,404 --> 00:19:00,841 +使用签名确保请求无法被 + +376 +00:19:00,841 --> 00:19:05,913 +不良行为者重现以访问您的协作 + +377 +00:19:05,913 --> 00:19:09,149 +数据可能是您从服务器上请求的挑战 + +378 +00:19:09,149 --> 00:19:13,187 +或设备上生成的随机数值 + +379 +00:19:13,187 --> 00:19:16,557 +此示例使用挑战方法讲解 + +380 +00:19:16,557 --> 00:19:19,459 +URL 传递给您 App 上的 + +381 +00:19:19,459 --> 00:19:22,196 +UIApplicationDelegate 方法 + +382 +00:19:22,196 --> 00:19:24,064 +该 URL 是与协作有关的 + +383 +00:19:24,064 --> 00:19:28,235 +通用链接 + +384 +00:19:28,235 --> 00:19:31,004 +该 URL 用于从 + +385 +00:19:31,004 --> 00:19:36,910 +SWHighlightCenter +获取相关 SWCollaborationHighlight + +386 +00:19:36,910 --> 00:19:39,913 +接下来 我将向我的服务器请求挑战 + +387 +00:19:39,913 --> 00:19:41,915 +并将我得到的数据 + +388 +00:19:41,915 --> 00:19:46,720 +和高亮部分一起传递给 +SWHighlightCenter 上的 + +389 +00:19:46,720 --> 00:19:50,190 +getSignedIdentityProof 方法 + +390 +00:19:50,190 --> 00:19:53,627 +此方法会返回签名后的身份证明 + +391 +00:19:53,627 --> 00:19:55,429 +稍后我将与您讨论服务器 + +392 +00:19:55,429 --> 00:19:58,532 +验证该数据的操作 + +393 +00:19:58,532 --> 00:20:03,036 +现在我可以将签名后的证明 +发送到我的服务器进行验证 + +394 +00:20:03,036 --> 00:20:09,176 +最后 我用该结果更新用户界面 + +395 +00:20:09,176 --> 00:20:11,545 +App 将证明连同公钥和 + +396 +00:20:11,545 --> 00:20:16,717 +签名数据发送到服务器 + +397 +00:20:16,717 --> 00:20:18,519 +该数据使用 +P-256 椭圆曲线上的 + +398 +00:20:18,519 --> 00:20:23,056 +椭圆曲线数字签名算法进行签名 + +399 +00:20:23,056 --> 00:20:27,294 +用 SHA256 作为哈希函数 + +400 +00:20:27,294 --> 00:20:29,496 +用身份证明中的公钥 + +401 +00:20:29,496 --> 00:20:32,933 +验证数据上的签名 + +402 +00:20:32,933 --> 00:20:35,035 +您可用最常用的加密库 + +403 +00:20:35,035 --> 00:20:38,572 +做到这一点 + +404 +00:20:38,572 --> 00:20:40,574 +验证签名后 + +405 +00:20:40,574 --> 00:20:43,410 +您可信任该身份证明是由 + +406 +00:20:43,410 --> 00:20:46,980 +与该公钥相关的设备发送 + +407 +00:20:46,980 --> 00:20:52,252 +接下来 您可使用 +身份证明重新计算根哈希值 + +408 +00:20:52,252 --> 00:20:55,322 +用我们之前看过的梅克尔树为例 + +409 +00:20:55,322 --> 00:20:59,826 +可了解 SWPersonIdentityProof +中包含的内容 + +410 +00:20:59,826 --> 00:21:04,031 +我们来用它来 +重建梅克尔树的根哈希值 + +411 +00:21:04,031 --> 00:21:06,934 +公钥是 P3 + +412 +00:21:06,934 --> 00:21:12,005 +包含哈希值 H4 7 和 11 + +413 +00:21:12,005 --> 00:21:15,008 +本地密钥索引为 2 表示 + +414 +00:21:15,008 --> 00:21:19,112 +树中公钥的位置 + +415 +00:21:19,112 --> 00:21:21,582 +以下示例展示了从证明上的属性 + +416 +00:21:21,582 --> 00:21:26,286 +重构一个根哈希值的方式 + +417 +00:21:26,286 --> 00:21:28,322 +递归算法在处理树数据结构时 + +418 +00:21:28,322 --> 00:21:32,759 +效果很好 因此我在这里使用此算法 + +419 +00:21:32,759 --> 00:21:37,831 +初次调用时 传入公钥的哈希值 + +420 +00:21:37,831 --> 00:21:44,538 +包含哈希集和和公钥索引 + +421 +00:21:44,538 --> 00:21:49,009 +接下来 第一个包含哈希被导出 + +422 +00:21:49,009 --> 00:21:51,712 +检查公钥索引以查看密钥是否 + +423 +00:21:51,712 --> 00:21:56,483 +位于其他密钥的左侧或右侧 + +424 +00:21:56,483 --> 00:21:58,785 +选定的哈希值按正确的顺序 + +425 +00:21:58,785 --> 00:22:03,090 +连接起来 然后进行散列 + +426 +00:22:03,090 --> 00:22:06,527 +接下来 inclusionHashes +数组中的消费节点 + +427 +00:22:06,527 --> 00:22:09,029 +被移除 其余的被传递给 + +428 +00:22:09,029 --> 00:22:14,134 +同一函数的递归调用 + +429 +00:22:14,134 --> 00:22:16,236 +公钥索引也一起更新 + +430 +00:22:16,236 --> 00:22:20,807 +以便为树中的下一个节点做好准备 + +431 +00:22:20,807 --> 00:22:23,410 +通过这个简单的函数 +您可以快速计算 + +432 +00:22:23,410 --> 00:22:28,549 +给定身份证明的根哈希值 + +433 +00:22:28,549 --> 00:22:31,185 +服务器现在可以 +检查这个生成的根哈希值 + +434 +00:22:31,185 --> 00:22:33,987 +是否位于发送时上传的文档所有者的 + +435 +00:22:33,987 --> 00:22:36,390 +根哈希列表中 + +436 +00:22:36,390 --> 00:22:38,926 +哈希值存在于已知哈希列表中 + +437 +00:22:38,926 --> 00:22:42,563 +因此服务器 +可以授予对文档的访问权限 + +438 +00:22:42,563 --> 00:22:46,266 +现在您可放心授予 +对文档的访问权限! + +439 +00:22:46,266 --> 00:22:49,736 +回顾一下您验证身份所需的步骤 + +440 +00:22:49,736 --> 00:22:51,972 +首先 在处理其通用链接时 + +441 +00:22:51,972 --> 00:22:55,442 +为您的内容查找协作高亮部分 + +442 +00:22:55,442 --> 00:22:59,746 +其次 签署某些数据 +并检索 proof of inclusion + +443 +00:22:59,746 --> 00:23:04,017 +将签名后的数据和 +证明发送到您的服务器 + +444 +00:23:04,017 --> 00:23:07,588 +验证数据上的签名 + +445 +00:23:07,588 --> 00:23:11,525 +使用 proof of inclusion +生成根哈希值 + +446 +00:23:11,525 --> 00:23:14,862 +最后 将根哈希值和与该内容相关的 + +447 +00:23:14,862 --> 00:23:19,833 +已知身份列表进行比较 + +448 +00:23:19,833 --> 00:23:22,135 +现在您已经了解了 +有关验证您的协作链接 + +449 +00:23:22,135 --> 00:23:24,505 +访问权限的所有信息 +我再来介绍一下 + +450 +00:23:24,505 --> 00:23:28,308 +如何使用 Messages +协调参与者更改 + +451 +00:23:28,308 --> 00:23:31,144 +当 Messages 组中的 +参与者发生变化 + +452 +00:23:31,144 --> 00:23:33,747 +且该组处于协作状态时 + +453 +00:23:33,747 --> 00:23:37,284 +用户可以选择将更改传至您的 App + +454 +00:23:37,284 --> 00:23:40,354 +就传在消息线程中的横幅上 + +455 +00:23:40,354 --> 00:23:42,856 +在此情况下 +您的 App 会收到另一个 + +456 +00:23:42,856 --> 00:23:46,193 +SWUpdateCollaborationParticipantsAction + +457 +00:23:46,193 --> 00:23:50,564 +其中包含添加和移除了的身份 + +458 +00:23:50,564 --> 00:23:53,567 +您将使用在设置 +协作时编写的相同代码 + +459 +00:23:53,567 --> 00:23:55,435 +来处理此操作 + +460 +00:23:55,435 --> 00:24:00,040 +但您还需要处理被移除的参与者 + +461 +00:24:00,040 --> 00:24:02,743 +关于移除操作 +只需查找与被移除身份 + +462 +00:24:02,743 --> 00:24:06,947 +相关的任何账户 撤销其访问权限 + +463 +00:24:06,947 --> 00:24:09,249 +如果还没有关联帐户 + +464 +00:24:09,249 --> 00:24:12,886 +只需从数据库中删除根哈希值 + +465 +00:24:12,886 --> 00:24:14,188 +这就是实现 + +466 +00:24:14,188 --> 00:24:19,226 +Devin 之前 +提到的更新参与者的操作 + +467 +00:24:19,226 --> 00:24:20,394 +这个例子使用 + +468 +00:24:20,394 --> 00:24:24,965 +操作上的移除身份属性 + +469 +00:24:24,965 --> 00:24:28,836 +并将其传递给 +类似的删除 API 请求 + +470 +00:24:28,836 --> 00:24:33,073 +请注意 此代码仅处理已移除的身份 + +471 +00:24:33,073 --> 00:24:34,908 +但一个完整的操作应该可以处理 + +472 +00:24:34,908 --> 00:24:38,579 +已添加和已移除的身份 + +473 +00:24:38,579 --> 00:24:42,482 +以上就是您处理 +参与者更改时所需的全部操作! + +474 +00:24:42,482 --> 00:24:45,819 +最后 当对协作进行更改时 + +475 +00:24:45,819 --> 00:24:48,322 +您的 App 会 +发布有关这些更改的通知 + +476 +00:24:48,322 --> 00:24:50,924 +直接显示在 Messages 中 + +477 +00:24:50,924 --> 00:24:53,126 +接下来这部分我会为大家介绍 + +478 +00:24:53,126 --> 00:24:55,295 +几种通知支持的类型 + +479 +00:24:55,295 --> 00:24:57,130 +通知在共享链接的 + +480 +00:24:57,130 --> 00:25:01,134 +对话中显示为横幅 + +481 +00:25:01,134 --> 00:25:03,937 +横幅包括对更改内容的描述 + +482 +00:25:03,937 --> 00:25:07,574 +以及变更人信息 + +483 +00:25:07,574 --> 00:25:09,810 +在这个对话中 +Charlie 对“烘焙食谱”文档 + +484 +00:25:09,810 --> 00:25:12,779 +进行了编辑 + +485 +00:25:12,779 --> 00:25:14,581 +点击显示按钮可直接将其 + +486 +00:25:14,581 --> 00:25:17,518 +与内容联系起来 + +487 +00:25:17,518 --> 00:25:19,887 +为了表示通知 +SharedWithYou 框架 + +488 +00:25:19,887 --> 00:25:24,424 +有一个名为 +SWHighlightEvent 的协议 + +489 +00:25:24,424 --> 00:25:27,227 +使用从 SWHighlightCenter API 检索的 + +490 +00:25:27,227 --> 00:25:31,732 +SWHighlights 初始化高亮事件 + +491 +00:25:31,732 --> 00:25:36,203 +Messages 可支持以下几类事件 + +492 +00:25:36,203 --> 00:25:40,240 +内容更新或评论的更改事件 + +493 +00:25:40,240 --> 00:25:44,244 +参与者加入或离开时的成员关系事件 + +494 +00:25:44,244 --> 00:25:49,449 +在协作中提及用户时的提及事件 + +495 +00:25:49,449 --> 00:25:54,021 +以及内容被移动 +或删除时的持久性事件 + +496 +00:25:54,021 --> 00:25:56,657 +以下示例展示如何对协作编辑 + +497 +00:25:56,657 --> 00:25:59,760 +发布更改事件 + +498 +00:25:59,760 --> 00:26:02,162 +使用高亮中心 API + +499 +00:26:02,162 --> 00:26:03,931 +为目标标识符 + +500 +00:26:03,931 --> 00:26:06,099 +检索协作高亮部分 + +501 +00:26:06,099 --> 00:26:09,770 +请记住 此标识符是您在 + +502 +00:26:09,770 --> 00:26:13,173 +协作启动期间定义的 +因此您的 App 应该有此标识符 + +503 +00:26:13,173 --> 00:26:17,110 +以便在进行内容更改时使用 + +504 +00:26:17,110 --> 00:26:21,748 +接下来 创建一个高亮更改事件实例 + +505 +00:26:21,748 --> 00:26:23,750 +初始化器有高亮 + +506 +00:26:23,750 --> 00:26:25,953 +和一个触发器枚举值 + +507 +00:26:25,953 --> 00:26:30,123 +在本例中 将其设置为编辑类型 + +508 +00:26:30,123 --> 00:26:32,860 +最后 再次使用高亮中心 + +509 +00:26:32,860 --> 00:26:36,196 +发布该事件的通知 + +510 +00:26:36,196 --> 00:26:39,299 +类似地 对于会员资格变更 + +511 +00:26:39,299 --> 00:26:41,101 +会发布会员资格事件 + +512 +00:26:41,101 --> 00:26:44,204 +这次是传递 addedCollaborator + +513 +00:26:44,204 --> 00:26:49,176 +或 removedCollaborator +触发器类型 + +514 +00:26:49,176 --> 00:26:52,346 +接下来 +如果您的 App 支持用户提及 + +515 +00:26:52,346 --> 00:26:55,182 +您可以发布提及事件 + +516 +00:26:55,182 --> 00:26:56,817 +利用被提及用户的 + +517 +00:26:56,817 --> 00:27:00,087 +根哈希值初始化个人身份 + +518 +00:27:00,087 --> 00:27:02,623 +请您回顾一下 您在验证访问权限时 + +519 +00:27:02,623 --> 00:27:07,761 +用您 App 中的用户帐户 +关联了一个人的身份 + +520 +00:27:07,761 --> 00:27:11,431 +然后 以同样的方式发布提及事件 + +521 +00:27:11,431 --> 00:27:15,636 +这次是将被提及身份作为参数传递 + +522 +00:27:15,636 --> 00:27:17,804 +此通知在 Messages 中 + +523 +00:27:17,804 --> 00:27:21,842 +仅显示给被提及用户 + +524 +00:27:21,842 --> 00:27:24,545 +最后 当内容被移动 重命名 + +525 +00:27:24,545 --> 00:27:29,750 +或删除时 使用持久性事件类型 + +526 +00:27:29,750 --> 00:27:32,119 +在此 以重命名触发器类型为例 + +527 +00:27:32,119 --> 00:27:37,791 +表示用户更改了内容的名称 + +528 +00:27:37,791 --> 00:27:41,161 +这就是您的 App +能通知协作者的方式 + +529 +00:27:41,161 --> 00:27:46,233 +以上都将在 Messages 中得到更新 + +530 +00:27:46,233 --> 00:27:48,101 +Devin:这样一来 您就可以 + +531 +00:27:48,101 --> 00:27:50,671 +通过以下几个步骤将您 App 的 + +532 +00:27:50,671 --> 00:27:52,773 +协作体验与消息结合起来 + +533 +00:27:52,773 --> 00:27:55,676 +即设置要协作共享的内容 + +534 +00:27:55,676 --> 00:27:58,645 +以加密方式验证参与者的访问权限 + +535 +00:27:58,645 --> 00:28:00,781 +追踪参与者变化 + +536 +00:28:00,781 --> 00:28:03,784 +并在 Messages 中 +发布通知将您的用户 + +537 +00:28:03,784 --> 00:28:06,553 +与内容联系起来 + +538 +00:28:06,553 --> 00:28:07,955 +请务必观看 + +539 +00:28:07,955 --> 00:28:11,258 +“使用 Messages 增强协作体验”的视频 + +540 +00:28:11,258 --> 00:28:13,193 +了解您可为协作显示的 + +541 +00:28:13,193 --> 00:28:15,996 +新 UI 元素 + +542 +00:28:15,996 --> 00:28:18,298 +Lance:我们迫不及待地 +想与您的 App 开始协作了! + +543 +00:28:18,298 --> 00:28:20,968 +Devin 和 Lance +您的加密签名协作伙伴 + +544 +00:28:20,968 --> 00:28:22,336 +Devin:感谢收看! + +545 +00:28:22,336 --> 00:28:25,939 +♪ + diff --git a/zho/2022 Session 10094 Add Shared with You to your app.srt b/zho/2022 Session 10094 Add Shared with You to your app.srt new file mode 100644 index 0000000..0b2e2df --- /dev/null +++ b/zho/2022 Session 10094 Add Shared with You to your app.srt @@ -0,0 +1,1146 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:10,010 --> 00:00:11,912 +Karthik: 大家好 我是 Karthik + +3 +00:00:11,945 --> 00:00:14,581 +是信息团队的一名工程师 + +4 +00:00:14,615 --> 00:00:18,318 +在本视频中 +我将向大家介绍“与您共享” + +5 +00:00:18,352 --> 00:00:20,921 +以及如何在您的 App 中使用它 + +6 +00:00:22,523 --> 00:00:25,959 +“与您共享” +是在 iOS 15 中发布的 + +7 +00:00:25,993 --> 00:00:29,830 +其设计目的是让用户更容易重新访问 + +8 +00:00:29,863 --> 00:00:33,667 +朋友和家人在“信息”中 +发送的链接 + +9 +00:00:33,700 --> 00:00:37,604 +可使用“与您共享”的 +系统 App 包括 + +10 +00:00:37,638 --> 00:00:40,240 +Safari 浏览器、新闻、 + +11 +00:00:40,274 --> 00:00:42,910 +音乐、播客、 + +12 +00:00:42,943 --> 00:00:46,213 +Apple TV 以及照片 App + +13 +00:00:46,246 --> 00:00:51,351 +“与您共享”也可以用于浏览内容 + +14 +00:00:51,385 --> 00:00:56,390 +很多时候 在我们准备好浏览之前 +就已经收到了内容 + +15 +00:00:56,423 --> 00:01:01,028 +例如 当您外出购物时 + +16 +00:01:01,061 --> 00:01:03,630 +一个朋友向您推荐了一个电视节目 + +17 +00:01:03,664 --> 00:01:07,901 +然后您忙了一天就忘记了 + +18 +00:01:07,935 --> 00:01:12,840 +但当您在 TV App 中浏览 +要观看的电视节目时 + +19 +00:01:12,873 --> 00:01:17,477 +“与您共享”就可以帮您 +更容易地找到这个节目 + +20 +00:01:17,511 --> 00:01:22,816 +“与您共享” +可以方便地从 App 中 + +21 +00:01:22,850 --> 00:01:25,252 +获取信息对话 + +22 +00:01:25,285 --> 00:01:29,456 +让您无需离开 App + +23 +00:01:29,489 --> 00:01:31,792 +就能了解共享的内容 + +24 +00:01:33,594 --> 00:01:36,964 +您的内容可以 +在“信息”中被置顶 + +25 +00:01:36,997 --> 00:01:42,436 +这样内容就会在 +“与您共享”和搜索中提前 + +26 +00:01:42,469 --> 00:01:45,405 +这是一个表示内容很重要的信号 + +27 +00:01:45,439 --> 00:01:48,809 +并会启动自动共享同意流程 + +28 +00:01:48,842 --> 00:01:51,211 +稍后我们将详细介绍这一点 + +29 +00:01:51,245 --> 00:01:57,618 +在 iOS 16 中“与您共享”还能包含 +您的 App 链接和内容 + +30 +00:01:57,651 --> 00:02:01,822 +这样一来“与您共享” +就让您的 App 更方便高效 + +31 +00:02:03,023 --> 00:02:06,927 +我先介绍一下您的 App 中 +“与您共享”的设计 + +32 +00:02:06,960 --> 00:02:09,997 +然后再演示它的工作原理 + +33 +00:02:10,030 --> 00:02:13,066 +接着 我会带您了解 +如何使用“与您共享” + +34 +00:02:14,401 --> 00:02:16,203 +我们先从设计开始 + +35 +00:02:16,236 --> 00:02:21,208 +您将会体验到 +“与您共享”的两个部分 + +36 +00:02:21,241 --> 00:02:26,013 +“与您共享”工具架 +和“与您共享”属性视图 + +37 +00:02:26,046 --> 00:02:29,516 +“与您共享”工具架是 +App 浏览体验中的 + +38 +00:02:29,550 --> 00:02:32,386 +一个专用空间 + +39 +00:02:32,419 --> 00:02:37,090 +用于突出显示消息中共享的内容 + +40 +00:02:37,124 --> 00:02:44,198 +例如 TV App 的“立即观看”标签页 +有一个“与您共享”工具架 + +41 +00:02:44,231 --> 00:02:48,502 +音乐和播客中的 +“现在就听”标签也是如此 + +42 +00:02:49,937 --> 00:02:55,475 +“与您共享”提供的内容 +是经过排名和排序的列表 + +43 +00:02:55,509 --> 00:02:58,879 +稍后我会在视频中介绍这一点 + +44 +00:02:58,912 --> 00:03:01,949 +“与您共享”工具架中的每个项目 + +45 +00:03:01,982 --> 00:03:07,087 +都具有丰富的预览和属性视图 + +46 +00:03:07,120 --> 00:03:11,391 +预览包含缩略图、标题、 + +47 +00:03:11,425 --> 00:03:14,361 +和副标题 (如有) + +48 +00:03:14,394 --> 00:03:19,166 +在本例中 +丰富的预览效果包括了播客图片、 + +49 +00:03:19,199 --> 00:03:22,669 +剧集名称和节目名称 + +50 +00:03:22,703 --> 00:03:27,341 +“与您共享”工具架中的 +每个共享内容 + +51 +00:03:27,374 --> 00:03:29,610 +还有一个属性视图 + +52 +00:03:29,643 --> 00:03:33,479 +它会提供足量信息 +让内容的对应情景 + +53 +00:03:33,513 --> 00:03:34,681 +一目了然 + +54 +00:03:36,083 --> 00:03:39,486 +有一个 Show More 元素 +可以扩展视图或导航 + +55 +00:03:39,520 --> 00:03:44,024 +来显示您 App 中的 +所有“与您共享”内容 + +56 +00:03:44,057 --> 00:03:47,794 +属性视图是一个进程外视图 + +57 +00:03:47,828 --> 00:03:54,434 +它将安全地显示分享者的姓名和头像 + +58 +00:03:54,468 --> 00:03:59,907 +它还会显示内容是否 +在“信息”中被置顶 + +59 +00:03:59,940 --> 00:04:05,012 +在内容的详细信息视图中 +显示属性视图 + +60 +00:04:05,045 --> 00:04:09,216 +这将允许用户将您 App 中的内容 + +61 +00:04:09,249 --> 00:04:12,886 +连接回其共享的“信息”对话中 + +62 +00:04:12,920 --> 00:04:17,124 +例如 当我浏览电视节目时 + +63 +00:04:17,157 --> 00:04:23,497 +属性视图可以帮助我回忆起 +某位朋友推荐的节目 + +64 +00:04:23,530 --> 00:04:28,202 +因此我可以方便地告诉这位朋友 +我就要看这个节目了 + +65 +00:04:28,235 --> 00:04:31,872 +所有这些操作都能 +在 App 中完成 + +66 +00:04:31,905 --> 00:04:36,376 +回复后 我马上就能观看节目 + +67 +00:04:36,410 --> 00:04:39,179 +属性视图是交互式的 + +68 +00:04:39,213 --> 00:04:42,482 +点击视图可以直接从 App 内部 + +69 +00:04:42,516 --> 00:04:45,185 +接入“信息”对话 + +70 +00:04:45,219 --> 00:04:50,123 +属性视图还提供上下文菜单选项 + +71 +00:04:50,157 --> 00:04:53,994 +如回复和移除 + +72 +00:04:54,027 --> 00:05:00,968 +回复内容菜单选项的功能 +类似于点击视图 + +73 +00:05:01,001 --> 00:05:04,638 +而“移除”上下文菜单选项 +则能让“与您共享” + +74 +00:05:04,671 --> 00:05:08,509 +停止继续显示内容 + +75 +00:05:08,542 --> 00:05:12,346 +您可以将相同的上下文菜单 + +76 +00:05:12,379 --> 00:05:16,717 +添加到内容的上下文菜单中 + +77 +00:05:16,750 --> 00:05:21,488 +您也可以自定义 +“移除”上下文菜单的标题 + +78 +00:05:21,522 --> 00:05:24,358 +例如 在 Safari 浏览器中 + +79 +00:05:24,391 --> 00:05:29,396 +网页的上下文菜单会显示"Remove Link" + +80 +00:05:29,429 --> 00:05:35,269 +我将在稍后的视频中介绍 +如何在您的 App 中执行此操作 + +81 +00:05:35,302 --> 00:05:38,872 +现在 您已经了解在哪里展示 +“与您共享”工具架 + +82 +00:05:38,906 --> 00:05:42,242 +以及在哪里显示属性视图 + +83 +00:05:42,276 --> 00:05:45,045 +现在我将向您演示 +“与您共享”的工作原理 + +84 +00:05:45,078 --> 00:05:52,386 +朋友和家人在“信息”中共享的链接 +会显示在“与您共享”中 + +85 +00:05:52,419 --> 00:05:55,589 +当至少有一个参与者是联系人时 + +86 +00:05:55,622 --> 00:05:59,826 +群组聊天的链接就会出现 + +87 +00:05:59,860 --> 00:06:05,332 +“与您共享”是基于 +通用链接背后的相同技术 + +88 +00:06:05,365 --> 00:06:11,505 +通用链接 +可以无缝链接到您的 App + +89 +00:06:11,538 --> 00:06:14,208 +或网站上的内容 + +90 +00:06:14,241 --> 00:06:19,346 +用户可以精确控制 +“与您共享”的内容 + +91 +00:06:20,414 --> 00:06:25,118 +他们可以选择在每个会话 + +92 +00:06:25,152 --> 00:06:27,988 +每个 App 或全球范围内 + +93 +00:06:28,021 --> 00:06:31,124 +共享“信息”之外的内容 + +94 +00:06:31,158 --> 00:06:36,396 +无需提前请求此权限 + +95 +00:06:36,430 --> 00:06:39,399 +这是自然发生的 + +96 +00:06:39,433 --> 00:06:46,340 +置顶链接是在“与您共享”中 +显示内容的隐含权限 + +97 +00:06:46,373 --> 00:06:52,012 +置顶内容可始终显示在 +App 中的“与您共享”中 + +98 +00:06:52,045 --> 00:06:57,951 +当 App 内容在“信息”中置顶时 +基于启发式方法 + +99 +00:06:57,985 --> 00:07:03,123 +会出现一个启用自动共享的选项 + +100 +00:07:03,156 --> 00:07:06,527 +启动自动共享后 + +101 +00:07:06,560 --> 00:07:12,299 +App 中的“与您共享” +将显示更多内容 + +102 +00:07:13,834 --> 00:07:17,304 +“与您共享”中的内容已调用 + +103 +00:07:17,337 --> 00:07:22,910 +“与您共享”工具架上的 +第一个项目是由 Siri 建议 + +104 +00:07:22,943 --> 00:07:26,914 +根据系统的各种信号整理的 + +105 +00:07:26,947 --> 00:07:30,751 +接下来是置顶项目 + +106 +00:07:30,784 --> 00:07:34,788 +列表的其余部分按时间顺序排列 + +107 +00:07:36,790 --> 00:07:40,661 +Siri 建议使用的信号包括 +用户是否看过内容 + +108 +00:07:40,694 --> 00:07:43,130 +或与内容进行了互动 + +109 +00:07:43,163 --> 00:07:45,032 +内容是否被置顶 + +110 +00:07:45,065 --> 00:07:48,902 +内容在何种情境中呈现 + +111 +00:07:48,936 --> 00:07:52,539 +您的 App 在提供此反馈方面 +发挥了一定作用 + +112 +00:07:52,573 --> 00:07:56,443 +稍后我将在视频中详细介绍 + +113 +00:07:56,476 --> 00:08:02,649 +所有这些都是为了确保内容 +不会过于短暂或过时 + +114 +00:08:02,683 --> 00:08:07,521 +在多次共享链接的会话中 + +115 +00:08:07,554 --> 00:08:12,726 +“与您共享”只显示最新的消息 + +116 +00:08:12,759 --> 00:08:17,331 +当链接在多条“信息”对话中共享时 + +117 +00:08:17,364 --> 00:08:23,470 +“与您共享”会通过属性视图 +直观地表示这一点 + +118 +00:08:23,504 --> 00:08:27,908 +例如 Enrique 和 Sarah 都分享了 + +119 +00:08:27,941 --> 00:08:31,178 +芝加哥前 25 名的播放列表 + +120 +00:08:31,211 --> 00:08:36,984 +属性视图显示了他们的联系人头像 + +121 +00:08:37,017 --> 00:08:41,889 +点击属性视图会出现一个消歧菜单 + +122 +00:08:41,922 --> 00:08:47,861 +允许您选择回复哪条“信息”对话 + +123 +00:08:47,895 --> 00:08:51,064 +在设计“与您共享”时 +安全性和隐私 + +124 +00:08:51,098 --> 00:08:53,967 +是首要考虑和重点 + +125 +00:08:54,001 --> 00:08:58,105 +属性视图和消歧视图 + +126 +00:08:58,138 --> 00:09:02,309 +是在流程之外代表您绘制的 + +127 +00:09:02,342 --> 00:09:05,279 +“与您共享” +会通过通用链接关联 + +128 +00:09:05,312 --> 00:09:08,215 +来保护您的 App 内容 + +129 +00:09:08,248 --> 00:09:12,219 +因此只有您的 App 有访问权 + +130 +00:09:12,252 --> 00:09:17,958 +App 无权访问“信息”收件人和对话 + +131 +00:09:19,426 --> 00:09:22,196 +现在您了解了 +“与您共享”的工作原理 + +132 +00:09:22,229 --> 00:09:24,131 +下面将是最激动人心的部分 + +133 +00:09:24,164 --> 00:09:27,568 +如何在您的 App 中使用 +“与您共享” + +134 +00:09:27,601 --> 00:09:31,104 +首先 采用通用链接 + +135 +00:09:31,138 --> 00:09:34,441 +然后 在 Xcode 的 +Capabilities (功能) 标签下 + +136 +00:09:34,474 --> 00:09:37,411 +添加新的“与您共享”功能 + +137 +00:09:37,444 --> 00:09:41,682 +接着 在您的 App 中放置一个 +“与您共享”工具架 + +138 +00:09:41,715 --> 00:09:46,420 +并将属性视图添加到您的内容中 + +139 +00:09:46,453 --> 00:09:50,224 +我简单地谈谈 +通用链接的使用 + +140 +00:09:51,491 --> 00:09:56,730 +通用链接允许用户智能地跟踪 + +141 +00:09:56,763 --> 00:09:59,633 +App 中的内容或网站的链接 + +142 +00:09:59,666 --> 00:10:03,537 +采取以下步骤来支持通用链接 + +143 +00:10:03,570 --> 00:10:06,974 +首先在 App 和网站之间 + +144 +00:10:07,007 --> 00:10:10,477 +创建双向关联 + +145 +00:10:10,511 --> 00:10:14,715 +并指定 App 处理的 URL + +146 +00:10:14,748 --> 00:10:20,854 +您可以通过向 App 添加关联的域权限 + +147 +00:10:20,888 --> 00:10:26,126 +并向 Web 服务器 +添加 JSON 文件来创建它们 + +148 +00:10:26,159 --> 00:10:28,929 +接下来 更新 App 委托 + +149 +00:10:28,962 --> 00:10:32,966 +以响应系统在通用链接路由到 App 时 + +150 +00:10:33,000 --> 00:10:36,670 +提供的用户活动对象 + +151 +00:10:36,703 --> 00:10:42,409 +有关更多信息 请观看视频 +“通用链接的新功能” + +152 +00:10:42,442 --> 00:10:47,614 +在 iOS 16 中 我们引入了 +一个新的 Shared with You 框架 + +153 +00:10:47,648 --> 00:10:51,752 +Shared with You 框架中 +有三个主要的类: + +154 +00:10:51,785 --> 00:10:54,121 +SWHighlightCenter + +155 +00:10:54,154 --> 00:10:59,026 +SWHighlight 和 SWAttributionView + +156 +00:10:59,059 --> 00:11:03,497 +SWHighlightCenter 是一个类 +能帮助您获取 App 中的 + +157 +00:11:03,530 --> 00:11:04,831 +“与您共享”内容 + +158 +00:11:04,865 --> 00:11:10,204 +SWHighlight 是一个模型对象 +用于包装 App 的共享内容 + +159 +00:11:10,237 --> 00:11:15,042 +SWAttributionView +则是一个视图 + +160 +00:11:15,075 --> 00:11:17,778 +可帮助将内容连接回 +“消息”的会话 + +161 +00:11:17,811 --> 00:11:20,547 +并显示属性信息 + +162 +00:11:21,949 --> 00:11:25,953 +Hihghlight center 是一个简单的对象 +它由以下部分组成 + +163 +00:11:25,986 --> 00:11:31,358 +Highlights 是 +SWHighlight 对象的数组 + +164 +00:11:31,391 --> 00:11:35,462 +还是一个委托属性 +当“与您共享” + +165 +00:11:35,495 --> 00:11:41,768 +添加、删除或更新内容时 +App 会得到通知 + +166 +00:11:41,802 --> 00:11:46,373 +Highlight +是通过 SWHighlight 类来显示的 + +167 +00:11:46,406 --> 00:11:52,513 +它用于传递在“信息”中共享的 +App 内容的 URL + +168 +00:11:52,546 --> 00:11:57,317 +您可以使用它来引用您的内容 +呈现丰富的预览 + +169 +00:11:57,351 --> 00:12:01,021 +以及导航到您的 App 中的内容 + +170 +00:12:01,054 --> 00:12:05,726 +我将向您演示如何在 App 中 +列举“与您共享”的内容 + +171 +00:12:06,994 --> 00:12:12,299 +首先 创建一个 +SWHighlightCenter 的实例 + +172 +00:12:12,332 --> 00:12:16,670 +然后设置委托属性 + +173 +00:12:16,703 --> 00:12:22,109 +执行 +SWHighlightCenterDelegate 方法 + +174 +00:12:22,142 --> 00:12:24,811 +使用 hightlight center 的 +highlight 属性 + +175 +00:12:24,845 --> 00:12:29,149 +来访问 +App 中的“与您共享”内容 + +176 +00:12:29,183 --> 00:12:32,786 +App 可以选择保留之前的 +highlight 列表 + +177 +00:12:32,819 --> 00:12:37,491 +以便快速地将该列表 +与最新列表区别开来 + +178 +00:12:39,193 --> 00:12:44,464 +使用每个 highlight 显示的 URL 属性 + +179 +00:12:44,498 --> 00:12:47,634 +来生成 App 内容的丰富预览 + +180 +00:12:47,668 --> 00:12:53,674 +在您的 App 中列举 +“与您共享”的内容就是这么简单 + +181 +00:12:53,707 --> 00:12:59,012 +接下来 我将向您展示 +如何为 App 中的“与您共享”内容 + +182 +00:12:59,046 --> 00:13:01,548 +添加和自定义属性视图 + +183 +00:13:01,582 --> 00:13:07,254 +SWAttributionView 视图 +用于显示内容共享者的 + +184 +00:13:07,287 --> 00:13:10,090 +姓名和头像 + +185 +00:13:10,123 --> 00:13:14,595 +每个 highlight 都有相应的属性视图 + +186 +00:13:14,628 --> 00:13:17,831 +在属性视图上设置 highlight 属性 + +187 +00:13:17,865 --> 00:13:22,102 +会触发属性信息的进程外呈现 + +188 +00:13:23,604 --> 00:13:28,275 +指定属性视图可以接受的最大宽度 + +189 +00:13:28,308 --> 00:13:34,281 +属性视图将根据需要填充或调整空间 + +190 +00:13:34,314 --> 00:13:39,853 +在最大空间内设置 +属性视图的对齐方式 + +191 +00:13:39,887 --> 00:13:41,321 +我们来看一个例子 + +192 +00:13:42,923 --> 00:13:46,693 +创建 SWAttributionView 实例 + +193 +00:13:46,727 --> 00:13:49,897 +并设置 highlight 属性 + +194 +00:13:49,930 --> 00:13:52,699 +设置 preferredMaxLayoutWidth + +195 +00:13:52,733 --> 00:13:57,905 +在本例中 +它跨越了共享内容缩略图的底部 + +196 +00:13:57,938 --> 00:14:00,507 +约束此视图的宽度锚点 + +197 +00:14:00,541 --> 00:14:05,879 +或设置其框架宽度 +以控制其内容的最大宽度 + +198 +00:14:05,913 --> 00:14:09,950 +根据需要使用 UIView 上的 +minimumContentSizeCategory + +199 +00:14:09,983 --> 00:14:13,153 +或 maximumContentSizeCategory 属性 + +200 +00:14:13,187 --> 00:14:18,392 +设置视图的最大 AX 内容大小类别 + +201 +00:14:18,425 --> 00:14:22,162 +在此视图周围提供足够的垂直空间 + +202 +00:14:22,196 --> 00:14:26,166 +视图的高度取决于 +preferredContentSizeCategory + +203 +00:14:26,200 --> 00:14:28,836 +和生成的字体大小 + +204 +00:14:28,869 --> 00:14:32,306 +如果视图高度受到不必要的约束 + +205 +00:14:32,339 --> 00:14:36,310 +那么视图可能会被剪裁或无法绘制 + +206 +00:14:36,343 --> 00:14:40,747 +在这种情况下 +horizontalAlignment 设置为 Leading + +207 +00:14:40,781 --> 00:14:44,084 +也可以设置为 Center + +208 +00:14:44,117 --> 00:14:46,887 +或 Trailing + +209 +00:14:46,920 --> 00:14:51,725 +接下来 我将向您展示如何 +自定义属性视图 + +210 +00:14:51,758 --> 00:14:54,561 +设置显示情景有助于 + +211 +00:14:54,595 --> 00:14:58,866 +通知系统用户如何使用属性化内容 + +212 +00:14:58,899 --> 00:15:03,303 +它还会影响 App 中 +“与您共享”的内容排名 + +213 +00:15:03,337 --> 00:15:06,106 +在将其添加到窗口之前进行设置 + +214 +00:15:06,139 --> 00:15:10,077 +属性视图的背景样式可以根据 + +215 +00:15:10,110 --> 00:15:14,615 +内容的背景进行自定义 + +216 +00:15:14,648 --> 00:15:17,284 +我们来看一个例子 + +217 +00:15:17,317 --> 00:15:22,990 +displayContext 属性的 +默认值是 summary + +218 +00:15:23,023 --> 00:15:28,762 +这表示正在显示内容以供使用 + +219 +00:15:28,795 --> 00:15:31,198 +当用户主动使用内容时 + +220 +00:15:31,231 --> 00:15:34,401 +如看电影或听播客时 + +221 +00:15:34,434 --> 00:15:39,173 +可将 displayContext 设置为 detail + +222 +00:15:39,206 --> 00:15:43,510 +设置 displayContext 是 +您的 App 可以提供的反馈 + +223 +00:15:43,544 --> 00:15:47,548 +这将帮助 Siri 建议为 +App 的内容进行排名 + +224 +00:15:47,581 --> 00:15:51,385 +将属性视图放置在单色背景上时 + +225 +00:15:51,418 --> 00:15:55,355 +应将属性视图的背景样式 +设置为“Color” + +226 +00:15:55,389 --> 00:15:57,558 +如本例所示 + +227 +00:15:57,591 --> 00:16:03,964 +在多色背景上放置属性视图时 +使用材质 + +228 +00:16:03,997 --> 00:16:08,669 +这将为视图内容设置材质背景模糊 + +229 +00:16:08,702 --> 00:16:14,041 +在本例中 Safari 浏览器的登录页面 +有一个背景图像 + +230 +00:16:14,074 --> 00:16:17,611 +通过设置正确的背景样式 + +231 +00:16:17,644 --> 00:16:21,582 +属性视图的内容更加清晰可见 + +232 +00:16:21,615 --> 00:16:26,086 +接下来 我将向您展示如何将 +“与您共享”的上下文菜单 + +233 +00:16:26,119 --> 00:16:30,324 +添加到 App 内容中 并自定义标题 + +234 +00:16:30,357 --> 00:16:34,127 +App 内容附带的现有上下文菜单 + +235 +00:16:34,161 --> 00:16:39,032 +可通过属性视图的菜单进行补充 + +236 +00:16:39,066 --> 00:16:42,669 +此菜单应与它所扩展的上下文菜单 + +237 +00:16:42,703 --> 00:16:48,175 +内联或在其末尾添加 + +238 +00:16:48,208 --> 00:16:53,814 +可以为“移除”上下文菜单选项 +提供自定义标题 + +239 +00:16:53,847 --> 00:16:59,052 +字符串应包含单词 Remove (移除) +并正确本地化 + +240 +00:16:59,086 --> 00:17:04,391 +在本例中 Safari 浏览器 +在其内容的上下文菜单的末尾 + +241 +00:17:04,424 --> 00:17:08,762 +将此菜单标题自定义为 +Remove Link (移除) + +242 +00:17:08,795 --> 00:17:12,533 +我将向您展示 +如何做到这一点 + +243 +00:17:12,566 --> 00:17:16,036 +首先 创建属性视图的实例 + +244 +00:17:16,069 --> 00:17:18,505 +并设置 highlight 属性 + +245 +00:17:18,539 --> 00:17:21,975 +通过 menuTitleForHideAction + +246 +00:17:22,009 --> 00:17:24,945 +为“移除”上下文菜单 +提供自定义标题 + +247 +00:17:24,978 --> 00:17:28,081 +配置内容的上下文菜单时 + +248 +00:17:28,115 --> 00:17:34,188 +请通过 supplementalMenu 属性 +从属性视图获取菜单 + +249 +00:17:34,221 --> 00:17:38,692 +然后 将它们附加到 +内容的上下文菜单中 + +250 +00:17:38,725 --> 00:17:43,363 +这些简单的步骤 可以让您的 App + +251 +00:17:43,397 --> 00:17:49,336 +将属性视图上的上下文菜单选项 +添加到内容的上下文菜单中 + +252 +00:17:49,369 --> 00:17:54,508 +现在 您了解了在 App 中 +使用“与您共享”的一切内容 + +253 +00:17:54,541 --> 00:17:59,680 +我们回顾一下在 App 中使用 +“与您共享”的三个简单步骤 + +254 +00:17:59,713 --> 00:18:01,849 +使用通用链接 + +255 +00:18:01,882 --> 00:18:07,354 +然后在 Xcode 中添加 +新的“与您共享”功能 + +256 +00:18:07,387 --> 00:18:11,625 +导入并使用新的 +Shared with You 框架 + +257 +00:18:11,658 --> 00:18:15,462 +希望您能在“信息”中共享内容 + +258 +00:18:15,495 --> 00:18:18,498 +并在您的 App 中 +使用“与您共享” + +259 +00:18:18,532 --> 00:18:21,869 +感谢您的时间和关注 + diff --git "a/zho/2022 Session 10096 What\342\200\231s new in privacy.srt" "b/zho/2022 Session 10096 What\342\200\231s new in privacy.srt" new file mode 100644 index 0000000..98be24c --- /dev/null +++ "b/zho/2022 Session 10096 What\342\200\231s new in privacy.srt" @@ -0,0 +1,1372 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,676 --> 00:00:12,546 +Justin Sagurton: 大家好 我是 +Privacy Engineering 部门的 Justin + +3 +00:00:12,579 --> 00:00:15,415 +欢迎收看 “What's new in Privacy” + +4 +00:00:15,449 --> 00:00:19,686 +在 Apple +我们相信隐私是一项基本人权 + +5 +00:00:19,720 --> 00:00:24,758 +保护人们的隐私是 +我们所做一切的核心 + +6 +00:00:24,791 --> 00:00:29,029 +您希望人们喜欢您的 App +并且成为他们生活的一部分 + +7 +00:00:29,062 --> 00:00:32,699 +创建一个优秀的功能 +是您获得用户关注的方式 + +8 +00:00:32,733 --> 00:00:36,436 +而建立隐私是您保持用户信任 + +9 +00:00:36,470 --> 00:00:39,239 +和您在他们生活中的地位的方式 + +10 +00:00:39,273 --> 00:00:44,111 +当人们了解收集了哪些关于他们的 +数据以及如何使用这些数据时 + +11 +00:00:44,144 --> 00:00:46,513 +他们就更有可能完全参与到 + +12 +00:00:46,547 --> 00:00:50,450 +您的 App 或服务中 +而不是选择替代方案 + +13 +00:00:51,618 --> 00:00:55,856 +在 Apple 我们优先为用户 +提供优秀的 + +14 +00:00:55,889 --> 00:00:57,891 +功能和隐私保护 + +15 +00:00:57,925 --> 00:01:01,161 +我们也想帮助您把这个服务 +传递给您的客户 + +16 +00:01:01,195 --> 00:01:06,567 +在 Apple 我们通过一系列 +可操作的模式和隐私原则 + +17 +00:01:06,600 --> 00:01:10,971 +来实现出色的功能和隐私目标 + +18 +00:01:11,004 --> 00:01:15,742 +这些对于您以及如何在您的 +App 中建立隐私是个很好的指南 + +19 +00:01:15,776 --> 00:01:18,912 +首先是数据最小化 + +20 +00:01:18,946 --> 00:01:23,083 +只使用构建功能所需的数据 + +21 +00:01:23,116 --> 00:01:25,719 +接着是设备上的处理 + +22 +00:01:25,752 --> 00:01:28,889 +如果该功能需要敏感数据 + +23 +00:01:28,922 --> 00:01:33,260 +请使用设备的能力 +避免与服务器共享 + +24 +00:01:33,293 --> 00:01:36,964 +第三是透明度和控制权 + +25 +00:01:36,997 --> 00:01:39,800 +如果敏感数据从设备发送出去 + +26 +00:01:39,833 --> 00:01:43,670 +请确保人们了解发送的内容 +如何使用 + +27 +00:01:43,704 --> 00:01:46,206 +并给予他们控制权 + +28 +00:01:46,240 --> 00:01:48,976 +最后 安全保护 + +29 +00:01:49,009 --> 00:01:52,579 +保护传输中的和存放的敏感数据 + +30 +00:01:52,613 --> 00:01:55,682 +无论是在设备上还是在设备外 + +31 +00:01:56,683 --> 00:02:01,989 +在这个视频中 +我将谈论一些会影响您的平台变化 + +32 +00:02:02,022 --> 00:02:06,093 +一些您应该采用的新的隐私增强功能 + +33 +00:02:06,126 --> 00:02:10,430 +以及一个影响隐私的重要新功能 + +34 +00:02:12,199 --> 00:02:17,571 +首先 我来谈一些 +将影响您的 App 的平台变化 + +35 +00:02:17,604 --> 00:02:23,744 +iOS 16 和 macOS Ventura +包括几个重要的变化 + +36 +00:02:23,777 --> 00:02:28,115 +新的设备名称授权 +用于限制对设备名称的访问 + +37 +00:02:29,349 --> 00:02:34,221 +位置指示器现在会在 +控制中心显示 App 的属性 + +38 +00:02:35,789 --> 00:02:39,159 +对 Gatekeeper 的改进 +可以在更多地方验证 + +39 +00:02:39,193 --> 00:02:42,262 +经过公证的 App 的完整性 + +40 +00:02:43,764 --> 00:02:47,301 +现在 在登录时启动 Mac App +会通知人们添加了什么 App + +41 +00:02:47,334 --> 00:02:49,803 +并具有简化的 API + +42 +00:02:51,371 --> 00:02:55,042 +传统的剪贴板访问现在需要许可 + +43 +00:02:55,976 --> 00:03:00,581 +我将从更改设备名称访问开始 + +44 +00:03:00,614 --> 00:03:03,016 +为了更容易识别设备 + +45 +00:03:03,050 --> 00:03:05,919 +用户的 Apple ID 账户名 + +46 +00:03:05,953 --> 00:03:11,225 +默认包含在 iOS 设备名中 + +47 +00:03:11,258 --> 00:03:15,495 +在 iOS 16 之前 +UIDevice API 允许 App + +48 +00:03:15,529 --> 00:03:18,832 +访问用户分配的设备名称 + +49 +00:03:18,866 --> 00:03:23,604 +为了更好地使 App +对该值的访问与用户期望保持一致 + +50 +00:03:23,637 --> 00:03:27,741 +UIDevice.name API +将返回设备的型号 + +51 +00:03:27,774 --> 00:03:32,980 +不是用户分配的名称 +也不管人们如何自定义 + +52 +00:03:34,915 --> 00:03:38,852 +我们了解到 +某些利用设备名称的 App + +53 +00:03:38,886 --> 00:03:40,687 +具有多设备体验 + +54 +00:03:40,721 --> 00:03:44,324 +例如让人们清楚地了解 +上次编辑文档的位置 + +55 +00:03:45,492 --> 00:03:51,331 +如果您的 App 使用多设备功能 +并使其在 App 的 UI 中可见 + +56 +00:03:51,365 --> 00:03:55,469 +您可以请求访问设备名称的授权 + +57 +00:03:55,502 --> 00:04:00,073 +即使有此授权 +也不允许与云托管服务提供商 + +58 +00:04:00,107 --> 00:04:04,411 +以外的第三方共享设备名称 + +59 +00:04:06,113 --> 00:04:10,417 +接下来是更新位置使用属性 + +60 +00:04:11,485 --> 00:04:16,390 +当 App 使用位置功能时 +iOS 会在状态栏中显示一个箭头 + +61 +00:04:17,824 --> 00:04:21,361 +在 iOS 16 中 从控制中心向下滑动 + +62 +00:04:21,395 --> 00:04:25,065 +显示哪个 App 正在使用位置 + +63 +00:04:25,098 --> 00:04:28,202 +确保您的 App 只在 +用户预期的时候 + +64 +00:04:28,235 --> 00:04:30,504 +使用位置 + +65 +00:04:32,873 --> 00:04:34,942 +现在我想谈谈 Mac + +66 +00:04:34,975 --> 00:04:38,679 +Gatekeeper 检查新下载的 +App 的完整性 + +67 +00:04:38,712 --> 00:04:41,481 +在 macOS Ventura 中 +Gatekeeper 将检查 + +68 +00:04:41,515 --> 00:04:45,853 +所有经过公证的 App 的完整性 +而不仅仅是隔离的 App + +69 +00:04:46,920 --> 00:04:49,756 +首先 App 需要正确签名 + +70 +00:04:49,790 --> 00:04:51,525 +从 macOS Ventura 开始 + +71 +00:04:51,558 --> 00:04:54,761 +如果您的已公证 App 签名失效 + +72 +00:04:54,795 --> 00:04:58,298 +将在首次启动时被 Gatekeeper 阻止 + +73 +00:04:58,332 --> 00:05:01,001 +您应该签名您所有的可执行文件和包 + +74 +00:05:01,034 --> 00:05:05,706 +并确保他们的签名在您 +修改 App 时保持有效 + +75 +00:05:05,739 --> 00:05:09,943 +除了检查完整性 Gatekeeper 还会 + +76 +00:05:09,977 --> 00:05:12,713 +防止您的 App 被以某种方式修改 + +77 +00:05:14,181 --> 00:05:17,885 +最常见的 App 修改方式是更新 + +78 +00:05:17,918 --> 00:05:23,090 +由同一个开发者账户或团队 +有效签名的 App + +79 +00:05:23,123 --> 00:05:24,424 +将能够继续相互更新 + +80 +00:05:24,458 --> 00:05:26,159 +这样就行了 + +81 +00:05:26,960 --> 00:05:29,563 +为了让其他开发团队 +更新您的 App + +82 +00:05:29,596 --> 00:05:32,833 +或限制为仅允许您的更新程序 + +83 +00:05:32,866 --> 00:05:35,936 +您可以更新您的 info-plist + +84 +00:05:35,969 --> 00:05:39,540 +例如 这里 +Unrelated App 可以允许 Pal About 更新 + +85 +00:05:39,573 --> 00:05:42,376 +只需更改 plist +即可对其进行更新 + +86 +00:05:44,745 --> 00:05:49,850 +只需添加您希望允许的 +NSUpdateSecurityPolicy + +87 +00:05:49,883 --> 00:05:55,489 +在 NSUpdateSecurityPolicy 中 +添加 AllowProcesses 字典 + +88 +00:05:55,522 --> 00:06:00,194 +将 team ID 射到 +签名标识符数组 + +89 +00:06:00,227 --> 00:06:03,664 +在此示例中 +该策略允许任何带有签名标识符 + +90 +00:06:03,697 --> 00:06:09,036 +com.example.pal.about 的进程 + +91 +00:06:09,069 --> 00:06:13,774 +通过 Pal About 的 team ID +来更新您的 App + +92 +00:06:13,807 --> 00:06:16,710 +如果 App 被一些其他 + +93 +00:06:16,743 --> 00:06:19,246 +开发团队签名的东西修改 + +94 +00:06:19,279 --> 00:06:23,617 +且不被 NSUpdateSecurityPolicy 允许 + +95 +00:06:23,650 --> 00:06:26,119 +macOS 会阻止修改 + +96 +00:06:26,153 --> 00:06:31,058 +并通知用户有个 App +想要管理其他 App + +97 +00:06:31,091 --> 00:06:35,062 +单击通知会将用户发送到 +系统设置 + +98 +00:06:35,095 --> 00:06:39,499 +在那里他们可以允许一个 App +更新和修改其他 App + +99 +00:06:41,235 --> 00:06:44,805 +为了准备 macOS Ventura +您应该签名您的 App 的可执行文件 + +100 +00:06:44,838 --> 00:06:47,307 +和包 并确保 + +101 +00:06:47,341 --> 00:06:50,777 +这些签名在更新后仍然有效 + +102 +00:06:50,811 --> 00:06:57,050 +采用 NSUpdateSecurityPolicy +并列举您使用的所有更新器 + +103 +00:06:57,084 --> 00:07:02,523 +记住 如果您的 App 尝试修改 +策略之外的其他 App + +104 +00:07:02,556 --> 00:07:04,992 +需要用户允许 + +105 +00:07:07,027 --> 00:07:11,765 +接下来 我将讨论如何 +在 Mac 上登陆 App + +106 +00:07:11,798 --> 00:07:16,203 +在 macOS Monterey 以及更早的版本中 +当有人登录到他们的 Mac 时 + +107 +00:07:16,236 --> 00:07:20,474 +App 可以在登录时使用启动代理 +或守护进程运行 + +108 +00:07:20,507 --> 00:07:24,111 +这很方便 +因为它允许 App 运行菜单助手 + +109 +00:07:24,144 --> 00:07:26,547 +在后台检查软件更新 + +110 +00:07:26,580 --> 00:07:29,950 +或在多个 App 之间同步数据 + +111 +00:07:31,051 --> 00:07:33,921 +有时 当用户登录到他们的 Mac 时 + +112 +00:07:33,954 --> 00:07:37,424 +不相关的 App 会打开 +并且可能会妨碍它们 + +113 +00:07:37,457 --> 00:07:43,463 +此外 App 或其他软件 +可以访问传感器或位置等数据 + +114 +00:07:43,497 --> 00:07:46,166 +人们并不总是清楚这种情况正在发生 + +115 +00:07:46,200 --> 00:07:49,236 +因为可能看不到正在运行的内容 + +116 +00:07:49,269 --> 00:07:50,737 +对于开发人员来说 + +117 +00:07:50,771 --> 00:07:54,174 +并不总是很清楚登录时 +使用哪种机制启动 + +118 +00:07:54,208 --> 00:07:58,045 +守护进程 代理 服务管理 + +119 +00:07:58,078 --> 00:08:01,815 +使用 macOS Ventura 这就简单多了 + +120 +00:08:03,250 --> 00:08:08,255 +在 macOS Ventura 中 +您可以使用新的单一 API + +121 +00:08:08,288 --> 00:08:11,191 +来启动您的 App 代理或守护进程 + +122 +00:08:11,225 --> 00:08:14,361 +默认情况下 您的 App +将被允许在登录时启动 + +123 +00:08:14,394 --> 00:08:16,763 +并且会通知用户 + +124 +00:08:16,797 --> 00:08:19,867 +如果您的 App 需要一个 +具有更高权限的守护进程 + +125 +00:08:19,900 --> 00:08:22,736 +将需要管理员批准才能启用 + +126 +00:08:25,339 --> 00:08:28,709 +点击这个通知会打开 +设置中的登录项窗口 + +127 +00:08:28,742 --> 00:08:33,280 +用户可以在那里管理 +在其系统上启动的 App + +128 +00:08:33,313 --> 00:08:36,550 +顶部控制登录时运行的 App + +129 +00:08:36,583 --> 00:08:40,487 +底部控制登录时运行的其他项目 + +130 +00:08:40,521 --> 00:08:44,324 +此窗口现在控制 App +在登录时运行的不同方式 + +131 +00:08:44,358 --> 00:08:48,362 +包括代理 守护进程 SMLoginItems + +132 +00:08:48,395 --> 00:08:51,331 +以及在登录时添加自己打开的 App + +133 +00:08:51,365 --> 00:08:53,967 +下面介绍如何使用这个新 API + +134 +00:08:55,569 --> 00:08:58,605 +Service Management 框架使您可以轻松地 + +135 +00:08:58,639 --> 00:09:00,574 +在登录时启动资源 + +136 +00:09:00,607 --> 00:09:04,444 +因为所有的代理和守护进程 +都存在于您的 App 包中 + +137 +00:09:04,478 --> 00:09:07,481 +因此不再需要使用安装程序 +来编写启动代理或创建清理脚本 + +138 +00:09:07,514 --> 00:09:12,986 +这也适用于 Mac App Store 的 App + +139 +00:09:13,020 --> 00:09:17,891 +从您的 App 调用 SMAppService API + +140 +00:09:17,925 --> 00:09:22,229 +来控制人们何时获得通知 +以及您的 App 图标在设置中的外观 + +141 +00:09:24,398 --> 00:09:27,634 +接下来是剪贴板访问 + +142 +00:09:29,736 --> 00:09:34,107 +以前 当用户不是在编辑选项中 +按下粘贴键时 + +143 +00:09:34,141 --> 00:09:38,045 +会有一个透明度的通知 +让用户知道 App 何时访问了剪贴板 + +144 +00:09:39,613 --> 00:09:44,985 +在 iOS 16 中 系统会确认 +访问其他 App 编写的 + +145 +00:09:45,018 --> 00:09:47,688 +剪贴板项目的意图 + +146 +00:09:47,721 --> 00:09:51,425 +如果您的 App 继续使用 +UIPasteboard API + +147 +00:09:51,458 --> 00:09:57,130 +访问剪贴板里的值 +那么系统将显示一个模态提示 + +148 +00:09:57,164 --> 00:10:00,801 +有三种方法可以避免 +该提示出现在 App 中 + +149 +00:10:00,834 --> 00:10:03,904 +第一种是使用编辑选项菜单 + +150 +00:10:03,937 --> 00:10:07,074 +第二种是使用键盘快捷键 + +151 +00:10:07,107 --> 00:10:10,244 +在 Features to adopt 部分 +我将讨论第三个选项 + +152 +00:10:10,277 --> 00:10:13,180 +新的 UIKit 粘贴控件 + +153 +00:10:14,448 --> 00:10:16,984 +这些都是您需要了解的 + +154 +00:10:17,017 --> 00:10:18,886 +平台隐私变化 + +155 +00:10:18,919 --> 00:10:22,856 +此外 还有一些新的隐私增强技术 + +156 +00:10:22,890 --> 00:10:26,159 +可以让您更轻松地在您的 App 中 + +157 +00:10:26,193 --> 00:10:28,595 +构建无缝的隐私体验 + +158 +00:10:29,730 --> 00:10:33,767 +我将从讨论 UIKit 粘贴控件开始 + +159 +00:10:35,169 --> 00:10:38,605 +将 UIKit 粘贴控件添加到 +您的 App 体验中 + +160 +00:10:38,639 --> 00:10:44,144 +因此人们可以通过按下按钮 +直观地访问他们的剪贴板 + +161 +00:10:44,178 --> 00:10:48,549 +采用 UIKit 粘贴控件允许粘贴时 + +162 +00:10:48,582 --> 00:10:50,984 +不需要编辑菜单 快捷键或系统提示 + +163 +00:10:51,018 --> 00:10:54,821 +系统通过确认按钮是否可见并点击 + +164 +00:10:54,855 --> 00:10:57,958 +来确认意图 + +165 +00:10:57,991 --> 00:11:00,594 +自定义这些按钮 +以适合您的 App 界面 + +166 +00:11:00,627 --> 00:11:02,362 +更改圆角或文本 + +167 +00:11:02,396 --> 00:11:06,500 +图标或背景的颜色 + +168 +00:11:06,533 --> 00:11:09,536 +只要确保按钮有足够的对比度 + +169 +00:11:09,570 --> 00:11:11,872 +没有隐藏在其他元素后面 + +170 +00:11:11,905 --> 00:11:13,740 +否则它将无法运行 + +171 +00:11:13,774 --> 00:11:17,678 +确保测试粘贴按钮是否按预期工作 + +172 +00:11:19,680 --> 00:11:22,416 +另一个在最小化数据访问的同时 + +173 +00:11:22,449 --> 00:11:27,421 +创建无缝体验的工具是媒体设备发现 + +174 +00:11:27,454 --> 00:11:30,557 +今天的 App 使用广泛的流协议 + +175 +00:11:30,591 --> 00:11:33,994 +具有自定义发现和通信逻辑 + +176 +00:11:35,295 --> 00:11:38,165 +以前使用这些协议流媒体时 + +177 +00:11:38,198 --> 00:11:41,101 +App 需要获得访问本地网络的许可 + +178 +00:11:41,134 --> 00:11:43,770 +通常还需要蓝牙 + +179 +00:11:43,804 --> 00:11:47,174 +这个许可是需要的 +因为管理设备选择 + +180 +00:11:47,207 --> 00:11:49,676 +需要了解所有的设备 + +181 +00:11:49,710 --> 00:11:53,380 +但这提供了超出必要范围的信息 + +182 +00:11:53,413 --> 00:11:56,817 +并带来了设备指纹的风险 + +183 +00:11:56,850 --> 00:12:01,388 +媒体设备发现可让您的 +App 流传输到选定的设备 + +184 +00:12:01,421 --> 00:12:05,659 +而无需显示网络或蓝牙访问提示 + +185 +00:12:05,692 --> 00:12:09,263 +流媒体设备与 AirPlay 显示在 +同一个选择器中 + +186 +00:12:09,296 --> 00:12:13,767 +而App 只能看到 +被选中的流传输到的设备 + +187 +00:12:13,800 --> 00:12:17,638 +这要得益于 DeviceDiscovery 扩展 + +188 +00:12:19,239 --> 00:12:23,143 +这个扩展可以搜索本地网络 +和蓝牙设备 + +189 +00:12:23,177 --> 00:12:28,549 +但是沙盒独立于 App +因此无法将扫描结果发回 + +190 +00:12:28,582 --> 00:12:33,120 +这意味着 App 访问本地网络 + +191 +00:12:33,153 --> 00:12:38,125 +或蓝牙不需要广泛的权限 +因为 App 不能看到整个网络 + +192 +00:12:38,158 --> 00:12:42,129 +相反 扩展只能将发现的附件 + +193 +00:12:42,162 --> 00:12:45,666 +发送到 +DeviceDiscoveryExtension 框架 + +194 +00:12:46,633 --> 00:12:50,304 +DeviceDiscoveryExtension 框架 + +195 +00:12:50,337 --> 00:12:54,508 +在选择器中显示发现的设备列表 + +196 +00:12:54,541 --> 00:12:58,011 +做出选择后 +系统启用与所选设备的通信 + +197 +00:12:58,045 --> 00:13:01,081 +不需要其他权限 + +198 +00:13:02,549 --> 00:13:06,019 +协议提供商应使用 +DeviceDiscoveryExtension + +199 +00:13:06,053 --> 00:13:08,889 +来创建 App 扩展 + +200 +00:13:08,922 --> 00:13:14,194 +扩展 AVRoutePickerView +以处理用户选择回调 + +201 +00:13:14,228 --> 00:13:18,432 +处理您的协议中用户选择的网络设备 + +202 +00:13:18,465 --> 00:13:22,569 +下载示例扩展和 App +来了解更多信息 + +203 +00:13:22,603 --> 00:13:26,306 +App 开发人员应联系 +他们的流协议提供商 + +204 +00:13:26,340 --> 00:13:30,310 +以实现 DeviceDiscoveryExtension + +205 +00:13:30,344 --> 00:13:34,414 +媒体设备发现是构建 +具有极大隐私性的 + +206 +00:13:34,448 --> 00:13:36,250 +出色功能的机会 + +207 +00:13:36,283 --> 00:13:40,254 +您的 App 可以准确访问 +流式传输需要的数据 + +208 +00:13:40,287 --> 00:13:45,292 +发现简单且无需提示 +用户还能获得良好的网络隐私 + +209 +00:13:45,325 --> 00:13:48,328 +各方都能受益 + +210 +00:13:48,362 --> 00:13:51,932 +就像媒体设备发现提供 +在没有提示的情况下 + +211 +00:13:51,965 --> 00:13:54,334 +仅访问所需设备的权限一样 + +212 +00:13:54,368 --> 00:13:57,137 +PHPicker API 提供了 + +213 +00:13:57,171 --> 00:14:01,408 +只访问所需照片的权限而没有提示 + +214 +00:14:01,441 --> 00:14:04,978 +PHPicker 现在在带有 +macOS Ventura 的 Mac + +215 +00:14:05,012 --> 00:14:08,282 +以及带有 watchOS 9 的手表上 + +216 +00:14:08,315 --> 00:14:12,219 +更新您的 Mac 和 Watch App +以访问照片 而不提示用户 + +217 +00:14:12,252 --> 00:14:14,922 +访问所有照片 + +218 +00:14:17,224 --> 00:14:21,962 +接下来是私有访问令牌 +它是一种强大的工具 + +219 +00:14:21,995 --> 00:14:24,398 +可以在没有验证码的情况下 +防止欺诈 + +220 +00:14:26,166 --> 00:14:30,704 +私有访问令牌取代了验证码 +并使用盲令牌构建 + +221 +00:14:30,737 --> 00:14:34,241 +允许网站或 API 开发人员 +识别合法设备 + +222 +00:14:34,274 --> 00:14:38,679 +而不能跟踪这些设备 + +223 +00:14:38,712 --> 00:14:42,783 +Apple 不知道设备 +为哪些网站获取令牌 + +224 +00:14:42,816 --> 00:14:46,119 +接收令牌的服务器也不知道 + +225 +00:14:46,153 --> 00:14:49,423 +发送令牌的设备身份 + +226 +00:14:49,456 --> 00:14:54,428 +私有访问令牌是 +Privacy Pass IETF 开放标准的一部分 + +227 +00:14:54,461 --> 00:14:58,398 +与我们用来验证 +私有中继用户真实性的 + +228 +00:14:58,432 --> 00:15:00,934 +技术相同 + +229 +00:15:00,968 --> 00:15:03,470 +要了解更多信息 请观看视频 + +230 +00:15:03,504 --> 00:15:06,907 +“Replace CAPTCHAs +with Private Access Tokens” + +231 +00:15:08,809 --> 00:15:11,778 +现在我来谈一谈 Passkey + +232 +00:15:12,713 --> 00:15:15,949 +Passkey 是验证帐户和保护 + +233 +00:15:15,983 --> 00:15:20,687 +个人数据安全的核心 +但它们存在严重问题 + +234 +00:15:20,721 --> 00:15:24,491 +很难记住 因此人们将它们简化 + +235 +00:15:24,525 --> 00:15:27,227 +或者在多个站点上重复使用 + +236 +00:15:27,261 --> 00:15:29,029 +他们可能被钓鱼 + +237 +00:15:30,464 --> 00:15:34,001 +Passkey 支持更强大的 +身份验证解决方案 + +238 +00:15:34,034 --> 00:15:37,271 +并使用与密码自动填充相同的 + +239 +00:15:37,304 --> 00:15:41,275 +即时熟悉的 UI 样式和生物特征验证 + +240 +00:15:45,179 --> 00:15:48,882 +密钥建立在公开密钥加密的基础上 + +241 +00:15:48,916 --> 00:15:51,952 +因此服务器存储的值不会很弱 + +242 +00:15:51,985 --> 00:15:53,453 +如果泄露了也无所谓 + +243 +00:15:53,487 --> 00:15:57,524 +因为它是真正公开的 + +244 +00:15:57,558 --> 00:16:01,862 +因为密钥本身就与它们 +对应的网站相关联 + +245 +00:16:01,895 --> 00:16:04,231 +所以不会被钓鱼 + +246 +00:16:04,264 --> 00:16:07,034 +关于实现密钥的更多信息 + +247 +00:16:07,067 --> 00:16:10,370 +有一个完整的视频 “Meet Passkeys” + +248 +00:16:12,339 --> 00:16:17,044 +这些都是令人兴奋和重要的隐私更新 +供你们采纳 + +249 +00:16:18,412 --> 00:16:22,649 +我想说的另一件重要的事情是 +iOS 16 中的一个新的 + +250 +00:16:22,683 --> 00:16:26,286 +隐私工具 叫做 Safety Check + +251 +00:16:26,320 --> 00:16:29,890 +Safety Check 旨在帮助遭受家庭暴力 + +252 +00:16:29,923 --> 00:16:35,095 +或亲密伴侣暴力的人审查和重置 + +253 +00:16:35,128 --> 00:16:38,332 +他们以前可能授予他人的访问权限 + +254 +00:16:39,533 --> 00:16:42,569 +Safety Check 通过以下方式提供帮助 + +255 +00:16:42,603 --> 00:16:47,808 +它通过关闭 FindMy 中的位置共享 + +256 +00:16:47,841 --> 00:16:52,412 +并停止在照片 便笺和日历中共享 +来停止与人们共享数据 + +257 +00:16:52,446 --> 00:16:56,884 +它通过重置所有第三方 App 的 +系统隐私权限 + +258 +00:16:56,917 --> 00:16:59,186 +来停止与 App 共享数据 + +259 +00:16:59,219 --> 00:17:04,191 +它可以帮助您在其他 iCloud设备上 +退出 FaceTime 和 iMessage + +260 +00:17:04,224 --> 00:17:09,530 +以确保消息和呼叫只发送到 +您手中的设备 + +261 +00:17:09,563 --> 00:17:13,700 +它会引导您退出其他 iCloud 设备 + +262 +00:17:13,734 --> 00:17:18,639 +以确保其他设备无法接收 +来自 FindMy 照片 + +263 +00:17:18,672 --> 00:17:21,475 +日历等的位置更新 + +264 +00:17:21,508 --> 00:17:24,778 +它可以帮助您更改设备 + +265 +00:17:24,811 --> 00:17:26,813 +和 iCloud 帐户的密码 + +266 +00:17:26,847 --> 00:17:30,918 +以及用于 iCloud 双重身份验证的 +可信电话号码 + +267 +00:17:30,951 --> 00:17:36,256 +它还可以帮助您管理紧急联系人 +以便根据需要进行任何更改 + +268 +00:17:36,290 --> 00:17:40,727 +所有这些东西一起帮助用户 +应对个人安全威胁 + +269 +00:17:40,761 --> 00:17:43,630 +控制对他们数据的访问 + +270 +00:17:44,698 --> 00:17:47,334 +使用安全检查有两种方法 + +271 +00:17:47,367 --> 00:17:52,339 +第一个是紧急重置 +适用于需要立即重置 + +272 +00:17:52,372 --> 00:17:56,777 +人员和 App 访问权限的紧急情况 + +273 +00:17:57,778 --> 00:18:01,215 +第二个是管理共享和访问 + +274 +00:18:01,248 --> 00:18:06,653 +它对 Safety Check 的每个功能 +提供更细粒度的控制 + +275 +00:18:08,288 --> 00:18:14,795 +紧急重置可让您快速对 +所有人和所有 App 采取行动 + +276 +00:18:14,828 --> 00:18:20,133 +并在您的其他设备上 +禁用对 FaceTime 和 iMessage 的访问 + +277 +00:18:20,167 --> 00:18:24,638 +然后 您将完成手中设备的 +iCloud 账户保护 + +278 +00:18:24,671 --> 00:18:28,375 +并检查您的紧急联系人 + +279 +00:18:28,408 --> 00:18:30,811 +和可信设备 + +280 +00:18:30,844 --> 00:18:34,681 +管理共享和访问可让您逐个查看 + +281 +00:18:34,715 --> 00:18:39,119 +以及逐 App 查看您的共享对象 + +282 +00:18:39,152 --> 00:18:43,724 +您可以按名称或您共享的信息类型 +对其进行排序 + +283 +00:18:43,757 --> 00:18:47,528 +这是了解和控制您与特定用户 + +284 +00:18:47,561 --> 00:18:49,563 +共享的好工具 + +285 +00:18:49,596 --> 00:18:52,499 +它还可以帮助您找到 +由有权访问您设备的人安装的 + +286 +00:18:52,533 --> 00:18:55,669 +具有敏感权限的 App + +287 +00:18:58,238 --> 00:19:01,642 +快速退出在所有的 +Safety Check 流程中都可用 + +288 +00:19:01,675 --> 00:19:03,877 +如果他们担心有人 +可能会看到他们在做什么 + +289 +00:19:03,911 --> 00:19:07,147 +可以快速退出流程 + +290 +00:19:07,181 --> 00:19:09,716 +按下这个键 它们就会回到主屏幕 + +291 +00:19:09,750 --> 00:19:11,852 +下次进入设置时 + +292 +00:19:11,885 --> 00:19:13,754 +它们就会回到主设置页 + +293 +00:19:13,787 --> 00:19:16,523 +而不是 Safety Check + +294 +00:19:16,557 --> 00:19:21,461 +Safety Check 可帮助遭受家庭暴力 +或亲密伴侣暴力的人 + +295 +00:19:21,495 --> 00:19:24,932 +重新控制自己的私人数据 + +296 +00:19:24,965 --> 00:19:29,436 +隐私不仅仅是在您 +分享数据的那一刻做出决定 + +297 +00:19:29,469 --> 00:19:35,209 +还包括能够在任何时候 +理解并改变这个决定 + +298 +00:19:35,242 --> 00:19:40,214 +这只是 Apple +如何设计隐私的一个例子 + +299 +00:19:40,247 --> 00:19:44,918 +在您的 App 中设计隐私 +将帮助您建立并保持 + +300 +00:19:44,952 --> 00:19:46,887 +与用户的信任 + +301 +00:19:46,920 --> 00:19:53,427 +iOS 16 和 macOS Ventura 带来了 +许多新技术来助您一臂之力 + +302 +00:19:53,460 --> 00:19:57,297 +准备好新的平台更新 +如 UI 设备名称的更改 + +303 +00:19:57,331 --> 00:19:59,833 +和 Gatekeeper 的改进 + +304 +00:19:59,867 --> 00:20:02,569 +采用媒体设备发现扩展 + +305 +00:20:02,603 --> 00:20:05,038 +UIKit 粘贴控件 + +306 +00:20:05,072 --> 00:20:09,243 +Private Access Token 和 Passkey + +307 +00:20:09,276 --> 00:20:10,811 +谢谢大家今天参加我的节目 + +308 +00:20:10,844 --> 00:20:13,380 +我们迫不及待地想看看 +你们如何在 App 中 + +309 +00:20:13,413 --> 00:20:15,516 +添加出色的功能和隐私保护 + +310 +00:20:15,549 --> 00:20:19,987 +[欢快的音乐] + diff --git a/zho/2022 Session 10098 Meet Web Push for Safari.srt b/zho/2022 Session 10098 Meet Web Push for Safari.srt new file mode 100644 index 0000000..b80178b --- /dev/null +++ b/zho/2022 Session 10098 Meet Web Push for Safari.srt @@ -0,0 +1,1178 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,877 --> 00:00:12,379 +Brady Eidson: +大家好 我叫 Brady Eidson + +3 +00:00:12,412 --> 00:00:15,082 +是 WebKit 架构团队的工程师 + +4 +00:00:15,115 --> 00:00:19,019 +我很高兴向您介绍 +Safari 浏览器中的网页推送功能 + +5 +00:00:19,052 --> 00:00:21,955 +网页推送可以让您 +给您的网络 App 用户 + +6 +00:00:21,989 --> 00:00:24,358 +发送远程通知 + +7 +00:00:24,391 --> 00:00:28,161 +这里 在屏幕的右上角 + +8 +00:00:28,195 --> 00:00:30,364 +是来自 webkit.org 的通知显示 + +9 +00:00:30,397 --> 00:00:34,601 +点击通知打开 +新窗口中的 WebKit 博客文章 + +10 +00:00:34,635 --> 00:00:37,971 +在我讲述它的工作原理的 +其它细节之前 + +11 +00:00:38,005 --> 00:00:41,708 +我想回答几个 +很多开发者想问的问题 + +12 +00:00:43,043 --> 00:00:47,848 +从 macOS Ventura 开始 +Mac Safari 浏览器开始支持网页推送 + +13 +00:00:47,881 --> 00:00:52,052 +明年 iOS 和 iPadOS +也会安装网页推送 + +14 +00:00:53,320 --> 00:00:56,723 +Apple 的 Safari 浏览器推送通知 +很久以前就向 + +15 +00:00:56,757 --> 00:00:59,660 +接触 Mac Safari 浏览器用户提供了 + +16 +00:00:59,693 --> 00:01:02,596 +如今 它还在继续起作用 +我很高兴地宣布 + +17 +00:01:02,629 --> 00:01:04,631 +我们增加了对网页推送的支持 + +18 +00:01:04,665 --> 00:01:08,402 +这是真正的网页推送 + +19 +00:01:08,435 --> 00:01:11,238 +各种网络标准的相同组合 + +20 +00:01:11,271 --> 00:01:13,774 +也在其它浏览器中使用 + +21 +00:01:13,807 --> 00:01:16,343 +我们稍后将讨论这些标准 但是 + +22 +00:01:16,376 --> 00:01:18,412 +最重要的是 + +23 +00:01:18,445 --> 00:01:22,182 +如果您对您的网络标准 App +进行过编码 + +24 +00:01:22,216 --> 00:01:25,219 +就无需在 Safari 浏览器中 +对它做任何改变 + +25 +00:01:25,252 --> 00:01:28,689 +当然 如果您不用 Safari 浏览器 +进行浏览器检测的话 + +26 +00:01:28,722 --> 00:01:30,257 +那么您还要做一些其它的工作 + +27 +00:01:30,290 --> 00:01:35,062 +现在是浏览器检测到 +功能检测的最佳时间 + +28 +00:01:35,095 --> 00:01:37,731 +功能检测一直是最佳实践 + +29 +00:01:37,764 --> 00:01:40,133 +我们使用的是相同的 +Apple 推送通知服务 + +30 +00:01:40,167 --> 00:01:44,071 +在所有 Mac 和 iOS 设备上 +为本地推送提供动力 + +31 +00:01:44,104 --> 00:01:48,609 +但没有 Apple Developer 帐户 +需要访问 Safari 浏览器用户 + +32 +00:01:48,642 --> 00:01:52,145 +我们正在使用新的 +网页推送的端点 URL + +33 +00:01:52,179 --> 00:01:57,084 +它带出另一件事 +可能在无意中排除了 Safari 浏览器 + +34 +00:01:57,117 --> 00:02:00,053 +如果您在服务器上严密管理推送端点 + +35 +00:02:00,087 --> 00:02:05,058 +请确保您允许 URL +来自 push.apple.com 的任何子域 + +36 +00:02:05,092 --> 00:02:08,161 +对于那些重要的问题 +让我们不但来解答 + +37 +00:02:08,195 --> 00:02:10,130 +更要详细地谈一下 + +38 +00:02:10,163 --> 00:02:13,233 +首先 我们从用户的角度来看一下 + +39 +00:02:13,267 --> 00:02:15,869 +Safari 浏览器中的网页推送体验 + +40 +00:02:15,903 --> 00:02:19,873 +然后我们将介绍整个网页推送流程 +从请求许可 + +41 +00:02:19,907 --> 00:02:23,710 +到在通知中心处理进入许可的点击 + +42 +00:02:23,744 --> 00:02:29,216 +最后 我们来看一看 从网页推送 +到现有的网络 App 需要添加什么 + +43 +00:02:29,249 --> 00:02:32,586 +但首先 我们来看一下 +Mac Safari 浏览器用户体验 + +44 +00:02:32,619 --> 00:02:36,757 +现场演示一下将是最好的介绍方法 + +45 +00:02:36,790 --> 00:02:39,793 +这是 macOS Ventura 上的 +Safari 浏览器 + +46 +00:02:39,826 --> 00:02:43,363 +在这个浏览器选项卡中 +我打开了 webkit.org + +47 +00:02:43,397 --> 00:02:46,266 +我需要用 WebKit 开源项目 +保持更新 + +48 +00:02:46,300 --> 00:02:49,069 +网页推送是一个很好的方法 + +49 +00:02:49,102 --> 00:02:53,040 +如果没有用户请求手势 + +50 +00:02:53,073 --> 00:02:56,109 +是不允许使用 webkit.org +请求推送权限的 + +51 +00:02:56,143 --> 00:03:01,181 +所以我会在这里 +点击这个钟形按钮订阅通知 + +52 +00:03:01,215 --> 00:03:04,885 +您在这里看到的是系统通知提示 + +53 +00:03:04,918 --> 00:03:07,888 +这与其它 App 是一样的 + +54 +00:03:07,921 --> 00:03:11,525 +在这种情况下 它代表 webkit.org + +55 +00:03:11,558 --> 00:03:15,162 +我将单击 allow 一切就绪 + +56 +00:03:15,195 --> 00:03:20,200 +webkit.org 给了我选择 +收到有关新博客文章的通知 + +57 +00:03:20,234 --> 00:03:23,070 +以及对源代码存储库的新的承诺 + +58 +00:03:23,103 --> 00:03:27,508 +我知道每次提交都会收到通知 +会分散我对重要工作的注意力 + +59 +00:03:27,541 --> 00:03:31,545 +但我真的想收到 +有关新的博客文章的消息 + +60 +00:03:31,578 --> 00:03:33,614 +所以我现在要检查那个框 + +61 +00:03:33,647 --> 00:03:37,417 +巧合的是 一定有人刚刚发布了 +关于网络推送的 + +62 +00:03:37,451 --> 00:03:39,152 +WebKit 博客文章 + +63 +00:03:39,186 --> 00:03:41,855 +此通知看起来和任何其它的一样 + +64 +00:03:41,889 --> 00:03:44,525 +是由 webkit.org 推送的 + +65 +00:03:44,558 --> 00:03:47,060 +我可以点击它来激活 + +66 +00:03:47,094 --> 00:03:50,163 +还有博客文章 +要在 Safari 浏览器中打开 + +67 +00:03:50,197 --> 00:03:53,367 +一旦用户授予网站权限 + +68 +00:03:53,400 --> 00:03:56,270 +他们就控制了该许可 + +69 +00:03:56,303 --> 00:03:59,873 +作为一个 macOS 用户 +我习惯了在系统设置里面 + +70 +00:03:59,907 --> 00:04:03,243 +管理通知首选项 那里就是我可以 + +71 +00:04:03,277 --> 00:04:07,281 +配置 webkit.org 的通知的地方 + +72 +00:04:07,314 --> 00:04:12,486 +同样丰富的配置 正如我在 +任何其他 App 或服务中所发现的那样 + +73 +00:04:12,519 --> 00:04:16,089 +作为 Safari 浏览器用户 +我习惯于从 Safari 浏览器偏好设置中 + +74 +00:04:16,123 --> 00:04:18,225 +管理网站设置 + +75 +00:04:18,258 --> 00:04:24,031 +我也可以去那里打开或关闭 +webkit.org 的权限 + +76 +00:04:24,064 --> 00:04:28,035 +这就是网页推送的工作原理 +适用于 Mac Safari 浏览器中的用户 + +77 +00:04:28,068 --> 00:04:32,606 +在我们继续之前 我想重新回复一下 +该演示中涵盖的一些内容 + +78 +00:04:32,639 --> 00:04:36,243 +首先 我们不希望用户 +被没有订阅的垃圾邮件 + +79 +00:04:36,276 --> 00:04:37,978 +所打扰 + +80 +00:04:38,011 --> 00:04:41,081 +所以一个网站只有在请求的时候 +通过点击鼠标或键盘 + +81 +00:04:41,114 --> 00:04:44,651 +才会推送订阅 + +82 +00:04:44,685 --> 00:04:48,222 +一旦网站获得许可 向用户显示通知 + +83 +00:04:48,255 --> 00:04:50,224 +用户就会控制该权限 + +84 +00:04:50,257 --> 00:04:54,328 +他们可以选择在 Safari 浏览器的首选项 +或系统设置中对它进行管理 + +85 +00:04:54,361 --> 00:04:57,998 +如果他们恰巧在两者中 +都对它进行管理 设置将保持同步 + +86 +00:04:58,031 --> 00:05:01,935 +最后 如果您针对不同类型的事件 +提供通知 + +87 +00:05:01,969 --> 00:05:05,372 +最好的做法是针对通知类型 +在您的网络 App 中 + +88 +00:05:05,405 --> 00:05:07,808 +提供精细化控制 + +89 +00:05:07,841 --> 00:05:09,409 +就像其他 App 一样 + +90 +00:05:09,443 --> 00:05:11,912 +现在您已经看到了 +网页推送的实际应用 + +91 +00:05:11,945 --> 00:05:14,815 +让我们深入了解一下 +每一步正在发生什么 + +92 +00:05:14,848 --> 00:05:17,951 +部分开发者已经对此非常熟悉 + +93 +00:05:17,985 --> 00:05:21,722 +但是对于那些刚接触网页推送的人来说 +我必须一步一步来 + +94 +00:05:21,755 --> 00:05:25,459 +向您推荐相关标准和过程中的文档 + +95 +00:05:25,492 --> 00:05:30,063 +首先是用户 +在浏览器选项卡中访问您的网站 + +96 +00:05:30,097 --> 00:05:33,133 +这是在 Safari 浏览器中 +打开的 webkit.org + +97 +00:05:33,166 --> 00:05:37,638 +由于它是在选项卡中打开的 +它可以安装一个 Service Worker + +98 +00:05:37,671 --> 00:05:40,807 +Service Worker 是一个在整个域中 +运行的 JavaScript 单元 + +99 +00:05:40,841 --> 00:05:45,913 +是从当前打开的浏览器选项卡 + +100 +00:05:45,946 --> 00:05:48,582 +一旦 Service Worker 脚本已安装 + +101 +00:05:48,615 --> 00:05:52,152 +您的网络 App 就符合了 +请求推送订阅的条件 + +102 +00:05:52,186 --> 00:05:56,823 +如前所述 +此请求必须与用户手势相关联 + +103 +00:05:56,857 --> 00:06:01,161 +当点击这个钟形按钮时 +webkit.org 请求就会得到许可 + +104 +00:06:01,195 --> 00:06:04,097 +这满足了用户手势要求 + +105 +00:06:04,131 --> 00:06:07,000 +当您的网站请求推送订阅时 + +106 +00:06:07,034 --> 00:06:09,436 +用户就会看到此系统提示 + +107 +00:06:09,469 --> 00:06:11,338 +这是他们可以进行 +关于授予您的网站这种强大能力的 + +108 +00:06:11,371 --> 00:06:13,941 +最终通话的地方 + +109 +00:06:15,142 --> 00:06:18,078 +用户可能会拒绝该请求 + +110 +00:06:18,111 --> 00:06:21,181 +您的 JavaScript 应该 +准备对它进行处理 + +111 +00:06:21,215 --> 00:06:23,483 +但假设用户授予了权限 + +112 +00:06:23,517 --> 00:06:26,854 +您的 JavaScript 就会回复一个 +PushSubscription 对象 + +113 +00:06:26,887 --> 00:06:30,324 +里面有您的服务器 +给这个浏览器的用户发送推送消息时 + +114 +00:06:30,357 --> 00:06:32,459 +所需的一切 + +115 +00:06:32,492 --> 00:06:36,096 +像这样的信息 +要使用确切的 URL 端点 + +116 +00:06:36,129 --> 00:06:39,833 +您可以以任何 +适合您的网络 App 的方式 + +117 +00:06:39,867 --> 00:06:42,669 +将 PushSubscription 的有效载荷 +返回您的服务器 + +118 +00:06:42,703 --> 00:06:47,541 +许多流行的服务器包都有 +网页推送支持管理订阅 + +119 +00:06:47,574 --> 00:06:49,543 +或者您可以自已翻阅 + +120 +00:06:49,576 --> 00:06:53,714 +在实际当中这同样适用于如何 +以及何时发送推送消息 + +121 +00:06:53,747 --> 00:06:56,416 +到您的服务器知道的 URL 端点 + +122 +00:06:56,450 --> 00:07:00,454 +我不能告诉您什么时候这样做 +这取决于您和您的网站 + +123 +00:07:00,487 --> 00:07:03,023 +但是一旦您决定发送该推送消息 + +124 +00:07:03,056 --> 00:07:05,125 +我可以在接下来发生的事情中 +为您提供帮助 + +125 +00:07:05,158 --> 00:07:09,329 +还记得推送请求 +是如何安装到 Service Worker 的吗 + +126 +00:07:09,363 --> 00:07:13,300 +一旦您的服务器发送了推送消息 +Safari 浏览器便会接收到它 + +127 +00:07:13,333 --> 00:07:18,238 +就会唤醒您的 Service Worker +并向其发送一个 JavaScript 推送事件 + +128 +00:07:18,272 --> 00:07:21,675 +在通知中心 向用户显示通知 + +129 +00:07:21,708 --> 00:07:25,379 +是处理推送事件时的要求 + +130 +00:07:25,412 --> 00:07:29,183 +如果您的网站当时 +在浏览器选项卡中处于打开状态 + +131 +00:07:29,216 --> 00:07:32,319 +网站就会接收推送事件 +并显示通知发生 + +132 +00:07:32,352 --> 00:07:36,557 +如果您的网站当前未在浏览器 +选项卡中打开 这种情况也会发生 + +133 +00:07:36,590 --> 00:07:39,226 +对于 macOS Ventura 上的 +Safari 浏览器 + +134 +00:07:39,259 --> 00:07:43,263 +即使 Safari 浏览器当前未运行 +也会发生这种情况 + +135 +00:07:43,297 --> 00:07:47,234 +最后一步 +如果您的用户点击了那个通知 + +136 +00:07:47,267 --> 00:07:50,838 +一个通知点击事件就会被 +发送到您的 Service Worker + +137 +00:07:50,871 --> 00:07:53,106 +这样它就会适时响应 + +138 +00:07:53,140 --> 00:07:55,809 +例如 通过打开一个新窗口 + +139 +00:07:55,843 --> 00:07:58,979 +让 URL 与该通知相关联 + +140 +00:07:59,012 --> 00:08:03,016 +我们带您了解了网页推送流程 + +141 +00:08:03,050 --> 00:08:05,252 +现在要通过 +向现有的网络 App + +142 +00:08:05,285 --> 00:08:09,089 +实际添加网页推送支持 +来了解更多细节 + +143 +00:08:09,122 --> 00:08:13,126 +除了 webkit.org +Browser Pet 对于 + +144 +00:08:13,160 --> 00:08:17,097 +Safari 浏览器和 WebKit 团队来说 +是最关键任务的内部工具 + +145 +00:08:17,130 --> 00:08:20,367 +让部门每个人对他们最喜欢的 +WebKitten 和 Pup + +146 +00:08:20,400 --> 00:08:24,404 +在 Safari 浏览器保持更新 +一直是 Browser Pet 的使命 + +147 +00:08:24,438 --> 00:08:27,207 +而网页推送让这比以往更加容易 + +148 +00:08:27,241 --> 00:08:31,178 +我们内部的 BrowserPet 域 +已经有一个 ServiceWorker 脚本被注册 + +149 +00:08:31,211 --> 00:08:35,983 +以加快页面加载 +并在多个选项卡之间同步 + +150 +00:08:36,016 --> 00:08:40,287 +概括地说 ServiceWorker 脚本 +和这有很大的相似之处 + +151 +00:08:40,320 --> 00:08:44,157 +当工程师访问 +选项卡中的 Browser Pet 页面时 + +152 +00:08:44,191 --> 00:08:47,861 +这个 JavaScript 摘录将确定 +Service Worker 脚本 + +153 +00:08:47,895 --> 00:08:51,932 +是否已经注册 或在必要时注册 + +154 +00:08:51,965 --> 00:08:55,302 +注意 前面提到 +我们在这里练习的功能检测 + +155 +00:08:55,335 --> 00:08:57,871 +是最佳实践 + +156 +00:08:57,905 --> 00:09:01,341 +使用 Service Worker 先决条件已搞定 + +157 +00:09:01,375 --> 00:09:03,877 +我们准备好订阅推送了 + +158 +00:09:03,911 --> 00:09:07,314 +请记住 没有明确的用户手势 + +159 +00:09:07,347 --> 00:09:10,250 +您不能要求推送订阅 + +160 +00:09:10,284 --> 00:09:13,387 +运行此脚本作为 +按钮的 onclick 处理程序的响应 + +161 +00:09:13,420 --> 00:09:16,490 +是满足该要求的多种方式之一 + +162 +00:09:16,523 --> 00:09:18,926 +用户点击该按钮之后 + +163 +00:09:18,959 --> 00:09:22,062 +这里就有了推送订阅的请求代码 + +164 +00:09:22,095 --> 00:09:24,831 +我将对这几点进行更深层次的探讨 + +165 +00:09:24,865 --> 00:09:29,236 +首先 我们需要配置推送订阅请求 + +166 +00:09:29,269 --> 00:09:32,673 +重要的一点是在我们的服务器上 +使用公钥 + +167 +00:09:32,706 --> 00:09:36,510 +到 Apple 推送服务器上识别自已 + +168 +00:09:36,543 --> 00:09:41,815 +这里 我们使用的标准技术叫做 VAPID +和其他浏览器一样 + +169 +00:09:41,849 --> 00:09:45,485 +有时候 我们不会再 +在这里重复 VAPID 的细节 + +170 +00:09:45,519 --> 00:09:47,654 +但是网上有资源来帮助您 + +171 +00:09:47,688 --> 00:09:51,391 +在您的的服务器设置中 +使用最好的解决方案 + +172 +00:09:51,425 --> 00:09:56,163 +有了 VAPID 密钥集 +我们就准备好配置订阅请求了 + +173 +00:09:56,196 --> 00:09:59,132 +请注意 我们明确说明 + +174 +00:09:59,166 --> 00:10:03,070 +我们承诺永远使推送用户可见 + +175 +00:10:03,103 --> 00:10:06,406 +当 JavaScript Push API 标准 + +176 +00:10:06,440 --> 00:10:09,676 +选择在 JavaScript 运行时 + +177 +00:10:09,710 --> 00:10:13,914 +对推送不予回应 +是大多数浏览器所不予支持的 + +178 +00:10:13,947 --> 00:10:16,216 +Safari 浏览器不支持这种情况 + +179 +00:10:16,250 --> 00:10:20,821 +和大多数网站一样 +Browser Pet 不需要这种情况 + +180 +00:10:20,854 --> 00:10:23,924 +然后我们请求推送权限 + +181 +00:10:23,957 --> 00:10:26,660 +对于权限提示中的 +这行 JavaScript 结果 + +182 +00:10:26,693 --> 00:10:30,063 +用户可以选择批准或拒绝 + +183 +00:10:30,097 --> 00:10:32,032 +假设用户授予权限 + +184 +00:10:32,065 --> 00:10:34,568 +为了 Browser Pet +所有 Safari 浏览器团队成员都会这样做 + +185 +00:10:34,601 --> 00:10:37,237 +这会给我们一个 +PushSubscription 对象 + +186 +00:10:37,271 --> 00:10:40,374 +它详细说明了如何在用户们的 +浏览器中接触到他们 + +187 +00:10:40,407 --> 00:10:44,244 +URL 端点以及密钥等 + +188 +00:10:44,278 --> 00:10:47,114 +可用于把中转的推送消息加密 + +189 +00:10:47,147 --> 00:10:51,218 +最后 我们需要把所有这些细节 +发送到我们的服务器上 + +190 +00:10:51,251 --> 00:10:54,955 +正如先前所说 基于您的具体应用 + +191 +00:10:54,988 --> 00:10:57,391 +具体情况会有所不同 + +192 +00:10:57,424 --> 00:11:00,961 +我们的 BrowserPet 服务器 +使用 WordPress + +193 +00:11:00,994 --> 00:11:04,097 +已经有一些插件用于支持 +标准网页推送 + +194 +00:11:04,131 --> 00:11:07,334 +很可能您在后端会发现同样的情况 + +195 +00:11:07,367 --> 00:11:10,337 +而且网上有资源 +能帮助找到几乎任何设置的 + +196 +00:11:10,370 --> 00:11:12,139 +正确解决方案 + +197 +00:11:12,172 --> 00:11:16,009 +现在我们需要回到 +我们的 Service Worker JavaScript 代码 + +198 +00:11:16,043 --> 00:11:20,681 +它需要处理一些 +从推送事件开始的新事件 + +199 +00:11:20,714 --> 00:11:25,118 +当推送消息从 Browser Pet 服务器 +换到这个浏览器时 + +200 +00:11:25,152 --> 00:11:28,655 +这个 Service Worker +就会收到一个推送事件 + +201 +00:11:28,689 --> 00:11:32,092 +这个引用名 +包含 PushMessageData 对象 + +202 +00:11:32,125 --> 00:11:35,929 +获取您的服务器发送的数据 +有多种方式 + +203 +00:11:35,963 --> 00:11:39,066 +我们在这里使用 JSON 访问器 + +204 +00:11:39,099 --> 00:11:41,468 +记住 当我们订阅推送时 + +205 +00:11:41,502 --> 00:11:45,005 +我们承诺的 JavaScript +始终是用户可见的吗 + +206 +00:11:45,038 --> 00:11:48,408 +这意味着我们在响应每次推送时 + +207 +00:11:48,442 --> 00:11:50,744 +必须始终显示为平台本机通知 + +208 +00:11:50,777 --> 00:11:55,249 +最好在您的推送事件处理中 +尽早执行此操作 + +209 +00:11:55,282 --> 00:11:57,818 +我们正全力从那个 JSON blob 中 + +210 +00:11:57,851 --> 00:12:02,656 +配置通知 包括使用 URL 设置操作 + +211 +00:12:02,689 --> 00:12:05,325 +这很快就会派上用场 + +212 +00:12:05,359 --> 00:12:09,897 +显示通知后 我们需要让用户点击它 + +213 +00:12:09,930 --> 00:12:13,333 +我们的 Service Worker 脚本 +还有一个事件要处理 + +214 +00:12:13,367 --> 00:12:18,005 +在这个 notificationclick 处理程序中 +BrowserPet 将从被点击的通知中 + +215 +00:12:18,038 --> 00:12:21,408 +获取 URL 以打开一个新窗口 + +216 +00:12:21,441 --> 00:12:24,178 +注意 这是一种非常常见的模式 + +217 +00:12:24,211 --> 00:12:28,782 +这是所有我们需要写入的 JavaScript +我们需要用它来支持网页推送 + +218 +00:12:28,815 --> 00:12:31,818 +当然 最好是在开发过程中 +获得一些帮助 + +219 +00:12:31,852 --> 00:12:35,556 +和往常一样 +这是 Web Inspector 的用武之地 + +220 +00:12:35,589 --> 00:12:39,059 +除了帮助 +您的网站在浏览器选项卡中打开 + +221 +00:12:39,092 --> 00:12:42,629 +Web Inspector 还可以检查 +Service Worker 实例 + +222 +00:12:42,663 --> 00:12:45,365 +并在事件处理程序上设置断点 + +223 +00:12:45,399 --> 00:12:48,836 +这一切会让您检查和调试 + +224 +00:12:48,869 --> 00:12:52,206 +订阅推送的 JavaScript +以及处理推送事件 + +225 +00:12:52,239 --> 00:12:55,776 +和通知事件的服务人员代码 + +226 +00:12:55,809 --> 00:12:59,012 +此外 Apple 推送通知服务器 + +227 +00:12:59,046 --> 00:13:01,682 +在您试图发布推送消息的时候 + +228 +00:13:01,715 --> 00:13:04,384 +如果出现了问题 +那么就会出现一些人类可读性错误 + +229 +00:13:04,418 --> 00:13:08,789 +查看与这次讲座相关的更多链接 +以获取更多资料 + +230 +00:13:08,822 --> 00:13:12,492 +在编写该代码时 我想就用户隐私 + +231 +00:13:12,526 --> 00:13:14,828 +和电源使用提出的几点 + +232 +00:13:14,862 --> 00:13:17,931 +进行更详细的讲解 + +233 +00:13:17,965 --> 00:13:20,868 +重要的是 我不是第一次这么说了 + +234 +00:13:20,901 --> 00:13:24,538 +订阅推送需要用户手势 + +235 +00:13:24,571 --> 00:13:28,041 +与其他网络平台的特权功能一样 + +236 +00:13:28,075 --> 00:13:30,410 +对于用户来说 在实际当中 + +237 +00:13:30,444 --> 00:13:34,481 +要求用户在启用网页推送时 +先回答问题是正确的选择 + +238 +00:13:34,515 --> 00:13:38,986 +正如我向您展示代码时所提到的 +关于如何请求推送订阅一样 + +239 +00:13:39,019 --> 00:13:42,856 +您必须保证 +推送的内容是用户可见的 + +240 +00:13:42,890 --> 00:13:46,393 +处理推送事件 +对您的 JavaScript 来说 + +241 +00:13:46,426 --> 00:13:48,662 +并不是让您获得静默后台运行 + +242 +00:13:48,695 --> 00:13:53,534 +这样做会破坏用户的信任 +和用户的电池寿命 + +243 +00:13:53,567 --> 00:13:56,837 +事实上 在处理推送事件时 您必须 + +244 +00:13:56,870 --> 00:13:59,773 +向通知中心发送通知 + +245 +00:13:59,806 --> 00:14:03,744 +其它浏览器都有 +用以确保推送用户可见的 + +246 +00:14:03,777 --> 00:14:07,181 +反对违反承诺对策 +Safari 浏览器也是如此 + +247 +00:14:07,214 --> 00:14:10,984 +在 macOS Ventura 的 Beta 版本中 +在三个推送事件之后 + +248 +00:14:11,018 --> 00:14:14,188 +您未能及时发布通知 + +249 +00:14:14,221 --> 00:14:16,857 +您网站的推送订阅将被撤销 + +250 +00:14:16,890 --> 00:14:19,893 +您将需要通过 +再次访问权限的工作流程 + +251 +00:14:19,927 --> 00:14:21,695 +就是这样 + +252 +00:14:21,728 --> 00:14:26,466 +我们为支持网页推送感到由衷的自豪 +并且很高兴任何网站都可以使用它 + +253 +00:14:26,500 --> 00:14:29,203 +无需 Apple 开发者帐户 + +254 +00:14:29,236 --> 00:14:33,073 +只要您按照标准编码并使用功能检测 + +255 +00:14:33,106 --> 00:14:37,010 +您就不会在不知不觉中排除 Safari 浏览器 +您的用户就会 + +256 +00:14:37,044 --> 00:14:41,448 +在 macOS Ventura 上的 Safari 16 中 +获得网页推送的好处 + +257 +00:14:41,481 --> 00:14:45,652 +和往常一样 今年我们已经为 Safari 浏览器 +和 WebKit 添加了很多其它的新功能 + +258 +00:14:45,686 --> 00:14:48,455 +我希望您能看一看那个讲座 +并了解更多 + +259 +00:14:48,488 --> 00:14:50,090 +感谢收看 + +260 +00:14:50,123 --> 00:14:53,727 +祝您余下的 +WWDC 2022 之旅一切顺利 + diff --git "a/zho/2022 Session 10099 What\342\200\231s new in Safari Web Extensions.srt" "b/zho/2022 Session 10099 What\342\200\231s new in Safari Web Extensions.srt" new file mode 100644 index 0000000..021ac93 --- /dev/null +++ "b/zho/2022 Session 10099 What\342\200\231s new in Safari Web Extensions.srt" @@ -0,0 +1,1586 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,810 --> 00:00:11,912 +Kiara Rose: 大家好 我是 Kiara Rose + +3 +00:00:11,945 --> 00:00:15,148 +我是一名 Safari 扩展工程师 + +4 +00:00:15,182 --> 00:00:19,353 +我今天非常开心能跟大家聊聊 + +5 +00:00:19,386 --> 00:00:22,823 +今年 +Safari Web Extensions 的新功能 + +6 +00:00:22,856 --> 00:00:25,259 +在我们开始今天的演讲之前 + +7 +00:00:25,292 --> 00:00:27,494 +我想花点时间感谢所有向 + +8 +00:00:27,528 --> 00:00:33,634 +App Store 提交 iOS iPadOS +和 macOS 扩展的人员 + +9 +00:00:33,667 --> 00:00:38,272 +展望未来 我们的目标是 +继续实施新功能和 API + +10 +00:00:38,305 --> 00:00:42,142 +以便你们可以为用户提供 +更好的使用体验 + +11 +00:00:42,176 --> 00:00:45,812 +今天 我将重点介绍我们去年生效的 + +12 +00:00:45,846 --> 00:00:48,515 +一些令人兴奋的新功能 + +13 +00:00:48,549 --> 00:00:52,052 +例如用于扩展的新 Manifest 版本 + +14 +00:00:52,085 --> 00:00:54,254 +更新的 API + +15 +00:00:54,288 --> 00:00:58,559 +以及跨多个设备同步扩展 + +16 +00:00:58,592 --> 00:01:01,261 +我们从 Manifest 版本 3 开始讲起 + +17 +00:01:02,062 --> 00:01:06,867 +Manifest 版本 3 是 web 扩展平台的 +下一个迭代 + +18 +00:01:06,900 --> 00:01:09,736 +它进行了性能和安全性提升 + +19 +00:01:09,770 --> 00:01:13,874 +并整合了流行的扩展 API + +20 +00:01:13,907 --> 00:01:18,478 +对于那些已经更新你的扩展 +到使用版本 3 的用户 + +21 +00:01:18,512 --> 00:01:23,283 +则现在可以在 Safari 15.4 +及更高版本中运行 + +22 +00:01:23,317 --> 00:01:26,386 +对于那些还没有更新的用户 +也不必担心 + +23 +00:01:26,420 --> 00:01:29,156 +因为我们将继续支持 +在 Safari 浏览器中 + +24 +00:01:29,189 --> 00:01:32,559 +使用 Manifest 版本 2 的扩展 + +25 +00:01:32,593 --> 00:01:35,362 +Manifest 版本 3 的一个关键新功能是 + +26 +00:01:35,395 --> 00:01:39,533 +你的扩展可以使用 service worker +而不是后台页面 + +27 +00:01:39,566 --> 00:01:43,470 +如果你是 Web 开发人员 +那么可能对 service worker 很熟悉 + +28 +00:01:43,504 --> 00:01:46,707 +这些是事件驱动的页面 +你可以在其中使用 + +29 +00:01:46,740 --> 00:01:50,110 +addEventListener API 注册监听 + +30 +00:01:50,143 --> 00:01:52,846 +这些页面还与支持 +Manifest 版本 3 的 + +31 +00:01:52,880 --> 00:01:55,682 +其他浏览器兼容 + +32 +00:01:55,716 --> 00:01:59,353 +如果你希望继续使用背景页面 + +33 +00:01:59,386 --> 00:02:03,790 +我们非常欢迎你们这样做 +但必须是暂时的 + +34 +00:02:03,824 --> 00:02:08,795 +版本 3 的另一个改进是 +在网页上执行 JavaScript + +35 +00:02:08,829 --> 00:02:14,301 +和样式 API 从标签 API +移到了新的脚本 API + +36 +00:02:15,269 --> 00:02:18,238 +这些方法的大部分功能保持不变 + +37 +00:02:18,272 --> 00:02:22,242 +但脚本提供了一些新的附加功能 + +38 +00:02:22,276 --> 00:02:26,313 +例如在网页上注入代码的新方法 + +39 +00:02:26,346 --> 00:02:31,218 +更多关于代码应该在页面上的 +哪些框架中执行的选项 + +40 +00:02:31,251 --> 00:02:36,924 +以及决定代码应该 +在哪个执行环境中运行的能力 + +41 +00:02:36,957 --> 00:02:39,860 +让我们看一下新脚本 API 的代码 + +42 +00:02:39,893 --> 00:02:42,629 +与选项卡 API 有何不同 + +43 +00:02:42,663 --> 00:02:46,733 +在此代码片段中 +我使用 tabs.executeScript API + +44 +00:02:46,767 --> 00:02:51,138 +将网页的背景色改为蓝色 + +45 +00:02:51,171 --> 00:02:55,576 +有了这个 API +我只能通过传递“代码”属性 + +46 +00:02:55,609 --> 00:02:58,278 +来注入包含在字符串中的代码 + +47 +00:02:58,312 --> 00:03:01,515 +但现在 使用新的脚本 API + +48 +00:03:01,548 --> 00:03:05,519 +我可以传递包含此代码的函数对象 + +49 +00:03:05,552 --> 00:03:07,487 +和任何其他函数一样 + +50 +00:03:07,521 --> 00:03:10,390 +它可以包含可以传入的参数 + +51 +00:03:10,424 --> 00:03:13,293 +这是一种更好的执行脚本方式 + +52 +00:03:13,327 --> 00:03:17,931 +因为你们不局限于 +用字符串编写代码 + +53 +00:03:17,965 --> 00:03:22,369 +注意 在编写脚本时 +有一个名为目标的新属性 + +54 +00:03:22,402 --> 00:03:26,540 +此属性用于指定脚本应该在何处运行 + +55 +00:03:26,573 --> 00:03:28,509 +为了执行脚本 + +56 +00:03:28,542 --> 00:03:33,347 +必须指定要在其中执行脚本的 +选项卡 ID + +57 +00:03:33,380 --> 00:03:37,651 +如果未指定选项卡 ID +此 API 将返回错误 + +58 +00:03:37,684 --> 00:03:41,321 +然后 如果你想选择 +注入代码的网页框架 + +59 +00:03:41,355 --> 00:03:45,726 +就可以指定框架 ID + +60 +00:03:45,759 --> 00:03:50,264 +请注意 使用选项卡 API +你只能指定一个 ID + +61 +00:03:50,297 --> 00:03:55,035 +但是使用脚本 可以指定多个 ID + +62 +00:03:55,068 --> 00:03:57,337 +但假设我有更多的代码 + +63 +00:03:57,371 --> 00:04:02,543 +如果我能把它包含在多个文件中 +就会看起来更简洁 + +64 +00:04:02,576 --> 00:04:05,379 +在 tabs.executeScript API 中 + +65 +00:04:05,412 --> 00:04:08,348 +我只能指定一个文件 + +66 +00:04:08,382 --> 00:04:13,654 +但在 scripting.executeScript 中 +我可以指定多个文件 + +67 +00:04:13,687 --> 00:04:17,224 +同样 该方法也可以用于 insertCSS + +68 +00:04:17,257 --> 00:04:20,594 +你可以在网页上注入样式 + +69 +00:04:20,627 --> 00:04:24,531 +removeCSS 也适用可以从网页上 + +70 +00:04:24,565 --> 00:04:26,066 +移除注入的样式 + +71 +00:04:26,099 --> 00:04:31,004 +这些 API +可用于 Manifest 版本 2 和 3 + +72 +00:04:31,038 --> 00:04:37,044 +但是 tabs.executeScript API +不适用于版本 3 + +73 +00:04:37,077 --> 00:04:39,513 +除了新的脚本 API + +74 +00:04:39,546 --> 00:04:43,717 +对其他 API 也进行了 +一些细微的改进 + +75 +00:04:43,750 --> 00:04:47,521 +其中一项就是针对 +web_accessible_resources + +76 +00:04:48,755 --> 00:04:52,893 +在 Manifest 版本 2 中 +如果你想要包含资源 + +77 +00:04:52,926 --> 00:04:55,996 +可以通过传递你想要 + +78 +00:04:56,029 --> 00:04:58,599 +网页访问的文件数组来实现 + +79 +00:04:58,632 --> 00:05:02,536 +但这可能会有问题 +因为它会让任何网页 + +80 +00:05:02,569 --> 00:05:06,139 +访问你在清单中指定的所有资源 + +81 +00:05:07,374 --> 00:05:09,977 +使用版本 3 中的新格式 + +82 +00:05:10,010 --> 00:05:14,948 +你可以控制任何 +给定站点上的可用资源 + +83 +00:05:14,982 --> 00:05:17,451 +我们看一个例子 + +84 +00:05:17,484 --> 00:05:20,654 +以前 cookie 和 pie 图像 + +85 +00:05:20,687 --> 00:05:23,757 +每个扩展的网站上都可以访问 + +86 +00:05:23,790 --> 00:05:26,126 +但是现在 使用版本 3 + +87 +00:05:26,159 --> 00:05:30,397 +我可以使 pie image +仅在 apple.com URL 上可用 + +88 +00:05:30,430 --> 00:05:34,501 +而 cookie 图像 +仅在 webkit.org 页面上可用 + +89 +00:05:34,535 --> 00:05:37,104 +现在让我们看看 + +90 +00:05:37,137 --> 00:05:40,274 +对 browser_action +和 page_action API 的改进 + +91 +00:05:41,608 --> 00:05:46,713 +在 Manifest 版本 2 中 +明确地指定这样操作 + +92 +00:05:46,747 --> 00:05:49,750 +但由于这些 API 功能相似 + +93 +00:05:49,783 --> 00:05:54,855 +因此它们在版本 3 中 +被合并为仅使用一个 API 即操作 + +94 +00:05:56,256 --> 00:05:59,860 +我们还更新了你为扩展声明 + +95 +00:05:59,893 --> 00:06:01,962 +内容安全策略的方式 + +96 +00:06:01,995 --> 00:06:06,900 +在版本 2 中 扩展的策略 +是使用字符串定义的 + +97 +00:06:06,934 --> 00:06:10,838 +但是 在版本 3 中 策略是 + +98 +00:06:10,871 --> 00:06:15,242 +使用带有键 extension_pages 的 +对象定义的 + +99 +00:06:15,275 --> 00:06:18,412 +请务必注意 版本 3 + +100 +00:06:18,445 --> 00:06:21,381 +不再支持远程脚本源 + +101 +00:06:21,415 --> 00:06:24,518 +最后的 API 更改是已弃用的 + +102 +00:06:24,551 --> 00:06:28,388 +browser.extension.getURL API + +103 +00:06:28,422 --> 00:06:31,658 +版本 3 不再支持此 API + +104 +00:06:31,692 --> 00:06:35,929 +相反 请使用 +browser.runtime 中的等效 API + +105 +00:06:35,963 --> 00:06:40,133 +所以我已经谈到了 +Manifest 版本 3 中推出的新功能 + +106 +00:06:40,167 --> 00:06:43,670 +现在让我们逐步完成更新扩展的过程 + +107 +00:06:43,704 --> 00:06:46,173 +以方便你们使用这些新功能 + +108 +00:06:47,774 --> 00:06:51,178 +我将从去年的演示中 +更新 Sea Creator 扩展 + +109 +00:06:51,211 --> 00:06:54,815 +以使用 Manifest 版本 3 + +110 +00:06:54,848 --> 00:07:00,020 +这个扩展用表情符号替换了 +所有出现的单词 fish + +111 +00:07:00,053 --> 00:07:04,491 +我要做的第一件事是将版本号 +从 2 更改为 3 + +112 +00:07:06,660 --> 00:07:10,163 +尽管我仍然可以在版本 3 中 +使用暂时性背景页面 + +113 +00:07:10,197 --> 00:07:13,967 +但我将对其进行更新 +以使用 service worker + +114 +00:07:14,001 --> 00:07:17,104 +这样我的扩展就可以 +与 Chrome 兼容了 + +115 +00:07:19,406 --> 00:07:23,510 +最后 我会将 browser_action +更改为 action + +116 +00:07:25,712 --> 00:07:28,315 +而就 Manifest 的结构而言 + +117 +00:07:28,348 --> 00:07:31,185 +这些是关键的变化 +我需要使这个扩展 + +118 +00:07:31,218 --> 00:07:34,521 +与版本 3 中的新规范兼容 + +119 +00:07:34,555 --> 00:07:40,360 +所以为了测试这个 我将构建扩展 + +120 +00:07:40,394 --> 00:07:42,763 +并在 Safari 浏览器中启用 + +121 +00:07:47,835 --> 00:07:51,505 +然后 导航到 webkit.org 博客页面 + +122 +00:07:51,538 --> 00:07:55,175 +在该页面中 我将使用此扩展程序 +将单词 fish 的每个实例 + +123 +00:07:55,209 --> 00:07:57,511 +替换为鱼表情符号 + +124 +00:07:59,213 --> 00:08:01,548 +但似乎出了点问题 + +125 +00:08:01,582 --> 00:08:05,686 +如你所见 此页面上的所有单词 +都没有被表情符号替换 + +126 +00:08:05,719 --> 00:08:08,822 +我们检查一下弹出框 +看看是否有任何错误消息 + +127 +00:08:15,429 --> 00:08:18,398 +在控制台选项卡中 +我看到有一条错误消息 + +128 +00:08:18,432 --> 00:08:22,836 +指出 browser.tabs.executeScript +未定义 + +129 +00:08:22,870 --> 00:08:26,907 +这是因为版本 3 中 +不再支持此 API + +130 +00:08:26,940 --> 00:08:31,879 +所以我应该更新扩展 +以使用新的脚本 API + +131 +00:08:31,912 --> 00:08:35,983 +在 Xcode 中 +我会回到 popup.js 文件 + +132 +00:08:36,016 --> 00:08:39,453 +然后将这一行改为使用脚本 + +133 +00:08:42,256 --> 00:08:44,291 +我会添加目标属性 + +134 +00:08:44,324 --> 00:08:48,328 +用于指定脚本应注入的位置 + +135 +00:08:50,230 --> 00:08:52,232 +使用新的脚本 API + +136 +00:08:52,266 --> 00:08:54,735 +我必须指定选项卡的 ID + +137 +00:08:54,768 --> 00:08:57,838 +可以通过使用 tabs.getCurrent API + +138 +00:08:57,871 --> 00:09:01,308 +来获取包含当前选项卡信息的对象 +来做到这一点 + +139 +00:09:08,048 --> 00:09:12,319 +然后我可以使用该对象 +来检索选项卡 ID + +140 +00:09:15,556 --> 00:09:18,892 +接下来 +添加包含要运行的脚本的文件 + +141 +00:09:21,094 --> 00:09:24,565 +最后 我要做的最后一个更改 +是在 Manifest 中 + +142 +00:09:24,598 --> 00:09:26,466 +添加脚本权限 + +143 +00:09:29,803 --> 00:09:34,608 +我将继续构建扩展 + +144 +00:09:34,641 --> 00:09:38,278 +并在 Safari 浏览器中使用这些更改 + +145 +00:09:38,312 --> 00:09:41,682 +如你所见 此扩展现在 +可以在 Safari 浏览器中使用 + +146 +00:09:41,715 --> 00:09:44,318 +使用 Manifest 版本 3 中的新功能 + +147 +00:09:44,351 --> 00:09:47,221 +这就是升级你的扩展是多么简单 + +148 +00:09:47,254 --> 00:09:49,990 +但是 如果你对这些新变化还不满意 + +149 +00:09:50,023 --> 00:09:53,193 +那么许多功能 例如脚本 +和 services workers + +150 +00:09:53,227 --> 00:09:56,230 +也可以在版本 2 中使用 + +151 +00:09:56,263 --> 00:10:00,834 +现在让我们看看今年更新的一些 API + +152 +00:10:00,868 --> 00:10:03,437 +从 declarative net request 开始 + +153 +00:10:03,470 --> 00:10:06,607 +declarative net request +是一种内容阻止 API + +154 +00:10:06,640 --> 00:10:10,878 +它为 web 扩展提供了一种 +快速且保护隐私的方式 + +155 +00:10:10,911 --> 00:10:15,182 +以使用规则集阻止或修改网络请求 + +156 +00:10:15,215 --> 00:10:18,819 +此 API 允许你将拦截 +和修改请求的所有工作 + +157 +00:10:18,852 --> 00:10:22,723 +委托给 Safari 浏览器 +你所要做的就是 + +158 +00:10:22,756 --> 00:10:26,293 +指定该应用的内容屏蔽规则 + +159 +00:10:26,326 --> 00:10:29,396 +你可以在 Manifest 中指定规则集 + +160 +00:10:30,831 --> 00:10:34,468 +我在这里添加了 +declarative net request 权限 + +161 +00:10:34,501 --> 00:10:37,204 +并使用 declarative_net_request 键 +添加了 + +162 +00:10:37,237 --> 00:10:40,541 +一个应该应用于所有页面的规则集 + +163 +00:10:40,574 --> 00:10:45,245 +以前 我最多只能在 Manifest 中 +声明 10 个规则集 + +164 +00:10:45,279 --> 00:10:48,282 +但是现在有了对该功能的更新 + +165 +00:10:48,315 --> 00:10:50,617 +你可以声明多达 50 个规则集 + +166 +00:10:50,651 --> 00:10:54,488 +这意味着你的扩展 +可自定义程度更高 + +167 +00:10:54,521 --> 00:10:59,760 +但是请记住 一次只能启用 +其中的 10 个规则集 + +168 +00:10:59,793 --> 00:11:03,297 +关于如何创建规则集的更多信息 + +169 +00:11:03,330 --> 00:11:06,700 +请查看去年关于 +Safari Web Extensions 的演讲 + +170 +00:11:06,733 --> 00:11:09,703 +我们对这个 API 进行了 +更深入的介绍 + +171 +00:11:09,736 --> 00:11:13,841 +让我们继续讨论 +declarative net request 的一些新功能 + +172 +00:11:13,874 --> 00:11:17,778 +以前 你只能在 Manifest 中 +声明规则集 + +173 +00:11:17,811 --> 00:11:21,515 +但现在我们实现了以下两个 API + +174 +00:11:21,548 --> 00:11:25,118 +可让你动态更新规则 + +175 +00:11:25,152 --> 00:11:28,322 +第一个 API 是 updateSessionRules + +176 +00:11:28,355 --> 00:11:31,959 +它允许你为扩展添加或删除规则 + +177 +00:11:31,992 --> 00:11:35,195 +但是需要注意的是 这些规则不会在 + +178 +00:11:35,229 --> 00:11:39,266 +浏览器会话或扩展更新中持续存在 + +179 +00:11:39,299 --> 00:11:41,902 +如果你想更新持久化的规则 + +180 +00:11:41,935 --> 00:11:45,839 +请使用 updateDynamicRules API + +181 +00:11:45,873 --> 00:11:48,141 +这将允许你在不更新 +整个扩展程序的情况下 + +182 +00:11:48,175 --> 00:11:50,777 +更新阻止规则 + +183 +00:11:50,811 --> 00:11:53,547 +让我们看看如何使用这些 API 之一 + +184 +00:11:53,580 --> 00:11:56,984 +来修改我们的规则集 + +185 +00:11:57,017 --> 00:12:01,788 +我将使用 sea creator 扩展 +来阻止网页上的一些内容 + +186 +00:12:01,822 --> 00:12:06,827 +然后 我将使用新的 API 来 +解除对选定页面上内容的阻止 + +187 +00:12:06,860 --> 00:12:09,563 +在扩展 Manifest 中 +我要做的第一件事 + +188 +00:12:09,596 --> 00:12:11,932 +是添加 +declarative net request 权限 + +189 +00:12:15,235 --> 00:12:20,040 +然后 我将使用 declarative net request 键 +来添加一个规则集 + +190 +00:12:24,912 --> 00:12:30,517 +正在应用的规则位于 +rules.json 文件中 + +191 +00:12:30,551 --> 00:12:36,356 +在这个文件中 我声明了一个规则 +它阻止所有 URL 上的所有图像 + +192 +00:12:36,390 --> 00:12:40,394 +我们构建这个扩展 +看看如何在 Safari 浏览器中应用此规则 + +193 +00:12:43,664 --> 00:12:47,267 +如你所见 此页面上的图像已经消失 + +194 +00:12:47,301 --> 00:12:49,736 +这正是我们所期望的 + +195 +00:12:49,770 --> 00:12:54,608 +这表明 Safari 浏览器已经成功地 +应用了我们的内容屏蔽规则 + +196 +00:12:54,641 --> 00:12:58,178 +如果我浏览维基百科关于鱼的页面 + +197 +00:12:58,212 --> 00:13:01,682 +我会看到这个网站上的图片 +也被阻止了 + +198 +00:13:01,715 --> 00:13:05,352 +但是假设我们想要更新我们的规则 +来阻止除 webkit.org 博客 + +199 +00:13:05,385 --> 00:13:09,022 +页面外的所有页面上的图像 + +200 +00:13:09,056 --> 00:13:12,993 +使用 declarative net request 的 +更新 API 之一 + +201 +00:13:13,026 --> 00:13:16,496 +我们可以做到这一点 + +202 +00:13:16,530 --> 00:13:20,067 +让我们回到 Xcode 并进行一些调整 + +203 +00:13:20,100 --> 00:13:22,002 +在 popup.js 文件中 + +204 +00:13:22,035 --> 00:13:25,806 +我将声明一个函数来更新 +我们的内容阻止规则 + +205 +00:13:28,275 --> 00:13:33,547 +我将把规则设置为允许在 +webkit.org/blog-files 页面上显示图像 + +206 +00:13:33,580 --> 00:13:39,987 +然后 我将使用 updateSessionRules API +将此规则添加到我们的规则集 + +207 +00:13:40,020 --> 00:13:44,725 +最后 我将构建扩展并在 +Safari 浏览器中测试所做的更改 + +208 +00:13:48,462 --> 00:13:52,099 +如你所见 +此博客文章中的图片已加载 + +209 +00:13:52,132 --> 00:13:56,370 +表明我们允许此站点上 +显示图片的新规则已生效 + +210 +00:13:56,403 --> 00:13:58,605 +如果我去维基百科网站 + +211 +00:13:58,639 --> 00:14:01,942 +我们会看到这个页面上的 +图像仍然被屏蔽 + +212 +00:14:01,975 --> 00:14:05,579 +这表明新规则没有应用到这个页面 + +213 +00:14:05,612 --> 00:14:08,549 +以上就是使用新的 +eclarative net request API + +214 +00:14:08,582 --> 00:14:11,018 +来更新内容阻止规则的方法 + +215 +00:14:12,219 --> 00:14:17,024 +现在 我们看看你的扩展 +如何与网页进行通信 + +216 +00:14:17,057 --> 00:14:20,994 +如果用户启用了你的扩展程序 + +217 +00:14:21,028 --> 00:14:24,431 +这个很棒的功能允许网站 +创建自定义行为 + +218 +00:14:24,464 --> 00:14:28,535 +该 API 称为外部可连接 + +219 +00:14:28,569 --> 00:14:32,940 +要想使用它 +你需要在 Manifest 中声明匹配模式 + +220 +00:14:32,973 --> 00:14:37,344 +这些匹配模式决定哪些页面 +可以与你的扩展通信 + +221 +00:14:39,313 --> 00:14:43,250 +需要注意的重要一点是 +该功能仅在 + +222 +00:14:43,283 --> 00:14:45,986 +使用浏览器名称空间时有效 + +223 +00:14:46,019 --> 00:14:50,324 +最后 用户必须授予你对页面的 +扩展访问权限 + +224 +00:14:50,357 --> 00:14:54,628 +然后才能发送或接收消息 + +225 +00:14:54,661 --> 00:14:59,433 +让我们来看看为了使用这个功能 +而在 web 页面中添加的代码 + +226 +00:14:59,466 --> 00:15:02,703 +首先 你需要获取 extensionID + +227 +00:15:02,736 --> 00:15:04,905 +它是此格式的扩展包标识符 + +228 +00:15:04,938 --> 00:15:08,175 +和团队标识符 + +229 +00:15:08,208 --> 00:15:11,979 +你可以在 developer.apple.com 上的 +帐户设置的 + +230 +00:15:12,012 --> 00:15:14,982 +会员选项中找到你的团队标识符 + +231 +00:15:15,015 --> 00:15:21,455 +然后 你将使用发送消息 API +将消息发布到扩展程序 + +232 +00:15:21,488 --> 00:15:24,391 +你可以通过传递函数来处理 + +233 +00:15:24,424 --> 00:15:27,294 +从扩展接收到的响应 + +234 +00:15:27,327 --> 00:15:30,063 +现在让我们看一下你的扩展程序 + +235 +00:15:30,097 --> 00:15:32,199 +必须接收消息的代码 + +236 +00:15:32,232 --> 00:15:34,768 +你的扩展可以通过监听 +onMessageExternal 事件 + +237 +00:15:34,801 --> 00:15:38,672 +接收来自网页的消息 + +238 +00:15:38,705 --> 00:15:41,675 +扩展可以使用传递给 +事件监听器的方法 + +239 +00:15:41,708 --> 00:15:45,045 +将消息发送回网页 + +240 +00:15:45,078 --> 00:15:49,383 +因为不同的浏览器有 +不同的扩展 web 存储 + +241 +00:15:49,416 --> 00:15:52,252 +扩展可以有许多不同的标识符 + +242 +00:15:52,286 --> 00:15:55,622 +因此 你需要确定要使用 + +243 +00:15:55,656 --> 00:15:58,692 +正确的 以确保正在 +向 Safari 浏览器网络扩展发送消息 + +244 +00:15:58,725 --> 00:16:01,528 +而不是 Chrome 或 Edge 扩展 + +245 +00:16:01,562 --> 00:16:07,167 +为此 你可以使用 +browser.runtime.sendMessage API + +246 +00:16:07,201 --> 00:16:10,704 +并调用 Promise.all + +247 +00:16:10,737 --> 00:16:16,143 +接下来 让我们看一些示例代码 +来帮助你执行此操作 + +248 +00:16:16,176 --> 00:16:19,379 +在网页上 你可以通过多个扩展名 + +249 +00:16:19,413 --> 00:16:21,715 +广播多条消息 + +250 +00:16:21,748 --> 00:16:24,751 +会从扩展中得到确切的响应 + +251 +00:16:24,785 --> 00:16:30,791 +这会让你知道使用哪个 +扩展 ID 来进行进一步的通信 + +252 +00:16:30,824 --> 00:16:36,363 +在这里 我有一个名为 +determineExtensionID 的函数 + +253 +00:16:36,396 --> 00:16:39,066 +此函数向扩展发送消息 + +254 +00:16:39,099 --> 00:16:43,370 +通过使用 +browser.runtime.sendMessage API + +255 +00:16:43,403 --> 00:16:46,173 +如果你有多个 ID 并且想确定 + +256 +00:16:46,206 --> 00:16:50,077 +要使用的正确 ID +则可以使用 Promise.all + +257 +00:16:50,110 --> 00:16:55,249 +进行多次调用 +使用确定扩展 ID 函数 + +258 +00:16:55,282 --> 00:16:59,386 +Promise.all 接受一个 Promise 数组 +然后返回一个 + +259 +00:16:59,419 --> 00:17:03,223 +带有所有已解析值数组的 Promise + +260 +00:17:03,257 --> 00:17:08,195 +你可以使用此数组 +来查找用户已安装的扩展 + +261 +00:17:08,228 --> 00:17:10,364 +在扩展程序的后台页面中 + +262 +00:17:10,397 --> 00:17:14,334 +你需要收听来自网页的消息 + +263 +00:17:14,368 --> 00:17:17,304 +当你收到消息时 +需要发回一条消息 + +264 +00:17:17,337 --> 00:17:20,874 +告诉网页你的扩展程序已安装 + +265 +00:17:20,908 --> 00:17:24,244 +这就是使用新的 +externally_connectable API + +266 +00:17:24,278 --> 00:17:28,081 +来允许你的扩展程序 +与网页通信的方式 + +267 +00:17:28,115 --> 00:17:31,251 +我们更新的下一个功能 +是我个人最喜欢的 + +268 +00:17:31,285 --> 00:17:33,420 +无限存储 + +269 +00:17:33,453 --> 00:17:37,824 +我很高兴地宣布 +unlimitedStorage 实际上是无限的 + +270 +00:17:37,858 --> 00:17:41,328 +鉴于你们对这个功能的要求很高 + +271 +00:17:41,361 --> 00:17:46,567 +我们很高兴地分享你的扩展程序 +将不再有 10 MB 的配额 + +272 +00:17:46,600 --> 00:17:50,404 +而是可以随意使用尽可能多的数据 + +273 +00:17:50,437 --> 00:17:52,773 +虽然 重要的是要注意 + +274 +00:17:52,806 --> 00:17:55,976 +用户可以在任何给定的时间 + +275 +00:17:56,009 --> 00:17:59,313 +清除数据正在使用的扩展 + +276 +00:17:59,346 --> 00:18:02,616 +因此 请确保只存储严格必要的数据 + +277 +00:18:02,649 --> 00:18:06,386 +这样用户就不会倾向于 +清除你的数据 + +278 +00:18:06,420 --> 00:18:10,557 +只需 storage +和 unlimitedStorage 权限 + +279 +00:18:10,591 --> 00:18:14,361 +在 Manifest 中声明就可以了 + +280 +00:18:14,394 --> 00:18:18,999 +以上就是我们去年 +为 Web 扩展更新的所有 API + +281 +00:18:19,032 --> 00:18:23,470 +最后 让我们谈谈一个新功能 +它可以让你的用户 + +282 +00:18:23,504 --> 00:18:27,274 +轻松地在他们的所有设备上 +获取你的扩展程序 + +283 +00:18:27,307 --> 00:18:33,480 +在 Safari 16 中 我们创造了 +使用扩展程序更加无缝的体验 + +284 +00:18:33,514 --> 00:18:37,184 +如果用户在他们的 +一台设备上打开你的扩展程序 + +285 +00:18:37,217 --> 00:18:40,821 +它将在他们的所有设备上打开 + +286 +00:18:40,854 --> 00:18:46,927 +最重要的是 我们使 +下载扩展程序的过程变得更加简单 + +287 +00:18:46,960 --> 00:18:49,129 +让我们看看这是如何工作的 + +288 +00:18:49,162 --> 00:18:53,901 +假设用户在他们的 Mac 上 +启用了你的扩展之一 + +289 +00:18:53,934 --> 00:18:57,404 +在他们任何其他设备上的 +Extension Setting 中 + +290 +00:18:57,437 --> 00:19:00,440 +可以选择下载你的扩展程序 + +291 +00:19:00,474 --> 00:19:03,510 +下载后 在它们的设备上 + +292 +00:19:03,544 --> 00:19:07,781 +会自动启用 +从而改善它们的用户体验 + +293 +00:19:07,814 --> 00:19:10,851 +现在 让我们深入了解 +如何为 Web 扩展 + +294 +00:19:10,884 --> 00:19:13,487 +和内容拦截器进行设置 + +295 +00:19:13,520 --> 00:19:17,925 +首先 我们建议你提交到 App Store 时 +列出适用于 iOS + +296 +00:19:17,958 --> 00:19:22,329 +iPadOS 和 macOS 的扩展程序 + +297 +00:19:22,362 --> 00:19:28,001 +这样 你的扩展程序 +将可在所有用户的设备上使用 + +298 +00:19:28,035 --> 00:19:31,839 +然后 为了让你的扩展程序 +在他们的设备上同步 + +299 +00:19:31,872 --> 00:19:35,375 +你需要使用以下两种方法之一 + +300 +00:19:35,409 --> 00:19:37,945 +最简单和推荐的方法 + +301 +00:19:37,978 --> 00:19:41,782 +就是采用通用购买 + +302 +00:19:41,815 --> 00:19:46,653 +通用购买允许用户 +在所有平台上享受你的扩展 + +303 +00:19:46,687 --> 00:19:49,690 +只需购买一次 + +304 +00:19:49,723 --> 00:19:52,826 +如果使用此方法 则一切就绪 + +305 +00:19:52,860 --> 00:19:55,128 +你的用户将在 +下载你的扩展程序一次后 + +306 +00:19:55,162 --> 00:19:58,999 +获得我展示的所有功能 + +307 +00:19:59,032 --> 00:20:00,934 +要设置通用购买 + +308 +00:20:00,968 --> 00:20:03,704 +你需要在扩展程序中 +使用单个捆绑标识符 + +309 +00:20:03,737 --> 00:20:08,242 +以便它可以关联 +App Store Connect 中的 + +310 +00:20:08,275 --> 00:20:11,411 +同一个应用记录 + +311 +00:20:11,445 --> 00:20:14,014 +有关如何执行此操作的更多信息 + +312 +00:20:14,047 --> 00:20:17,551 +查看我们的文档 +了解如何为你的扩展 + +313 +00:20:17,584 --> 00:20:19,353 +设置通用购买 + +314 +00:20:19,386 --> 00:20:22,022 +但如果你选择不设置通用购买 + +315 +00:20:22,055 --> 00:20:24,491 +可以手动链接你的 App + +316 +00:20:24,525 --> 00:20:29,162 +为此 你将使用 Xcode 在信息列表中 + +317 +00:20:29,196 --> 00:20:32,432 +为你想要同步的 App +和扩展添加捆绑标识符 + +318 +00:20:32,466 --> 00:20:36,503 +要将你的 iOS app +和扩展程序与 macOS 同步 + +319 +00:20:36,537 --> 00:20:40,407 +你需要使用信息列表中的特定键 + +320 +00:20:40,440 --> 00:20:44,178 +你将把这个密钥 +放在你的 macOS app 列表中 + +321 +00:20:44,211 --> 00:20:48,215 +以及 macOS 扩展列表中的这个密钥 + +322 +00:20:48,248 --> 00:20:53,720 +同样 你将遵循相同的过程 +来同步 macOS app + +323 +00:20:53,754 --> 00:20:58,125 +通过将此密钥添加到 iOS app 列表 + +324 +00:20:58,158 --> 00:21:01,962 +并将此密钥添加到 iOS 扩展列表 + +325 +00:21:01,995 --> 00:21:04,364 +让我们看看在 Xcode 中是如何工作的 + +326 +00:21:04,398 --> 00:21:09,670 +在 Xcode 中 我们需要做的第一件事 +是更新每个目标的设置 + +327 +00:21:09,703 --> 00:21:14,341 +以包括我们想要同步的扩展 +和 App 的包标识符 + +328 +00:21:14,374 --> 00:21:18,712 +我将首先在 iOS app 的信息列表中 +添加相应的 + +329 +00:21:18,745 --> 00:21:21,715 +macOS app 的包标识符 + +330 +00:21:24,051 --> 00:21:28,021 +可以看到 +我对 macOS app 做了相同的处理 + +331 +00:21:28,055 --> 00:21:30,991 +添加了 iOS app 包标识符 + +332 +00:21:31,024 --> 00:21:37,497 +同样 iOS 扩展也可以 +添加 macOS 扩展包标识符 + +333 +00:21:37,531 --> 00:21:40,133 +最后 为 macOS 扩展 + +334 +00:21:40,167 --> 00:21:43,871 +添加 iOS 扩展包标识符 + +335 +00:21:43,904 --> 00:21:46,874 +这就是将你的应用 +和扩展连接的简单之处 + +336 +00:21:46,907 --> 00:21:50,043 +这样你的用户 +就可以在任何地方使用它们 + +337 +00:21:50,077 --> 00:21:54,314 +总而言之 你可以让用户使用此功能 + +338 +00:21:54,348 --> 00:21:57,384 +通过设置通用购买 + +339 +00:21:57,417 --> 00:22:04,491 +或者在 Xcode 中为每 个iOS +和 macOS 应用和扩展添加捆绑标识符 + +340 +00:22:04,525 --> 00:22:08,896 +今天 我们讨论了 Manifest 版本 3 + +341 +00:22:08,929 --> 00:22:10,664 +我们更新的 API + +342 +00:22:10,697 --> 00:22:14,434 +和跨多个设备同步扩展 + +343 +00:22:14,468 --> 00:22:17,838 +我希望你和我一样 +对所有这些新功能感到兴奋 + +344 +00:22:17,871 --> 00:22:20,174 +用于 Safari Web 扩展 + +345 +00:22:20,207 --> 00:22:24,244 +敬请下载今天讲座的 +示例代码项目 + +346 +00:22:24,278 --> 00:22:28,315 +并使用我们提供的这些 API + +347 +00:22:28,348 --> 00:22:30,951 +接下来 我们很想知道你们的想法 + +348 +00:22:30,984 --> 00:22:34,021 +在 Safari Developer Forums 上 +使用反馈助手提交错误 + +349 +00:22:34,054 --> 00:22:37,057 +或与我们聊天 以提供 + +350 +00:22:37,090 --> 00:22:40,928 +有关我们如何更好地 +为你们开发扩展的反馈 + +351 +00:22:40,961 --> 00:22:43,397 +不 真的 我们想知道你们的想法 + +352 +00:22:43,430 --> 00:22:46,400 +考虑一下加入 WebExtensions 社区组 + +353 +00:22:46,433 --> 00:22:49,236 +来塑造 web 扩展的未来 + +354 +00:22:49,269 --> 00:22:55,108 +最后 看看我们在 WWDC 上 +关于创建 web 检查器扩展的演示 + +355 +00:22:55,142 --> 00:22:59,913 +感谢收看本期讲座 +祝你余下的 WWDC 之旅一切顺利 + diff --git a/zho/2022 Session 10100 Create Safari Web Inspector Extensions.srt b/zho/2022 Session 10100 Create Safari Web Inspector Extensions.srt new file mode 100644 index 0000000..8d71355 --- /dev/null +++ b/zho/2022 Session 10100 Create Safari Web Inspector Extensions.srt @@ -0,0 +1,1260 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:13,080 +Devin Rousso: 大家好 我是 Devin Rousso +WebKit 团队的一名工程师 + +3 +00:00:13,113 --> 00:00:16,250 +今天我想在这里与你分享 +一个激动人心的新机会 + +4 +00:00:16,283 --> 00:00:19,186 +为 Safari 浏览器的 +Web Inspector 创建扩展 + +5 +00:00:19,219 --> 00:00:22,589 +Web Inspector +是在所有 Apple 平台上 + +6 +00:00:22,623 --> 00:00:24,791 +调试网络内容的主要开发工具 + +7 +00:00:24,825 --> 00:00:29,162 +它已经有了大量 +用于调试网站的内置功能 + +8 +00:00:29,196 --> 00:00:31,231 +但是通常网络开发的一些领域 + +9 +00:00:31,265 --> 00:00:35,102 +很难构建成一个通用的开发工具 + +10 +00:00:35,135 --> 00:00:38,038 +也许你正在调试 +一个流行的 JavaScript 库 + +11 +00:00:38,071 --> 00:00:41,375 +或者你只是需要一些更具体的东西 + +12 +00:00:41,408 --> 00:00:44,077 +Web Inspector 扩展是这些 +个人工作流程场景的 + +13 +00:00:44,111 --> 00:00:46,313 +绝佳解决方案 + +14 +00:00:47,381 --> 00:00:51,818 +通过利用跨浏览器网络扩展 +和 DevTools APIs + +15 +00:00:51,852 --> 00:00:56,456 +你现在可以在 Safari 16 的 +Web Inspector 中添加自己的标签 + +16 +00:00:56,490 --> 00:00:59,793 +我们来快速浏览一下 +Web Inspector 扩展 + +17 +00:00:59,826 --> 00:01:02,162 +然后我将向你展示 +如何构建自己的扩展 + +18 +00:01:02,196 --> 00:01:05,265 +首先我将打开 +Safari 浏览器的扩展偏好设置 + +19 +00:01:07,701 --> 00:01:10,070 +并启用 Web Inspector 扩展 + +20 +00:01:10,103 --> 00:01:13,807 +然后我会关闭 Safari 浏览器的 +扩展偏好设置并检查页面 + +21 +00:01:15,409 --> 00:01:19,046 +我将从开发菜单中选择 +显示 Web Inspector + +22 +00:01:19,079 --> 00:01:22,416 +在 Web Inspector 中 +我不仅可以看到许多内置的选项卡 + +23 +00:01:22,449 --> 00:01:23,951 +如 Elements Tab + +24 +00:01:23,984 --> 00:01:28,121 +还可以看到我刚刚启用的 +Web Inspector 扩展的选项卡 + +25 +00:01:28,155 --> 00:01:30,591 +因为我们刚刚启用了这个扩展 + +26 +00:01:30,624 --> 00:01:34,628 +但是我们首先必须给它权限 +来处理当前检查的页面 + +27 +00:01:34,661 --> 00:01:37,965 +我有和 Web Inspector 之外的 + +28 +00:01:37,998 --> 00:01:39,700 +其他扩展相同的权限持续时间选项 + +29 +00:01:39,733 --> 00:01:42,336 +所以现在让我们给它一天的访问权限 + +30 +00:01:42,369 --> 00:01:45,839 +我将在本期讲座中 +构建这个 Open Graph 扩展 + +31 +00:01:45,873 --> 00:01:49,810 +它显示大多数网站放在页面上的 +常见社交媒体元数据 + +32 +00:01:49,843 --> 00:01:52,012 +通过 Messages +和其他社交媒体网站的链接 + +33 +00:01:52,045 --> 00:01:54,882 +预览使用 + +34 +00:01:54,915 --> 00:01:58,552 +现在我们已经快速了解了 +Web Inspector 扩展的功能 + +35 +00:01:58,585 --> 00:02:00,687 +让我们来谈谈它们是如何构建的 + +36 +00:02:00,721 --> 00:02:03,757 +与其他 Safari Web 扩展一样 +Web Inspector 扩展 + +37 +00:02:03,790 --> 00:02:06,527 +通过 App Store 中的 App 来分发 + +38 +00:02:07,961 --> 00:02:11,798 +要构建自己的 Web Inspector 扩展 +你需要有 Xcode + +39 +00:02:11,832 --> 00:02:15,936 +这是 Apple 用于构建 Mac +和 iOS app 的应用程序创建工具 + +40 +00:02:15,969 --> 00:02:19,273 +Xcode 还附带项目模板 +以帮助快速制作 + +41 +00:02:19,306 --> 00:02:21,408 +新的 Safari 浏览器扩展 App + +42 +00:02:21,441 --> 00:02:23,777 +如果你已经有了为另一个浏览器 + +43 +00:02:23,810 --> 00:02:25,512 +创建的现有网络扩展 + +44 +00:02:25,546 --> 00:02:28,815 +你也可以使用 Xcode 的 +捆绑转换工具 + +45 +00:02:28,849 --> 00:02:32,219 +只需从终端运行 +safari-web-extension-converter + +46 +00:02:32,252 --> 00:02:34,621 +传递包含 manifest.json 文件的 + +47 +00:02:34,655 --> 00:02:37,491 +扩展目录的路径 + +48 +00:02:37,524 --> 00:02:40,527 +然后将为你的扩展 +创建一个完整的 App 项目 + +49 +00:02:40,561 --> 00:02:42,029 +并准备好构建和运行 + +50 +00:02:43,197 --> 00:02:44,932 +有关此工具的更多信息 + +51 +00:02:44,965 --> 00:02:48,836 +请查看 WWDC 2020 中的 + +52 +00:02:48,869 --> 00:02:50,971 +Meet Safari Web Extensions +以及在线文档 + +53 +00:02:51,004 --> 00:02:56,476 +因此 今天我将介绍 +Web Inspector 扩展的基本结构 + +54 +00:02:56,510 --> 00:03:00,147 +介绍如何最好地评估该扩展中的代码 + +55 +00:03:00,180 --> 00:03:03,650 +并讨论一些适合用户的最佳实践 + +56 +00:03:03,684 --> 00:03:05,118 +我们开始吧 + +57 +00:03:06,653 --> 00:03:11,024 +Web Inspector 扩展的结构 +与其他 Safari Web Extension 一样 + +58 +00:03:11,058 --> 00:03:14,928 +有工具栏图标 背景页 内容脚本等 + +59 +00:03:14,962 --> 00:03:18,432 +但它们也有专用的开发工具背景页 + +60 +00:03:18,465 --> 00:03:21,068 +我们来看看它在实践中是如何工作的 + +61 +00:03:21,101 --> 00:03:23,403 +典型的 Safari Web 扩展的结构 + +62 +00:03:23,437 --> 00:03:26,473 +从一个清单文件开始 +该文件声明了扩展的 + +63 +00:03:26,507 --> 00:03:30,944 +基本细节 如名称 图标 描述等 + +64 +00:03:30,978 --> 00:03:34,882 +它可以声明一个背景页来处理 +你的扩展程序的 + +65 +00:03:34,915 --> 00:03:36,450 +所有幕后逻辑 + +66 +00:03:36,483 --> 00:03:40,287 +还可以声明任何用于将功能注入到 + +67 +00:03:40,320 --> 00:03:43,790 +用户访问网页中的内容脚本 + +68 +00:03:43,824 --> 00:03:47,794 +对于 Web Inspector 扩展 +还有一些其他的页面 + +69 +00:03:47,828 --> 00:03:50,898 +首先有一个必需的开发工具背景页 + +70 +00:03:50,931 --> 00:03:54,401 +用于 Web Inspector 扩展的幕后逻辑 + +71 +00:03:54,434 --> 00:03:58,338 +该页面可以访问独特的开发工具 API + +72 +00:03:58,372 --> 00:04:01,775 +和有限的内容脚本 API + +73 +00:04:01,808 --> 00:04:06,113 +从这个开发工具背景页 +你可以创建在 Web Inspector 中 + +74 +00:04:06,146 --> 00:04:08,215 +显示的开发工具选项卡页面 + +75 +00:04:08,248 --> 00:04:11,485 +但所有这些都只是针对 +单个 Web Inspector + +76 +00:04:11,518 --> 00:04:15,422 +如果有多个 Web Inspector +每个都有自己的 + +77 +00:04:15,455 --> 00:04:17,758 +相同的开发工具背景页实例 + +78 +00:04:17,791 --> 00:04:21,762 +在相关 Web Inspector 打开期间 +保持活动状态 + +79 +00:04:21,795 --> 00:04:24,932 +因此 每个开发工具选项卡页面 + +80 +00:04:24,965 --> 00:04:27,701 +也可能有多个实例 + +81 +00:04:27,734 --> 00:04:30,103 +我们来看看这种结构 +在实践中是怎样的 + +82 +00:04:30,137 --> 00:04:33,607 +并开始构建我的 +Open Graph Web Inspector 扩展 + +83 +00:04:34,708 --> 00:04:37,544 +首先我会在 Xcode 中创建一个新项目 + +84 +00:04:41,081 --> 00:04:45,219 +我要创建的项目类型是 +Safari Extension App + +85 +00:04:45,252 --> 00:04:48,755 +我只需要 macOS +但我会让它在多平台中保持原样 + +86 +00:04:48,789 --> 00:04:52,392 +以防我将来想添加 iOS 功能 + +87 +00:04:52,426 --> 00:04:56,496 +我会把它命名为 Open Graph +并保留其余的默认值 + +88 +00:04:56,530 --> 00:05:00,300 +请注意 你需要根据 +你使用的 Apple 开发者帐户 + +89 +00:05:00,334 --> 00:05:02,970 +选择一个团队和捆绑包标识符 + +90 +00:05:03,003 --> 00:05:05,672 +最后 我把它保存在桌面上 + +91 +00:05:07,474 --> 00:05:11,979 +现在我有了一个通用的 +Safari Web 扩展项目 可以随时修改 + +92 +00:05:12,012 --> 00:05:14,681 +我首先进入 manifest.json 文件 + +93 +00:05:14,715 --> 00:05:18,151 +这是每个网络扩展的根配置文件 + +94 +00:05:18,185 --> 00:05:22,422 +清单文件引用 +构成扩展程序的其他资源 + +95 +00:05:22,456 --> 00:05:26,693 +本地化 图像 页面 脚本 样式等 + +96 +00:05:26,727 --> 00:05:30,330 +对于我的 Web Inspector 扩展 +我不需要其中的一些文件 + +97 +00:05:30,364 --> 00:05:33,867 +如背景页 内容脚本或弹出窗口 + +98 +00:05:33,901 --> 00:05:36,303 +所以我会从清单和整个项目中 + +99 +00:05:36,336 --> 00:05:38,772 +删除它们 + +100 +00:05:42,543 --> 00:05:46,313 +好的 让我们开始把它 +变成一个 Web Inspector 扩展 + +101 +00:05:46,346 --> 00:05:50,184 +为此 我需要将开发工具背景页 + +102 +00:05:50,217 --> 00:05:52,386 +添加到清单并为其创建相应的文件 + +103 +00:05:52,419 --> 00:05:55,722 +以及我会在其中使用的 +JavaScript 文件 + +104 +00:05:55,756 --> 00:05:58,926 +我将点击 File New File + +105 +00:06:01,762 --> 00:06:04,765 +向下滚动找到 Empty 文件模板 + +106 +00:06:12,773 --> 00:06:16,176 +我将此文件命名为 +devtools_background.htm + +107 +00:06:16,210 --> 00:06:18,679 +以匹配我在清单中使用的名称 + +108 +00:06:20,848 --> 00:06:24,318 +该位置已经设置在我的其他资源 +和部分正确目标的旁边 + +109 +00:06:24,351 --> 00:06:28,589 +所以我不需要在这里做任何更改 + +110 +00:06:31,325 --> 00:06:35,329 +我将再次对 JavaScript 文件 +重复相同的步骤 + +111 +00:06:40,968 --> 00:06:44,338 +我将其命名为 +“devtools_background.js” + +112 +00:06:48,375 --> 00:06:52,679 +最后 我需要在我的开发工具 +背景页中包含 JavaScript 文件 + +113 +00:06:54,314 --> 00:06:57,985 +请记住 此页面是在 +Web Inspector 打开时创建的 + +114 +00:06:58,018 --> 00:07:02,189 +负责创建出现在 +Web Inspector 中的自定义选项卡 + +115 +00:07:02,222 --> 00:07:04,191 +我几乎总是想创建一个选项卡 + +116 +00:07:04,224 --> 00:07:07,294 +这样 如果有需要的话 我之前 + +117 +00:07:07,327 --> 00:07:09,997 +看到的权限将在线显示给我的用户 + +118 +00:07:10,030 --> 00:07:11,598 +而不是在其他地方 + +119 +00:07:11,632 --> 00:07:15,502 +这个开发工具面板创建 API +需要三个简单的参数 + +120 +00:07:15,536 --> 00:07:18,539 +第一个是选项卡的名称 + +121 +00:07:18,572 --> 00:07:21,074 +为此 我使用本地化方法来查找 + +122 +00:07:21,108 --> 00:07:23,977 +扩展的本地化名称 + +123 +00:07:24,011 --> 00:07:26,947 +下一个参数是要拿来使用的图标路径 + +124 +00:07:26,980 --> 00:07:31,018 +请注意 如果用户选择 +缩放他们的用户界面 + +125 +00:07:31,051 --> 00:07:33,921 +这应该是一个矢量图像 +以便平滑地缩放到任何大小 + +126 +00:07:33,954 --> 00:07:37,758 +但是为了使用这个图标 +我需要确保它是我项目的一部分 + +127 +00:07:37,791 --> 00:07:40,827 +还有我的扩展需要的所有其他图标 + +128 +00:07:40,861 --> 00:07:44,965 +“图像”文件夹中的图标 +仍然是项目模板中的默认图标 + +129 +00:07:44,998 --> 00:07:47,534 +因此让我们从项目中删除这些内容 + +130 +00:07:50,838 --> 00:07:53,373 +用我之前创作的一些图标来代替它们 + +131 +00:07:57,277 --> 00:08:02,115 +包括我在创建开发工具选项卡时 +尝试使用的 logo.svg + +132 +00:08:04,751 --> 00:08:08,522 +现在 我将返回到开发工具后台脚本 + +133 +00:08:10,624 --> 00:08:14,595 +第三个参数是 Web Inspector 中 +选项卡使用的 HTML + +134 +00:08:14,628 --> 00:08:16,496 +就像刚才的图片一样 + +135 +00:08:16,530 --> 00:08:19,566 +我需要创建这个页面才能使用它 + +136 +00:08:26,740 --> 00:08:29,643 +我将此命名为 devtools_tab.html + +137 +00:08:29,676 --> 00:08:32,179 +以匹配我给 API 起的名称 + +138 +00:08:36,450 --> 00:08:39,019 +然而 与开发工具背景页不同 + +139 +00:08:39,052 --> 00:08:42,756 +这个开发工具选项卡页面 +实际上会显示给用户 + +140 +00:08:42,789 --> 00:08:47,194 +所以这次我将创建 +一个 JavaScript 和 CSS 文件 + +141 +00:08:55,836 --> 00:08:59,640 +我将这个 JavaScript 文件 +命名为 devtools_tab.js + +142 +00:09:03,443 --> 00:09:06,947 +CSS 文件命名为 devtools_tab.css + +143 +00:09:08,615 --> 00:09:10,817 +很好 我已经设置了这个结构 + +144 +00:09:10,851 --> 00:09:13,787 +但现在我只添加常用的 Hello World + +145 +00:09:13,820 --> 00:09:15,822 +来确保一切正常运行 + +146 +00:09:15,856 --> 00:09:18,859 +但别担心 我们稍后会 +更深入地讨论这个问题 + +147 +00:09:18,892 --> 00:09:22,129 +因为首先 我们还有几个图标要替换 + +148 +00:09:22,162 --> 00:09:25,232 +以确保此扩展具有一致的外观 + +149 +00:09:25,265 --> 00:09:28,569 +首先我们需要替换默认的大图标 + +150 +00:09:31,238 --> 00:09:33,140 +删除它 + +151 +00:09:35,275 --> 00:09:37,644 +并将我的大图标拖到原来的位置 + +152 +00:09:41,348 --> 00:09:44,017 +但是由于这个大图标是 App 的一部分 + +153 +00:09:44,051 --> 00:09:46,520 +因此我需要把它添加到正确的目标中 + +154 +00:09:50,557 --> 00:09:53,727 +其余图标都是资产目录的一部分 + +155 +00:09:53,760 --> 00:09:56,530 +特别是 AppIcon 集 + +156 +00:09:59,900 --> 00:10:03,670 +我已经准备好这些图标 +所以我将它们粘贴进去 + +157 +00:10:03,704 --> 00:10:07,241 +我认为我们已经替换了所有默认图标 + +158 +00:10:07,274 --> 00:10:08,976 +所以现在要运行我的扩展程序 + +159 +00:10:09,009 --> 00:10:13,347 +请注意 在第一次构建项目时 +运行可能需要几秒钟时间 + +160 +00:10:20,354 --> 00:10:21,622 +就是这样 + +161 +00:10:21,655 --> 00:10:24,091 +这个 UI 的大部分来自 Xcode 模板 + +162 +00:10:24,124 --> 00:10:27,895 +但是我确实看到了我的图标 +而不是默认图标 + +163 +00:10:27,928 --> 00:10:30,964 +只要启动了至少一次 +Safari 浏览器扩展应用程序 + +164 +00:10:30,998 --> 00:10:33,233 +我们就可以把它关闭 + +165 +00:10:33,267 --> 00:10:34,902 +因为 Safari 浏览器不需要 +再运行该 App 来启动它 + +166 +00:10:39,373 --> 00:10:41,508 +但是在 Safari 浏览器中看到它之前 + +167 +00:10:41,542 --> 00:10:44,611 +我必须在 Develop 菜单中 +允许未签名的扩展 + +168 +00:10:44,645 --> 00:10:47,514 +因为这是一个本地构建的未签名 App + +169 +00:10:47,548 --> 00:10:49,950 +现在 +在 Safari 浏览器的扩展首选项中 + +170 +00:10:49,983 --> 00:10:53,520 +我可以看到 Open Graph +我把它打开 + +171 +00:10:53,554 --> 00:10:56,790 +我将打开一个 Safari 浏览器选项卡 +并浏览至 apple.com + +172 +00:10:56,823 --> 00:10:59,026 +这样我就可以尝试我的扩展程序 + +173 +00:10:59,059 --> 00:11:02,596 +已经可以看到我的图标在工具栏中 + +174 +00:11:04,031 --> 00:11:06,834 +我的扩展选项卡现在在选项卡栏中 + +175 +00:11:06,867 --> 00:11:09,369 +切换到这里 + +176 +00:11:09,403 --> 00:11:12,239 +我们可以看到跟之前看到的 +相同的权限提示 + +177 +00:11:12,272 --> 00:11:14,508 +如果扩展需要权限 + +178 +00:11:14,541 --> 00:11:16,944 +则会自动显示此权限提示 + +179 +00:11:16,977 --> 00:11:20,414 +就像之前一样 我给它一天时间 + +180 +00:11:21,682 --> 00:11:25,219 +还有我之前添加到 +开发工具标签页的 Hello World + +181 +00:11:25,252 --> 00:11:30,457 +以上就是如何为 Safari 16 +创建 Web Inspector 扩展的基础知识 + +182 +00:11:30,490 --> 00:11:31,825 +我们来回顾一下 + +183 +00:11:31,859 --> 00:11:36,063 +我声明了开发工具的背景页 +并将其添加到我的 Xcode 项目中 + +184 +00:11:36,096 --> 00:11:39,733 +从那里 我能够在 Web Inspector 中 +创建新的选项卡 + +185 +00:11:39,766 --> 00:11:41,335 +来显示我的定制工具 + +186 +00:11:41,368 --> 00:11:45,305 +最后 我开始考虑扩展所需的权限 + +187 +00:11:45,339 --> 00:11:49,443 +对于 Web Inspector 扩展 +这通常归结为 + +188 +00:11:49,476 --> 00:11:52,446 +评估被检查页面中的代码 +通常是提取一些数据 + +189 +00:11:52,479 --> 00:11:54,448 +以在 Web Inspector 中显示 + +190 +00:11:54,481 --> 00:11:58,252 +Web Extension 已经有许多 +评估代码的方法 + +191 +00:11:58,285 --> 00:11:59,987 +对于 Web Inspector 扩展 + +192 +00:12:00,020 --> 00:12:02,322 +还有另一个 API 是评估 + +193 +00:12:02,356 --> 00:12:05,392 +被检查页面内脚本的首选方法 + +194 +00:12:05,425 --> 00:12:10,631 +我们来看一下这个 API 看看如何 +将它用于我的 OpenGraph 扩展 + +195 +00:12:10,664 --> 00:12:14,735 +这个开发工具扩展 API +在被检查的窗口中评估 JavaScript + +196 +00:12:14,768 --> 00:12:17,171 +是快速获得结果的最佳方式 + +197 +00:12:17,204 --> 00:12:20,407 +它将自动定位 +与运行扩展的 Web Inspector + +198 +00:12:20,440 --> 00:12:22,476 +相关联的页面 + +199 +00:12:22,509 --> 00:12:27,447 +记住 用户可以同时检查多个页面 + +200 +00:12:27,481 --> 00:12:30,050 +这个 API 还有一些有用的选项 + +201 +00:12:30,083 --> 00:12:32,452 +可以帮助你获得正确的结果 + +202 +00:12:32,486 --> 00:12:35,889 +默认情况下 这个 API 的表达式 + +203 +00:12:35,923 --> 00:12:39,893 +是在被检查页面的主框架的 +上下文中计算的 + +204 +00:12:39,927 --> 00:12:42,162 +但是你可以使用 frameURL 选项 + +205 +00:12:42,196 --> 00:12:45,465 +在不同的框架内指定评估 + +206 +00:12:45,499 --> 00:12:48,035 +当你的扩展需要从页面中 + +207 +00:12:48,068 --> 00:12:50,971 +许多可能的子框架之一提取数据时 +这是必需的 + +208 +00:12:51,004 --> 00:12:54,842 +对于我的 OpenGraph 扩展 +我只需要担心主框架 + +209 +00:12:54,875 --> 00:12:56,543 +但是我建议你在评估 + +210 +00:12:56,577 --> 00:12:59,880 +Web Inspector 扩展的脚本时 +记住这一点 + +211 +00:12:59,913 --> 00:13:02,983 +我们来看看如何在我的扩展中 + +212 +00:13:03,016 --> 00:13:05,853 +使用这个函数来获取和显示 +被检查页面的数据 + +213 +00:13:05,886 --> 00:13:09,790 +我将首先用 HTML 替换 +我之前添加的占位符 Hello World + +214 +00:13:09,823 --> 00:13:14,094 +它实际上加载了 +我的 CSS 和 JavaScript 文件 + +215 +00:13:18,398 --> 00:13:22,503 +然后我将添加一些基本的 CSS 来给 +开发工具选项卡一个漂亮的样式 + +216 +00:13:24,071 --> 00:13:27,674 +我想确保我的开发工具选项卡 +与 Web Inspector 的其余部分相适应 + +217 +00:13:27,708 --> 00:13:31,578 +因此我声明了一个“颜色方案”的根属性 + +218 +00:13:31,612 --> 00:13:36,083 +该属性使我的开发工具选项卡与 +Web Inspector 其余部分外观相匹配 + +219 +00:13:36,116 --> 00:13:41,054 +使用系统字体系列并继承字体大小 + +220 +00:13:41,088 --> 00:13:44,725 +并匹配更重要文本的颜色 + +221 +00:13:44,758 --> 00:13:48,529 +至于功能 + +222 +00:13:48,562 --> 00:13:50,264 +我将从添加一些文本开始 + +223 +00:13:50,297 --> 00:13:53,834 +以防页面没有任何 opengraph 元数据 + +224 +00:13:53,867 --> 00:13:57,971 +请注意 我可以在 Web Inspector 中 +使用 Web 扩展本地化字符串 + +225 +00:13:58,005 --> 00:14:00,474 +就像我在 Web 扩展的其他地方 +可以做到的一样 + +226 +00:14:00,507 --> 00:14:04,478 +但为了做到这一点 +我需要将相同的本地化字符串标识符 + +227 +00:14:04,511 --> 00:14:06,380 +添加到本地化字符串文件中 + +228 +00:14:07,514 --> 00:14:09,783 +接下来 + +229 +00:14:09,816 --> 00:14:13,687 +我将创建提供给功能强大的开发工具 + +230 +00:14:13,720 --> 00:14:15,789 +devtools-inspectedWindow-eval API 的 +JavaScript + +231 +00:14:15,822 --> 00:14:18,192 +这让我在检查过的页面中 +对其进行评估 + +232 +00:14:18,225 --> 00:14:21,428 +在本例中 +我想查询被检查页面的 DOM + +233 +00:14:21,461 --> 00:14:24,097 +以查找一些常见的 opengraph 元数据 + +234 +00:14:24,131 --> 00:14:28,836 +特别是标题 描述 + +235 +00:14:30,737 --> 00:14:33,607 +和图像 + +236 +00:14:33,640 --> 00:14:37,344 +以及被检查页面文档的当前就绪状态 + +237 +00:14:37,377 --> 00:14:41,815 +将其捆绑在一起 +通过返回值发送回开发工具页面 + +238 +00:14:41,849 --> 00:14:45,152 +完成后 我可以获取对应于 + +239 +00:14:45,185 --> 00:14:48,488 +每个属性的 HTML 元素 +并对其进行配置 + +240 +00:14:48,522 --> 00:14:51,992 +以便它们显示收集的数据 + +241 +00:14:54,261 --> 00:14:58,699 +如果文档还没有准备好 +我可以稍等片刻后再试一次 + +242 +00:15:00,434 --> 00:15:03,837 +我还想在每次检查页面导航时 +重复所有这些操作 因此我将为 + +243 +00:15:03,871 --> 00:15:07,074 +开发工具网络 onNavigated +添加一个侦听器 + +244 +00:15:15,916 --> 00:15:19,653 +这一切看起来都很棒 +所以我将再次构建来测试它 + +245 +00:15:26,126 --> 00:15:30,297 +现在每当我打开 Web Inspector 或在 +Web Inspector 已经打开的情况下导航时 + +246 +00:15:30,330 --> 00:15:34,968 +我都可以看到每个页面的 +opengraph 标题 描述和图像 + +247 +00:15:35,002 --> 00:15:38,305 +这是一个简单的示例 +展示了如何使用许多新的 + +248 +00:15:38,338 --> 00:15:41,275 +强大的 Web Inspector 扩展 API + +249 +00:15:41,308 --> 00:15:44,378 +我的 OpenGraph 扩展 +进展得很顺利 + +250 +00:15:44,411 --> 00:15:47,414 +我的 Web Inspector 扩展的 +开发工具标签页 + +251 +00:15:47,447 --> 00:15:50,684 +现在可以在被检查的页面中进行评估 + +252 +00:15:50,717 --> 00:15:54,221 +我能够获取结果数据并对其进行处理 + +253 +00:15:54,254 --> 00:15:57,491 +以用户友好的格式显示出来 +以便快速访问 + +254 +00:15:57,524 --> 00:16:00,761 +那么在创建 Web Inspector 扩展时 + +255 +00:16:00,794 --> 00:16:02,729 +有哪些好方法可以让用户体验更好呢 + +256 +00:16:02,763 --> 00:16:07,301 +始终从开发工具后台页面 +创建开发工具选项卡页面 + +257 +00:16:07,334 --> 00:16:11,572 +这样用户可以看到这些选项卡将 +出现在 Web Inspector 中的什么位置 + +258 +00:16:11,605 --> 00:16:15,075 +并且任何适当的权限提示 +都将内嵌显示 + +259 +00:16:15,108 --> 00:16:17,744 +与其要求特定的主机权限 + +260 +00:16:17,778 --> 00:16:19,880 +不如尝试使用 activeTab 权限 + +261 +00:16:19,913 --> 00:16:22,816 +来尽可能有针对性地 +保持 Web Inspector 扩展 + +262 +00:16:22,850 --> 00:16:25,719 +并确保使用 CSS 颜色方案属性 + +263 +00:16:25,752 --> 00:16:28,422 +或 Web 扩展开发工具主题 API + +264 +00:16:28,455 --> 00:16:30,657 +来匹配 Web Inspector 的整体主题 + +265 +00:16:30,691 --> 00:16:34,161 +今天我向你展示了如何使用 + +266 +00:16:34,194 --> 00:16:36,096 +Web Inspector 扩展 +来创建全新的调试工具 + +267 +00:16:36,129 --> 00:16:39,399 +并介绍了一些在这样做时 +要牢记的最佳实践 + +268 +00:16:39,433 --> 00:16:42,603 +如果你想更深入地了解自己 + +269 +00:16:42,636 --> 00:16:44,271 +欢迎你在本讲座的相关资源中 + +270 +00:16:44,304 --> 00:16:46,473 +下载 OpenGraph Web Inspector 扩展 + +271 +00:16:48,275 --> 00:16:50,444 +我们非常想听听你的想法 + +272 +00:16:50,477 --> 00:16:54,481 +所以请使用反馈助手 +提交错误和功能请求 + +273 +00:16:54,515 --> 00:16:58,385 +或者在 Safari 浏览器开发者论坛上 +与我们聊天 + +274 +00:16:58,418 --> 00:17:01,421 +甚至可以考虑加入 +WebExtensions 社区团体 + +275 +00:17:01,455 --> 00:17:04,057 +来帮助塑造网络扩展的未来 + +276 +00:17:05,325 --> 00:17:09,096 +此外请务必查看 +What's new in Safari Web Extensions + +277 +00:17:09,129 --> 00:17:13,433 +以及在线文档 +以了解今年更多的新增功能 + +278 +00:17:13,467 --> 00:17:16,603 +我真的希望你喜欢学习 +在 Web Inspector 中 + +279 +00:17:16,637 --> 00:17:19,072 +创建自定义工具的惊人的新功能 + +280 +00:17:19,106 --> 00:17:22,876 +我们迫不及待地想看到你将会创造出 +多么棒的 Web Inspector 扩展 + +281 +00:17:22,910 --> 00:17:26,280 +并期待你以各种方式突破可能的界限 + +282 +00:17:26,313 --> 00:17:27,748 +非常感谢你的收听 + +283 +00:17:27,781 --> 00:17:30,751 +希望你余下的 WWDC 之旅精彩无限 + diff --git a/zho/2022 Session 10101 Go bindless with Metal 3.srt b/zho/2022 Session 10101 Go bindless with Metal 3.srt new file mode 100644 index 0000000..d8a5cbb --- /dev/null +++ b/zho/2022 Session 10101 Go bindless with Metal 3.srt @@ -0,0 +1,2531 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,743 --> 00:00:10,911 +Alè: 大家好 欢迎 + +3 +00:00:10,944 --> 00:00:15,048 +我是 Alè Segovia Azapian +来自 Apple GPU Software 团队 + +4 +00:00:15,082 --> 00:00:18,385 +Mayur: 我是 Mayur +也是来自 GPU Software 团队 + +5 +00:00:18,418 --> 00:00:21,755 +Alè: 在本次讲座中 我们将与 +大家一起探究下无绑定渲染 + +6 +00:00:21,788 --> 00:00:25,692 +无绑定渲染模型是 +为着色器提供资源 + +7 +00:00:25,726 --> 00:00:29,096 +解锁高级渲染技巧 如光线追踪的 +全新方法 + +8 +00:00:29,129 --> 00:00:34,201 +今天 我首先与大家回顾下 +无绑定渲染模型的运作 + +9 +00:00:34,234 --> 00:00:39,339 +您用 Metal 3 可以如何在 +游戏和 App 中应用无绑定 + +10 +00:00:40,440 --> 00:00:44,111 +无绑定渲染通过汇总数据 +为提高 CPU 和 GPU 的性能 + +11 +00:00:44,144 --> 00:00:47,247 +提供了新机会 + +12 +00:00:47,281 --> 00:00:52,519 +我今天会给您两个具体的 +改善 CPU 和 GPU 时间的方法 + +13 +00:00:53,387 --> 00:00:54,755 +然后将会由 Mayur + +14 +00:00:54,788 --> 00:00:58,859 +为大家展示这些工具 +是如何帮您应用无绑定模型的 + +15 +00:00:59,760 --> 00:01:02,129 +在无绑定模型中 +资源是通过参数缓冲区 + +16 +00:01:02,162 --> 00:01:04,998 +聚合连接到一起的 + +17 +00:01:05,032 --> 00:01:07,501 +从概念上讲 看起来是这样的 + +18 +00:01:07,534 --> 00:01:12,005 +在这个示例中 一个数组 +聚合了场景中所有网格 + +19 +00:01:12,039 --> 00:01:15,676 +在传统绑定模型下 +每个资源独立绑定 + +20 +00:01:15,709 --> 00:01:17,644 +到管线的具体位置中 + +21 +00:01:17,678 --> 00:01:22,082 +而无绑定模型则不同 +资源首先在内存中连接在一起 + +22 +00:01:22,115 --> 00:01:25,786 +让您的着色器可以通过 +自由遍历单个缓冲区 + +23 +00:01:25,819 --> 00:01:27,888 +来访问所需的资源 + +24 +00:01:27,921 --> 00:01:32,259 +以计算复杂的表面和光照 + +25 +00:01:32,292 --> 00:01:34,261 +App 采用无绑定后 + +26 +00:01:34,294 --> 00:01:36,997 +光线追踪着色器可访问 +它们需要的所有数据 + +27 +00:01:37,030 --> 00:01:39,800 +绘制漂亮的反射 + +28 +00:01:39,833 --> 00:01:42,069 +这个 App 可以将 +3D 模型和纹理 + +29 +00:01:42,102 --> 00:01:46,073 +包括地面 卡车 它们的材料 +甚至天空 + +30 +00:01:46,106 --> 00:01:48,175 +全部放置在参数缓冲区 + +31 +00:01:48,208 --> 00:01:51,979 +让光线追踪着色器获取 + +32 +00:01:52,012 --> 00:01:54,815 +更好的是 无绑定渲染 +与其它 Metal 例如堆的功能配对时 + +33 +00:01:54,848 --> 00:01:59,319 +减少了 CPU 压力 + +34 +00:01:59,353 --> 00:02:02,489 +让 App 和游戏获得更好的性能 + +35 +00:02:02,523 --> 00:02:05,792 +我给大家解释下 Metal 3 中 +对无绑定渲染来说比较有用的 + +36 +00:02:05,826 --> 00:02:08,929 +四个具体的增强功能 + +37 +00:02:09,530 --> 00:02:12,833 +参数缓冲区作为 +基础 Metal 构造 + +38 +00:02:12,866 --> 00:02:15,702 +允许您将资源连接在一起 + +39 +00:02:15,736 --> 00:02:20,007 +它们引用了资源 +如纹理和其它缓冲区 + +40 +00:02:20,040 --> 00:02:24,278 +有了 Metal 3 +写入参数缓冲区比之前更简单 + +41 +00:02:24,311 --> 00:02:28,315 +因为现在您不再需要 +参数编码器对象 + +42 +00:02:28,348 --> 00:02:31,785 +对非固定数组也一样 + +43 +00:02:31,818 --> 00:02:34,254 +您现在可以从 Metal 堆中 + +44 +00:02:34,288 --> 00:02:36,223 +分配加速结构 + +45 +00:02:36,256 --> 00:02:39,092 +如果资源没有驻留在 +GPU 内存中 + +46 +00:02:39,126 --> 00:02:42,496 +着色器验证层会 +发出警告 + +47 +00:02:42,529 --> 00:02:47,467 +这四个功能让无绑定 +变得更为简单 + +48 +00:02:48,735 --> 00:02:54,107 +特别是在 Metal 3 中写入 +参数缓冲区轻松愉快 + +49 +00:02:54,141 --> 00:02:56,343 +要将场景编码到参数缓冲区中 + +50 +00:02:56,376 --> 00:02:58,512 +您可以将场景数据写入 +这些缓冲区 + +51 +00:02:58,545 --> 00:03:03,150 +如实例 网格 材料和纹理 + +52 +00:03:03,183 --> 00:03:07,621 +在 Metal 2 中 +这些是用参数编码器来完成的 + +53 +00:03:07,654 --> 00:03:10,858 +所以 我先带大家回顾下 +这些对象是如何工作的 + +54 +00:03:10,891 --> 00:03:14,928 +然后我给大家演示 +Metal 3 可以如何简化您的代码 + +55 +00:03:14,962 --> 00:03:19,299 +用参数编码器 第一步是 +创建编码器实例 + +56 +00:03:19,333 --> 00:03:21,568 +您可通过着色器函数映射 + +57 +00:03:21,602 --> 00:03:25,105 +或通过向 Metal +描述结构体成员来创建 + +58 +00:03:25,138 --> 00:03:29,309 +有了编码器实例后 +设置其记录目标和 + +59 +00:03:29,343 --> 00:03:32,145 +到目标参数缓冲的偏移 + +60 +00:03:32,179 --> 00:03:36,083 +然后使用其方法将数据 +写入缓冲区 + +61 +00:03:36,116 --> 00:03:38,151 +您可查看去年的无绑定讲座 + +62 +00:03:38,185 --> 00:03:42,856 +回顾更多关于参数缓冲区 +和参数编码器的信息 + +63 +00:03:42,890 --> 00:03:44,725 +现在这个机制非常好 + +64 +00:03:44,758 --> 00:03:48,562 +但是编码器对象有时候 +不好管理 + +65 +00:03:48,595 --> 00:03:51,798 +Metal 提供了两种创建 +参数编码器的机制 + +66 +00:03:51,832 --> 00:03:55,369 +哪种适合您的 App +可能不太明确 + +67 +00:03:55,402 --> 00:04:00,507 +此外 在多线程中使用 +参数编码器需要格外小心 + +68 +00:04:00,541 --> 00:04:04,111 +开发者们都很直观地了解 +如何写一个 C 结构体 + +69 +00:04:04,144 --> 00:04:09,316 +有了 Metal 3 您可以用同样的方法 +使用参数缓冲区 + +70 +00:04:09,349 --> 00:04:12,319 +Metal 3 可让您 +方便地写入参数缓冲区 + +71 +00:04:12,352 --> 00:04:16,857 +就象其他任何 CPU 端的结构一样 +直接写入 + +72 +00:04:16,890 --> 00:04:20,060 +现在您可以访问 +虚拟 GPU 地址 + +73 +00:04:20,093 --> 00:04:23,797 +和您资源的资源 ID 了 + +74 +00:04:23,830 --> 00:04:26,366 +当您直接将这些写入 +参数缓冲区时 + +75 +00:04:26,400 --> 00:04:29,937 +Metal 现在理解您要引用的 +是哪种资源 + +76 +00:04:29,970 --> 00:04:32,873 +和之前用参数编码器 +来编码引用的方式相比 + +77 +00:04:32,906 --> 00:04:37,678 +两者在功能上是一样的 +只是不再需要编码器了 + +78 +00:04:37,711 --> 00:04:41,915 +这种功能支持所有支持 +二级参数缓冲区的设备 + +79 +00:04:41,949 --> 00:04:45,452 +也就是说 所有高于 +2016 版本的 Mac + +80 +00:04:45,485 --> 00:04:50,123 +和所有搭载 A13 仿生芯片 +或更高版本的 iOS 设备 + +81 +00:04:51,892 --> 00:04:54,962 +如果您不确定设备是否支持 +二级参数缓冲区 + +82 +00:04:54,995 --> 00:05:00,267 +可使用 MTLDevice 对象中的 +功能咨询 非常方便 + +83 +00:05:00,300 --> 00:05:03,904 +该过程在 Metal 3 中 +是这样的 + +84 +00:05:03,937 --> 00:05:09,376 +首先 定义 CPU 可见的结构 +缓冲区的地址和纹理的 MTLResourceID + +85 +00:05:09,409 --> 00:05:13,680 +需要使用 64 位类型 + +86 +00:05:13,714 --> 00:05:16,550 +然后 分配参数缓冲区 + +87 +00:05:16,583 --> 00:05:23,056 +您可直接从 MTLDevice +或从 MTLHeap 分配缓冲区 + +88 +00:05:23,090 --> 00:05:29,062 +您获得缓冲区内容 并将它转换为 +参数缓冲区结构类型 + +89 +00:05:29,096 --> 00:05:34,001 +最后 将地址和资源 ID +写入结构体成员 + +90 +00:05:34,034 --> 00:05:37,938 +看下这在混合渲染示范程序中 +是如何操作的 + +91 +00:05:37,971 --> 00:05:41,542 +这是代码 是不是很简单 + +92 +00:05:41,575 --> 00:05:46,880 +宿主结构直接存储 +法线缓冲区的 GPU 地址 + +93 +00:05:46,914 --> 00:05:52,653 +这是 64 位 无符号整数 +所以我使用了 uint64_t + +94 +00:05:52,686 --> 00:05:54,488 +现在没有编码器对象了 + +95 +00:05:54,521 --> 00:05:59,459 +对于参数缓冲区 +您只需使用结构体大小 + +96 +00:05:59,493 --> 00:06:03,697 +Metal 可确保 GPU +和 CPU 结构的尺寸和对齐 + +97 +00:06:03,730 --> 00:06:07,100 +与 clang 和 Metal 着色器编译器 +相匹配 + +98 +00:06:08,769 --> 00:06:13,273 +接下来 如往常一样分配缓冲区 + +99 +00:06:13,307 --> 00:06:16,143 +如果缓冲区的存储模式是 +Managed 或 Shared + +100 +00:06:16,176 --> 00:06:21,648 +可将缓冲区的指针 +强制转换为结构类型 + +101 +00:06:21,682 --> 00:06:25,185 +最后 将法线成员 +设置为 gpuAddress + +102 +00:06:25,219 --> 00:06:29,623 +如果需要, +再加上对齐 GPU 内存所需的地址偏移 + +103 +00:06:32,359 --> 00:06:35,963 +有一点要强调的是 结构声明 +如何在 Metal 着色语言 + +104 +00:06:35,996 --> 00:06:39,833 +和 C 语言声明之间改变 + +105 +00:06:39,867 --> 00:06:42,135 +在这个例子中 这些是独立的 + +106 +00:06:42,169 --> 00:06:46,573 +但如果您愿意 可以在 +共享头文件上只做一次结构声明 + +107 +00:06:46,607 --> 00:06:49,243 +使用条件编译来区分 + +108 +00:06:49,276 --> 00:06:52,412 +着色器编译器类型 +和 C 语言类型 + +109 +00:06:53,146 --> 00:06:56,149 +这是 C 语言中的统一声明 + +110 +00:06:56,183 --> 00:07:00,254 +__METAL_VERSION__ 宏只在 +编译着色器代码时定义 + +111 +00:07:00,287 --> 00:07:05,692 +用它在头文件声明中 +区分 GPU 和 CPU 代码 + +112 +00:07:05,726 --> 00:07:09,062 +如果您的 App 以 C++ 为目标 +可将其更进一步 + +113 +00:07:09,096 --> 00:07:12,866 +用模板来统一声明 + +114 +00:07:13,867 --> 00:07:18,005 +看下参数缓冲区 +示例代码的最佳实践方法 + +115 +00:07:18,038 --> 00:07:20,374 +你可以这样写一个结构 + +116 +00:07:20,407 --> 00:07:24,378 +但您也可以用无限数组 +来写入多个结构 + +117 +00:07:24,411 --> 00:07:28,315 +您可能在 Metal 中已经通过参数编码器 +实现了无限数组 + +118 +00:07:28,348 --> 00:07:31,251 +但 Metal 3 进一步简化了流程 + +119 +00:07:31,285 --> 00:07:35,122 +使其可以仅填写一个结构数组 + +120 +00:07:36,223 --> 00:07:40,160 +这就是与写入 +一个结构之间的区别 + +121 +00:07:40,194 --> 00:07:46,400 +您现在需要为您想要存储的 +所有结构分配足够的存储空间 + +122 +00:07:46,433 --> 00:07:52,539 +然后 循环访问数组 +为每个结构写入数据 + +123 +00:07:53,540 --> 00:07:57,244 +回到代码示例 +首先 扩展缓冲区大小 + +124 +00:07:57,277 --> 00:08:01,615 +以便存储场景中 +所有网格的结构 + +125 +00:08:01,648 --> 00:08:05,385 +这与您在 CPU 缓冲区的所做的 +是完全一样的 + +126 +00:08:05,419 --> 00:08:10,524 +用网格数量乘以结构大小 + +127 +00:08:10,557 --> 00:08:13,827 +我想要花点时间 +看下这有多强大 + +128 +00:08:13,861 --> 00:08:17,631 +这一个变量完全控制了 +数组的大小 + +129 +00:08:17,664 --> 00:08:19,600 +着色器完全不需要 +向 Metal 着色器编译器 + +130 +00:08:19,633 --> 00:08:21,835 +声明该大小 + +131 +00:08:21,869 --> 00:08:24,771 +而且可随意索引任何位置 + +132 +00:08:24,805 --> 00:08:28,475 +这就是 Metal 中无绑定模型 +如此灵活的部分原因 + +133 +00:08:28,509 --> 00:08:32,579 +因为您可以编写着色器 +毫无约束地访问任何大小的数组 + +134 +00:08:32,613 --> 00:08:34,448 +真的很好用 + +135 +00:08:36,416 --> 00:08:40,187 +接下来 分配这个大小的缓冲区 + +136 +00:08:40,220 --> 00:08:44,892 +将指向内容的指针强制转换为 +正确的结构类型 + +137 +00:08:46,860 --> 00:08:50,397 +现在缓冲区已经足够大了 +可以通过简单的循环 + +138 +00:08:50,430 --> 00:08:55,102 +按照网格结构的大小递进 + +139 +00:08:55,135 --> 00:08:59,706 +最后 直接设置数组中 +每个结构的 GPUAddress + +140 +00:08:59,740 --> 00:09:02,309 +以及根据需要添加对齐偏移 + +141 +00:09:04,144 --> 00:09:06,613 +从 GPU 端的着色器来说 + +142 +00:09:06,647 --> 00:09:09,650 +这是代表无限数组的 +一种方法 + +143 +00:09:09,683 --> 00:09:14,955 +这里 我将其声明为网格指针参数 +传送到着色器 + +144 +00:09:16,657 --> 00:09:19,893 +这样它可以 +如所有 C 语言数组一样 + +145 +00:09:19,927 --> 00:09:22,529 +直接自由访问内容 + +146 +00:09:25,365 --> 00:09:30,370 +另一个选项是将所有无限数组 +放入一个结构 + +147 +00:09:30,404 --> 00:09:35,275 +这可以通过在单一位置聚合数据 +保持着色器整洁 + +148 +00:09:35,309 --> 00:09:37,377 +在这个例子中 +所有网格和材料 + +149 +00:09:37,411 --> 00:09:40,347 +都统一在一个场景结构中 + +150 +00:09:42,549 --> 00:09:45,719 +使用该场景结构 +场景可通过绑定一个缓冲区 + +151 +00:09:45,752 --> 00:09:47,421 +直接传递到着色器 + +152 +00:09:47,454 --> 00:09:50,691 +而不是独立传送 +每个无限数组 + +153 +00:09:52,459 --> 00:09:54,394 +访问也如往常一样 + +154 +00:09:54,428 --> 00:09:58,832 +现在 可以通过场景结构 +获取网格数组了 + +155 +00:09:59,666 --> 00:10:04,371 +这就是在 Metal 3 中写入 +参数缓冲区和无限数组的方法 + +156 +00:10:04,404 --> 00:10:07,241 +完整修订的 API 现在 +让其更直观 + +157 +00:10:07,274 --> 00:10:12,212 +与您在 CPU 结构或结构数组中 +的做法相匹配 + +158 +00:10:12,246 --> 00:10:14,114 +通过今年的光线追踪更新 + +159 +00:10:14,147 --> 00:10:17,284 +光线追踪加速结构可 +与您的缓冲区和纹理一起 + +160 +00:10:17,317 --> 00:10:19,786 +通过 Metal 堆分配 + +161 +00:10:21,722 --> 00:10:24,491 +这意味着它们可以彼此聚合在一起 + +162 +00:10:24,525 --> 00:10:26,960 +也可以与其它资源类型聚合 + +163 +00:10:26,994 --> 00:10:30,864 +这就很好 因为如果您将 +所有加速结构聚合到堆 + +164 +00:10:30,898 --> 00:10:35,269 +就可以用 useHeap 在单次调用中 +将它们全部标记为常驻 + +165 +00:10:35,302 --> 00:10:38,438 +这在您 App 的渲染线程中 + +166 +00:10:38,472 --> 00:10:41,041 +可极大地节约 CPU + +167 +00:10:42,476 --> 00:10:46,113 +这是一些在堆中 +使用加速结构的技巧 + +168 +00:10:46,146 --> 00:10:49,349 +首先 从堆中配置时 +加速结构在对齐和大小方面 + +169 +00:10:49,383 --> 00:10:53,787 +有一定的要求 +且因设备而异 + +170 +00:10:53,820 --> 00:10:56,790 +这是一项新的查询 +查看堆分配的加速结构的 + +171 +00:10:56,823 --> 00:11:00,227 +大小和对齐 + +172 +00:11:00,260 --> 00:11:03,864 +使用 MTLDevice 的 heapAccelerationStructureSize +andAlignWithDescriptor 方法 + +173 +00:11:03,897 --> 00:11:06,834 +为结构描述符 + +174 +00:11:06,867 --> 00:11:09,803 +确定 SizeAndAlignment + +175 +00:11:09,837 --> 00:11:11,705 +要记住 这和 MTLDevice 设备中的 + +176 +00:11:11,738 --> 00:11:14,408 +accelerationStructureSizes +WithDescriptor 方法 + +177 +00:11:14,441 --> 00:11:16,443 +是不同的 + +178 +00:11:18,612 --> 00:11:22,015 +现在加速结构 +在 MTLHeap 对象中了 + +179 +00:11:22,049 --> 00:11:25,652 +调用 useHeap: 通过一次调用 +让它们都成为常驻 + +180 +00:11:25,686 --> 00:11:31,758 +这比为每个独立资源 +调用 useResource 更快 + +181 +00:11:31,792 --> 00:11:35,095 +记住 除非您选择堆为 +风险跟踪 + +182 +00:11:35,128 --> 00:11:38,999 +Metal 不会防止 +资源的竞态条件 + +183 +00:11:39,032 --> 00:11:41,768 +所以您需要同步彼此之间的 +加速结构构建 + +184 +00:11:41,802 --> 00:11:44,938 +且与光线追踪运行同步 + +185 +00:11:44,972 --> 00:11:47,441 +不过不用担心 +我稍后会再详细阐述这部分 + +186 +00:11:48,942 --> 00:11:50,310 +记得要查看今年的 + +187 +00:11:50,344 --> 00:11:53,180 +“Maximize your Metal ray tracing +performance” 讲座 + +188 +00:11:53,213 --> 00:11:54,081 +以获得更多关于 + +189 +00:11:54,114 --> 00:11:58,118 +这个话题和 Metal 3 其它 +光线追踪性能改进的信息 + +190 +00:11:58,151 --> 00:12:02,122 +使用堆分配的加速结构 +在必要的时候 + +191 +00:12:02,155 --> 00:12:06,059 +让你有机会减少 App 的 +CPU 使用率 + +192 +00:12:06,093 --> 00:12:09,763 +最后 这是我今年最喜欢的 +功能之一 + +193 +00:12:09,796 --> 00:12:12,866 +即着色器验证增强功能 + +194 +00:12:13,867 --> 00:12:16,436 +在 useResource +和 useHeap 的话题中 + +195 +00:12:16,470 --> 00:12:18,972 +非常重要的一点是 +App 为 Metal + +196 +00:12:19,006 --> 00:12:22,075 +对所有间接访问资源标注驻留 + +197 +00:12:22,109 --> 00:12:25,712 +如果忘了这一操作意味着 +支持这些资源的存储页面 + +198 +00:12:25,746 --> 00:12:28,582 +不一定会在渲染时间出现 + +199 +00:12:28,615 --> 00:12:34,188 +这可能会导致指令缓冲失败 +GPU 重启或甚至图像损坏 + +200 +00:12:34,221 --> 00:12:37,457 +不幸的是 这些问题在开启了 + +201 +00:12:37,491 --> 00:12:40,494 +无绑定流程期间很常遇到 +因为在无绑定中 + +202 +00:12:40,527 --> 00:12:43,864 +场景资源的大部分 +是间接访问的 + +203 +00:12:43,897 --> 00:12:48,769 +着色器在运行期间 +做出指针遍历决策 + +204 +00:12:48,802 --> 00:12:51,705 +今年 Metal 3 推出了全新的 + +205 +00:12:51,738 --> 00:12:54,908 +着色器验证层功能 +可帮助您追踪 + +206 +00:12:54,942 --> 00:12:58,712 +指令缓冲执行过程中 +未驻留的资源 + +207 +00:12:58,745 --> 00:13:01,181 +我给大家看一个具体的例子 + +208 +00:13:01,215 --> 00:13:03,951 +在混合渲染 App 的 +更新过程中 + +209 +00:13:03,984 --> 00:13:09,356 +我们有时会遇到反射错误的 +现实问题 + +210 +00:13:09,389 --> 00:13:14,127 +我给大家演示下验证层 +是如何帮助诊断和修正问题的 + +211 +00:13:15,362 --> 00:13:19,533 +要向 Metal 标记驻留 +App 在加载期间将所有独立的 + +212 +00:13:19,566 --> 00:13:24,538 +不是分配在堆上的 +资源存入一个可变集合 + +213 +00:13:24,571 --> 00:13:28,809 +App 添加缓冲区 +添加纹理 + +214 +00:13:28,842 --> 00:13:32,779 +在渲染期间 在 App 发送 +光线追踪核心程序前 + +215 +00:13:32,813 --> 00:13:37,050 +它向 Metal 示意使用 +集内的所有资源 + +216 +00:13:37,084 --> 00:13:39,953 +这是一个简单的流程 +App 在遍历集合 + +217 +00:13:39,987 --> 00:13:43,190 +在每个元素上 +调用 useResource + +218 +00:13:43,223 --> 00:13:46,026 +随后 Metal 在开始 +光线追踪工作前 + +219 +00:13:46,059 --> 00:13:49,263 +将所有资源设为驻留 + +220 +00:13:49,296 --> 00:13:53,800 +这是 App 将资源 +加入集合的部分代码 + +221 +00:13:53,834 --> 00:13:58,772 +App 将其作为参数缓冲区 +写入流程的一部分 + +222 +00:13:58,805 --> 00:14:03,810 +App 的加载函数 +遍历每个子网格 + +223 +00:14:03,844 --> 00:14:06,346 +它抓取所需要的数据 +写入参数缓冲区 + +224 +00:14:06,380 --> 00:14:11,151 +即索引数据 材料的纹理数据 + +225 +00:14:11,185 --> 00:14:16,123 +然后将索引缓冲区地址 +存入参数缓冲区 + +226 +00:14:16,156 --> 00:14:18,959 +而在材料方面 它查看纹理数组 + +227 +00:14:18,992 --> 00:14:24,865 +将纹理 GPU 资源 ID +写入参数缓冲区 + +228 +00:14:24,898 --> 00:14:27,935 +最后 它将子网格材料中 +所有独立纹理 + +229 +00:14:27,968 --> 00:14:31,138 +添加到 sceneResources 集 + +230 +00:14:31,171 --> 00:14:34,174 +从而在发送的时候 +将它们标记为驻留 + +231 +00:14:35,976 --> 00:14:39,713 +不幸的是 这里有一个 +小 bug + +232 +00:14:39,746 --> 00:14:41,648 +App 运行指令缓冲区 + +233 +00:14:41,682 --> 00:14:45,285 +在某些情况下 反射会丢失 + +234 +00:14:45,319 --> 00:14:49,556 +之前 这很难追踪 + +235 +00:14:49,590 --> 00:14:53,827 +现在 在 Metal 3 中 +着色器验证层可以帮上大忙 + +236 +00:14:53,861 --> 00:14:57,865 +这种问题现在会在 +指令缓冲执行期间生成错误 + +237 +00:14:57,898 --> 00:15:01,768 +示意错误的内容 + +238 +00:15:01,802 --> 00:15:03,604 +错误信息会指示 + +239 +00:15:03,637 --> 00:15:07,007 +触发问题的着色器名称 + +240 +00:15:07,040 --> 00:15:09,409 +通道名称 + +241 +00:15:09,443 --> 00:15:14,181 +metal 文件和检测到访问的 +代码行 + +242 +00:15:14,214 --> 00:15:17,317 +甚至是缓冲区标签和大小 + +243 +00:15:17,351 --> 00:15:20,554 +以及它未驻留的事实 + +244 +00:15:20,587 --> 00:15:24,825 +作为一个专业建议 标记 Metal 对象 +总是最佳实践 + +245 +00:15:24,858 --> 00:15:27,694 +工具使用标签 在尝试识别 + +246 +00:15:27,728 --> 00:15:30,831 +调试您 App 的对象时很有用 + +247 +00:15:30,864 --> 00:15:32,799 +手上有了这些细节信息 + +248 +00:15:32,833 --> 00:15:36,770 +现在就很容易在着色器代码中 +找到丢失的资源了 + +249 +00:15:36,803 --> 00:15:40,340 +更好的是 当调试断点启用后 + +250 +00:15:40,374 --> 00:15:44,011 +Xcode 很方便地展示了 +着色器验证检测到问题的 + +251 +00:15:44,044 --> 00:15:47,447 +具体着色器代码行 + +252 +00:15:47,481 --> 00:15:51,852 +在 demo App 中 +索引缓冲区没有驻留 + +253 +00:15:51,885 --> 00:15:55,422 +修正方法就很直接了 + +254 +00:15:55,455 --> 00:15:57,658 +回到代码 + +255 +00:15:57,691 --> 00:15:59,960 +App 现在将丢失的索引缓冲区 + +256 +00:15:59,993 --> 00:16:02,829 +存储到了驻留资源集中 + +257 +00:16:02,863 --> 00:16:05,532 +有了这些调整 +在稍后的光线追踪时间内 + +258 +00:16:05,566 --> 00:16:10,838 +Metal 知道要让索引缓冲区 +对于 GPU 可用 从而解决问题 + +259 +00:16:10,871 --> 00:16:13,841 +这是一个很必要的工具 +也是一个游戏改变者 + +260 +00:16:13,874 --> 00:16:19,079 +这能在您无绑定旅程中 +大大节约了潜在的调试时间 + +261 +00:16:19,112 --> 00:16:22,349 +所以这些就是 Metal 3 带来的 +管理和引用 + +262 +00:16:22,382 --> 00:16:24,685 +无绑定资源的增强功能 + +263 +00:16:24,718 --> 00:16:27,321 +现在我要换个话题 +跟大家分享下在无绑定过程中 + +264 +00:16:27,354 --> 00:16:30,190 +如何最大化游戏性能 + +265 +00:16:30,224 --> 00:16:32,793 +在这一部分 我会讲两个话题 + +266 +00:16:32,826 --> 00:16:36,597 +非持有资源及 +未追踪资源 + +267 +00:16:36,630 --> 00:16:40,133 +这些技巧可以帮助您 +在有长期和聚合的资源时 + +268 +00:16:40,167 --> 00:16:44,638 +可获得更好的 CPU +和 GPU 性能 + +269 +00:16:44,671 --> 00:16:48,509 +现在我们来看下如何通过 +长期资源提高 CPU 性能 + +270 +00:16:48,542 --> 00:16:51,678 +我先与大家回顾下 +Metal 资源的生命周期 + +271 +00:16:51,712 --> 00:16:56,884 +Objective-C 和 Swift 通过 +引用计数处理对象生命周期 + +272 +00:16:56,917 --> 00:16:59,319 +Metal 资源沿袭了这一模型 + +273 +00:16:59,353 --> 00:17:02,222 +资源的 retainCount 始于 1 + +274 +00:17:02,256 --> 00:17:07,461 +在所有强引用消失后 +运行时会释放它们 + +275 +00:17:07,494 --> 00:17:10,998 +因为 CPU 和 GPU +是并行操作的 + +276 +00:17:11,031 --> 00:17:14,401 +如果 CPU 在 GPU 还在使用时 +就允许 retainCount 达到 0 + +277 +00:17:14,434 --> 00:17:18,672 +并释放这个资源 +将会导致问题 + +278 +00:17:19,706 --> 00:17:23,377 +为了避免这一问题 Metal +指令缓冲区为其使用的 + +279 +00:17:23,410 --> 00:17:25,179 +所有资源创建了强引用 + +280 +00:17:25,212 --> 00:17:30,284 +确保 retainCount 最少为 1 + +281 +00:17:30,317 --> 00:17:33,120 +Metal 为您直接绑定至管线的 + +282 +00:17:33,153 --> 00:17:35,222 +资源创建了强引用 + +283 +00:17:35,255 --> 00:17:39,693 +如通过 setVertexBuffer +或 setFragmentTexture 这些函数 + +284 +00:17:39,726 --> 00:17:42,896 +也还包括渲染附件 + +285 +00:17:42,930 --> 00:17:48,168 +您通过 useHeap API 标记为 +驻留的 Metal 堆对象 + +286 +00:17:48,202 --> 00:17:50,637 +以及您通过 useResource API + +287 +00:17:50,671 --> 00:17:55,475 +设为驻留的间接资源 +即使它们是堆的一部分 + +288 +00:17:55,509 --> 00:17:58,078 +您可查看今年的 “Program Metal +in C++ with metal-cpp” 讲座 + +289 +00:17:58,111 --> 00:18:03,317 +以了解更多关于 Mental 对象 +生命周期的信息 + +290 +00:18:03,350 --> 00:18:06,486 +现在 Metal 创建这些引用 +是非常有用的 + +291 +00:18:06,520 --> 00:18:08,722 +因为作为程序设计员来说 +您无需担心 + +292 +00:18:08,755 --> 00:18:13,393 +可能释放了 +GPU 正在使用的对象 + +293 +00:18:13,427 --> 00:18:17,264 +Metal 为您提供的这种安全保证 +可以很快执行 + +294 +00:18:17,297 --> 00:18:20,534 +但也还是会带来一个小小的 +CPU 成本 + +295 +00:18:20,567 --> 00:18:25,305 +在无绑定模型中 +Apps 将资源聚合为堆 + +296 +00:18:25,339 --> 00:18:28,842 +这些应该是长期的 +与应用范围相匹配 + +297 +00:18:28,876 --> 00:18:34,214 +例如 在游戏中 资源 +在整个关卡的持续时间都是活跃的 + +298 +00:18:34,248 --> 00:18:36,917 +在这种情况下 针对资源的 +生命周期 + +299 +00:18:36,950 --> 00:18:40,587 +Metal 无需提供额外的保证 + +300 +00:18:41,288 --> 00:18:44,324 +那您可以通过让 Metal +指令缓冲器不要保持 + +301 +00:18:44,358 --> 00:18:49,329 +它们到资源的引用 +来收回 CPU 成本 + +302 +00:18:50,564 --> 00:18:53,133 +要关闭 Metal 的自动保持 +资源引用计数的功能 + +303 +00:18:53,166 --> 00:18:57,271 +只要创建一个非持有引用的 +指令缓冲区 + +304 +00:18:57,304 --> 00:19:00,040 +您可以直接从 MTLCommandQueue +来完成 + +305 +00:19:00,073 --> 00:19:03,143 +如同您创建常规指令缓冲区一样 + +306 +00:19:03,177 --> 00:19:05,479 +您不需要对 App 做出任何改变 + +307 +00:19:05,512 --> 00:19:08,815 +只要您已确保了资源生命周期 + +308 +00:19:09,783 --> 00:19:12,519 +要记住这个设置的粒度级别 + +309 +00:19:12,553 --> 00:19:14,454 +是整个指令缓冲区 + +310 +00:19:14,488 --> 00:19:18,825 +它要么持有所有引用资源 +或要么完全不持有 + +311 +00:19:19,826 --> 00:19:21,361 +在小规模基准测试中 + +312 +00:19:21,395 --> 00:19:26,099 +仅仅通过转换为非持有引用的 +指令缓冲区 + +313 +00:19:26,133 --> 00:19:29,403 +CPU 使用率在指令缓冲区的 +生命周期就减少了 2% + +314 +00:19:29,436 --> 00:19:32,172 +但这些时间完全用在了 + +315 +00:19:32,206 --> 00:19:36,043 +创建和摧毁不必要的强引用上 + +316 +00:19:37,044 --> 00:19:42,216 +总的来说 非持有资源 +在您已经确保了资源生命周期时 + +317 +00:19:42,249 --> 00:19:46,220 +提供了节约额外 CPU 的机会 + +318 +00:19:46,253 --> 00:19:49,456 +与非持有资源相似 +非跟踪资源 + +319 +00:19:49,489 --> 00:19:52,359 +提供了一个禁用安全功能 + +320 +00:19:52,392 --> 00:19:55,095 +获取更多性能的机会 + +321 +00:19:55,128 --> 00:19:58,599 +有许多视觉技巧都需要 +先渲染到中间纹理和写入缓存区 + +322 +00:19:58,632 --> 00:20:02,803 +并在后续的通道中使用 + +323 +00:20:02,836 --> 00:20:07,674 +阴影映射 蒙皮和后期处理 +都是很好的例子 + +324 +00:20:07,708 --> 00:20:11,378 +现在 生成并立即消费资源 + +325 +00:20:11,411 --> 00:20:15,115 +会带来写完后再读的风险 + +326 +00:20:15,148 --> 00:20:18,318 +此外 如多个通道 +写到同一个资源中 + +327 +00:20:18,352 --> 00:20:19,520 +如两条渲染通道 + +328 +00:20:19,553 --> 00:20:22,956 +相继绘制到同一个附件中 + +329 +00:20:22,990 --> 00:20:26,226 +或两个位块传输编码器 +写入同一个资源中 + +330 +00:20:26,260 --> 00:20:28,662 +由于 Metal 在 GPU 上 +调度工作的方式 + +331 +00:20:28,695 --> 00:20:33,133 +会产生写完后再写的风险 + +332 +00:20:33,166 --> 00:20:36,436 +当您使用被跟踪资源时 +Metal 自动使用 + +333 +00:20:36,470 --> 00:20:41,375 +同步原语以避免 +GPU 时间线上的风险 + +334 +00:20:41,408 --> 00:20:43,810 +比如 Metal 让 GPU 等到 + +335 +00:20:43,844 --> 00:20:46,547 +写入缓冲区的 +计算蒙皮通道结束后 + +336 +00:20:46,580 --> 00:20:50,617 +再启动读取同样缓冲区的 +场景渲染通道 + +337 +00:20:51,652 --> 00:20:52,819 +这非常好 + +338 +00:20:52,853 --> 00:20:57,090 +正因为如此 Metal 被认为是 +易于接受的图形 API + +339 +00:20:57,124 --> 00:20:59,193 +但对于聚合资源到堆的 +App 来说 + +340 +00:20:59,226 --> 00:21:02,229 +还是有一些性能考虑的 + +341 +00:21:03,230 --> 00:21:05,265 +思考下这个示例 + +342 +00:21:05,299 --> 00:21:06,867 +这个 GPU 正在运行中 + +343 +00:21:06,900 --> 00:21:09,036 +相继绘制两帧 +包含顶点蒙皮 + +344 +00:21:09,069 --> 00:21:13,640 +渲染场景 应用色调映射 + +345 +00:21:13,674 --> 00:21:17,578 +GPU 在 App 的指示下持续运行 +Metal 基于资源依赖关系 + +346 +00:21:17,611 --> 00:21:22,850 +发现渲染和计算工作 +可重叠的机会 + +347 +00:21:22,883 --> 00:21:26,019 +如没有对应的依赖关系 +条件也合适 + +348 +00:21:26,053 --> 00:21:29,756 +Metal 会重叠调度工作 +并行运行 + +349 +00:21:29,790 --> 00:21:33,293 +这能让 GPU 的工作饱和 +在同样的时间内 + +350 +00:21:33,327 --> 00:21:36,296 +能完成更多工作 + +351 +00:21:38,298 --> 00:21:41,568 +现在 App 将资源聚合到堆时 + +352 +00:21:41,602 --> 00:21:45,606 +所有子资源都以一个整体 +出现在 Metal 前 + +353 +00:21:45,639 --> 00:21:48,642 +因此堆的协作更高效 + +354 +00:21:48,675 --> 00:21:52,779 +但这意味着 Metal +看到读写工作是在同一资源上 + +355 +00:21:52,813 --> 00:21:56,950 +且必须谨慎计划 以避免竞态条件 + +356 +00:21:56,984 --> 00:22:00,087 +哪怕并没有实际风险存在时 + +357 +00:22:02,823 --> 00:22:06,393 +如您所料 +这个情况称为“伪共享” + +358 +00:22:06,426 --> 00:22:10,464 +它增加了 GPU 工作 +执行的持续时间 + +359 +00:22:10,497 --> 00:22:12,232 +所以有一个性能方面的小技巧 + +360 +00:22:12,266 --> 00:22:15,969 +如果您知道堆中的资源 +没有依赖关系 + +361 +00:22:16,003 --> 00:22:17,938 +那您可以避免这一行为 + +362 +00:22:18,939 --> 00:22:23,310 +要避免伪共享 您可将资源 +排除在风险追踪之外 + +363 +00:22:23,343 --> 00:22:27,681 +直接向 Metal 示意 +细粒度依赖关系 + +364 +00:22:27,714 --> 00:22:29,383 +您通过将资源描述符的 + +365 +00:22:29,416 --> 00:22:34,121 +hazardTracking 设置为 Untracked +从而将资源追踪排除 + +366 +00:22:34,154 --> 00:22:37,591 +因为这太重要了 +所以这是堆的默认设置 + +367 +00:22:37,624 --> 00:22:40,494 +它允许您解锁更多 + +368 +00:22:40,527 --> 00:22:43,397 +GPU 得以立刻 +并行运行工作的机会 + +369 +00:22:43,430 --> 00:22:45,499 +一旦您开始使用非追踪资源 + +370 +00:22:45,532 --> 00:22:48,969 +您要使用以下原语 +传达依赖关系 + +371 +00:22:49,002 --> 00:22:54,675 +基于不同的情况 +使用 Fences Events + +372 +00:22:54,708 --> 00:22:58,946 +Shared Events 或 Memory Barriers + +373 +00:22:58,979 --> 00:23:02,282 +Metal Fences 可以为 +同一指令队列内 + +374 +00:23:02,316 --> 00:23:04,585 +不同的渲染和计算通道间 + +375 +00:23:04,618 --> 00:23:07,921 +访问一个或更多资源做同步 + +376 +00:23:07,955 --> 00:23:10,290 +这是一种分离屏障式的原语 + +377 +00:23:10,324 --> 00:23:15,195 +因此消费者通道会等到 +生产者发出 Fence 信号 + +378 +00:23:18,966 --> 00:23:22,202 +您唯一需要记住的要求是 +当使用 Fences 时 + +379 +00:23:22,236 --> 00:23:26,006 +就是先提交或入队 +生产者指令缓冲区 + +380 +00:23:26,039 --> 00:23:29,643 +再到消费者指令缓冲区 + +381 +00:23:29,676 --> 00:23:31,378 +当您无法保证顺序 + +382 +00:23:31,411 --> 00:23:34,615 +或是为同一设备上 +多个队列来同步时 + +383 +00:23:34,648 --> 00:23:37,150 +可以使用 MTL Events + +384 +00:23:37,184 --> 00:23:41,622 +使用 Events 消费者者指令缓冲区 +等待生产者的指令缓冲区 + +385 +00:23:41,655 --> 00:23:44,992 +发出指定数值的 Event 信号 + +386 +00:23:45,025 --> 00:23:48,829 +在其发出数值信号后 +就可安全读取资源 + +387 +00:23:48,862 --> 00:23:54,568 +使用 Events 来提示 GPU +暂停工作 直至指令发出 Event 信号 + +388 +00:23:54,601 --> 00:23:58,372 +MTLSharedEvents 与常规 Events +行为非常相似 + +389 +00:23:58,405 --> 00:24:02,743 +但工作范围更大 +可以超越单独 GPU 工作 + +390 +00:24:02,776 --> 00:24:04,945 +使用这些来同步不同 +Metal 设备之间的 + +391 +00:24:04,978 --> 00:24:08,815 +资源访问 甚至包括 CPU + +392 +00:24:08,849 --> 00:24:11,185 +例如 使用 Shared Events 来 +处理 GPU + +393 +00:24:11,218 --> 00:24:14,188 +取自 CPU 的 计算结果 + +394 +00:24:14,221 --> 00:24:16,123 +以下是示例 + +395 +00:24:16,156 --> 00:24:19,526 +这个例子中的 GPU +用计算通道为网格蒙皮 + +396 +00:24:19,560 --> 00:24:23,530 +CPU 存储姿态到磁盘 + +397 +00:24:23,564 --> 00:24:25,899 +因为有两个独立的设备 + +398 +00:24:25,933 --> 00:24:31,471 +使用 Shared Event 让 CPU 等待 +直到 GPU 生成资源 + +399 +00:24:31,505 --> 00:24:34,107 +起初 CPU 无条件地开始等待 + +400 +00:24:34,141 --> 00:24:38,846 +GPU 发出 Shared Event 信号 + +401 +00:24:38,879 --> 00:24:42,482 +当 GPU 生成资源 +将其放置于统一内存中时 + +402 +00:24:42,516 --> 00:24:44,518 +它发出 Shared Event 信号 + +403 +00:24:44,551 --> 00:24:47,921 +在这时 CPU 的等待线程唤醒 + +404 +00:24:47,955 --> 00:24:50,424 +安全使用资源 + +405 +00:24:52,426 --> 00:24:55,462 +最后一种原语类型 +是 Memory Barriers + +406 +00:24:55,495 --> 00:24:58,765 +Memory Barriers 强迫所有 +单一渲染或计算通道中的 + +407 +00:24:58,799 --> 00:25:02,936 +后续指令等待 +直到之前的所有指令完成 + +408 +00:25:02,970 --> 00:25:08,208 +在大部分情况下 barrier 的成本 +与 Fence 的成本接近 + +409 +00:25:08,242 --> 00:25:10,944 +然而 只有一个例外 + +410 +00:25:14,348 --> 00:25:19,186 +这个例外就是渲染通道中 +片元阶段后的 barriers + +411 +00:25:19,219 --> 00:25:21,622 +这些 barriers 成本非常高 + +412 +00:25:21,655 --> 00:25:24,525 +相当于打断了渲染通道 + +413 +00:25:24,558 --> 00:25:28,462 +Metal 在 Apple GPUs 上 +禁用片元阶段后的 barriers + +414 +00:25:28,495 --> 00:25:32,199 +从而帮助您的 Apps +保持在最快的驱动路径 + +415 +00:25:32,232 --> 00:25:35,469 +如果您在 Apple GPUs 上 +在片元阶段后添加 barrier + +416 +00:25:35,502 --> 00:25:39,940 +Metal 调试层甚至会生成 +验证错误 + +417 +00:25:39,973 --> 00:25:43,110 +推荐使用 Fence 来 + +418 +00:25:43,143 --> 00:25:45,345 +同步片元阶段后资源访问 + +419 +00:25:46,413 --> 00:25:48,916 +以下是同步原语的简短总结 + +420 +00:25:48,949 --> 00:25:51,185 +以及该何时使用它们 + +421 +00:25:51,218 --> 00:25:53,987 +最好使用 Fences +以确保成本最低 + +422 +00:25:54,021 --> 00:25:55,789 +它适合提交和入队的工作 + +423 +00:25:55,822 --> 00:25:59,793 +在同一指令队列 +以先生成再消费的顺序情况下 + +424 +00:25:59,826 --> 00:26:04,298 +Fences 对大多数常用情况来说 +是很好的 + +425 +00:26:04,331 --> 00:26:06,500 +当提交指令无法确定顺序时 + +426 +00:26:06,533 --> 00:26:11,138 +或当有多个指令队列时 +使用 Metal Events + +427 +00:26:11,171 --> 00:26:14,107 +Shared Events 允许 +多 GPUs 相互之间 + +428 +00:26:14,141 --> 00:26:16,243 +或与 CPU 同步 + +429 +00:26:16,276 --> 00:26:20,948 +只在这些特定的 +多设备情况下来使用它们 + +430 +00:26:20,981 --> 00:26:25,586 +在通道内的同步场景 +最好使用 Memory Barriers + +431 +00:26:25,619 --> 00:26:28,255 +Barriers 是大部分案例下的 +快速原语 + +432 +00:26:28,288 --> 00:26:32,226 +如并发的计算通道 +及 draw call 之间的顶点阶段 + +433 +00:26:32,259 --> 00:26:36,230 +但温馨提示下 在通道间的 +片元阶段后同步 + +434 +00:26:36,263 --> 00:26:38,765 +使用 Fence +而不是 barrier + +435 +00:26:38,799 --> 00:26:42,936 +因为这些 barriers 成本很高 +Apple GPUs 并不允许 + +436 +00:26:44,071 --> 00:26:47,741 +使用非跟踪资源及 +手动细粒度追踪 + +437 +00:26:47,774 --> 00:26:51,712 +您现在可以在最大化 +GPU 并行时 + +438 +00:26:51,745 --> 00:26:55,782 +拥有数据聚合的所有优势 + +439 +00:26:55,816 --> 00:26:59,186 +这些是通过无绑定 + +440 +00:26:59,219 --> 00:27:02,923 +充分利用 CPU 和 GPU +提升性能的技巧 + +441 +00:27:02,956 --> 00:27:05,359 +对于 Metal 3 如何解锁简化 + +442 +00:27:05,392 --> 00:27:07,194 +和高效的无绑定工作流 +我今天说了很多 + +443 +00:27:07,227 --> 00:27:09,429 +但写代码只是等式的一半 + +444 +00:27:09,463 --> 00:27:12,266 +另一半是这些可用的工具 +如何帮助您验证 + +445 +00:27:12,299 --> 00:27:15,002 +GPU 是如何看待 +和执行工作的 + +446 +00:27:15,035 --> 00:27:16,570 +现在我们有请 Mayur + +447 +00:27:16,603 --> 00:27:19,806 +来为大家分享下 Metal 3 的 +无绑定工具有哪些更新 + +448 +00:27:19,840 --> 00:27:22,576 +Mayur: 谢谢 Alè + +449 +00:27:22,609 --> 00:27:26,046 +今天 很高兴能为大家演示 +Metal Debugger 的一些 + +450 +00:27:26,079 --> 00:27:31,752 +强大的新功能 帮助您调试 +和优化无绑定 Apps + +451 +00:27:31,785 --> 00:27:34,788 +我用 Alè 刚刚给您看的 +混合渲染 App 中 + +452 +00:27:34,821 --> 00:27:37,191 +抓取的一帧为例 + +453 +00:27:37,224 --> 00:27:39,660 +当您在 Metal Debugger 中 +抓到一帧 + +454 +00:27:39,693 --> 00:27:41,795 +您会先看到 Summary 页面 + +455 +00:27:41,828 --> 00:27:44,698 +给您提供帧概览 + +456 +00:27:44,731 --> 00:27:50,037 +以及如何提升 App 性能的 +帮助建议 + +457 +00:27:50,070 --> 00:27:54,308 +但今天 我很高兴地问您展示 +一个全新的依赖关系图 + +458 +00:27:54,341 --> 00:28:00,347 +要打开它 您只需点击 +左边的 Dependencies + +459 +00:28:00,380 --> 00:28:02,683 +这是新的依赖关系图 + +460 +00:28:02,716 --> 00:28:08,088 +其特点在于全新功能带来的 +全新的设计 + +461 +00:28:08,121 --> 00:28:12,593 +依赖关系图将您的 +工作负荷 + +462 +00:28:12,626 --> 00:28:14,928 +用基于图形的方式来展示 + +463 +00:28:14,962 --> 00:28:18,866 +图形中的每个节点 +都代表一个通道 + +464 +00:28:18,899 --> 00:28:25,439 +由一个指令编码器编码 +和它的输出资源 + +465 +00:28:25,472 --> 00:28:31,245 +边缘展现了通道之间的 +资源依赖 + +466 +00:28:31,278 --> 00:28:34,381 +通过今年新推出的功能 +您可以根据两种依赖关系 + +467 +00:28:34,414 --> 00:28:37,751 +来分析您的工作负荷 + +468 +00:28:37,784 --> 00:28:40,387 +数据流和同步 + +469 +00:28:40,420 --> 00:28:43,690 +实线代表数据流 + +470 +00:28:43,724 --> 00:28:47,294 +它们为您展示了 +数据在您 App 上是如何流动的 + +471 +00:28:47,327 --> 00:28:52,199 +虚线代表同步 +它们展示了通道之间 + +472 +00:28:52,232 --> 00:28:57,738 +进行 GPU 同步的依赖关系 + +473 +00:28:57,771 --> 00:29:03,343 +您可以点击任意编码器 +资源或边缘来了解更多信息 + +474 +00:29:03,377 --> 00:29:09,283 +调试器会在新的侧边栏为您展示 +许多详细信息 + +475 +00:29:09,316 --> 00:29:12,886 +例如 这一边缘添加了同步 + +476 +00:29:12,920 --> 00:29:17,391 +且在这些通道间有数据流 + +477 +00:29:17,424 --> 00:29:21,295 +默认情况下依赖关系图 +同时展示数据流 + +478 +00:29:21,328 --> 00:29:23,964 +和同步依赖关系 + +479 +00:29:23,997 --> 00:29:27,501 +但您可以最底部的菜单 + +480 +00:29:27,534 --> 00:29:31,238 +来查看一个依赖类型 + +481 +00:29:31,271 --> 00:29:36,977 +这里 我只查看同步 + +482 +00:29:37,010 --> 00:29:41,281 +如 Alè 刚才所说 +伪共享是在追踪堆里 + +483 +00:29:41,315 --> 00:29:45,853 +读写不同资源的常见问题 + +484 +00:29:45,886 --> 00:29:50,424 +依赖关系图让捕捉这些问题 +变得更简单 + +485 +00:29:50,457 --> 00:29:54,027 +我抓取的这一示例 +来自早期的开发版本 + +486 +00:29:54,061 --> 00:29:57,097 +正是出现了该问题 + +487 +00:29:57,130 --> 00:30:02,069 +如果我点击这个堆 +依赖关系图会显示 + +488 +00:30:02,102 --> 00:30:04,438 +该堆已被追踪 + +489 +00:30:04,471 --> 00:30:09,910 +因此在两条通道之间添加同步 + +490 +00:30:09,943 --> 00:30:16,016 +依赖关系图也强调了 +在堆内部分配的资源 + +491 +00:30:16,049 --> 00:30:21,054 +如这个渲染编码器存储的 +渲染目标纹理 + +492 +00:30:21,088 --> 00:30:26,593 +以及计算编码器读取和写入的 +缓冲区 + +493 +00:30:26,627 --> 00:30:32,633 +问题在于 两条通道之间的同步 +并不必要 + +494 +00:30:32,666 --> 00:30:39,139 +因为计算编码器没有使用 +之前编码器中的任何资源 + +495 +00:30:39,173 --> 00:30:44,545 +要移除该依赖关系 +我可以调整 App 以使用非跟踪堆 + +496 +00:30:44,578 --> 00:30:48,615 +在同步需要的地方插入 Fences + +497 +00:30:48,649 --> 00:30:55,022 +通过这一调整 这两条通道 +现在可并行运行了 + +498 +00:30:55,055 --> 00:30:58,192 +Xcode 14 中另一个改进 + +499 +00:30:58,225 --> 00:31:02,729 +帮助调试您的无绑定 App +是最新的资源清单 + +500 +00:31:02,763 --> 00:31:09,002 +我可以导航到想要调试的 draw call +并打开它 + +501 +00:31:09,036 --> 00:31:13,373 +当使用无绑定时 +数百个甚至数千个资源 + +502 +00:31:13,407 --> 00:31:17,144 +在 GPU 任意时间都是可用的 + +503 +00:31:17,177 --> 00:31:20,714 +今年 Metal 调试器为您提供了 + +504 +00:31:20,747 --> 00:31:24,585 +检查 draw call 访问的是 +哪个资源的能力 + +505 +00:31:24,618 --> 00:31:29,189 +只要点击顶上的 +“Accessed” 模式即可 + +506 +00:31:29,223 --> 00:31:33,594 +现在调试器只展示了 +draw call 访问的 + +507 +00:31:33,627 --> 00:31:40,267 +少数资源 以及每个访问的类型 + +508 +00:31:40,300 --> 00:31:46,173 +这对于理解您的着色器 +从参数缓冲区访问了 + +509 +00:31:46,206 --> 00:31:48,675 +哪些资源非常有用 + +510 +00:31:48,709 --> 00:31:53,213 +知道您的 draw call 使用了 +哪些资源 这样太好了 + +511 +00:31:53,247 --> 00:31:56,550 +但如果它只展示了 +非您预期的资源 + +512 +00:31:56,583 --> 00:32:01,321 +您可以使用着色器调试器 +来看下是什么情况 + +513 +00:32:01,355 --> 00:32:03,223 +要启动着色器调试器 + +514 +00:32:03,257 --> 00:32:07,694 +只要点击底部工具栏的 +调试按钮 + +515 +00:32:07,728 --> 00:32:11,465 +选择您要调试的像素 + +516 +00:32:11,498 --> 00:32:15,102 +点击调试按钮 + +517 +00:32:15,135 --> 00:32:19,072 +现在您已进入着色器调试器 + +518 +00:32:19,106 --> 00:32:24,912 +着色器调试器展示了 +您的代码是如何逐行执行的 + +519 +00:32:24,945 --> 00:32:29,149 +包括访问了哪个资源 + +520 +00:32:29,183 --> 00:32:35,122 +在这些行中 +着色器从参数缓冲区读取纹理 + +521 +00:32:35,155 --> 00:32:39,026 +我可将详细视图扩展到右侧栏 + +522 +00:32:39,059 --> 00:32:43,730 +查看读取的是哪个资源 + +523 +00:32:43,764 --> 00:32:47,835 +这可帮助识别您的着色器访问了 + +524 +00:32:47,868 --> 00:32:51,605 +哪个错误的参数缓冲区元素 + +525 +00:32:51,638 --> 00:32:56,009 +在这个 demo 中 我问大家展示了 +如何使用新的依赖关系视图 + +526 +00:32:56,043 --> 00:32:59,446 +来分析和验证资源依赖关系 + +527 +00:32:59,479 --> 00:33:03,717 +如何使用新的资源清单 +来理解 draw call 访问了 + +528 +00:33:03,750 --> 00:33:05,686 +哪个资源 + +529 +00:33:05,719 --> 00:33:09,690 +以及如何使用着色器调试器 +来逐行分析 + +530 +00:33:09,723 --> 00:33:12,159 +着色器是如何执行的 + +531 +00:33:12,192 --> 00:33:15,262 +我已经迫不及待看看大家 +是如何使用这些新功能 + +532 +00:33:15,295 --> 00:33:17,931 +来创建强大的 Metal +无绑定 Apps 了 + +533 +00:33:17,965 --> 00:33:19,666 +交回给您 Alè + +534 +00:33:19,700 --> 00:33:23,003 +Alè: 谢谢 Mayur +非常了不起的 demo + +535 +00:33:23,036 --> 00:33:27,474 +总结一下 Metal 3 +为无绑定带来了许多改进 + +536 +00:33:27,508 --> 00:33:29,743 +通过简化参数缓冲区编码 + +537 +00:33:29,776 --> 00:33:31,812 +分配在堆上的加速结构 + +538 +00:33:31,845 --> 00:33:34,715 +提升验证层和工具 + +539 +00:33:34,748 --> 00:33:36,650 +Metal 3 是一个优秀的 API + +540 +00:33:36,683 --> 00:33:40,654 +能为您的游戏和 App +带来有效和高性能的无绑定 + +541 +00:33:40,687 --> 00:33:45,225 +通过今年的增强功能 +混合渲染 App 比之前更好了 + +542 +00:33:45,259 --> 00:33:47,461 +我们将它公布在了 +Metal 示例代码库中 + +543 +00:33:47,494 --> 00:33:51,098 +有更新版本 App 的 +全部源码 + +544 +00:33:51,131 --> 00:33:53,367 +您可以下载 学习和修改 + +545 +00:33:53,400 --> 00:33:56,103 +作为练习 我给大家一个考验 +将其更进一步 + +546 +00:33:56,136 --> 00:33:59,306 +为镜像表面增加递归 + +547 +00:33:59,339 --> 00:34:01,074 +我等不及看看您能用这个功能 +来做什么了 + +548 +00:34:01,108 --> 00:34:04,845 +Metal 3 迎来了前所未有的 +无绑定时代 + +549 +00:34:04,878 --> 00:34:06,914 +感谢大家的观看 + +550 +00:34:06,947 --> 00:34:09,950 +[欢快的音乐] + diff --git a/zho/2022 Session 10102 Target and optimize GPU binaries with Metal 3.srt b/zho/2022 Session 10102 Target and optimize GPU binaries with Metal 3.srt new file mode 100644 index 0000000..370209b --- /dev/null +++ b/zho/2022 Session 10102 Target and optimize GPU binaries with Metal 3.srt @@ -0,0 +1,1128 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:10,744 +Galo Avila: 大家好 欢迎大家 + +3 +00:00:10,777 --> 00:00:13,747 +我是 Galo Avila +GPU 软件开发经理 + +4 +00:00:13,780 --> 00:00:15,782 +在本次讲座中 我和 Eylon +将很高兴与大家分享 + +5 +00:00:15,816 --> 00:00:19,353 +如何使用 Metal 3 改进 App 的 +GPU 二进制生成 + +6 +00:00:19,386 --> 00:00:22,222 +首先 我讲一下 +如何通过离线编译帮助你 + +7 +00:00:22,256 --> 00:00:26,660 +减少 App 掉帧 +首次启动和新关卡加载时间 + +8 +00:00:26,693 --> 00:00:30,364 +然后 Eylon 将介绍如何通过使用 +优化大小的编译器选项 + +9 +00:00:30,397 --> 00:00:34,067 +来调整代码扩展转换 +并缩短编译时间 + +10 +00:00:35,636 --> 00:00:39,873 +离线编译可以让你将 GPU 二进制 +生成转移到项目构建期间 + +11 +00:00:39,907 --> 00:00:43,443 +为了充分了解采用这种方式可以为你的 +Metal 应用程序带来的好处 + +12 +00:00:43,477 --> 00:00:47,948 +我首先回顾一下已有的 +生成 GPU 二进制的方式 + +13 +00:00:47,981 --> 00:00:52,920 +在你的 Metal app 中 +GPU 二进制在构建和运行时生成 + +14 +00:00:52,953 --> 00:00:56,924 +例如 假设你从源码实例化一个 Metal 库 + +15 +00:00:56,957 --> 00:01:00,127 +这将在 App 运行时生成 +Apple's Intermediate Representation + +16 +00:01:00,160 --> 00:01:02,129 +也被称为 AIR + +17 +00:01:02,162 --> 00:01:04,298 +这会是一个 CPU 密集型操作 + +18 +00:01:04,331 --> 00:01:05,699 +你可以通过将源代码 + +19 +00:01:05,732 --> 00:01:08,202 +预编译成 Metal 库 然后从文件实例化 + +20 +00:01:08,235 --> 00:01:11,171 +将这一步转移到 App 构建时 + +21 +00:01:11,205 --> 00:01:14,575 +一旦将 Metal 库放入内存中 +创建包含状态和函数的 + +22 +00:01:14,608 --> 00:01:18,278 +管线状态描述符 +就是一个轻量级操作 + +23 +00:01:18,312 --> 00:01:20,280 +直到开始创建管线状态对象 + +24 +00:01:20,314 --> 00:01:22,850 +这会是另一个 CPU 密集型操作 + +25 +00:01:22,883 --> 00:01:26,220 +这里会实时生成 GPU 二进制 + +26 +00:01:28,522 --> 00:01:32,759 +由于在运行时生成 GPU 二进制 +可能是 CPU 密集型操作 + +27 +00:01:32,793 --> 00:01:36,063 +Metal 会帮助你加速 +管线状态对象的创建 + +28 +00:01:36,096 --> 00:01:37,431 +当你实例化 PSO 时 + +29 +00:01:37,464 --> 00:01:41,235 +Metal 将你的 GPU 二进制 +存储在文件系统缓存中 + +30 +00:01:41,268 --> 00:01:43,337 +每创建一个新的 PSO + +31 +00:01:43,370 --> 00:01:46,373 +就会添加所有新生成的函数 + +32 +00:01:46,406 --> 00:01:48,976 +因此 之前生成的 +任何被引用的二进制 + +33 +00:01:49,009 --> 00:01:50,577 +都可以从缓存中加载 + +34 +00:01:52,546 --> 00:01:56,316 +Metal 还允许你使用二进制存档 +明确控制何时何地 + +35 +00:01:56,350 --> 00:01:58,519 +缓存 GPU 二进制 + +36 +00:01:58,552 --> 00:02:03,156 +只需使用 PSO 描述符通过存档文件 +缓存 GPU 二进制 + +37 +00:02:03,190 --> 00:02:05,526 +多少次都可以 + +38 +00:02:05,559 --> 00:02:09,630 +这样 创建 PSO 就变成了 +一个轻量级操作 + +39 +00:02:09,663 --> 00:02:11,965 +二进制存档支持更灵活的缓存 + +40 +00:02:11,999 --> 00:02:14,668 +但它们仍然必须在运行时生成 + +41 +00:02:14,701 --> 00:02:16,236 +在许多情况下 你真正想要的 + +42 +00:02:16,270 --> 00:02:18,438 +是在构建时生成这些存档 + +43 +00:02:18,472 --> 00:02:20,474 +现在终于可以实现了 + +44 +00:02:20,507 --> 00:02:23,610 +通过离线二进制生成 +你可以在项目构建时 + +45 +00:02:23,644 --> 00:02:26,280 +指定一个名为 +Metal 管线脚本的新产物 + +46 +00:02:26,313 --> 00:02:29,550 +与 Metal 源代码或 Metal 库配合 + +47 +00:02:29,583 --> 00:02:32,152 +管线脚本在编译器工具链上 + +48 +00:02:32,186 --> 00:02:35,222 +相当于 API 中的管线描述符的集合 + +49 +00:02:35,255 --> 00:02:38,659 +编译过程的输出是二进制存档 + +50 +00:02:38,692 --> 00:02:42,029 +App 运行时无需再生成 GPU 代码 + +51 +00:02:42,062 --> 00:02:46,600 +只需加载离线构建的二进制存档 +即可加速创建 PSO + +52 +00:02:48,435 --> 00:02:52,339 +离线编译通过减少运行时的 +CPU 占用率让你的 App 受益 + +53 +00:02:52,372 --> 00:02:55,876 +这是 Metal 作为底层 API 的核心价值 + +54 +00:02:55,909 --> 00:03:00,681 +此外 通过这种方式可以 +从两个方面显著改善 App 的体验 + +55 +00:03:00,714 --> 00:03:03,951 +首次启动和新关卡的加载 +会大大加快 + +56 +00:03:03,984 --> 00:03:07,454 +从而可能带来更好的参与度和互动 + +57 +00:03:07,487 --> 00:03:10,123 +由于运行时编译而导致的卡顿 +或帧速率下降 + +58 +00:03:10,157 --> 00:03:11,592 +最终也可以消除 + +59 +00:03:11,625 --> 00:03:15,429 +无需再为预热帧提供内存或 CPU 成本 + +60 +00:03:15,462 --> 00:03:18,465 +接下来我将更详细地探讨这些优势 + +61 +00:03:19,499 --> 00:03:22,803 +这里是传统的 App 运行时的 +二进制生成 + +62 +00:03:22,836 --> 00:03:25,706 +在这个例子中 你的 App 在加载屏幕后 + +63 +00:03:25,739 --> 00:03:28,275 +花费大约三分之二的时间编译 +GPU 二进制 + +64 +00:03:28,308 --> 00:03:31,011 +然后你才能开始与它进行交互 + +65 +00:03:31,044 --> 00:03:35,616 +但是通过离线编译 你的运行时 +着色器生成将移动到 APP 构建时间 + +66 +00:03:35,649 --> 00:03:38,018 +PSO 的创建只需要一小部分时间 + +67 +00:03:38,051 --> 00:03:40,187 +你可以更快地与 App 交互 + +68 +00:03:40,220 --> 00:03:42,890 +而不是在加载屏幕上空转 + +69 +00:03:43,924 --> 00:03:47,694 +离线编译也有助于减少卡顿 + +70 +00:03:47,728 --> 00:03:49,930 +使用传统的运行时二进制生成 + +71 +00:03:49,963 --> 00:03:52,900 +为了避免在加载时 +创建过多的管线状态 + +72 +00:03:52,933 --> 00:03:56,470 +你可能会按需即时创建一些状态 + +73 +00:03:56,503 --> 00:03:59,139 +发生这种情况时 你可能会遇到 + +74 +00:03:59,173 --> 00:04:02,476 +由于编译而暂时中断命令编码 +导致的掉帧 + +75 +00:04:03,343 --> 00:04:05,979 +离线编译消除了这些讨厌的气泡 + +76 +00:04:06,013 --> 00:04:10,217 +因为你可以在 App 构建时 +编译更多的着色器 + +77 +00:04:10,250 --> 00:04:12,352 +接下来 我将分享一个 +新的开发工作流 + +78 +00:04:12,386 --> 00:04:15,389 +帮助你利用离线编译的优势 + +79 +00:04:16,590 --> 00:04:19,693 +在以下工作流中 +你将学习如何使用新的工具链功能 + +80 +00:04:19,726 --> 00:04:21,962 +离线构建 GPU 二进制 + +81 +00:04:21,995 --> 00:04:25,732 +我将向你们展示如何生成新的 +管线脚本输入文件 + +82 +00:04:25,766 --> 00:04:29,703 +然后 如何调用工具链生成 GPU 二进制 + +83 +00:04:29,736 --> 00:04:32,940 +管线脚本文件是一个 + +84 +00:04:32,973 --> 00:04:35,976 +或多个 API 管线状态描述符的 +JSON 格式描述 + +85 +00:04:36,009 --> 00:04:38,145 +可以通过多种方式生成 + +86 +00:04:38,178 --> 00:04:41,181 +例如 在你最喜欢的 +JSON 编辑器中编写它们 + +87 +00:04:41,215 --> 00:04:46,520 +或者通过处理在开发和测试期间 +序列化的二进制存档获取 + +88 +00:04:46,553 --> 00:04:50,324 +这里有一段 Metal 代码 +它生成了一个具有 + +89 +00:04:50,357 --> 00:04:54,528 +状态和函数的渲染管线描述符 +及其等效的 JSON 描述 + +90 +00:04:54,561 --> 00:04:59,633 +首先 将 API metal 库文件 +指定为库路径属性 + +91 +00:04:59,666 --> 00:05:04,471 +然后你的 API 渲染描述符函数名称 +作为渲染管线属性 + +92 +00:05:04,505 --> 00:05:07,241 +最后 其他管线状态 +如 raster_sample_count + +93 +00:05:07,274 --> 00:05:11,111 +或像素格式 也被记录为脚本属性 + +94 +00:05:11,144 --> 00:05:15,082 +在 Metal 的开发文档中 +查找更多 JSON 结构定义详细信息 + +95 +00:05:16,917 --> 00:05:19,753 +你可能还想开启 JSON 脚本生成 + +96 +00:05:19,786 --> 00:05:22,289 +可以使用 Metal 运行时 + +97 +00:05:22,322 --> 00:05:24,525 +只需在运行时生成二进制存档 + +98 +00:05:24,558 --> 00:05:27,728 +并在开发和测试过程中将它们序列化 + +99 +00:05:27,761 --> 00:05:31,098 +现在我将向你们展示 +如何使用 Metal API 完成此任务 + +100 +00:05:32,933 --> 00:05:34,968 +你们可以在运行时通过创建 + +101 +00:05:35,002 --> 00:05:38,939 +带有状态和函数的管线描述符 +开始收集过程 + +102 +00:05:38,972 --> 00:05:43,076 +将其添加到生成 +GPU 二进制的存档中 + +103 +00:05:43,110 --> 00:05:45,779 +并将其序列化到文件系统以导入 + +104 +00:05:45,812 --> 00:05:47,981 +你的 App 包 再从中加载 + +105 +00:05:48,015 --> 00:05:52,419 +Metal 3 运行时将你的管线描述符 +与 GPU 二进制一起存储 + +106 +00:05:52,452 --> 00:05:55,622 +现在我将向你们展示如何提取它们 + +107 +00:05:55,656 --> 00:05:58,292 +metal-source 允许从现有存档中 + +108 +00:05:58,325 --> 00:06:00,494 +提取 JSON 管线脚本 + +109 +00:06:00,527 --> 00:06:05,599 +这对于将二进制生成从运行时 +迁移到 App 构建时非常方便 + +110 +00:06:05,632 --> 00:06:07,801 +只需调用 metal-source 时 +使用 flatbuffers 和 + +111 +00:06:07,835 --> 00:06:10,137 +输出目录选项 + +112 +00:06:10,170 --> 00:06:11,805 +就可以产生管线脚本文件 + +113 +00:06:11,839 --> 00:06:14,942 +你可以对其进行编辑 +以生成额外的二进制 + +114 +00:06:14,975 --> 00:06:18,912 +现在 我将向你展示如何调用工具链 + +115 +00:06:18,946 --> 00:06:22,983 +在 Xcode 项目构建阶段 +生成 GPU 二进制很容易 + +116 +00:06:23,016 --> 00:06:26,553 +只需象从终端调用 metal 一样 +提供源代码 管线脚本 + +117 +00:06:26,587 --> 00:06:29,523 +和输出文件 + +118 +00:06:29,556 --> 00:06:32,326 +输出的 metal 库 +现在就包含 GPU 二进制 + +119 +00:06:32,359 --> 00:06:36,330 +并且可以部署在 +任何工具链支持的设备上 + +120 +00:06:36,363 --> 00:06:38,866 +如果你有一个 Metal 库而不是源码 + +121 +00:06:38,899 --> 00:06:42,569 +也可以将其传递给工具链 + +122 +00:06:42,603 --> 00:06:45,072 +使用 Metal 转换工具 +从现有的 Metal 库 + +123 +00:06:45,105 --> 00:06:48,141 +生成二进制也同样简单 + +124 +00:06:48,175 --> 00:06:51,512 +只需像在终端中调用 metal-tt 一样 + +125 +00:06:51,545 --> 00:06:53,947 +提供源码 管线脚本和输出文件 + +126 +00:06:53,981 --> 00:06:56,550 +得到的 Metal 库现在包含所有工具链 + +127 +00:06:56,583 --> 00:07:00,787 +支持设备的 GPU 二进制 + +128 +00:07:00,821 --> 00:07:03,056 +现在你知道如何离线创建二进制 + +129 +00:07:03,090 --> 00:07:05,459 +我将回顾如何加载它们 + +130 +00:07:05,492 --> 00:07:09,162 +只需在创建存档描述符时 +提供二进制的 URL + +131 +00:07:09,196 --> 00:07:10,964 +并使用它来实例化存档 + +132 +00:07:10,998 --> 00:07:12,299 +就是这样 + +133 +00:07:12,332 --> 00:07:14,935 +有关 Metal 的 +二进制存档 API 的更多信息 + +134 +00:07:14,968 --> 00:07:18,071 +请查阅我们过去几年的演讲 + +135 +00:07:18,105 --> 00:07:21,275 +最后 是关于 Metal 如何处理 +这些通过离线生成的 + +136 +00:07:21,308 --> 00:07:25,145 +GPU 二进制的兼容性的一点说明 + +137 +00:07:25,179 --> 00:07:27,681 +为确保离线生成的二进制 + +138 +00:07:27,714 --> 00:07:30,317 +与未来的操作系统版本 +和产品前向兼容 + +139 +00:07:30,350 --> 00:07:33,420 +Metal 会在操作系统更新期间 +或 App 安装时优雅地升级 + +140 +00:07:33,453 --> 00:07:34,688 +你的二进制存档 + +141 +00:07:34,721 --> 00:07:38,392 +它会在后台异步执行此操作 + +142 +00:07:38,425 --> 00:07:41,495 +我迫不及待地想 +让你们利用离线编译的优势 + +143 +00:07:41,528 --> 00:07:45,632 +来消除运行时卡顿 +并减少首次启动和新关卡加载时间 + +144 +00:07:45,666 --> 00:07:47,701 +这种提升对其他人来说是切实可见的 + +145 +00:07:47,734 --> 00:07:49,837 +并增强了他们的整体使用体验 + +146 +00:07:49,870 --> 00:07:51,538 +现在 让我们交给 Eylon + +147 +00:07:51,572 --> 00:07:53,507 +Eylon: 谢谢 Galo + +148 +00:07:53,540 --> 00:07:55,976 +接下来 我将介绍新的编译选项 + +149 +00:07:56,009 --> 00:07:58,278 +用于优化大小 + +150 +00:07:58,312 --> 00:08:02,549 +Metal 编译器积极优化代码 +以提高运行时性能 + +151 +00:08:02,583 --> 00:08:05,919 +一些优化会扩大 GPU 程序的大小 + +152 +00:08:05,953 --> 00:08:09,223 +这可能会带来意想不到的成本 + +153 +00:08:09,256 --> 00:08:12,292 +例如 函数内联是一种避免 + +154 +00:08:12,326 --> 00:08:14,828 +函数调用消耗的优化 + +155 +00:08:14,862 --> 00:08:19,099 +它通过将被调用函数的函数体 +内联到调用点来实现 + +156 +00:08:19,132 --> 00:08:22,035 +这个示例内核看起来没有很多代码 + +157 +00:08:22,069 --> 00:08:23,670 +但内联之后 + +158 +00:08:23,704 --> 00:08:26,206 +它将包含函数 f 和 g 的副本 + +159 +00:08:26,240 --> 00:08:29,176 +可能还包含从 f 和 g 调用的函数 + +160 +00:08:29,209 --> 00:08:32,412 +比如辅助函数和非原始库函数 + +161 +00:08:34,114 --> 00:08:36,817 +另一种优化是循环展开 + +162 +00:08:36,850 --> 00:08:39,052 +它会内联循环体的额外副本 + +163 +00:08:39,086 --> 00:08:41,388 +以暴露迭代之间的并行性 + +164 +00:08:41,421 --> 00:08:44,591 +并避免分支消耗 + +165 +00:08:44,625 --> 00:08:48,562 +编译器有可能只展开循环的两次迭代 + +166 +00:08:48,595 --> 00:08:53,734 +也可能展开具有 +固定边界的循环的所有迭代 + +167 +00:08:53,767 --> 00:08:56,937 +当通过象这样的优化创建一个 +非常大的程序时 + +168 +00:08:56,970 --> 00:09:00,073 +编译器也必须花费 +更多的时间来编译它 + +169 +00:09:00,107 --> 00:09:04,511 +在某些情况下 +你可能希望避免这些成本 + +170 +00:09:04,545 --> 00:09:10,684 +Xcode 14 推出了一种新的 +Metal 优化模式 尺寸优化 + +171 +00:09:10,717 --> 00:09:13,287 +当编译器应用性能优化时 + +172 +00:09:13,320 --> 00:09:15,389 +此模式限制了尺寸扩展转换 + +173 +00:09:15,422 --> 00:09:18,592 +例如内联和循环展开 + +174 +00:09:18,625 --> 00:09:21,895 +这样做的好处是 +可以使 GPU 的二进制代码更小 + +175 +00:09:21,929 --> 00:09:25,399 +编译时间更短 +特别在默认优化 + +176 +00:09:25,432 --> 00:09:27,534 +代价过大的情况下 + +177 +00:09:27,568 --> 00:09:29,203 +在对大小进行优化时 + +178 +00:09:29,236 --> 00:09:32,606 +可能会造成较低的运行时性能 + +179 +00:09:32,639 --> 00:09:35,275 +这是否真的发生取决于程序 + +180 +00:09:35,309 --> 00:09:39,713 +所以你们需要尝试两种优化模式 +并进行比较 + +181 +00:09:39,746 --> 00:09:43,650 +优化大小可能不会提高所有 +着色器的大小和编译时间 + +182 +00:09:43,684 --> 00:09:46,553 +它最有可能对具有深度调用路径 + +183 +00:09:46,587 --> 00:09:48,488 +和循环的大型程序有益 + +184 +00:09:48,522 --> 00:09:50,958 +内联和展开在这些程序里很常见 + +185 +00:09:50,991 --> 00:09:52,926 +当遇到默认优化导致的编译时间 + +186 +00:09:52,960 --> 00:09:57,064 +异常长时 该选项值得尝试 + +187 +00:09:57,097 --> 00:10:02,236 +无论在项目构建期 +还是程序运行时编译 该选项都可用 + +188 +00:10:02,269 --> 00:10:06,206 +在这种情况下 +对大小进行优化会产生不同的效果 + +189 +00:10:06,240 --> 00:10:09,843 +Cycles 是 Blender 3D 设计环境的 + +190 +00:10:09,877 --> 00:10:12,112 +产品渲染器的开源项目 + +191 +00:10:12,145 --> 00:10:15,148 +最近进行了更新以支持 Metal + +192 +00:10:15,182 --> 00:10:17,918 +Apple 最近加入了 Blender 开发基金 + +193 +00:10:17,951 --> 00:10:21,688 +我们所了解的是 Blender 的 +路径跟踪算法 + +194 +00:10:21,722 --> 00:10:25,425 +使用了大型计算着色器 +有许多辅助函数和循环 + +195 +00:10:25,459 --> 00:10:28,328 +它的编译时间加起来可以达到几分钟 + +196 +00:10:28,362 --> 00:10:31,365 +事实证明 这些正是可以 +从 Metal 3 的 + +197 +00:10:31,398 --> 00:10:34,334 +新尺寸优化选项中受益的着色器 + +198 +00:10:36,136 --> 00:10:39,439 +在 Apple 芯片 GPU 上渲染这些场景时 + +199 +00:10:39,473 --> 00:10:42,776 +启用优化尺寸会改善 +Blender 的设置时间 + +200 +00:10:42,809 --> 00:10:48,215 +包括编译着色器管线 最多快 1.4 倍 + +201 +00:10:48,248 --> 00:10:52,953 +它提供了加速 +对渲染时间影响很小甚至没有影响 + +202 +00:10:52,986 --> 00:10:55,022 +有些渲染速度下降了 4% + +203 +00:10:55,055 --> 00:10:57,457 +有些根本没有下降 + +204 +00:10:57,491 --> 00:11:00,227 +因此 有可能运行时性能会降低 + +205 +00:11:00,260 --> 00:11:04,531 +但在某些情况下 对大小进行优化 +也可能提高运行时性能 + +206 +00:11:04,565 --> 00:11:07,334 +这是个例子 + +207 +00:11:07,367 --> 00:11:10,204 +这些是在英特尔 GPU 上 +启用尺寸优化后 + +208 +00:11:10,237 --> 00:11:14,174 +相同场景的渲染时间加速 + +209 +00:11:14,208 --> 00:11:16,610 +好处不仅在于更快的编译速度 + +210 +00:11:16,643 --> 00:11:20,480 +还在于更快的渲染速度 +最高可达 1.6 倍 + +211 +00:11:20,514 --> 00:11:21,481 +怎么样 + +212 +00:11:21,515 --> 00:11:25,018 +因为较小的 GPU 程序可以避免一些 + +213 +00:11:25,052 --> 00:11:26,620 +大尺寸带来的运行时损失 + +214 +00:11:26,653 --> 00:11:28,922 +它可以受益于更少的指令缓存缺失 + +215 +00:11:28,956 --> 00:11:30,757 +或者需要更少的寄存器 + +216 +00:11:30,791 --> 00:11:32,659 +这意味着更少溢出到内存 + +217 +00:11:32,693 --> 00:11:35,295 +甚至更多的并行线程 + +218 +00:11:35,329 --> 00:11:38,932 +请记住 这些结果并不是所有 +着色器和场景的典型结果 + +219 +00:11:38,966 --> 00:11:40,868 +性能下降是有可能的 + +220 +00:11:40,901 --> 00:11:44,104 +对于你的项目 需要评估对编译时间 + +221 +00:11:44,137 --> 00:11:47,107 +和运行性能的实际影响 + +222 +00:11:47,140 --> 00:11:50,677 +你们可以在三种不同的环境中 + +223 +00:11:50,711 --> 00:11:53,046 +从 Metal 源代码编译时启用优化大小 + +224 +00:11:53,080 --> 00:11:55,349 +在 Xcode 14 用户界面中 + +225 +00:11:55,382 --> 00:11:58,352 +在构建设置中指定尺寸优化 + +226 +00:11:58,385 --> 00:12:00,888 +在 Metal Compiler - Build Options 下 + +227 +00:12:00,921 --> 00:12:03,290 +找到 Optimization Level 设置 + +228 +00:12:03,323 --> 00:12:07,528 +“Default” 级别优化了性能 +正如 Metal 过去所做的那样 + +229 +00:12:07,561 --> 00:12:10,397 +“Size” 级别可以优化大小 + +230 +00:12:11,899 --> 00:12:14,268 +通过命令行编译 Metal 源码时 + +231 +00:12:14,301 --> 00:12:18,238 +使用选项 -Os 指定尺寸优化 + +232 +00:12:18,272 --> 00:12:23,343 +第一个示例指定单个编译 +和链接命令的选项 + +233 +00:12:23,377 --> 00:12:25,946 +第二个示例有两个编译命令 + +234 +00:12:25,979 --> 00:12:28,115 +并指定其中一个选项 + +235 +00:12:28,148 --> 00:12:30,551 +使其只对一些着色器启用 + +236 +00:12:30,584 --> 00:12:32,920 +该选项不需要传递给 link 命令 + +237 +00:12:32,953 --> 00:12:34,721 +或任何后续命令 + +238 +00:12:34,755 --> 00:12:38,125 +你们可以选择 +是否和本演讲前面介绍的 + +239 +00:12:38,158 --> 00:12:42,529 +生成 GPU 二进制的命令一起 +使用尺寸优化 + +240 +00:12:44,398 --> 00:12:49,069 +最后 在运行时使用 Metal Framework API +编译 Metal 源代码时 + +241 +00:12:49,102 --> 00:12:51,138 +例如通过 newLibraryWithSource + +242 +00:12:51,171 --> 00:12:54,942 +指定为尺寸优化 +只需在 MTLCompileOptions 对象中 + +243 +00:12:54,975 --> 00:12:57,811 +使用属性 optimizationLevel + +244 +00:12:57,845 --> 00:13:02,316 +优化级别可以是 “default” 或 “size” + +245 +00:13:02,349 --> 00:13:05,719 +我希望你们的项目能够 +从 Metal 编译器中的 + +246 +00:13:05,752 --> 00:13:07,988 +这种新优化模式中受益 + +247 +00:13:08,021 --> 00:13:10,657 +Galo:总结一下 我介绍了离线编译 + +248 +00:13:10,691 --> 00:13:14,328 +这是一种完全在 App 构建时 +生成 GPU 二进制的新工作流 + +249 +00:13:14,361 --> 00:13:18,298 +以减少应用内卡顿 首次启动 +和新关卡加载时间 + +250 +00:13:18,332 --> 00:13:20,934 +Eylon:然后我提出了尺寸优化 + +251 +00:13:20,968 --> 00:13:23,871 +一种在源代码编译时新的 +Metal 优化模式 + +252 +00:13:23,904 --> 00:13:27,541 +以减少程序大小和编译时间 + +253 +00:13:27,574 --> 00:13:29,710 +Galo: 我们希望这些改进 +能够帮助你的 App + +254 +00:13:29,743 --> 00:13:31,578 +或游戏提供更好的用户体验 + +255 +00:13:31,612 --> 00:13:34,648 +Eylon: 让设置和加载时间更短 +卡顿更少 + +256 +00:13:34,681 --> 00:13:39,253 +还有新的工作流程 +感谢运行时更低的编译消耗 + +257 +00:13:39,286 --> 00:13:41,221 +齐: 感谢收看 + diff --git a/zho/2022 Session 10103 Boost performance with MetalFX Upscaling.srt b/zho/2022 Session 10103 Boost performance with MetalFX Upscaling.srt new file mode 100644 index 0000000..407c4af --- /dev/null +++ b/zho/2022 Session 10103 Boost performance with MetalFX Upscaling.srt @@ -0,0 +1,1960 @@ +1 +00:00:00,334 --> 00:00:03,837 +[欢快的音乐] + +2 +00:00:10,043 --> 00:00:11,411 +Kelvin Chiu: 大家好 欢迎 + +3 +00:00:11,445 --> 00:00:14,948 +我是 Kelvin Chiu +来自 Apple GPU Software 团队 + +4 +00:00:14,982 --> 00:00:17,985 +今天 我来谈下如何 +用 MetalFX Upscaling 功能 + +5 +00:00:18,018 --> 00:00:20,087 +提高您的 Metal 应用性能 + +6 +00:00:20,721 --> 00:00:23,090 +MetalFX 是一个新的 API + +7 +00:00:23,123 --> 00:00:26,627 +为 Metal 应用 +提供平台优化的图形效果 + +8 +00:00:27,361 --> 00:00:29,730 +它通过高性能放大 + +9 +00:00:29,763 --> 00:00:31,865 +提高应用的性能 + +10 +00:00:31,899 --> 00:00:34,868 +同时维持渲染质量 + +11 +00:00:34,902 --> 00:00:38,172 +渲染高分辨率帧是非常 +耗费 GPU 时间的 + +12 +00:00:38,205 --> 00:00:41,041 +为了减少这一时间 通常会使用 + +13 +00:00:41,074 --> 00:00:42,910 +低分辨率渲染的方法 + +14 +00:00:42,943 --> 00:00:45,879 +然而 代价就是低渲染质量 + +15 +00:00:45,913 --> 00:00:47,748 +通过 MetalFX 放大 + +16 +00:00:47,781 --> 00:00:49,716 +您的应用可以在渲染帧时 + +17 +00:00:49,750 --> 00:00:52,686 +使用低分辨率 减少渲染时间 + +18 +00:00:52,719 --> 00:00:55,923 +同时无需为渲染质量做妥协 + +19 +00:00:55,956 --> 00:00:58,292 +MetalFX 放大经过优化 + +20 +00:00:58,325 --> 00:01:00,928 +可更好地 +在 Apple 设备上运行 + +21 +00:01:00,961 --> 00:01:04,364 +应用到游戏中也易如反掌 + +22 +00:01:04,398 --> 00:01:07,000 +MetalFX 提供了两种放大效果 + +23 +00:01:07,034 --> 00:01:09,236 +我稍后将详细解释 + +24 +00:01:09,269 --> 00:01:11,338 +空间放大使用简单 + +25 +00:01:11,371 --> 00:01:13,674 +也能带来极大的性能提高 + +26 +00:01:14,541 --> 00:01:17,611 +时序抗锯齿和放大 +可整合多帧信息 + +27 +00:01:17,644 --> 00:01:20,914 +从而生成高质量输出 + +28 +00:01:22,216 --> 00:01:24,418 +我稍后会跟大家说下 + +29 +00:01:24,451 --> 00:01:27,020 +使用这些效果的最佳实践 + +30 +00:01:27,054 --> 00:01:29,022 +在讲座的最后 我会为大家 + +31 +00:01:29,056 --> 00:01:31,625 +演示实际效果 + +32 +00:01:32,893 --> 00:01:35,329 +我们先从空间放大开始 + +33 +00:01:36,096 --> 00:01:37,865 +MetalFX 空间放大 + +34 +00:01:37,898 --> 00:01:40,167 +分析输入的空间信息 + +35 +00:01:40,200 --> 00:01:43,003 +以生成全新的 放大的样本 + +36 +00:01:43,036 --> 00:01:45,506 +整合空间放大很简单 + +37 +00:01:45,539 --> 00:01:48,475 +只需抗锯齿色彩输入 + +38 +00:01:48,509 --> 00:01:51,445 +即可生成空间放大色彩输出 + +39 +00:01:51,478 --> 00:01:54,248 +在典型游戏渲染管线中 + +40 +00:01:54,281 --> 00:01:57,484 +有多个渲染通道 包括抗锯齿渲染 + +41 +00:01:57,518 --> 00:02:00,721 +和多种后期效果处理 + +42 +00:02:00,754 --> 00:02:02,623 +将 MetalFX 空间放大 + +43 +00:02:02,656 --> 00:02:04,725 +紧接着添加在游戏的色彩映射过程 + +44 +00:02:04,758 --> 00:02:05,792 +完成之后 + +45 +00:02:05,826 --> 00:02:08,595 +如果输入已完成色彩映射 +且在视觉色彩空间中 + +46 +00:02:08,629 --> 00:02:10,497 +运行效果最佳 + +47 +00:02:10,531 --> 00:02:13,634 +我们来看看 MetalFX +空间放大的实际效果 + +48 +00:02:15,135 --> 00:02:18,505 +这个象棋场景是 +高质量参考渲染器 + +49 +00:02:18,539 --> 00:02:20,140 +在 4K 分辨率下生成的 + +50 +00:02:20,174 --> 00:02:23,076 +它使用路径跟踪 结合复杂的图形效果 + +51 +00:02:23,110 --> 00:02:26,413 +如光线追踪反射和阴影 + +52 +00:02:26,446 --> 00:02:28,882 +这是并排比较 + +53 +00:02:28,916 --> 00:02:31,451 +左边是 540p 输入 + +54 +00:02:32,553 --> 00:02:36,023 +右边通过 MetalFX 空间放大 +以 1080p 输出 + +55 +00:02:38,926 --> 00:02:41,595 +如果我放大这个皇后 左边 + +56 +00:02:41,628 --> 00:02:44,965 +图像缺少细节 分辨率低 + +57 +00:02:44,998 --> 00:02:47,568 +右边 空间放大输出下 + +58 +00:02:47,601 --> 00:02:50,938 +倒影更清晰 边缘更精细 + +59 +00:02:52,439 --> 00:02:55,943 +接下来 我和大家一起看下 +如何实现 MetalFX 空间放大 + +60 +00:02:57,044 --> 00:03:00,080 +在 Metal 中 您通常会创建 +一个指令编码器 + +61 +00:03:00,113 --> 00:03:02,382 +将指令编码到指令缓冲区 + +62 +00:03:02,416 --> 00:03:04,885 +为效果生成输入 + +63 +00:03:04,918 --> 00:03:08,388 +类似的 您也可以创建一个 +MetalFX 效果对象 + +64 +00:03:08,422 --> 00:03:11,758 +将指令编码到指令缓冲区 +从而运行效果 + +65 +00:03:12,226 --> 00:03:15,362 +最后 创建第三个指令缓冲区 +编码指令 + +66 +00:03:15,395 --> 00:03:17,965 +使用 MetalFX 输出 + +67 +00:03:17,998 --> 00:03:20,634 +您应该只在 App 首次运行 + +68 +00:03:20,667 --> 00:03:22,302 +或改变显示分辨率时 + +69 +00:03:22,336 --> 00:03:24,505 +创建一个新的空间缩放器对象 + +70 +00:03:24,538 --> 00:03:26,507 +因为它创建的成本很高 + +71 +00:03:27,541 --> 00:03:29,676 +首先 创建和配置 + +72 +00:03:29,710 --> 00:03:32,846 +一个 MTLFXSpatialScalerDescriptor + +73 +00:03:32,880 --> 00:03:34,948 +然后 通过调用 +makeSpatialScaler() 方法 + +74 +00:03:34,982 --> 00:03:37,818 +创建缩放器对象 + +75 +00:03:37,851 --> 00:03:39,720 +在初始化代码中 + +76 +00:03:39,753 --> 00:03:41,822 +先为描述符 + +77 +00:03:41,855 --> 00:03:43,290 +填入输入和输出纹理的 + +78 +00:03:43,323 --> 00:03:45,559 +宽度和高度 + +79 +00:03:45,592 --> 00:03:48,662 +然后 为稍后要在缩放器对象上 +设置的纹理 + +80 +00:03:48,695 --> 00:03:50,597 +设置纹理格式 + +81 +00:03:50,631 --> 00:03:53,200 +设置色彩处理模式 + +82 +00:03:53,233 --> 00:03:55,435 +告诉 API 输入和输出 + +83 +00:03:55,469 --> 00:03:57,804 +在什么色彩空间 + +84 +00:03:57,838 --> 00:04:00,474 +您可以将模式设置为 + +85 +00:04:00,507 --> 00:04:03,310 +视觉 线性 或 HDR 色彩空间 + +86 +00:04:03,343 --> 00:04:06,647 +描述符填完后 创建缩放器对象 + +87 +00:04:08,549 --> 00:04:11,985 +创建缩放器对象后 +您可以随时 + +88 +00:04:12,019 --> 00:04:14,354 +修改属性 + +89 +00:04:14,388 --> 00:04:17,491 +然后调用 encode() 方法 +开始放大过程 + +90 +00:04:18,458 --> 00:04:21,628 +在您每帧的绘图代码中 +在缩放效果编码到指令缓冲区前 + +91 +00:04:21,662 --> 00:04:24,331 +确保缩放器对象上 + +92 +00:04:24,364 --> 00:04:27,501 +输入和输出纹理都已设置正确 + +93 +00:04:28,335 --> 00:04:31,839 +空间放大提供了 +可提高性能的简单方法 + +94 +00:04:32,906 --> 00:04:35,209 +如果您想要更高质量的渲染 + +95 +00:04:35,242 --> 00:04:37,377 +MetalFX 时序抗锯齿和放大 + +96 +00:04:37,411 --> 00:04:39,479 +就可以发挥作用了 + +97 +00:04:39,513 --> 00:04:42,583 +时序抗锯齿和放大技术 + +98 +00:04:42,616 --> 00:04:45,819 +使用了上一帧的数据 +来生成高质量放大输出 + +99 +00:04:46,286 --> 00:04:49,089 +这意味着上一帧的放大输出 + +100 +00:04:49,122 --> 00:04:52,559 +将会成为当前帧放大的输入之一 + +101 +00:04:53,961 --> 00:04:57,364 +为了更好地理解为什么 +时序抗锯齿和放大 + +102 +00:04:57,397 --> 00:04:58,565 +需要上一帧的数据 + +103 +00:04:58,599 --> 00:05:01,368 +我先回顾下超级采样的概念 + +104 +00:05:02,536 --> 00:05:03,937 +在超级采样中 + +105 +00:05:03,971 --> 00:05:06,707 +每个像素会做多重采样计算 + +106 +00:05:06,740 --> 00:05:09,877 +然后再整合到一个像素值中 + +107 +00:05:09,910 --> 00:05:12,279 +我们整合到每个像素的样本越多 + +108 +00:05:12,312 --> 00:05:14,548 +效果就越好 + +109 +00:05:14,581 --> 00:05:16,783 +然而 在单一帧内计算 + +110 +00:05:16,817 --> 00:05:18,652 +每个像素的多重样本 + +111 +00:05:18,685 --> 00:05:21,121 +成本很高 + +112 +00:05:21,154 --> 00:05:23,524 +但是 你可以通过时序采样 + +113 +00:05:23,557 --> 00:05:25,292 +代替在同一帧内 + +114 +00:05:25,325 --> 00:05:27,995 +对每个像素进行多重位置采样 + +115 +00:05:28,028 --> 00:05:30,430 +时序采样这一概念 +指的是在指定帧内 + +116 +00:05:30,464 --> 00:05:31,865 +为所有像素 + +117 +00:05:31,899 --> 00:05:34,368 +都按不同的采样位置渲染 + +118 +00:05:34,401 --> 00:05:37,004 +这让您能以极低的成本 + +119 +00:05:37,037 --> 00:05:40,507 +通过多重帧 +获得超级采样的质量 + +120 +00:05:41,308 --> 00:05:44,378 +通过从多重帧对应采样位置 + +121 +00:05:44,411 --> 00:05:46,113 +累积采样 + +122 +00:05:46,146 --> 00:05:47,948 +时序抗锯齿和放大 + +123 +00:05:47,981 --> 00:05:49,683 +可以将样本合理地 + +124 +00:05:49,716 --> 00:05:51,919 +整合为目标分辨率像素 + +125 +00:05:52,052 --> 00:05:55,556 +带来高质量抗锯齿放大输出 + +126 +00:05:56,323 --> 00:05:59,760 +然而 由于内容通常 +在帧与帧之间变化 + +127 +00:05:59,793 --> 00:06:02,963 +它会要求更多输入数据 +来感知这些变化 + +128 +00:06:03,931 --> 00:06:06,133 +除了上一帧的输出 + +129 +00:06:06,166 --> 00:06:08,569 +时序抗锯齿和放大也需要 + +130 +00:06:08,602 --> 00:06:10,871 +抖动色彩输入 + +131 +00:06:10,904 --> 00:06:14,341 +以及场景中的运动数据 +和深度数据 + +132 +00:06:14,942 --> 00:06:18,245 +我会逐一解释其原因 + +133 +00:06:19,613 --> 00:06:21,982 +首先是抖动色彩输入 + +134 +00:06:23,383 --> 00:06:26,820 +这是无抖动渲染的红色三角形 + +135 +00:06:26,854 --> 00:06:30,123 +亮白色的边缘代表三角形已渲染 + +136 +00:06:30,757 --> 00:06:33,760 +每个小正方形代表一个像素 + +137 +00:06:33,794 --> 00:06:37,130 +中间的灰点是像素采样处 + +138 +00:06:38,999 --> 00:06:40,868 +这是通过微小抖动 + +139 +00:06:40,901 --> 00:06:43,270 +渲染的同一个三角形 + +140 +00:06:43,303 --> 00:06:46,573 +灰点表示指定像素的采样位置 + +141 +00:06:47,174 --> 00:06:50,377 +抖动偏移对一组数量的帧来说是唯一的 + +142 +00:06:50,410 --> 00:06:53,380 +从而可以充分收集到所需数量的样本 + +143 +00:06:54,147 --> 00:06:57,451 +我稍后将会详细讲到 +抖动序列的话题 + +144 +00:06:58,685 --> 00:07:01,889 +接下来是来自场景的运动信息 + +145 +00:07:01,922 --> 00:07:03,824 +来自场景的运动信息指的是 + +146 +00:07:03,857 --> 00:07:05,559 +对象从上一帧移动了多少 + +147 +00:07:05,592 --> 00:07:09,096 +从哪个方向移动 + +148 +00:07:09,129 --> 00:07:12,566 +时序抗锯齿和放大 +通过回溯运动信息 + +149 +00:07:12,599 --> 00:07:15,102 +找到上一帧的对应位置 + +150 +00:07:15,135 --> 00:07:17,437 +从而正确收集采样 + +151 +00:07:18,739 --> 00:07:21,842 +另一个输入是来自场景的 +深度信息 + +152 +00:07:22,476 --> 00:07:23,744 +通过场景的深度数据 + +153 +00:07:23,777 --> 00:07:26,914 +可以知道什么在前 +什么在后 + +154 +00:07:26,947 --> 00:07:30,217 +这对于优先处理 +前景边缘抗锯齿非常重要 + +155 +00:07:30,651 --> 00:07:33,887 +也可在上一帧收集采样时 +提供相关线索 + +156 +00:07:33,921 --> 00:07:37,257 +提示有哪些其它对象可能是新出现的 + +157 +00:07:37,291 --> 00:07:40,627 +最后一个输入数据是 +上一帧的输出 + +158 +00:07:42,729 --> 00:07:45,365 +上一帧的输出包括 + +159 +00:07:45,399 --> 00:07:48,836 +之前整合的所有采样 + +160 +00:07:48,869 --> 00:07:52,139 +这些与当前帧的抖动色彩输入相融合 + +161 +00:07:52,172 --> 00:07:55,409 +增加了每像素的采样数据 + +162 +00:07:56,176 --> 00:07:59,513 +通过结合当前帧和上一帧的信息 + +163 +00:07:59,546 --> 00:08:02,649 +生成的图像提供更多细节 + +164 +00:08:02,683 --> 00:08:05,552 +MetalFX 持续跟踪放大输出 + +165 +00:08:05,586 --> 00:08:07,521 +所以您只需传入当前渲染帧的 + +166 +00:08:07,554 --> 00:08:10,490 +色彩 动作和深度即可 + +167 +00:08:11,191 --> 00:08:13,861 +回到典型游戏的渲染管线 + +168 +00:08:13,894 --> 00:08:16,697 +MetalFX 时序抗锯齿和放大应在 + +169 +00:08:16,730 --> 00:08:18,832 +所有后期效果处理前运行 + +170 +00:08:18,866 --> 00:08:20,834 +因为这些效果将会 + +171 +00:08:20,868 --> 00:08:23,103 +干扰放大效果 + +172 +00:08:24,371 --> 00:08:26,306 +我们再来看这个象棋渲染 + +173 +00:08:26,340 --> 00:08:29,810 +这次用的是 MetalFX +时序抗锯齿和放大 + +174 +00:08:29,843 --> 00:08:33,347 +左边是 1080p 输入 +右边是 4K 放大输出 + +175 +00:08:34,248 --> 00:08:36,583 +我们对两者并排比较 + +176 +00:08:41,488 --> 00:08:44,258 +放大看下皇后 + +177 +00:08:44,291 --> 00:08:47,361 +输入为低分辨率 带锯齿 + +178 +00:08:47,394 --> 00:08:50,430 +而右边的时序放大输出 +为高分辨率 + +179 +00:08:50,464 --> 00:08:53,934 +边缘平滑 反射细节更精细 + +180 +00:08:55,068 --> 00:08:58,372 +如空间缩放器一样 +创建新的时序缩放器 + +181 +00:08:58,405 --> 00:09:00,440 +成本高 只应在 + +182 +00:09:00,474 --> 00:09:02,209 +App 首次启动 + +183 +00:09:02,242 --> 00:09:05,312 +或改变显示分辨率时完成 + +184 +00:09:05,345 --> 00:09:07,247 +首先 您要分配及填写 + +185 +00:09:07,281 --> 00:09:10,117 +一个 MTLFXTemporalScalerDescriptor + +186 +00:09:10,851 --> 00:09:14,354 +然后调用 makeTemporalScaler() 方法 +来创建缩放器对象 + +187 +00:09:15,656 --> 00:09:19,092 +在初始化代码中 +先从描述符开始 + +188 +00:09:19,726 --> 00:09:23,230 +填入输入和输出纹理的 +宽度和高度 + +189 +00:09:23,897 --> 00:09:25,632 +然后为缩放器对象上 + +190 +00:09:25,666 --> 00:09:27,501 +稍后作为输入纹理的 +抖动色彩 深度 + +191 +00:09:27,534 --> 00:09:30,971 +和动作纹理的设置格式 + +192 +00:09:32,339 --> 00:09:35,042 +最后 为 MetalFX +存储放大输出的 + +193 +00:09:35,075 --> 00:09:38,378 +输出纹理设置格式 + +194 +00:09:38,412 --> 00:09:41,515 +描述符填写好后 +创建缩放器对象 + +195 +00:09:42,482 --> 00:09:45,686 +在缩放器对象中 +设置动作缩放属性 + +196 +00:09:45,719 --> 00:09:49,223 +这可以帮助您按 API 期望的方式 +缩放 App 的动作数据 + +197 +00:09:50,057 --> 00:09:51,992 +MetalFX 期望运动数据 + +198 +00:09:52,025 --> 00:09:54,661 +是在渲染分辨率像素空间 + +199 +00:09:54,695 --> 00:09:57,497 +提供从当前帧的位置 + +200 +00:09:57,531 --> 00:09:59,733 +到上一帧的位置 + +201 +00:09:59,766 --> 00:10:01,034 +作为示例 + +202 +00:10:01,068 --> 00:10:03,637 +我用了 1080p 的渲染分辨率 + +203 +00:10:03,670 --> 00:10:06,707 +假设有一个对象 +从剪辑空间坐标 + +204 +00:10:06,740 --> 00:10:09,243 +(-0.75, -0.75) 开始 + +205 +00:10:09,276 --> 00:10:12,346 +移动到 +剪辑空间坐标 (0.25, 0.25) + +206 +00:10:12,913 --> 00:10:15,582 +动作数据存储为 (1, 1) + +207 +00:10:17,150 --> 00:10:19,119 +设置运动矢量比例属性 + +208 +00:10:19,152 --> 00:10:21,021 +为 (-960, 540) + +209 +00:10:21,054 --> 00:10:24,358 +这样 MetalFX 可以 +正确分析您游戏的动作数据 + +210 +00:10:26,660 --> 00:10:29,530 +您可以随时修改 + +211 +00:10:29,563 --> 00:10:30,464 +缩放器对象的属性 + +212 +00:10:30,497 --> 00:10:33,934 +调用 encode() 方法 +来开启放大过程 + +213 +00:10:35,402 --> 00:10:37,304 +在每帧绘图代码方面 + +214 +00:10:37,337 --> 00:10:39,606 +首先设置 resetHistory 属性 + +215 +00:10:39,640 --> 00:10:42,476 +当您的 App 加载第一帧 +或场景切换时 + +216 +00:10:42,509 --> 00:10:44,745 +将数值设置为 true + +217 +00:10:44,778 --> 00:10:48,148 +然后设置效果输入的纹理 + +218 +00:10:48,182 --> 00:10:50,984 +随后是输出纹理 + +219 +00:10:51,018 --> 00:10:53,253 +接下来 设置 +reversedDepth 属性 + +220 +00:10:53,287 --> 00:10:56,323 +表明深度值 +是否采用反向 Z 映射 + +221 +00:10:57,558 --> 00:10:58,825 +编码缩放器效果前 + +222 +00:10:58,859 --> 00:11:02,062 +最后一个要设置的属性 +是当前的抖动补偿 + +223 +00:11:03,263 --> 00:11:05,465 +正确获取抖动补偿 +对输出质量来说 + +224 +00:11:05,499 --> 00:11:06,967 +是很重要的 + +225 +00:11:07,000 --> 00:11:10,103 +我们来快速看下 +如何设置抖动补偿 + +226 +00:11:11,371 --> 00:11:14,775 +在示例中 左边是 +抖动渲染的三角形 + +227 +00:11:16,376 --> 00:11:19,379 +右边是像素的放大视图 + +228 +00:11:19,413 --> 00:11:22,716 +样本位于 +(0.625, 0.78) 坐标 + +229 +00:11:23,150 --> 00:11:26,153 +橙色点的位置是像素中心 + +230 +00:11:26,186 --> 00:11:28,889 +位于坐标 (0.5, 0.5) + +231 +00:11:30,357 --> 00:11:31,425 +在这个示例中 + +232 +00:11:31,458 --> 00:11:34,895 +抖动补偿是 (-0.125, -0.28) + +233 +00:11:35,796 --> 00:11:37,431 +注意抖动补偿的范围 + +234 +00:11:37,464 --> 00:11:40,634 +通常是 -0.5 至 0.5 + +235 +00:11:40,667 --> 00:11:43,670 +要验证您提供的抖动补偿 +是否正确 + +236 +00:11:43,704 --> 00:11:46,340 +用不同的抖动补偿序列 +在没有镜头和对象动作的情况下 + +237 +00:11:46,373 --> 00:11:49,343 +渲染场景 + +238 +00:11:49,376 --> 00:11:51,445 +左边是设置了 + +239 +00:11:51,478 --> 00:11:53,881 +错误抖动补偿的示例 + +240 +00:11:53,914 --> 00:11:57,050 +静态对象会偏移 细线变得模糊 + +241 +00:11:57,718 --> 00:11:59,453 +右边是设置了 + +242 +00:11:59,486 --> 00:12:01,688 +正确抖动补偿的输出 + +243 +00:12:01,722 --> 00:12:03,056 +对象保持在正确位置 + +244 +00:12:03,090 --> 00:12:05,626 +细线逐步得以解析 + +245 +00:12:05,659 --> 00:12:08,328 +MetalFX 的时序抗锯齿和放大效果 + +246 +00:12:08,362 --> 00:12:09,930 +提高了您 App 的性能 + +247 +00:12:09,963 --> 00:12:13,033 +为您提供了可与原生目标分辨率渲染 + +248 +00:12:13,066 --> 00:12:16,069 +相比拟的放大质量 + +249 +00:12:16,103 --> 00:12:18,672 +当使用两种放大效果时 + +250 +00:12:18,705 --> 00:12:20,607 +为了获得最佳质量和性能 + +251 +00:12:20,641 --> 00:12:24,011 +我来为大家展示一些最佳实践 + +252 +00:12:25,245 --> 00:12:28,081 +首先是空间放大 + +253 +00:12:28,115 --> 00:12:30,584 +为了达到最佳空间放大质量 + +254 +00:12:30,617 --> 00:12:33,754 +色彩输入应为抗锯齿且无噪声 + +255 +00:12:33,787 --> 00:12:35,289 +因为噪声效果和锯齿图像 + +256 +00:12:35,322 --> 00:12:38,325 +影响边缘判定 + +257 +00:12:38,358 --> 00:12:41,094 +进而影响空间放大质量 + +258 +00:12:41,929 --> 00:12:43,597 +要达到最佳性能 + +259 +00:12:43,630 --> 00:12:46,066 +请使用视觉色彩处理模式 + +260 +00:12:46,099 --> 00:12:48,702 +这意味着您的输入色彩 +应为经过色彩映射 + +261 +00:12:48,735 --> 00:12:52,172 +在 sRGB 色彩空间中 +从 0 到 1 的数值 + +262 +00:12:53,073 --> 00:12:56,043 +最后 要为更高的纹理细节 + +263 +00:12:56,076 --> 00:12:58,712 +设置合适的负向 mip bias + +264 +00:12:58,745 --> 00:13:00,848 +为空间放大 + +265 +00:13:00,881 --> 00:13:03,450 +推荐的 mip bias 计算方法为 + +266 +00:13:03,483 --> 00:13:05,018 +渲染分辨率宽度 + +267 +00:13:05,052 --> 00:13:07,187 +除以目标分辨率宽度 +再取 log2 + +268 +00:13:08,388 --> 00:13:11,525 +比如 将每个渲染分辨率尺寸 + +269 +00:13:11,558 --> 00:13:15,062 +按 2x 缩放 +结果是 -1 mip bias + +270 +00:13:15,095 --> 00:13:17,865 +而如果按 1.5x 比例缩放 + +271 +00:13:17,898 --> 00:13:20,801 +结果是 -0.58 mip bias + +272 +00:13:21,602 --> 00:13:24,838 +注意较低的 mip 等级 +可能会导致高频图案的 + +273 +00:13:24,872 --> 00:13:26,573 +纹理闪烁 + +274 +00:13:26,607 --> 00:13:28,876 +如果看到这种失真现象 应调整 + +275 +00:13:28,909 --> 00:13:31,378 +特定纹理的 mip bias + +276 +00:13:31,411 --> 00:13:33,514 +接下来 我为大家介绍下 + +277 +00:13:33,547 --> 00:13:35,449 +时序抗锯齿和放大的最佳实践 + +278 +00:13:36,183 --> 00:13:39,486 +时序抗锯齿和放大 +要获得最高质量 + +279 +00:13:39,520 --> 00:13:42,990 +选择良好的抖动序列是很重要的 + +280 +00:13:43,023 --> 00:13:44,324 +要找到一个抖动序列 + +281 +00:13:44,358 --> 00:13:46,560 +可以为放大后目标分辨率中 + +282 +00:13:46,593 --> 00:13:47,628 +所有的像素 + +283 +00:13:47,661 --> 00:13:50,230 +都能提供良好的分布 + +284 +00:13:50,264 --> 00:13:53,333 +通常 每个输出像素 +8 个抖动样本 + +285 +00:13:53,367 --> 00:13:56,703 +可生成高质量的 +抗锯齿放大输出 + +286 +00:13:57,671 --> 00:14:00,908 +在 2x 缩放的案例中建议使用 + +287 +00:14:00,941 --> 00:14:03,710 +有 32 次抖动的 Halton (2,3) 序列 + +288 +00:14:03,744 --> 00:14:06,513 +生成抖动色彩输入 + +289 +00:14:06,547 --> 00:14:09,483 +这是 Halton (2,3) 序列中 + +290 +00:14:09,516 --> 00:14:11,318 +前 32 个样本位置 + +291 +00:14:11,351 --> 00:14:14,521 +每个输出像素大约生成 +8 个样本 + +292 +00:14:15,322 --> 00:14:18,525 +设置合适的负向 mip bias +对更高纹理细节 + +293 +00:14:18,559 --> 00:14:20,661 +同样重要 + +294 +00:14:20,694 --> 00:14:22,529 +时序抗锯齿和放大的 + +295 +00:14:22,563 --> 00:14:24,498 +推荐 mip bias 计算方法为 + +296 +00:14:24,531 --> 00:14:27,367 +渲染分辨率宽度 + +297 +00:14:27,401 --> 00:14:30,771 +除以目标分辨率宽度 取 log2 +再减去 1 + +298 +00:14:31,538 --> 00:14:34,808 +比如 每个渲染分辨率尺寸 + +299 +00:14:34,842 --> 00:14:38,011 +以 2x 比例缩放 +结果是 -2 mip bias + +300 +00:14:38,045 --> 00:14:40,480 +而每个尺寸 + +301 +00:14:40,514 --> 00:14:43,483 +以 1.5x 比例缩放 +结果是 -1.58 mip bias + +302 +00:14:44,318 --> 00:14:47,487 +接下来 我给大家演示下 +mip bias 如何在不同情况下 + +303 +00:14:47,521 --> 00:14:49,656 +影响您的输出的示例 + +304 +00:14:50,524 --> 00:14:52,659 +这是同一个场景下 + +305 +00:14:52,693 --> 00:14:54,461 +MetalFX 时序抗锯齿和放大输出 + +306 +00:14:54,494 --> 00:14:57,998 +分别使用 0 -1 和 -2 的 mip bias + +307 +00:15:00,167 --> 00:15:01,869 +-2 的 mip bias 可生成 + +308 +00:15:01,902 --> 00:15:03,904 +锐化度最高 最清晰的输出 + +309 +00:15:03,937 --> 00:15:05,639 +而 0 mip bias 生成 + +310 +00:15:05,672 --> 00:15:08,175 +最柔和 最模糊的输出 + +311 +00:15:09,610 --> 00:15:11,712 +这是使用时序放大效果的 + +312 +00:15:11,745 --> 00:15:14,381 +电路板的三种渲染 + +313 +00:15:14,414 --> 00:15:16,984 +从上到下 纹理采样时 + +314 +00:15:17,017 --> 00:15:19,319 +应用的 mip bias 数值分别是 + +315 +00:15:19,353 --> 00:15:21,922 +0 -1 -2 + +316 +00:15:21,955 --> 00:15:25,359 +因为电路板的纹理 +有高频图案 + +317 +00:15:25,392 --> 00:15:27,661 +如微型跟踪电线 + +318 +00:15:27,694 --> 00:15:30,264 +-2 的 mip bias 会导致闪烁 + +319 +00:15:30,297 --> 00:15:31,865 +和波纹效果 + +320 +00:15:31,899 --> 00:15:34,134 +然而 -1 的 mip bias + +321 +00:15:34,168 --> 00:15:35,769 +可极大减少这种效果 + +322 +00:15:35,802 --> 00:15:38,705 +0 mip bias 可完全抵消 +该效果 + +323 +00:15:39,673 --> 00:15:43,143 +低 mip 水平 +能带来更精细的细节 + +324 +00:15:43,177 --> 00:15:45,913 +使用我们的 mip bias 建议 +作为初始点 + +325 +00:15:45,946 --> 00:15:47,948 +但为高频图案的纹理 + +326 +00:15:47,981 --> 00:15:50,150 +选择 mip bias 时要谨慎 + +327 +00:15:50,184 --> 00:15:53,120 +遵循这些方法就可以确保 + +328 +00:15:53,153 --> 00:15:54,621 +通过 MetalFX 时序抗锯齿和放大 + +329 +00:15:54,655 --> 00:15:57,858 +产生抗锯齿的高质量的放大输出 + +330 +00:16:00,561 --> 00:16:02,863 +最后 我再说下使用 +MetalFX 放大以获得 + +331 +00:16:02,896 --> 00:16:05,399 +最佳性能的方法 + +332 +00:16:05,432 --> 00:16:08,468 +要通过 MetalFX 放大 +获得最佳性能 + +333 +00:16:08,502 --> 00:16:11,338 +你应该注意避免 +两个没有依赖关系的渲染器 + +334 +00:16:11,371 --> 00:16:14,174 +或计算通道 + +335 +00:16:14,208 --> 00:16:16,043 +绑定同样的资源产生读写 + +336 +00:16:16,076 --> 00:16:18,879 +这样会 +造成错误依赖关系 + +337 +00:16:18,912 --> 00:16:21,014 +在 Metal 中应该尽量避免 + +338 +00:16:21,048 --> 00:16:22,816 +错误的依赖关系 + +339 +00:16:22,850 --> 00:16:25,786 +但这对 MetalFX 放大来说 +尤为重要 + +340 +00:16:25,819 --> 00:16:27,688 +我稍后会进一步阐述 + +341 +00:16:27,721 --> 00:16:30,424 +在这个例子中 有两个帧 + +342 +00:16:30,457 --> 00:16:33,794 +阴影和后处理通道完全无关 + +343 +00:16:33,827 --> 00:16:36,997 +没有资源依赖 + +344 +00:16:37,030 --> 00:16:39,666 +Metal 会用当前帧的 +后处理通道 + +345 +00:16:39,700 --> 00:16:42,369 +重叠下一帧的阴影通道 + +346 +00:16:43,504 --> 00:16:45,906 +然而 如果后处理通道 +在阴影通道 + +347 +00:16:45,939 --> 00:16:48,475 +要读取 Metal 缓冲区时 + +348 +00:16:48,509 --> 00:16:50,410 +还在写入同一缓冲区 + +349 +00:16:50,444 --> 00:16:53,347 +Metal 会阻止这两个通道 + +350 +00:16:53,380 --> 00:16:56,617 +在 GPU 上并发运行 +以此避免读取同时写入 + +351 +00:16:56,650 --> 00:16:59,786 +同一资源的潜在风险 + +352 +00:16:59,820 --> 00:17:01,555 +帧与帧之间的错误依赖关系 + +353 +00:17:01,588 --> 00:17:03,223 +对 MetalFX 的放大性能 + +354 +00:17:03,257 --> 00:17:05,492 +会带来负面影响 + +355 +00:17:05,526 --> 00:17:07,160 +如果帧与帧之间 + +356 +00:17:07,194 --> 00:17:09,496 +没有错误依赖关系 + +357 +00:17:09,530 --> 00:17:11,965 +下一帧的阴影通道可能会 + +358 +00:17:11,999 --> 00:17:14,935 +与上一帧的 +MetalFX 放大重叠 + +359 +00:17:14,968 --> 00:17:17,204 +然而 由于帧与帧之间的 + +360 +00:17:17,237 --> 00:17:18,272 +错误依赖关系 + +361 +00:17:18,305 --> 00:17:19,540 +现在的性能下降了 + +362 +00:17:19,573 --> 00:17:20,674 +还包括了 + +363 +00:17:20,707 --> 00:17:22,109 +MetalFX 放大用于 + +364 +00:17:22,142 --> 00:17:23,944 +完成处理的时间 + +365 +00:17:23,977 --> 00:17:25,479 +理想情况上 您应该确保 + +366 +00:17:25,512 --> 00:17:26,847 +在帧与帧之间 + +367 +00:17:26,880 --> 00:17:28,715 +没有错误的依赖关系 + +368 +00:17:28,749 --> 00:17:30,851 +允许不同帧之间的任务可以重叠 + +369 +00:17:30,884 --> 00:17:32,786 +确保使用 +MetalFX 放大时的 + +370 +00:17:32,819 --> 00:17:35,822 +最佳性能 + +371 +00:17:35,856 --> 00:17:36,957 +在这个示例中 + +372 +00:17:36,990 --> 00:17:38,725 +您可以为后期处理和阴影通道 + +373 +00:17:38,759 --> 00:17:40,894 +创建一个独立的缓冲区 + +374 +00:17:40,928 --> 00:17:44,264 +来阻止错误的依赖关系 + +375 +00:17:44,298 --> 00:17:46,233 +使得独立通道彼此可以 + +376 +00:17:46,266 --> 00:17:48,435 +并行执行 + +377 +00:17:49,436 --> 00:17:52,306 +避免错误依赖关系 +是您在应用 + +378 +00:17:52,339 --> 00:17:55,142 +MetalFX 放大时 +需要留意的 + +379 +00:17:55,175 --> 00:17:57,978 +在确定这两个效果之间 +如何选择时 + +380 +00:17:58,011 --> 00:18:01,215 +有几个因素需要考虑 + +381 +00:18:01,949 --> 00:18:05,152 +对于不断增长的着色成本 +和像素数量 + +382 +00:18:05,185 --> 00:18:07,855 +可以考虑 +时序抗锯齿和放大 + +383 +00:18:07,888 --> 00:18:11,058 +按时序分期绘制像素 +可以增加视觉保真 + +384 +00:18:11,091 --> 00:18:12,993 +并提高性能 + +385 +00:18:13,026 --> 00:18:15,996 +如果您还没有较好的 +时序抗锯齿方案 + +386 +00:18:16,029 --> 00:18:17,664 +并且可以渲染抖动色彩 + +387 +00:18:17,698 --> 00:18:19,933 +位移和深度缓冲区 + +388 +00:18:19,967 --> 00:18:22,336 +MetalFX 时序抗锯齿和放大 + +389 +00:18:22,369 --> 00:18:24,438 +可为您提供 + +390 +00:18:24,471 --> 00:18:26,206 +强大的平台优化方案 + +391 +00:18:26,240 --> 00:18:28,275 +如果您没有所需的输入 + +392 +00:18:28,308 --> 00:18:30,644 +或者已经有了一个调整好的 +抗锯齿方案 + +393 +00:18:30,677 --> 00:18:34,114 +可以考虑使用 MetalFX 空间放大 + +394 +00:18:34,147 --> 00:18:36,917 +希望您现在对选择 +哪种放大效果 + +395 +00:18:36,950 --> 00:18:39,219 +有了较好的了解 + +396 +00:18:39,253 --> 00:18:42,256 +接下来我为大家演示下 +Metal 应用程序中的 + +397 +00:18:42,289 --> 00:18:44,658 +实际运行效果 + +398 +00:18:44,691 --> 00:18:47,361 +这是我们 “Modern Rendering +with Metal” 代码中 + +399 +00:18:47,394 --> 00:18:50,130 +“Bistro” 场景的并排比较 + +400 +00:18:50,163 --> 00:18:52,666 +它提供多种实时渲染算法功能 + +401 +00:18:52,699 --> 00:18:56,203 +如环境光遮蔽和体积雾 + +402 +00:18:56,236 --> 00:18:58,839 +左边是 1080p 本地渲染 + +403 +00:18:58,872 --> 00:19:00,140 +右边是使用 +MetalFX 空间放大的 + +404 +00:19:00,174 --> 00:19:02,876 +4K 输出 + +405 +00:19:02,910 --> 00:19:06,246 +这个示例有自己的 +时序抗锯齿解决方案 + +406 +00:19:06,280 --> 00:19:09,550 +我们以此作为 MetalFX 空间放大的输入 + +407 +00:19:10,584 --> 00:19:13,520 +放大仔细看看这部摩托车 + +408 +00:19:15,422 --> 00:19:18,692 +左边的图像有点模糊 而右边 + +409 +00:19:18,725 --> 00:19:20,894 +空间放大输出 + +410 +00:19:20,928 --> 00:19:23,697 +图像锐化度更高 +边缘更清晰 + +411 +00:19:23,730 --> 00:19:26,967 +车把的直线抗锯齿效果很好 + +412 +00:19:28,268 --> 00:19:31,305 +车身的曲线也比较平滑 + +413 +00:19:32,239 --> 00:19:35,509 +我们来对比下性能 + +414 +00:19:35,542 --> 00:19:38,512 +左边是 4K 的原生渲染 + +415 +00:19:38,545 --> 00:19:40,547 +右边是 MetalFX 空间放大的 + +416 +00:19:40,581 --> 00:19:42,850 +4K 输出 + +417 +00:19:44,184 --> 00:19:46,954 +随着镜头的移动 +左边的原生渲染 + +418 +00:19:46,987 --> 00:19:48,956 +运行帧率有起伏 + +419 +00:19:48,989 --> 00:19:50,891 +而右边的空间放大输出 + +420 +00:19:50,924 --> 00:19:53,060 +则更为平滑 + +421 +00:19:55,429 --> 00:19:57,531 +接下来是光线跟踪场景的 + +422 +00:19:57,564 --> 00:20:00,400 +并排比较 +有很多反射和阴影 + +423 +00:20:01,235 --> 00:20:04,438 +左边是 1080p 的原生渲染 + +424 +00:20:04,471 --> 00:20:06,507 +右边是 MetalFX 时序抗锯齿和放大的 + +425 +00:20:06,540 --> 00:20:08,976 +4K 输出 + +426 +00:20:10,310 --> 00:20:13,347 +放大仔细看看吊灯 + +427 +00:20:14,448 --> 00:20:17,651 +左边的原生输出有锯齿 + +428 +00:20:17,684 --> 00:20:19,720 +而右边的时序放大输出 + +429 +00:20:19,753 --> 00:20:22,890 +边缘锐化度更高 细节更精细 + +430 +00:20:22,923 --> 00:20:26,393 +阴影很清晰 不会模糊 + +431 +00:20:26,426 --> 00:20:29,396 +吊灯上的细节都能看清楚 + +432 +00:20:32,266 --> 00:20:34,201 +MetalFX 时序抗锯齿和放大下 + +433 +00:20:34,234 --> 00:20:37,037 +性能提升很明显 + +434 +00:20:37,070 --> 00:20:40,007 +左边是 4K 原生渲染 + +435 +00:20:40,040 --> 00:20:41,909 +右边是 MetalFX 时序抗锯齿和放大的 + +436 +00:20:41,942 --> 00:20:44,978 +4K 输出 + +437 +00:20:45,012 --> 00:20:47,748 +随着镜头的移动 +左边的原生渲染 + +438 +00:20:47,781 --> 00:20:49,983 +运行帧率非常低 + +439 +00:20:50,017 --> 00:20:51,585 +而右边的时序放大输出 + +440 +00:20:51,618 --> 00:20:53,654 +则更平滑 + +441 +00:21:06,967 --> 00:21:08,836 +顶尖的游戏开发者们 + +442 +00:21:08,869 --> 00:21:11,605 +对 MetalFX 放大的实力 +都很兴奋 + +443 +00:21:11,638 --> 00:21:13,807 +今年晚些时候将会带来 + +444 +00:21:13,841 --> 00:21:15,576 +“Grid: Legends” +“Resident Evil: Village” + +445 +00:21:15,609 --> 00:21:18,512 +和 “No Man’s Sky” + +446 +00:21:18,545 --> 00:21:21,682 +接下来 我为大家演示下 +使用这一框架的初期作品 + +447 +00:21:21,715 --> 00:21:24,718 +[隆隆声和撞击声] + +448 +00:21:25,986 --> 00:21:28,689 +在这个场景中 我们可以看到 + +449 +00:21:28,722 --> 00:21:30,824 +使用 MetalFX 时序抗锯齿和放大 + +450 +00:21:30,858 --> 00:21:33,794 +带来的叹为观止的视觉效果 +和流畅的游戏体验 + +451 +00:21:33,827 --> 00:21:34,795 +[羊叫声] + +452 +00:21:34,828 --> 00:21:37,331 +[引擎轰隆声] + +453 +00:21:41,301 --> 00:21:42,269 +回顾下 + +454 +00:21:42,302 --> 00:21:45,639 +MetalFX 是专注于放大的全新 API + +455 +00:21:45,672 --> 00:21:47,841 +空间放大应用简单 + +456 +00:21:47,875 --> 00:21:50,043 +可以带来明显的性能提升 + +457 +00:21:50,077 --> 00:21:52,246 +您也可以使用时序抗锯齿和放大 + +458 +00:21:52,279 --> 00:21:54,715 +获得高质量的渲染 + +459 +00:21:54,748 --> 00:21:57,818 +按照我之前跟您说的 +最佳实践 + +460 +00:21:57,851 --> 00:22:01,121 +可以确保您充分利用 +MetalFX 放大的功能 + +461 +00:22:01,154 --> 00:22:02,656 +感谢大家的观看 + +462 +00:22:02,689 --> 00:22:06,193 +[欢快的音乐] + diff --git a/zho/2022 Session 10104 Load resources faster with Metal 3.srt b/zho/2022 Session 10104 Load resources faster with Metal 3.srt new file mode 100644 index 0000000..70597e6 --- /dev/null +++ b/zho/2022 Session 10104 Load resources faster with Metal 3.srt @@ -0,0 +1,1911 @@ +1 +00:00:00,267 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:10,077 +♪ + +3 +00:00:10,077 --> 00:00:11,912 +嗨 我是 Jaideep Joshi + +4 +00:00:11,912 --> 00:00:14,781 +我是 Apple 的 +一名 GPU 软件工程师 + +5 +00:00:14,781 --> 00:00:16,517 +在今天的讲座中 我将介绍 + +6 +00:00:16,517 --> 00:00:19,253 +Metal 3 中的一项新功能 + +7 +00:00:19,253 --> 00:00:23,223 +它将为您的游戏和 App +简化和优化资源加载 + +8 +00:00:23,223 --> 00:00:24,458 +我将首先向您展示 + +9 +00:00:24,458 --> 00:00:26,426 +快速资源加载功能可以如何 + +10 +00:00:26,426 --> 00:00:30,230 +适配于您 App 的资产加载管线 + +11 +00:00:30,230 --> 00:00:33,700 +它的几项核心功能 +可以在 Apple 产品上 + +12 +00:00:33,700 --> 00:00:36,236 +充分利用新存储技术 + +13 +00:00:36,236 --> 00:00:39,039 +快速资源加载的一些高阶功能 + +14 +00:00:39,039 --> 00:00:43,343 +可以解决您的 App +可能遇到的有趣场景 + +15 +00:00:43,343 --> 00:00:45,646 +还有一些您应当了解的 + +16 +00:00:45,646 --> 00:00:47,414 +最佳实践的建议 它们会帮助您 + +17 +00:00:47,414 --> 00:00:52,319 +在 App 中有效地使用这些功能 + +18 +00:00:52,319 --> 00:00:55,022 +当您向 App +添加快速资源加载时 + +19 +00:00:55,022 --> 00:00:58,392 +Metal System Trace +和 GPU 调试器等工具 + +20 +00:00:58,392 --> 00:01:02,896 +可以帮助分析性能和 +解决您可能遇到的问题 + +21 +00:01:02,896 --> 00:01:05,232 +最后 我将介绍一个 + +22 +00:01:05,232 --> 00:01:09,636 +展示快速资源加载实际运用的案例 + +23 +00:01:09,636 --> 00:01:13,173 +以下这些都是 Metal 3 的快速资源 +加载功能可以为您做到的 + +24 +00:01:15,175 --> 00:01:17,277 +借助 Metal 3 的 +快速资源加载功能 + +25 +00:01:17,277 --> 00:01:20,547 +您的游戏和 App +将以低延迟和高通量 + +26 +00:01:20,547 --> 00:01:23,050 +加载资产 这些是借助 + +27 +00:01:23,050 --> 00:01:25,652 +Apple 芯片统一内存架构 + +28 +00:01:25,652 --> 00:01:30,357 +以及 Apple 平台配备的 +快速 SSD 存储来实现的 + +29 +00:01:30,357 --> 00:01:31,658 +您将了解到 用于流式传输和 + +30 +00:01:31,658 --> 00:01:34,094 +和减少加载时间的 以确保您的 + +31 +00:01:34,094 --> 00:01:38,599 +游戏资产按时准备就绪的 +最好的方法 + +32 +00:01:38,599 --> 00:01:41,001 +减少加载时间的一个关键在于 + +33 +00:01:41,001 --> 00:01:42,903 +以尽可能小的粒度 + +34 +00:01:42,903 --> 00:01:45,973 +只加载您所需要的资源 + +35 +00:01:45,973 --> 00:01:49,142 +Metal 3 中的高通量 +和低延迟 + +36 +00:01:49,142 --> 00:01:52,012 +让您的 App 可以 +流式传输更高质量的资产 + +37 +00:01:52,012 --> 00:01:56,283 +包括纹理 音频和几何数据 + +38 +00:01:56,283 --> 00:01:59,219 +现在我将向您介绍一个游戏中 + +39 +00:01:59,219 --> 00:02:01,622 +资产加载的案例 + +40 +00:02:01,622 --> 00:02:03,624 +在游戏第一次启动 + +41 +00:02:03,624 --> 00:02:07,361 +或在新关卡开始时 +通常会显示加载画面 + +42 +00:02:07,361 --> 00:02:10,931 +这样就可以将游戏的 +资产加载到内存当中 + +43 +00:02:10,931 --> 00:02:12,866 +当玩家在关卡中移动时 + +44 +00:02:12,866 --> 00:02:16,436 +游戏会为场景加载更多资产 + +45 +00:02:16,436 --> 00:02:19,940 +缺点是玩家需要花费很长时间 + +46 +00:02:19,940 --> 00:02:21,842 +等待游戏向存储系统发起 + +47 +00:02:21,842 --> 00:02:25,846 +多个请求 来进行资产的预先加载 + +48 +00:02:25,846 --> 00:02:29,850 +而且 这些资产 +还可能会占用大量内存 + +49 +00:02:29,850 --> 00:02:34,221 +有几种方法可以改善这种体验 + +50 +00:02:34,221 --> 00:02:35,822 +游戏可以通过 + +51 +00:02:35,822 --> 00:02:37,691 +在玩家离对象越来越近时 + +52 +00:02:37,691 --> 00:02:40,427 +对其进行动态流式传输 +来改善这种状况 + +53 +00:02:40,427 --> 00:02:44,131 +这样一来 游戏只需要 +加载它一开始需要的内容 + +54 +00:02:44,131 --> 00:02:46,366 +并在玩家在关卡中移动时 + +55 +00:02:46,366 --> 00:02:49,369 +逐渐流式传输其他资源 + +56 +00:02:49,369 --> 00:02:53,340 +比如说 游戏最初加载这块黑板时 + +57 +00:02:53,340 --> 00:02:56,710 +使用了较低分辨率 +但当玩家走向它时 + +58 +00:02:56,710 --> 00:03:00,314 +游戏就加载了更高分辨率的版本 + +59 +00:03:00,314 --> 00:03:03,050 +这种方法减少了玩家在加载画面中 + +60 +00:03:03,050 --> 00:03:05,219 +等待的时间 + +61 +00:03:05,219 --> 00:03:08,922 +但是 玩家仍然有可能 +看到分辨率较低的物体 + +62 +00:03:08,922 --> 00:03:11,758 +即使是在近距离场景中 + +63 +00:03:11,758 --> 00:03:13,760 +因为加载高分辨率版本 + +64 +00:03:13,760 --> 00:03:16,797 +所需要的时间太长 + +65 +00:03:16,797 --> 00:03:19,900 +解决这个问题的一种方法是 +将每项资产以较小份额 + +66 +00:03:19,900 --> 00:03:23,270 +进行流式传输 + +67 +00:03:23,270 --> 00:03:26,206 +比如说 您的游戏可以只加载 +场景的可见区域 + +68 +00:03:26,206 --> 00:03:29,877 +用稀疏的纹理流式传输图块 + +69 +00:03:29,877 --> 00:03:32,279 +而不是所有 mip 等级 + +70 +00:03:32,279 --> 00:03:34,781 +这大大减少了您的 App + +71 +00:03:34,781 --> 00:03:37,317 +需要进行流式传输的数据量 + +72 +00:03:37,317 --> 00:03:40,053 +使用这种方法 加载请求变得更小 + +73 +00:03:40,053 --> 00:03:41,955 +但数量更多 + +74 +00:03:41,955 --> 00:03:44,892 +但没关系 因为现代存储硬件 + +75 +00:03:44,892 --> 00:03:48,529 +可以同时运行多个加载请求 + +76 +00:03:48,529 --> 00:03:50,731 +这意味着您可以在 + +77 +00:03:50,731 --> 00:03:55,202 +不损失可玩性的前提下 +提高场景的分辨率和规模 + +78 +00:03:55,202 --> 00:03:58,405 +在发出大量小载入请求的同时 + +79 +00:03:58,405 --> 00:04:02,075 +您还可以设定载入请求的优先级 + +80 +00:04:02,075 --> 00:04:06,380 +确保高优先级的请求及时完成 + +81 +00:04:06,380 --> 00:04:07,948 +刚才我已经向您介绍了 + +82 +00:04:07,948 --> 00:04:11,952 +提高游戏视觉保真度 +同时减少加载时间的方法 + +83 +00:04:11,952 --> 00:04:15,022 +现在我将向您展示 +Metal 3 的快速资源加载功能 + +84 +00:04:15,022 --> 00:04:16,523 +如何帮助您做到这一点 + +85 +00:04:16,523 --> 00:04:19,660 +快速资源加载是一种 + +86 +00:04:19,660 --> 00:04:22,296 +从存储中加载资源的异步 API + +87 +00:04:22,296 --> 00:04:26,166 +与现有的加载 API 不同 +发起加载的线程 + +88 +00:04:26,166 --> 00:04:29,503 +不需要等待加载完成 + +89 +00:04:29,503 --> 00:04:32,239 +加载操作通过并行执行 + +90 +00:04:32,239 --> 00:04:36,310 +来更有效地利用加速存储的通量 + +91 +00:04:36,310 --> 00:04:38,278 +您可以批量进行加载操作 + +92 +00:04:38,278 --> 00:04:42,049 +进一步将资源加载的 +额外开销降到最低限度 + +93 +00:04:42,049 --> 00:04:43,984 +最后 使用 Metal 3 + +94 +00:04:43,984 --> 00:04:48,622 +您可以优先处理 +用于降低延迟的加载操作 + +95 +00:04:48,622 --> 00:04:50,524 +现在我将向您展示 + +96 +00:04:50,524 --> 00:04:53,160 +可以帮助您构建 +资产加载管道的核心功能 + +97 +00:04:53,160 --> 00:04:56,430 +首先从加载资源的步骤开始 + +98 +00:04:56,430 --> 00:04:59,099 +加载资源分为三个步骤 + +99 +00:04:59,099 --> 00:05:00,501 +打开一个文件 + +100 +00:05:00,501 --> 00:05:02,936 +发出必要的加载命令 + +101 +00:05:02,936 --> 00:05:07,040 +然后将加载命令与渲染工作同步 + +102 +00:05:07,040 --> 00:05:10,911 +下面是具体方法 首先打开一个文件 + +103 +00:05:10,911 --> 00:05:14,414 +可以通过使用 Metal 设备 +实例创建文件句柄 + +104 +00:05:14,414 --> 00:05:16,817 +来打开现有文件 + +105 +00:05:16,817 --> 00:05:20,420 +例如 这段代码 +使用 Metal 设备实例 + +106 +00:05:20,420 --> 00:05:21,822 +通过调用它的 + +107 +00:05:21,822 --> 00:05:28,562 +新 makeIOHandle 方法 +传入文件路径 URL 来创建文件柄 + +108 +00:05:28,562 --> 00:05:30,297 +一旦有了文件句柄 + +109 +00:05:30,297 --> 00:05:33,934 +您就可以使用它来发出加载命令 + +110 +00:05:33,934 --> 00:05:36,470 +在这个 App 的典型场景中 + +111 +00:05:36,470 --> 00:05:40,274 +它在执行加载操作 +和编码 GPU 的工作 + +112 +00:05:40,274 --> 00:05:43,577 +使用现有的加载 API +App 必须等待加载工作完成 + +113 +00:05:43,577 --> 00:05:46,680 +才能对渲染工作进行编码 + +114 +00:05:46,680 --> 00:05:48,382 +Metal 3 让您的 App + +115 +00:05:48,382 --> 00:05:51,852 +可以异步执行加载命令 + +116 +00:05:51,852 --> 00:05:55,255 +首先创建一个 +Metal IO 命令队列 + +117 +00:05:55,255 --> 00:05:58,792 +然后使用该队列 +创建 IO 命令缓冲 + +118 +00:05:58,792 --> 00:06:02,529 +并将加载命令编码到缓冲 + +119 +00:06:02,529 --> 00:06:05,799 +不过 由于命令缓冲在命令队列上 + +120 +00:06:05,799 --> 00:06:09,002 +异步执行 您的 App 无需等待 + +121 +00:06:09,002 --> 00:06:12,206 +加载操作完成 + +122 +00:06:12,206 --> 00:06:14,174 +实际上 不仅 IO 命令缓冲内 + +123 +00:06:14,174 --> 00:06:17,010 +所有命令并发执行 + +124 +00:06:17,010 --> 00:06:20,180 +IO 命令缓冲本身也并发执行 + +125 +00:06:20,180 --> 00:06:22,616 +并乱序完成 + +126 +00:06:22,616 --> 00:06:26,086 +这种并列执行模型通过 + +127 +00:06:26,086 --> 00:06:30,324 +最大化通量来 +更好地利用加速存储硬件 + +128 +00:06:30,324 --> 00:06:35,195 +您可以将三种类型的 +IO 命令编码到命令缓冲 + +129 +00:06:35,195 --> 00:06:37,831 +loadTexture +加载到 Metal 纹理上 + +130 +00:06:37,831 --> 00:06:39,433 +用于纹理的流式传输 + +131 +00:06:39,433 --> 00:06:41,835 +loadBuffer +加载到 Metal 缓冲上 + +132 +00:06:41,835 --> 00:06:44,371 +用于流式传输场景和几何数据 + +133 +00:06:44,371 --> 00:06:49,476 +还有 loadBytes +加载到 CPU 可访问的内存 + +134 +00:06:49,476 --> 00:06:53,514 +您可以从 IO 命令队列上 +创建 IO 命令缓冲 + +135 +00:06:53,514 --> 00:06:56,517 +要创建队列 首先制作和配置 + +136 +00:06:56,517 --> 00:06:59,419 +一个 IO 命令队列描述符 + +137 +00:06:59,419 --> 00:07:02,389 +默认情况下 队列是并行的 + +138 +00:07:02,389 --> 00:07:04,791 +但您也可以将它们设置为 +按顺序 完全不打乱地 + +139 +00:07:04,791 --> 00:07:08,161 +运行命令缓冲 + +140 +00:07:08,161 --> 00:07:10,163 +然后 请传递队列描述符 + +141 +00:07:10,163 --> 00:07:16,370 +到 Metal 设备实例的 +makeIOCommandQueue 方法 + +142 +00:07:16,370 --> 00:07:18,172 +请调用命令队列的 + +143 +00:07:18,172 --> 00:07:22,843 +makeCommandBuffer 方法 +来创建 IO 命令缓冲 + +144 +00:07:22,843 --> 00:07:26,446 +然后使用该命令缓冲对 +加载纹理和缓存的 + +145 +00:07:26,446 --> 00:07:29,116 +加载命令进行编码 + +146 +00:07:29,116 --> 00:07:32,085 +Metal 的验证层将在运行时 + +147 +00:07:32,085 --> 00:07:33,554 +捕获编码错误 + +148 +00:07:33,554 --> 00:07:36,823 +加载命令使用之前创建的 + +149 +00:07:36,823 --> 00:07:39,393 +fileHandle 实例 + +150 +00:07:39,393 --> 00:07:42,362 +在您将加载命令添加到命令缓冲后 + +151 +00:07:42,362 --> 00:07:44,665 +请通过调用命令 +缓冲的 commit 方法 + +152 +00:07:44,665 --> 00:07:49,203 +将它提交到队列中进行执行 + +153 +00:07:49,203 --> 00:07:52,139 +介绍完如何创建 IO 命令队列 + +154 +00:07:52,139 --> 00:07:54,341 +命令缓冲 发出加载命令 + +155 +00:07:54,341 --> 00:07:57,144 +并将它们提交到队列中之后 +我想向您展示 + +156 +00:07:57,144 --> 00:08:01,915 +如何将加载工作 +与其他 GPU 工作同步 + +157 +00:08:01,915 --> 00:08:04,518 +App 通常会在完成渲染资源的 + +158 +00:08:04,518 --> 00:08:08,488 +加载之后 启动此渲染工作 + +159 +00:08:08,488 --> 00:08:11,358 +但是使用快速资源加载的 App + +160 +00:08:11,358 --> 00:08:14,294 +需要一种方法来将 IO 命令队列 + +161 +00:08:14,294 --> 00:08:17,197 +与渲染命令队列同步 + +162 +00:08:17,197 --> 00:08:21,301 +您可以通过 Metal 共享事件 +让这些队列同步 + +163 +00:08:21,301 --> 00:08:24,571 +Metal 共享事件让您可以同步 + +164 +00:08:24,571 --> 00:08:27,140 +IO 队列中的命令缓冲区 + +165 +00:08:27,140 --> 00:08:30,110 +与渲染队列中的命令缓冲区 + +166 +00:08:30,110 --> 00:08:33,046 +您可以通过编码 +waitEvent 命令 + +167 +00:08:33,046 --> 00:08:35,782 +告知命令缓冲区需等待共享事件 + +168 +00:08:35,782 --> 00:08:38,285 +同样地 您也可以通过 +编码 signalEvent 命令 + +169 +00:08:38,285 --> 00:08:42,456 +告知命令缓冲区 +发出共享事件信号 + +170 +00:08:42,456 --> 00:08:44,791 +Metal 确保所有命令缓冲内的 + +171 +00:08:44,791 --> 00:08:46,927 +IO 命令 +在它发出共享事件信号 + +172 +00:08:46,927 --> 00:08:50,130 +之前都已经完成 + +173 +00:08:50,130 --> 00:08:52,099 +要使各个命令缓冲同步 + +174 +00:08:52,099 --> 00:08:55,002 +您首先需要 +一个 Metal 共享事件 + +175 +00:08:55,002 --> 00:08:57,838 +您可以调用 +waitForEvent 方法 + +176 +00:08:57,838 --> 00:09:01,175 +告知命令缓冲区需等待共享事件 + +177 +00:09:01,175 --> 00:09:03,310 +同样 您也可以通过调用 +signalEvent 方法 + +178 +00:09:03,310 --> 00:09:04,611 +告知命令缓冲需发出 + +179 +00:09:04,611 --> 00:09:07,681 +共享事件信号 + +180 +00:09:07,681 --> 00:09:08,949 +您可以将类似的逻辑添加到 + +181 +00:09:08,949 --> 00:09:11,018 +相应的 GPU 命令缓冲区 + +182 +00:09:11,018 --> 00:09:13,220 +使它等待 IO 命令缓冲区 + +183 +00:09:13,220 --> 00:09:15,489 +发出相同共享事件的信号 + +184 +00:09:15,489 --> 00:09:18,292 +来回顾一下 +这些是在 Metal App + +185 +00:09:18,292 --> 00:09:21,762 +加载资源的核心功能和 API + +186 +00:09:21,762 --> 00:09:25,365 +创建 Metal 文件句柄 +来打开文件 + +187 +00:09:25,365 --> 00:09:28,669 +通过创建 IO 命令队列 +和 IO 命令缓冲 + +188 +00:09:28,669 --> 00:09:30,871 +来发出加载命令 + +189 +00:09:30,871 --> 00:09:33,607 +接下来 将加载命令 +编码到命令缓冲区 + +190 +00:09:33,607 --> 00:09:36,109 +在队列中执行 + +191 +00:09:36,109 --> 00:09:38,912 +最后 +使用 Metal 共享事件的 + +192 +00:09:38,912 --> 00:09:41,648 +wait +和 signalEvent 命令 + +193 +00:09:41,648 --> 00:09:43,984 +来同步加载与渲染 + +194 +00:09:43,984 --> 00:09:46,220 +现在 我将介绍一些您可能会 + +195 +00:09:46,220 --> 00:09:48,689 +觉得有帮助的高阶功能 + +196 +00:09:48,689 --> 00:09:50,090 +一个典型的例子就是 + +197 +00:09:50,090 --> 00:09:53,393 +游戏无法将整个地图放进内存 + +198 +00:09:53,393 --> 00:09:56,296 +因此它将地图细分为区域 + +199 +00:09:56,296 --> 00:09:58,432 +随着玩家在地图上前进 + +200 +00:09:58,432 --> 00:10:02,536 +游戏开始预加载地图的部分区域 + +201 +00:10:02,536 --> 00:10:05,172 +根据玩家的方向 游戏判定 + +202 +00:10:05,172 --> 00:10:07,975 +最适合预加载的区域是西北区 + +203 +00:10:07,975 --> 00:10:10,277 +西区和西南区 + +204 +00:10:10,277 --> 00:10:13,113 +但是 一旦玩家移动到西区 + +205 +00:10:13,113 --> 00:10:14,815 +并开始转向南方 + +206 +00:10:14,815 --> 00:10:18,752 +那么预加载西北区就不再有用 + +207 +00:10:18,752 --> 00:10:21,121 +为了减少未来加载的延迟 + +208 +00:10:21,121 --> 00:10:25,859 +Metal 3 允许您 +尝试取消加载操作 + +209 +00:10:25,859 --> 00:10:29,696 +让我们来看看如何在实践中进行操作 + +210 +00:10:29,696 --> 00:10:31,765 +当玩家处在中心区域时 + +211 +00:10:31,765 --> 00:10:36,036 +为三个区域编码 +并提交 IO 命令缓冲 + +212 +00:10:36,036 --> 00:10:38,105 +之后 当玩家到达西区 + +213 +00:10:38,105 --> 00:10:41,208 +并开始往南移动时 +使用 tryCancel 方法 + +214 +00:10:41,208 --> 00:10:44,811 +取消西北区的加载 + +215 +00:10:44,811 --> 00:10:48,215 +取消的粒度是命令缓冲区 + +216 +00:10:48,215 --> 00:10:51,852 +因此您可以在 +执行过程中取消命令缓冲区 + +217 +00:10:51,852 --> 00:10:53,987 +如果之后您想知道 + +218 +00:10:53,987 --> 00:10:56,390 +该区域是否已完全加载 + +219 +00:10:56,390 --> 00:11:00,928 +您可以检查命令缓冲区的状态 + +220 +00:11:00,928 --> 00:11:05,666 +Metal 3 还可以让您 +将 IO 工作优先处理 + +221 +00:11:05,666 --> 00:11:08,502 +设想一下 当玩家被传送到 + +222 +00:11:08,502 --> 00:11:12,139 +新的场景区域时 +您的游戏开始流式传输 + +223 +00:11:12,139 --> 00:11:14,641 +大量的图形资产 + +224 +00:11:14,641 --> 00:11:16,009 +同时 + +225 +00:11:16,009 --> 00:11:19,546 +游戏需要播放传送音效 + +226 +00:11:19,546 --> 00:11:23,183 +快速资源加载功能 +允许您加载 App 的所有资产 + +227 +00:11:23,183 --> 00:11:25,519 +包括音频数据 + +228 +00:11:25,519 --> 00:11:28,222 +要加载音频 您可以使用 +前面谈到的 loadBytes 命令 + +229 +00:11:28,222 --> 00:11:32,492 +来加载到 App 分配的内存 + +230 +00:11:32,492 --> 00:11:36,129 +在这个例子中 +纹理和音频 IO 命令缓冲 + +231 +00:11:36,129 --> 00:11:40,667 +在单个 IO 命令队列上并列执行 + +232 +00:11:40,667 --> 00:11:43,103 +这张简化图标展示了 + +233 +00:11:43,103 --> 00:11:45,005 +存储层的请求 + +234 +00:11:45,005 --> 00:11:46,974 +存储系统能够同时执行 + +235 +00:11:46,974 --> 00:11:50,577 +音频和纹理加载请求 + +236 +00:11:50,577 --> 00:11:53,080 +为了避免音频延迟 +至关重要的一点是 + +237 +00:11:53,080 --> 00:11:55,516 +流式传输系统能够将 + +238 +00:11:55,516 --> 00:11:58,685 +音频请求优先于 纹理请求进行处理 + +239 +00:11:58,685 --> 00:12:01,421 +要将音频请求优先 您可以创建 + +240 +00:12:01,421 --> 00:12:06,326 +一个单独的 IO 命令队列 +并将其优先级设置为高 + +241 +00:12:06,326 --> 00:12:10,430 +存储系统将 +确保高优先级的 IO 请求 + +242 +00:12:10,430 --> 00:12:15,269 +具有较低的延迟并优先于其他请求 + +243 +00:12:15,269 --> 00:12:17,871 +在为音频资产创建单独的 + +244 +00:12:17,871 --> 00:12:20,374 +高优先级队列后 音频加载请求的 + +245 +00:12:20,374 --> 00:12:22,976 +执行时间变短了 + +246 +00:12:22,976 --> 00:12:25,212 +而并行的纹理加载请求的 + +247 +00:12:25,212 --> 00:12:28,148 +执行时间变长了 + +248 +00:12:28,148 --> 00:12:31,084 +创建高优先级队列的方法是这样的 + +249 +00:12:31,084 --> 00:12:34,555 +您只需要将命令队列 +描述符的优先级属性 + +250 +00:12:34,555 --> 00:12:36,089 +设置为高 + +251 +00:12:36,089 --> 00:12:39,393 +您还可以将优先级设置为正常或低 + +252 +00:12:39,393 --> 00:12:41,428 +然后像往常一样从描述符中 + +253 +00:12:41,428 --> 00:12:44,331 +创建一个新的 IO 命令队列 + +254 +00:12:44,331 --> 00:12:47,267 +但需要记住 在创建队列之后 +您就不能再更改 + +255 +00:12:47,267 --> 00:12:49,670 +它的优先级了 + +256 +00:12:49,670 --> 00:12:52,573 +当您向 App 添加 +快速资源加载功能时 + +257 +00:12:52,573 --> 00:12:56,443 +有一些最佳实践需要牢记 + +258 +00:12:56,443 --> 00:12:59,213 +首先 请考虑对资产进行压缩 + +259 +00:12:59,213 --> 00:13:01,882 +您可以通过内置或自定义压缩 + +260 +00:13:01,882 --> 00:13:05,018 +来降低 App 的磁盘占用 + +261 +00:13:05,018 --> 00:13:07,588 +压缩让您可以用运行时性能 + +262 +00:13:07,588 --> 00:13:10,457 +换取更小的磁盘占用空间 + +263 +00:13:10,457 --> 00:13:12,960 +此外 在使用稀疏纹理时 + +264 +00:13:12,960 --> 00:13:17,397 +您可以通过调整 +稀疏页大小来提高存储通量 + +265 +00:13:17,397 --> 00:13:20,100 +接下来我将更详细地介绍它们 + +266 +00:13:20,100 --> 00:13:22,302 +首先是压缩 + +267 +00:13:22,302 --> 00:13:24,805 +您可以使用 +Metals 3 的 API + +268 +00:13:24,805 --> 00:13:28,475 +离线压缩您的资产文件 + +269 +00:13:28,475 --> 00:13:31,645 +首先 创建一个压缩上下文并使用 + +270 +00:13:31,645 --> 00:13:35,215 +chunk size 和 +compression 方法对它进行配置 + +271 +00:13:35,215 --> 00:13:38,285 +然后将部分资产文件传递给上下文 + +272 +00:13:38,285 --> 00:13:42,556 +生成所有文件的单一压缩版本 + +273 +00:13:42,556 --> 00:13:46,059 +压缩上下文将所有数据分块 + +274 +00:13:46,059 --> 00:13:48,795 +使用您选择的 +编解码器对其进行压缩 + +275 +00:13:48,795 --> 00:13:51,732 +并将其存储到包文件中 + +276 +00:13:51,732 --> 00:13:53,467 +在这个例子中 + +277 +00:13:53,467 --> 00:13:57,337 +上下文将数据 +压缩为 64KB 大小的分块 + +278 +00:13:57,337 --> 00:13:59,673 +但您也可以根据需要压缩的数据 + +279 +00:13:59,673 --> 00:14:03,844 +自身的大小和类型 +来选择合适的分块大小 + +280 +00:14:03,844 --> 00:14:08,115 +下面为您介绍 +如何在 Metal 3 中使用压缩 API + +281 +00:14:08,115 --> 00:14:10,384 +首先 提供创建压缩文件的路径 + +282 +00:14:10,384 --> 00:14:13,520 +压缩方法和分块大小 + +283 +00:14:13,520 --> 00:14:16,857 +来创建压缩上下文 + +284 +00:14:16,857 --> 00:14:20,861 +接下来 获取文件数据 +并将其附加到上下文上 + +285 +00:14:20,861 --> 00:14:24,765 +在这里 文件数据 +处于一个 NSData 对象中 + +286 +00:14:24,765 --> 00:14:27,134 +您可以通过多次调用附加数据 + +287 +00:14:27,134 --> 00:14:31,138 +附加来自不同文件的数据 + +288 +00:14:31,138 --> 00:14:32,840 +添加完数据后 + +289 +00:14:32,840 --> 00:14:34,908 +您就可以调用刷新 +和销毁压缩上下文函数 + +290 +00:14:34,908 --> 00:14:40,480 +来完成并保存压缩文件 + +291 +00:14:40,480 --> 00:14:43,350 +您可以通过创建文件句柄 + +292 +00:14:43,350 --> 00:14:45,686 +打开并访问压缩文件 + +293 +00:14:45,686 --> 00:14:49,656 +文件句柄在发出加载命令时使用 + +294 +00:14:49,656 --> 00:14:53,594 +对于压缩文件 +Metal 3 执行内联解压 + +295 +00:14:53,594 --> 00:14:56,096 +通过将偏移量转换为需要解压的 + +296 +00:14:56,096 --> 00:15:00,634 +分块列表 并将它们 +加载到您的资源中 + +297 +00:15:00,634 --> 00:15:05,639 +您可以使用 Metal 设备实例 +创建文件句柄 + +298 +00:15:05,639 --> 00:15:08,742 +比如说 这段代码 +使用 Metal 设备实例 + +299 +00:15:08,742 --> 00:15:10,244 +创建文件句柄的方式是 + +300 +00:15:10,244 --> 00:15:12,579 +通过提供压缩文件路径 + +301 +00:15:12,579 --> 00:15:16,350 +到我之前介绍过的 +makeIOHandle 方法中 + +302 +00:15:16,350 --> 00:15:18,886 +压缩文件的一个附加参数 + +303 +00:15:18,886 --> 00:15:21,221 +是压缩方法 + +304 +00:15:21,221 --> 00:15:22,856 +它与您在创建压缩文件时使用的 + +305 +00:15:22,856 --> 00:15:26,960 +压缩方法一致 + +306 +00:15:26,960 --> 00:15:28,028 +现在 我将介绍 + +307 +00:15:28,028 --> 00:15:30,464 +支持的各种压缩方法 + +308 +00:15:30,464 --> 00:15:32,666 +以及每一种的特点 + +309 +00:15:32,666 --> 00:15:36,136 +来帮助您了解 +如何在它们之间进行选择 + +310 +00:15:36,136 --> 00:15:39,439 +当解压速度非常关键 +并且您的 App + +311 +00:15:39,439 --> 00:15:42,776 +可以承受较大的磁盘 +占用空间时 您可以使用 LZ4 + +312 +00:15:42,776 --> 00:15:45,646 +如果平衡编解码器速度和压缩比 + +313 +00:15:45,646 --> 00:15:51,251 +对您来说很重要 那就请选择 +ZLib、LZBitmap 或 LZFSE + +314 +00:15:51,251 --> 00:15:53,086 +在注重平衡的编解码器中 + +315 +00:15:53,086 --> 00:15:56,757 +ZLib 更适用于 +非 Apple 设备 + +316 +00:15:56,757 --> 00:16:00,761 +LZBitmap 编码 +和解码速度很快 + +317 +00:16:00,761 --> 00:16:04,264 +而 LZFSE 具有很高的压缩比 + +318 +00:16:04,264 --> 00:16:06,667 +如果您需要最佳压缩比 + +319 +00:16:06,667 --> 00:16:09,102 +请考虑选用 LZMA 编解码器 + +320 +00:16:09,102 --> 00:16:14,408 +前提是您的 App +能承受解码资产所需的额外时间 + +321 +00:16:14,408 --> 00:16:18,412 +您也可以使用您自己的压缩方案 + +322 +00:16:18,412 --> 00:16:20,948 +在一些情况中 您的数据可能会从 + +323 +00:16:20,948 --> 00:16:23,283 +自定义压缩编解码器中受益 + +324 +00:16:23,283 --> 00:16:26,253 +如果是这样 +您可以使用自己的压缩器 + +325 +00:16:26,253 --> 00:16:29,056 +和平移偏移量替换压缩上下文 + +326 +00:16:29,056 --> 00:16:33,393 +并在运行时自行解压 + +327 +00:16:33,393 --> 00:16:35,462 +现在您已经知道该如何使用压缩 + +328 +00:16:35,462 --> 00:16:37,297 +来减少磁盘占用了 + +329 +00:16:37,297 --> 00:16:40,634 +让我们来看看如何调整稀疏页大小 + +330 +00:16:40,634 --> 00:16:43,337 +先前版本的 Metal 支持加载 + +331 +00:16:43,337 --> 00:16:47,374 +稀疏纹理粒度 +在 16KB 大小的图块 + +332 +00:16:47,374 --> 00:16:51,778 +使用 Metal 3 您可以 +指定两种新的稀疏图块大小: + +333 +00:16:51,778 --> 00:16:54,748 +64KB 和 256KB + +334 +00:16:54,748 --> 00:16:57,451 +这些新尺寸可以让您 + +335 +00:16:57,451 --> 00:17:00,220 +以更大的粒度进行纹理的流式传输 + +336 +00:17:00,220 --> 00:17:02,990 +更充分地利用存储硬件并使它饱和 + +337 +00:17:02,990 --> 00:17:04,691 +请注意 您需要权衡 + +338 +00:17:04,691 --> 00:17:06,960 +流式传输更大尺寸的图块 + +339 +00:17:06,960 --> 00:17:09,329 +和流式传输的数据量 + +340 +00:17:09,329 --> 00:17:12,666 +所以您必须使用 App +及其稀疏纹理进行测试 + +341 +00:17:12,666 --> 00:17:16,103 +找到最合适的尺寸 + +342 +00:17:16,103 --> 00:17:18,272 +接下来 让我们来看看如何借助 + +343 +00:17:18,272 --> 00:17:21,575 +一组 Metal 开发者工具 + +344 +00:17:21,575 --> 00:17:24,111 +为您 App 的快速加载 +资源功能进行性能分析和调试 + +345 +00:17:24,111 --> 00:17:28,949 +Xcode 14 包含了对 +快速资源加载功能的全面支持 + +346 +00:17:28,949 --> 00:17:32,019 +从使用 Metal System Trace +的运行时性能分析 + +347 +00:17:32,019 --> 00:17:35,322 +到使用 +Metal 调试器的 API 检查 + +348 +00:17:35,322 --> 00:17:37,257 +和高级依赖分析 + +349 +00:17:39,393 --> 00:17:42,129 +首先是运行时性能分析 + +350 +00:17:42,129 --> 00:17:45,933 +在 Xcode 14 中 Instruments 可以 +使用 Metal System Trace 模板 + +351 +00:17:45,933 --> 00:17:48,435 +对快速资源加载功能进行性能分析 + +352 +00:17:48,435 --> 00:17:51,538 +Instruments 是一个强大的 +性能分析工具 + +353 +00:17:51,538 --> 00:17:53,507 +可以帮助您 +在 Metal App 中 + +354 +00:17:53,507 --> 00:17:56,043 +达成最佳性能 + +355 +00:17:56,043 --> 00:17:58,679 +Metal System Trace 模板 +允许您在 + +356 +00:17:58,679 --> 00:18:02,182 +加载操作被编码和执行时进行检查 + +357 +00:18:02,182 --> 00:18:04,484 +您将理解它们是如何与 + +358 +00:18:04,484 --> 00:18:06,787 +您的 App 在 CPU +和 GPU 上运行的操作 + +359 +00:18:06,787 --> 00:18:10,257 +相互关联的 + +360 +00:18:10,257 --> 00:18:13,660 +如需了解如何使用 Instruments +对您的 Metal App 进行性能分析 + +361 +00:18:13,660 --> 00:18:16,096 +请查看之前的讲座 + +362 +00:18:16,096 --> 00:18:19,366 +“使用 GPU 计数器 +优化 Metal App 和游戏” + +363 +00:18:19,366 --> 00:18:23,237 +以及“针对 +Apple GPU 优化高端游戏” + +364 +00:18:23,237 --> 00:18:26,373 +现在 让我们来谈谈调试 + +365 +00:18:26,373 --> 00:18:28,909 +使用 Xcode 14 中的 +Metal 调试器 + +366 +00:18:28,909 --> 00:18:30,777 +您现在可以分析游戏中新的 + +367 +00:18:30,777 --> 00:18:33,981 +快速资源加载 API 的使用情况 + +368 +00:18:33,981 --> 00:18:36,717 +进行帧捕获后 您就可以检查 + +369 +00:18:36,717 --> 00:18:40,554 +所有快速资源加载 API 的调用 + +370 +00:18:40,554 --> 00:18:43,123 +从创建的 IO 命令缓冲 + +371 +00:18:43,123 --> 00:18:46,560 +到已发出的加载操作 + +372 +00:18:46,560 --> 00:18:48,228 +您现在可以使用新的依赖关系查看器 + +373 +00:18:48,228 --> 00:18:50,297 +来对快速资源加载依赖关系 + +374 +00:18:50,297 --> 00:18:53,367 +进行可视化检查 + +375 +00:18:53,367 --> 00:18:56,203 +依赖关系查看器提供了 + +376 +00:18:56,203 --> 00:18:59,306 +IO 命令缓冲和 Metal +传递之间资源依赖关系的 + +377 +00:18:59,306 --> 00:19:01,542 +详细描述 + +378 +00:19:01,542 --> 00:19:04,144 +从这里出发 您可以使用新的 + +379 +00:19:04,144 --> 00:19:05,913 +依赖关系查看器中的各种功能 + +380 +00:19:05,913 --> 00:19:09,483 +比如新的同步边缘和图形筛选 + +381 +00:19:09,483 --> 00:19:13,587 +来深入研究并优化资源加载依赖关系 + +382 +00:19:13,587 --> 00:19:17,357 +如需了解 Xcode 14 中 +新的依赖关系查看器的更多信息 + +383 +00:19:17,357 --> 00:19:18,759 +请查看今年的 + +384 +00:19:18,759 --> 00:19:22,362 +“利用 Metal 3 实现无绑定” 讲座 + +385 +00:19:22,362 --> 00:19:26,333 +现在让我们看看 +快速资源加载的实际效果 + +386 +00:19:26,333 --> 00:19:27,968 +这个测试场景使用了 + +387 +00:19:27,968 --> 00:19:31,338 +新的快速资源加载 API +以 16KB 的图块大小 + +388 +00:19:31,338 --> 00:19:35,309 +进行纹理数据的流式传输 + +389 +00:19:35,309 --> 00:19:38,779 +该视频来自配备 +M1 Pro 芯片的 MacBook Pro + +390 +00:19:38,779 --> 00:19:40,247 +流式传输系统查询 + +391 +00:19:40,247 --> 00:19:44,518 +GPU 的稀疏纹理访问计数器 +来确认两项内容 + +392 +00:19:44,518 --> 00:19:46,687 +已采样但未加载的图块 + +393 +00:19:46,687 --> 00:19:49,423 +以及 App 未使用的已加载图块 + +394 +00:19:49,423 --> 00:19:52,659 +App 使用此信息对所需图块的 + +395 +00:19:52,659 --> 00:19:54,127 +加载列表以及 + +396 +00:19:54,127 --> 00:19:57,397 +不需要图块的回收列表进行编码 + +397 +00:19:57,397 --> 00:20:00,234 +这样一来 工作集中只包含 + +398 +00:20:00,234 --> 00:20:03,203 +App 最有可能使用的图块 + +399 +00:20:03,203 --> 00:20:06,340 +如果玩家决定前往场景的另一部分 + +400 +00:20:06,340 --> 00:20:08,909 +App 就需要对一套全新的 + +401 +00:20:08,909 --> 00:20:11,011 +高分辨率纹理进行流式传输 + +402 +00:20:11,011 --> 00:20:13,347 +如果流式传输系统足够快 + +403 +00:20:13,347 --> 00:20:17,117 +玩家就不会注意到传输正在发生 + +404 +00:20:17,117 --> 00:20:18,385 +如果我暂停这个场景 + +405 +00:20:18,385 --> 00:20:21,321 +您就可以更清楚地观察画面差异 + +406 +00:20:21,321 --> 00:20:23,624 +左侧画面是在单个线程上 + +407 +00:20:23,624 --> 00:20:26,527 +使用 pread API +加载稀疏图块 + +408 +00:20:26,527 --> 00:20:28,629 +右侧画面是 +使用快速资源加载 API + +409 +00:20:28,629 --> 00:20:31,732 +加载稀疏图块 + +410 +00:20:31,732 --> 00:20:33,667 +当玩家进入场景时 + +411 +00:20:33,667 --> 00:20:36,737 +大部分纹理尚未完全加载 + +412 +00:20:36,737 --> 00:20:39,907 +加载完成后 就可以看到最终的 + +413 +00:20:39,907 --> 00:20:42,910 +高分辨率版本纹理 + +414 +00:20:42,910 --> 00:20:46,113 +如果我回到场景的开头并进行慢放 + +415 +00:20:46,113 --> 00:20:48,482 +您将更容易注意到 + +416 +00:20:48,482 --> 00:20:51,418 +快速资源加载功能带来的改善 + +417 +00:20:51,418 --> 00:20:54,054 +为了突出差异 渲染中将用 + +418 +00:20:54,054 --> 00:20:59,426 +红色标出 App 尚未加载的图块 + +419 +00:20:59,426 --> 00:21:01,528 +一开始 场景显示 + +420 +00:21:01,528 --> 00:21:05,632 +App 尚未加载大多数图块 + +421 +00:21:05,632 --> 00:21:08,602 +然而 在玩家进入场景时 + +422 +00:21:08,602 --> 00:21:11,038 +与单线程 pread 版本相比 + +423 +00:21:11,038 --> 00:21:14,007 +快速资源加载功能 +改善了高分辨率图块的加载 + +424 +00:21:14,007 --> 00:21:18,712 +并最大限度减少了延迟 + +425 +00:21:18,712 --> 00:21:21,782 +Metal 3 的快速资源 +加载功能可以 + +426 +00:21:21,782 --> 00:21:24,685 +帮助您构建强大而高效的资产 +流式传输系统 让您的 App + +427 +00:21:24,685 --> 00:21:28,388 +充分利用最新的存储技术 + +428 +00:21:28,388 --> 00:21:32,793 +您可以使用它来及时流式传输 +包括更高质量的图像 + +429 +00:21:32,793 --> 00:21:35,762 +在内的资产以减少加载时间 + +430 +00:21:35,762 --> 00:21:40,234 +您也使用 Metal 的共享事件 +在 GPU 渲染场景时 + +431 +00:21:40,234 --> 00:21:43,103 +异步加载资产 + +432 +00:21:43,103 --> 00:21:46,006 +对于您 App 急需的资产 + +433 +00:21:46,006 --> 00:21:48,809 +可以通过创建具有更高 +优先级的命令队列 + +434 +00:21:48,809 --> 00:21:51,011 +将延迟降到最低 + +435 +00:21:51,011 --> 00:21:54,014 +请记住 一定要提前发送加载命令 + +436 +00:21:54,014 --> 00:21:56,283 +让存储系统保持繁忙 + +437 +00:21:56,283 --> 00:22:00,954 +您可以随时取消不需要的命令 + +438 +00:22:00,954 --> 00:22:04,258 +Metal 3 中的快速资源 +加载功能引入了一些新方法 + +439 +00:22:04,258 --> 00:22:06,860 +来发挥现代存储硬件的力量 + +440 +00:22:06,860 --> 00:22:09,830 +实现高通量资产加载 + +441 +00:22:09,830 --> 00:22:12,266 +我迫不及待想看看 +您是如何使用这些功能 + +442 +00:22:12,266 --> 00:22:15,969 +来提高您 App 的 +视觉质量和响应能力的 + +443 +00:22:15,969 --> 00:22:17,137 +感谢您的观看 + +444 +00:22:17,137 --> 00:22:20,874 +♪ + diff --git a/zho/2022 Session 10105 Maximize your Metal ray tracing performance.srt b/zho/2022 Session 10105 Maximize your Metal ray tracing performance.srt new file mode 100644 index 0000000..61a968b --- /dev/null +++ b/zho/2022 Session 10105 Maximize your Metal ray tracing performance.srt @@ -0,0 +1,2394 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,545 +Yi Liu: 大家好 我是 Yi + +3 +00:00:11,578 --> 00:00:13,814 +大家好 我是 Dominik + +4 +00:00:13,847 --> 00:00:16,283 +我们是 GPU 软件工程师 + +5 +00:00:16,316 --> 00:00:20,287 +Yi: 今天 Dominik 和我 +将和大家讨论今年我们在 + +6 +00:00:20,320 --> 00:00:23,690 +Metal Ray Tracing API 中 +增加的性能增强和功能 + +7 +00:00:23,724 --> 00:00:27,060 +以帮助您最大限度地提高 +光线追踪 App 的性能 + +8 +00:00:27,094 --> 00:00:30,731 +光线追踪 App 可以模拟 +在场景间反射的 + +9 +00:00:30,764 --> 00:00:33,000 +单个光线 + +10 +00:00:33,033 --> 00:00:36,570 +这被用于游戏和离线渲染的场景中 + +11 +00:00:36,603 --> 00:00:41,975 +以产生逼真的反射 阴影 +全局光照等效果 + +12 +00:00:42,009 --> 00:00:44,545 +这需要模拟大量光线 + +13 +00:00:44,578 --> 00:00:47,814 +因此性能对于这些 App 至关重要 + +14 +00:00:47,848 --> 00:00:51,585 +幸运的是 Metal 内置了针对所有 + +15 +00:00:51,618 --> 00:00:54,388 +Apple 设备优化的光线追踪支持 + +16 +00:00:54,421 --> 00:00:57,357 +让我们简要回顾下光线追踪 +在 Metal 中的工作原理 + +17 +00:00:57,391 --> 00:01:01,662 +Metal 光线追踪 API 可用于 +如计算或片元函数等 + +18 +00:01:01,695 --> 00:01:05,265 +着色器函数 + +19 +00:01:05,299 --> 00:01:09,503 +我们首先产生一些光线 +将它们发射到场景中 + +20 +00:01:09,536 --> 00:01:13,473 +接下来 我们创建一个相交处理对象 +并用它来检查 + +21 +00:01:13,507 --> 00:01:18,011 +我们的光线和场景中的 +几何形体之间的交点 + +22 +00:01:18,045 --> 00:01:21,114 +稍后 我将介绍今年 + +23 +00:01:21,148 --> 00:01:24,418 +为加快相交搜索而添加的一些新功能 + +24 +00:01:24,451 --> 00:01:26,920 +此过程依赖于一种特殊的数据结构 + +25 +00:01:26,954 --> 00:01:29,056 +它叫做加速结构 + +26 +00:01:29,089 --> 00:01:32,292 +它也表示场景中的几何形体 + +27 +00:01:32,326 --> 00:01:36,129 +今天我还将谈谈几个关于加速结构的 + +28 +00:01:36,163 --> 00:01:38,732 +新功能和性能改进 + +29 +00:01:38,765 --> 00:01:41,835 +相交处理返回一个交点结果对象 + +30 +00:01:41,869 --> 00:01:45,038 +描述每条光线所命中的图元 + +31 +00:01:45,072 --> 00:01:50,711 +交点结果用于产生 +写入输出图像的颜色 + +32 +00:01:50,744 --> 00:01:53,514 +它也可以用来产生额外的光线 + +33 +00:01:53,547 --> 00:01:55,749 +这些光线会再次经过这个过程 + +34 +00:01:55,782 --> 00:01:58,485 +我们可以多次重复这个过程 + +35 +00:01:58,519 --> 00:02:01,054 +只要我们想模拟 +光线在场景中反射的效果 + +36 +00:02:01,088 --> 00:02:05,392 +如果您想了解更多有关 +Metal 光线追踪 API 的基础知识 + +37 +00:02:05,425 --> 00:02:09,796 +我建议您看看我们之前的 WWDC 讲座 + +38 +00:02:09,830 --> 00:02:14,334 +我们首先在 WWDC20 上引入了 +Metal 光线追踪 API + +39 +00:02:14,368 --> 00:02:19,139 +去年 我们引入了 +包括支持运动模糊在内的新功能 + +40 +00:02:19,173 --> 00:02:22,576 +今天我们要讨论三件事 + +41 +00:02:22,609 --> 00:02:26,680 +首先 我将介绍一些新功能 + +42 +00:02:26,713 --> 00:02:29,082 +这些功能有助于提高您的 App 中 +光线追踪的性能 + +43 +00:02:30,817 --> 00:02:33,954 +接下来 我将介绍我们添加到 + +44 +00:02:33,987 --> 00:02:36,323 +加速结构 API 中的改进和功能 + +45 +00:02:38,258 --> 00:02:40,994 +最后 Dominik 将介绍用于光线追踪的 + +46 +00:02:41,028 --> 00:02:43,897 +GPU 工具的改进 + +47 +00:02:43,931 --> 00:02:46,266 +今年 我们添加了三个新功能 + +48 +00:02:46,300 --> 00:02:48,802 +旨在提高光线追踪性能 + +49 +00:02:48,836 --> 00:02:51,004 +或者简化您的代码 + +50 +00:02:51,038 --> 00:02:54,708 +它们分别是逐图元数据 +从相交函数表中 + +51 +00:02:54,741 --> 00:02:56,844 +获取缓冲区的能力 + +52 +00:02:56,877 --> 00:02:59,980 +以及间接指令缓冲区对 +光线追踪的支持 + +53 +00:03:01,949 --> 00:03:04,484 +我们先说说逐图元数据 + +54 +00:03:04,518 --> 00:03:08,956 +App 通常具有与其场景中的 +图元相关联的数据 + +55 +00:03:08,989 --> 00:03:12,559 +例如顶点颜色 法线和纹理坐标 + +56 +00:03:13,894 --> 00:03:16,296 +今年 我们添加了在加速结构中 + +57 +00:03:16,330 --> 00:03:21,235 +直接为每个图元 +存储少量数据的功能 + +58 +00:03:21,268 --> 00:03:25,305 +访问这些数据时可以更少使用 +内存间接寻址和碰到缓存缺失 + +59 +00:03:25,339 --> 00:03:27,374 +从而提高性能 + +60 +00:03:27,407 --> 00:03:31,645 +这也减少了存储复杂的 +辅助数据结构的需要 + +61 +00:03:31,678 --> 00:03:35,883 +这些数据结构通常是查找 +与图元相关的数据所必需的 + +62 +00:03:37,184 --> 00:03:38,785 +我们来看一个例子 + +63 +00:03:39,853 --> 00:03:42,823 +Alpha 测试是一种用于在不增加 + +64 +00:03:42,856 --> 00:03:47,127 +三角形计数的情况下 +增加透明几何形体复杂性的技术 + +65 +00:03:47,160 --> 00:03:51,064 +在这种技术中 映射到三角形上的 +纹理的 alpha 通道 + +66 +00:03:51,098 --> 00:03:55,435 +用于确定光线是应该 +击中三角形还是继续发射 + +67 +00:03:56,670 --> 00:03:59,573 +要实现这一点 就需要配置相交处理 + +68 +00:03:59,606 --> 00:04:03,477 +以便在射线击中三角形时 +调用自定义相交函数 + +69 +00:04:04,645 --> 00:04:08,982 +最终目标是从与三角形关联的 +纹理中采样 + +70 +00:04:09,016 --> 00:04:13,187 +并测试 alpha 值是否允许 +光线继续穿过图元 + +71 +00:04:13,220 --> 00:04:16,757 +要达到这个目的 您需要两条信息 + +72 +00:04:16,790 --> 00:04:20,093 +纹理对象和 UV 坐标 + +73 +00:04:20,127 --> 00:04:22,829 +在 alpha 测试的典型实现中 + +74 +00:04:22,863 --> 00:04:25,832 +您需要访问 Metal 设备内存中的 + +75 +00:04:25,866 --> 00:04:29,002 +多个中间缓冲区才能获得此信息 + +76 +00:04:30,370 --> 00:04:34,341 +首先 将与图元关联的纹理 + +77 +00:04:34,374 --> 00:04:36,410 +存储在某种材质结构中 + +78 +00:04:37,878 --> 00:04:41,081 +几种材料将被装入缓冲区 + +79 +00:04:41,114 --> 00:04:45,052 +存储每个图元的材质结构 +是不切实际的 + +80 +00:04:45,085 --> 00:04:48,856 +因为它们可能非常大 +并且可能有很多图元 + +81 +00:04:48,889 --> 00:04:52,125 +相反 您只需要将每个图元的材料 ID + +82 +00:04:52,159 --> 00:04:56,630 +存储在缓冲区中 +并使用它们查找材料 + +83 +00:04:56,663 --> 00:05:00,200 +接下来 要计算 UV +您就需要从另一个缓冲区加载 + +84 +00:05:00,234 --> 00:05:04,104 +每个顶点的 UV 并对其进行插值 + +85 +00:05:04,137 --> 00:05:07,875 +最后 假设您使用的是 +实例化几何形体 + +86 +00:05:07,908 --> 00:05:12,279 +您可能希望每个实例 +都有自己的材质和 UV 映射 + +87 +00:05:12,312 --> 00:05:14,848 +为支持这一点 您可以将 + +88 +00:05:14,882 --> 00:05:19,119 +指向 UV 和材质 ID 缓冲区的指针 +存储在实例数据缓冲区中 + +89 +00:05:19,152 --> 00:05:22,556 +为函数添加另一个间接级别 + +90 +00:05:22,589 --> 00:05:26,827 +这种方法要求您维护一个 +相当复杂的缓冲区设置 + +91 +00:05:26,860 --> 00:05:31,798 +并涉及许多层的间接关系 +以获得您需要的数据 + +92 +00:05:31,832 --> 00:05:33,901 +这也可能导致缓存丢失 + +93 +00:05:33,934 --> 00:05:37,371 +从而对性能产生负面影响 + +94 +00:05:37,404 --> 00:05:40,908 +我们看看实现此图表所需的代码 + +95 +00:05:40,941 --> 00:05:44,278 +然后 我将展示如何使用 + +96 +00:05:44,311 --> 00:05:46,180 +逐图元数据逐步简化它 + +97 +00:05:46,213 --> 00:05:50,817 +这是 alpha 测试相交函数的原始实现 + +98 +00:05:50,851 --> 00:05:54,922 +当光线击中经过 alpha 测试的三角形时 +该函数就会被调用 + +99 +00:05:54,955 --> 00:05:58,859 +该函数从内存加载实例数据开始 + +100 +00:05:58,892 --> 00:06:02,896 +这个缓冲区包含指向 UV 的指针 +和实例使用的 + +101 +00:06:02,930 --> 00:06:04,464 +材料缓冲区 + +102 +00:06:04,498 --> 00:06:07,267 +接下来 该函数从 UV 缓冲区 + +103 +00:06:07,301 --> 00:06:10,237 +加载 UV 坐标 并对其进行插值 + +104 +00:06:10,270 --> 00:06:12,105 +这又是一个内存加载 + +105 +00:06:12,139 --> 00:06:15,976 +然后 该函数从另一个缓冲区 +加载材质索引 + +106 +00:06:16,009 --> 00:06:18,445 +最后 该函数加载材质 + +107 +00:06:18,478 --> 00:06:20,681 +并对相应的纹理进行采样 + +108 +00:06:20,714 --> 00:06:24,051 +此时 函数得到所需的 alpha 值 + +109 +00:06:24,084 --> 00:06:26,086 +可以将其与阈值进行比较 + +110 +00:06:26,119 --> 00:06:29,656 +现在 我将展示如何使用逐图元数据 + +111 +00:06:29,690 --> 00:06:33,327 +来简化这段代码并提高其性能 + +112 +00:06:33,360 --> 00:06:35,829 +您可以直接在加速结构中只存储 + +113 +00:06:35,863 --> 00:06:38,198 +相交函数需要的每个逐图元数据 + +114 +00:06:38,232 --> 00:06:41,702 +而不是使用复杂的 + +115 +00:06:41,735 --> 00:06:45,405 +多层间接缓冲区设置 + +116 +00:06:45,439 --> 00:06:47,941 +在此示例中 您可以为每个图元 + +117 +00:06:47,975 --> 00:06:51,645 +创建一个包含纹理和 UV 坐标的结构 + +118 +00:06:51,678 --> 00:06:54,815 +在构建加速结构时提供该数据 + +119 +00:06:54,848 --> 00:06:57,384 +当光线击中图元时 + +120 +00:06:57,417 --> 00:07:00,254 +相交函数只接收指向该数据的指针 + +121 +00:07:00,287 --> 00:07:03,190 +您可以在逐图元数据中 +存储任何需要的内容 + +122 +00:07:03,223 --> 00:07:07,327 +但较小的存储量 +将有助于获得最佳性能 + +123 +00:07:07,361 --> 00:07:10,597 +我将从相交函数的输入开始 + +124 +00:07:10,631 --> 00:07:13,901 +可以访问所有这些数据让你在实现时 + +125 +00:07:13,934 --> 00:07:15,869 +获得很大的灵活性 + +126 +00:07:15,903 --> 00:07:19,406 +但也会增加 GPU 上的 +寄存器使用量 + +127 +00:07:19,439 --> 00:07:22,676 +有了逐图元数据 而不是整个缓冲区 + +128 +00:07:22,709 --> 00:07:26,146 +您只需要访问图元数据指针 + +129 +00:07:26,180 --> 00:07:30,317 +这是您直接存储在加速结构中的数据 + +130 +00:07:30,350 --> 00:07:34,354 +在这种情况下 +每个图元都有自己的纹理对象 + +131 +00:07:34,388 --> 00:07:36,757 +和所有顶点的 UV + +132 +00:07:36,790 --> 00:07:41,461 +接下来是对全局材质缓冲区 +和实例数据缓冲区的加载 + +133 +00:07:41,495 --> 00:07:43,063 +这两个您都不需要 + +134 +00:07:43,096 --> 00:07:47,467 +相反 您可以从每个逐图元数据指针 +加载一次 + +135 +00:07:47,501 --> 00:07:51,004 +这是此函数中唯一需要的 +设备内存访问 + +136 +00:07:51,038 --> 00:07:52,606 +接下来是 UV + +137 +00:07:52,639 --> 00:07:56,343 +您可以简单地访问嵌入在 +逐图元数据结构中的数据 + +138 +00:07:56,376 --> 00:08:01,014 +而不是对实例数据 +获取的指针解引用 + +139 +00:08:01,048 --> 00:08:04,785 +代码中的更改很细微 +但对性能很重要 + +140 +00:08:04,818 --> 00:08:07,721 +因为不涉及额外的内存加载 + +141 +00:08:07,754 --> 00:08:10,424 +最后 还有材料属性 + +142 +00:08:10,457 --> 00:08:13,794 +由于所需材质的唯一部分是纹理 + +143 +00:08:13,827 --> 00:08:15,729 +因此可以在逐图元数据结构中 + +144 +00:08:15,762 --> 00:08:18,098 +直接对图元的纹理进行编码 + +145 +00:08:18,131 --> 00:08:20,767 +这意味着您不再需要访问 + +146 +00:08:20,801 --> 00:08:22,936 +材料和材料索引缓冲区 + +147 +00:08:22,970 --> 00:08:24,972 +您可以直接使用纹理 + +148 +00:08:25,005 --> 00:08:28,442 +而无需支付额外的内存解引用成本 + +149 +00:08:28,475 --> 00:08:31,178 +这就是使用逐图元数据时 + +150 +00:08:31,211 --> 00:08:33,313 +相交代码的简单程度 + +151 +00:08:33,347 --> 00:08:35,916 +所有代价高昂的内存访问 + +152 +00:08:35,949 --> 00:08:39,486 +都被图元数据指针的一次加载所取代 + +153 +00:08:39,520 --> 00:08:43,524 +最重要的是 代码更简单 更易理解 + +154 +00:08:44,224 --> 00:08:47,160 +接下来 我将展示如何在加速结构中 + +155 +00:08:47,194 --> 00:08:49,363 +存储图元数据 + +156 +00:08:49,396 --> 00:08:53,233 +您需要先执行此操作 +然后才能通过相交函数访问它 + +157 +00:08:53,267 --> 00:08:55,369 +您需要在加速结构 + +158 +00:08:55,402 --> 00:08:57,804 +几何形体描述符中设置几个字段 + +159 +00:08:57,838 --> 00:09:01,008 +首先 设置存储数据的 Metal 缓冲区 + +160 +00:09:01,041 --> 00:09:05,345 +接下来 指定将为每个图元 +存储的数据的大小 + +161 +00:09:05,379 --> 00:09:07,814 +如果数据没有在缓冲区中紧凑打包 + +162 +00:09:07,848 --> 00:09:10,284 +或者没有从缓冲区的开头开始 + +163 +00:09:10,317 --> 00:09:13,287 +您还可以指定步进和偏移量 + +164 +00:09:13,320 --> 00:09:17,591 +否则 这些默认值为 0 +因此不需要设置它们 + +165 +00:09:17,624 --> 00:09:20,527 +您已经了解了如何在相交函数中 + +166 +00:09:20,561 --> 00:09:21,828 +使用逐图元数据 + +167 +00:09:21,862 --> 00:09:24,398 +它只是作为指针传递给函数 + +168 +00:09:24,431 --> 00:09:28,402 +但这还不是全部 您可以在 +任何需要的地方访问这些数据 + +169 +00:09:28,435 --> 00:09:32,306 +这包括由交叉点返回的最终相交结果 + +170 +00:09:32,339 --> 00:09:36,844 +如果使用相交查询 +候选相交和提交相交的 + +171 +00:09:36,877 --> 00:09:39,746 +图元数据也是可用的 + +172 +00:09:39,780 --> 00:09:43,116 +这意味着除了相交测试之外 + +173 +00:09:43,150 --> 00:09:45,319 +您还可以使用逐图元数据进行着色 + +174 +00:09:45,352 --> 00:09:48,021 +通过减少内存访问和间接访问的数量 + +175 +00:09:48,055 --> 00:09:50,657 +逐图元数据可以提高 + +176 +00:09:50,691 --> 00:09:54,828 +相交代码和着色代码的性能 + +177 +00:09:54,862 --> 00:09:58,265 +事实上 我们在自己的 +一个测试 App 中发现 + +178 +00:09:58,298 --> 00:10:03,704 +使用逐图元数据可以使性能 +提高 10% 到 16% + +179 +00:10:03,737 --> 00:10:05,472 +我们期待您的尝试 + +180 +00:10:05,506 --> 00:10:08,008 +看看您能在性能和代码质量方面 + +181 +00:10:08,041 --> 00:10:11,712 +获得怎样的改进 + +182 +00:10:11,745 --> 00:10:14,748 +今年 我们还为 Metal 着色语言 + +183 +00:10:14,781 --> 00:10:18,952 +添加了另一个方便的功能 +以帮助您简化光线追踪内核 + +184 +00:10:18,986 --> 00:10:22,322 +App 通常将同一组绑定 + +185 +00:10:22,356 --> 00:10:26,593 +传递给它们的相交函数 +和主光线追踪内核 + +186 +00:10:26,627 --> 00:10:29,530 +例如 我们的光线追踪示例代码 + +187 +00:10:29,563 --> 00:10:32,065 +使用相交函数来渲染球体 + +188 +00:10:32,099 --> 00:10:35,068 +此相交函数访问 + +189 +00:10:35,102 --> 00:10:37,471 +包含每个球体信息的资源缓冲区 + +190 +00:10:37,504 --> 00:10:40,174 +为了将此缓冲区传递给相交函数 + +191 +00:10:40,207 --> 00:10:43,477 +App 将缓冲区绑定到相交函数表 + +192 +00:10:43,510 --> 00:10:48,315 +然而 主光线追踪内核还需要 +访问资源缓冲区 + +193 +00:10:48,348 --> 00:10:50,851 +因此 App 也将缓冲区绑定到那里 + +194 +00:10:50,884 --> 00:10:53,554 +今年 Metal 着色语言允许访问 + +195 +00:10:53,587 --> 00:10:57,191 +绑定到相交函数表的缓冲区 + +196 +00:10:57,224 --> 00:10:59,726 +有了这个新功能 您可以省去 + +197 +00:10:59,760 --> 00:11:03,797 +为内核绑定缓冲区的操作 从而直接 + +198 +00:11:03,830 --> 00:11:05,699 +从相交函数表中访问它 + +199 +00:11:05,732 --> 00:11:08,468 +您可以通过调用相交函数表上的 + +200 +00:11:08,502 --> 00:11:11,839 +get_buffer 方法 +并提供其指针类型来实现这一点 + +201 +00:11:11,872 --> 00:11:15,642 +您还可以通过函数类型 +来访问可见的函数表 + +202 +00:11:15,676 --> 00:11:20,180 +间接指令缓冲区允许您在 GPU 上 +独立地对 GPU 进行编码 + +203 +00:11:20,214 --> 00:11:24,618 +代表着 GPU 驱动管线的 +基本元素 + +204 +00:11:24,651 --> 00:11:26,653 +要想了解间接指令缓冲区 + +205 +00:11:26,687 --> 00:11:29,756 +和 GPU 驱动渲染的更多信息 +建议您观看 + +206 +00:11:29,790 --> 00:11:33,894 +WWDC 2019 的讲座 +“Modern rendering with Metal” + +207 +00:11:33,927 --> 00:11:37,464 +在间接指令缓冲区中 +启用光线追踪支持很容易 + +208 +00:11:37,497 --> 00:11:40,601 +您所要做的就是在描述符上 + +209 +00:11:40,634 --> 00:11:42,069 +设置 supportRayTracing 标志 + +210 +00:11:42,102 --> 00:11:46,139 +间接指令缓冲区发送图形和计算函数 + +211 +00:11:46,173 --> 00:11:50,344 +因此您可以像往常一样 +轻松地从这些函数使用光线追踪 + +212 +00:11:50,377 --> 00:11:53,881 +这是我们今年添加的 +所有新功能的概要 + +213 +00:11:53,914 --> 00:11:58,218 +用来帮助您在 App 中 +获得更好的光线追踪性能 + +214 +00:11:58,252 --> 00:12:01,755 +接下来 我们来谈谈加速结构 + +215 +00:12:01,788 --> 00:12:04,424 +我们已经实现了几项性能改进 + +216 +00:12:04,458 --> 00:12:08,228 +并增加了专注于构建加速结构的功能 + +217 +00:12:08,262 --> 00:12:10,631 +让我们回顾一下它们的用途 + +218 +00:12:10,664 --> 00:12:13,033 +加速结构是加速 + +219 +00:12:13,066 --> 00:12:15,802 +光线追踪过程的数据结构 + +220 +00:12:15,836 --> 00:12:18,805 +它们通过递归划分空间来实现这一点 + +221 +00:12:18,839 --> 00:12:23,343 +这样我们可以快速找到哪些三角形 +可能与光线相交 + +222 +00:12:23,377 --> 00:12:25,412 +为了支持构建复杂场景 + +223 +00:12:25,445 --> 00:12:28,549 +Metal 支持两种类型的加速结构 + +224 +00:12:28,582 --> 00:12:31,518 +基本加速结构和实例加速结构 + +225 +00:12:31,552 --> 00:12:34,221 +单个的几何图形使用 + +226 +00:12:34,254 --> 00:12:36,690 +基本加速结构来表示 + +227 +00:12:36,723 --> 00:12:40,194 +它们可以是一些简单的形状 +比如平面或者立方体 + +228 +00:12:40,227 --> 00:12:44,398 +也可以是一些更复杂的形状 +比如球体或者三角网格 + +229 +00:12:44,431 --> 00:12:48,635 +您可以使用实例加速结构 +来创建更复杂的场景 + +230 +00:12:48,669 --> 00:12:51,338 +实例加速结构创建 + +231 +00:12:51,371 --> 00:12:53,140 +基本加速结构的副本 + +232 +00:12:53,173 --> 00:12:58,078 +首先 为场景中的每个对象 +定义变换矩阵 + +233 +00:12:58,111 --> 00:13:01,014 +然后 使用变换矩阵数组 + +234 +00:13:01,048 --> 00:13:02,916 +和基本加速结构 + +235 +00:13:02,950 --> 00:13:05,619 +构建实例加速结构 + +236 +00:13:05,652 --> 00:13:09,823 +这就是如何使用加速结构 +来构建静态场景的方法 + +237 +00:13:09,857 --> 00:13:12,659 +接下来 让我们看看 +像游戏这样的动态 App + +238 +00:13:12,693 --> 00:13:15,128 +将如何使用加速结构 + +239 +00:13:16,196 --> 00:13:18,131 +我们从头开始 + +240 +00:13:18,165 --> 00:13:19,933 +在第一次启动游戏 + +241 +00:13:19,967 --> 00:13:22,970 +或加载新关卡时 +您需要完成几个任务 + +242 +00:13:23,003 --> 00:13:27,674 +这包括加载模型和纹理等常规任务 + +243 +00:13:27,708 --> 00:13:31,612 +使用光线追踪 还需要为将要使用的 + +244 +00:13:31,645 --> 00:13:34,515 +所有模型构建基本加速结构 + +245 +00:13:34,548 --> 00:13:37,951 +我们建议您在加载时 +构建尽可能多的 + +246 +00:13:37,985 --> 00:13:42,189 +基本加速结构 +以节省主渲染循环的时间 + +247 +00:13:42,222 --> 00:13:44,391 +您可以根据需要使用实例加速结构 + +248 +00:13:44,424 --> 00:13:48,529 +在场景中添加或移除这些对象 + +249 +00:13:48,562 --> 00:13:51,765 +一旦您的 App 完成加载 +就会进入主循环 + +250 +00:13:51,798 --> 00:13:54,868 +每一帧 它都使用光栅化 + +251 +00:13:54,902 --> 00:13:58,438 +光线追踪和后期处理的组合 +来渲染场景 + +252 +00:13:58,472 --> 00:14:01,041 +然而 由于游戏是动态的 + +253 +00:14:01,074 --> 00:14:05,045 +您可能需要更新一些加速结构 + +254 +00:14:05,078 --> 00:14:08,348 +这通常包括修整一些形变 + +255 +00:14:08,382 --> 00:14:11,518 +或动画模型 如为角色蒙皮 + +256 +00:14:11,552 --> 00:14:14,688 +修整现有的加速结构比完全重建 + +257 +00:14:14,721 --> 00:14:18,859 +要快得多 +所以我们建议在这种情况下使用它 + +258 +00:14:18,892 --> 00:14:22,563 +您还应该对实例加速结构 +进行完全重建 + +259 +00:14:22,596 --> 00:14:26,500 +这是必要的 因为自上一帧以来 + +260 +00:14:26,533 --> 00:14:30,504 +对象可能已从场景中添加或移除 +或者它们可能已显著移动 + +261 +00:14:30,537 --> 00:14:33,974 +在这种情况下 +完全重新构建是可行的 + +262 +00:14:34,007 --> 00:14:35,576 +因为只有一个实例加速结构 + +263 +00:14:35,609 --> 00:14:39,246 +而且通常只包含几千个对象 + +264 +00:14:39,279 --> 00:14:43,483 +今年 我们改进了 +所有这些场景的性能 + +265 +00:14:43,517 --> 00:14:46,253 +首先 Apple 芯片上的加速结构 + +266 +00:14:46,286 --> 00:14:49,957 +构建速度现在提高了 2.3 倍 + +267 +00:14:49,990 --> 00:14:53,427 +其次 修整速度也快了 38% + +268 +00:14:54,428 --> 00:14:58,832 +这意味着加载时间 +和每帧开销都减少了 + +269 +00:14:58,866 --> 00:15:00,534 +但还有更好的 + +270 +00:15:00,567 --> 00:15:03,370 +一些 App 可以构建数百 +甚至数千个 + +271 +00:15:03,403 --> 00:15:05,606 +小型基本加速结构 + +272 +00:15:05,639 --> 00:15:08,475 +这些小的构建 +单独没有足够多的工作 + +273 +00:15:08,509 --> 00:15:13,547 +来填充 GPU +会导致 GPU 利用率长期处于低水平 + +274 +00:15:13,580 --> 00:15:16,450 +因此 现在只要有可能 + +275 +00:15:16,483 --> 00:15:19,520 +在 Apple 芯片上就会自动 +并行执行多个构建 + +276 +00:15:19,553 --> 00:15:22,322 +并行运行使得构建速度 + +277 +00:15:22,356 --> 00:15:24,224 +提高了 2.8 倍 + +278 +00:15:24,258 --> 00:15:26,426 +这进一步减少了加载时间 + +279 +00:15:26,460 --> 00:15:28,395 +这不仅仅适用于构建 + +280 +00:15:28,428 --> 00:15:31,365 +它适用于所有加速结构操作 + +281 +00:15:31,398 --> 00:15:34,134 +包括压缩和修整 + +282 +00:15:34,168 --> 00:15:37,504 +因此您的每帧开销也会减少 + +283 +00:15:37,538 --> 00:15:39,840 +您需要遵循一些指导原则 + +284 +00:15:39,873 --> 00:15:43,043 +以确保您能够从这种优化中受益 + +285 +00:15:43,076 --> 00:15:46,780 +下面是一个构建加速结构数组的例子 + +286 +00:15:46,813 --> 00:15:49,850 +要并行执行构建 您需要确保在 + +287 +00:15:49,883 --> 00:15:53,387 +多个构建操作中使用 +相同的加速结构指令编码器 + +288 +00:15:53,420 --> 00:15:58,492 +此外 使用相同临时缓冲区 +的构建不能并行运行 + +289 +00:15:58,525 --> 00:16:02,396 +因此 您需要确保依次通过 +一个小的临时缓冲区池 + +290 +00:16:02,429 --> 00:16:06,033 +而不是为每个构建 +使用相同的临时缓冲区 + +291 +00:16:07,234 --> 00:16:09,369 +这些都是我们为构建 + +292 +00:16:09,403 --> 00:16:12,606 +加速结构所做的性能改进 + +293 +00:16:12,639 --> 00:16:14,675 +我们还增加了三个新功能 + +294 +00:16:14,708 --> 00:16:18,212 +使构建加速结构更加容易和有效 + +295 +00:16:19,546 --> 00:16:24,284 +它们支持额外的顶点格式 变换矩阵 + +296 +00:16:24,318 --> 00:16:26,954 +和在堆上分配的加速结构 + +297 +00:16:29,089 --> 00:16:32,326 +我们从顶点格式开始 + +298 +00:16:32,359 --> 00:16:35,596 +常见的性能优化是对顶点数据 + +299 +00:16:35,629 --> 00:16:39,166 +使用量化或降低精度的格式 + +300 +00:16:39,199 --> 00:16:41,468 +从而降低内存使用 + +301 +00:16:41,502 --> 00:16:44,137 +今年 您可以从各种 + +302 +00:16:44,171 --> 00:16:46,607 +顶点格式构建加速结构 + +303 +00:16:46,640 --> 00:16:50,577 +这包括半精度浮点格式 + +304 +00:16:50,611 --> 00:16:53,981 +平面几何图形的两分量顶点格式 + +305 +00:16:54,014 --> 00:16:57,584 +以及所有常见的规格化整数格式 + +306 +00:16:57,618 --> 00:17:00,687 +以前 加速度结构需要 + +307 +00:17:00,721 --> 00:17:04,191 +三分量 全精度浮点顶点数据 + +308 +00:17:04,224 --> 00:17:07,427 +在本例中 App 具有 + +309 +00:17:07,461 --> 00:17:10,097 +半精度顶点格式的顶点数据 + +310 +00:17:10,130 --> 00:17:14,067 +为了构建加速结构 +需要将这些数据解包 + +311 +00:17:14,101 --> 00:17:16,537 +并复制到临时缓冲区中 + +312 +00:17:16,570 --> 00:17:18,605 +有了新的顶点格式功能 + +313 +00:17:18,639 --> 00:17:21,808 +加速结构构建现在可以使用 + +314 +00:17:21,842 --> 00:17:24,111 +任何受支持的格式的顶点数据 + +315 +00:17:24,144 --> 00:17:27,281 +而不需要创建临时副本 + +316 +00:17:27,314 --> 00:17:29,850 +设置顶点格式再简单不过了 + +317 +00:17:29,883 --> 00:17:34,121 +您所需要做的就是 +设置几何描述符上的属性 + +318 +00:17:34,154 --> 00:17:37,357 +接下来 我们来谈谈变换矩阵 + +319 +00:17:37,391 --> 00:17:40,227 +此功能是对新顶点格式的补充 + +320 +00:17:40,260 --> 00:17:42,629 +因此您可以在构建加速结构之前 + +321 +00:17:42,663 --> 00:17:45,199 +对顶点数据进行预变换 + +322 +00:17:45,232 --> 00:17:47,701 +例如 您可能希望使用它们来 + +323 +00:17:47,734 --> 00:17:51,505 +解包以规格化格式存储的复杂网格 + +324 +00:17:51,538 --> 00:17:54,808 +让我们来看看这个场景中的 +小熊猫模型 + +325 +00:17:54,842 --> 00:17:58,712 +为了规范化几何图形 +以使用我们的压缩格式之一 + +326 +00:17:58,745 --> 00:18:01,715 +需要获取网格 计算其边界 + +327 +00:18:01,748 --> 00:18:04,952 +然后将其缩放到 0 到 1 的范围 + +328 +00:18:04,985 --> 00:18:09,189 +然后 您可以使用一种规范化的 +整数顶点格式来存储网格 + +329 +00:18:09,223 --> 00:18:13,760 +从而减少它在磁盘 +和内存中占用的空间 + +330 +00:18:13,794 --> 00:18:17,598 +在运行时 您可以提供一个矩阵 + +331 +00:18:17,631 --> 00:18:21,134 +将每个顶点缩放和偏移到最终位置 + +332 +00:18:21,168 --> 00:18:25,038 +应用该矩阵以获取原始模型 + +333 +00:18:25,072 --> 00:18:28,509 +现在 我们来了解一下 +如何通过变换矩阵 + +334 +00:18:28,542 --> 00:18:30,611 +来建立加速结构 + +335 +00:18:30,644 --> 00:18:33,714 +首先创建变换缓冲区 + +336 +00:18:33,747 --> 00:18:38,519 +一种方法是创建一个 +包含缩放和偏移变换矩阵的 + +337 +00:18:38,552 --> 00:18:41,889 +MTLPackedFloat4x3 对象 + +338 +00:18:41,922 --> 00:18:46,193 +然后 创建一个 +足以容纳矩阵的 Metal Buffer + +339 +00:18:46,226 --> 00:18:49,796 +最后 将矩阵复制到缓冲区 + +340 +00:18:49,830 --> 00:18:52,666 +接下来 设置加速结构 + +341 +00:18:52,699 --> 00:18:55,536 +首先 创建三角形几何描述符 + +342 +00:18:55,569 --> 00:18:58,705 +然后 指定变换矩阵缓冲区 + +343 +00:18:58,739 --> 00:19:01,575 +最后是缓冲区偏移量 + +344 +00:19:01,608 --> 00:19:05,179 +这就是设置转换矩阵所需的全部操作 + +345 +00:19:05,212 --> 00:19:09,550 +这些矩阵还可以用于 +组合简单的加速结构 + +346 +00:19:09,583 --> 00:19:11,985 +以提高光线追踪的性能 + +347 +00:19:12,019 --> 00:19:14,188 +让我们看一个示例场景 + +348 +00:19:14,221 --> 00:19:19,092 +在这里 长方体和球体 +都是相对简单的网格 + +349 +00:19:19,126 --> 00:19:22,729 +这提供了一个在场景的前端 + +350 +00:19:22,763 --> 00:19:25,566 +优化加速结构的机会 + +351 +00:19:25,599 --> 00:19:28,535 +关注实例加速结构 光线击中的 + +352 +00:19:28,569 --> 00:19:32,272 +每个实例都会产生间接消耗 + +353 +00:19:32,306 --> 00:19:34,441 +变换光线 然后从实例 + +354 +00:19:34,474 --> 00:19:38,412 +切换到基本加速结构是有成本的 + +355 +00:19:38,445 --> 00:19:42,316 +这种情况更常发生在 +实例重叠的情况下 + +356 +00:19:42,349 --> 00:19:44,151 +若要减少实例数 + +357 +00:19:44,184 --> 00:19:46,954 +可以生成同时包含长方体和球体的 + +358 +00:19:46,987 --> 00:19:50,591 +单个基本加速结构 + +359 +00:19:50,624 --> 00:19:53,427 +为此 可以为每个对象创建 +一个几何描述符 + +360 +00:19:53,460 --> 00:19:57,397 +每个对象都有自己的变换矩阵 + +361 +00:19:57,431 --> 00:20:00,834 +生成的基本加速结构 + +362 +00:20:00,868 --> 00:20:05,606 +是实例加速结构中的单个实例 +包含长方体和球体 + +363 +00:20:05,639 --> 00:20:09,309 +这会产生性能更好的加速结构 + +364 +00:20:09,343 --> 00:20:11,378 +让我们看看如何在代码中设置它 + +365 +00:20:12,779 --> 00:20:16,416 +首先定义球体几何描述符 + +366 +00:20:16,450 --> 00:20:20,721 +接下来 像往常一样 +为基本加速结构设置顶点缓冲区 + +367 +00:20:20,754 --> 00:20:24,024 +索引缓冲区和其他属性 + +368 +00:20:24,057 --> 00:20:26,927 +不同之处在于 您还可以指定包含 + +369 +00:20:26,960 --> 00:20:30,797 +用于复制球体的变换矩阵的 +变换缓冲区 + +370 +00:20:32,466 --> 00:20:35,502 +对于长方体 +有多个几何描述符 + +371 +00:20:35,536 --> 00:20:38,372 +共享一个顶点和索引缓冲区 + +372 +00:20:38,405 --> 00:20:42,609 +您只需为每个副本 +指定不同的转换缓冲区 + +373 +00:20:42,643 --> 00:20:47,114 +最后 在为基本加速结构 +创建描述符时 + +374 +00:20:47,147 --> 00:20:49,750 +添加所有的几何描述符 + +375 +00:20:49,783 --> 00:20:52,419 +这将生成一个基本加速结构 + +376 +00:20:52,452 --> 00:20:56,123 +您可以通过实体变换 +将其实例化到场景中 + +377 +00:20:56,156 --> 00:20:59,393 +与单独的加速结构相比 +这种基本加速结构的 + +378 +00:20:59,426 --> 00:21:03,330 +构建时间更短 并且相交速度更快 + +379 +00:21:04,998 --> 00:21:08,502 +最后 加速结构的堆分配 + +380 +00:21:08,535 --> 00:21:11,605 +是我们最需要的功能之一 + +381 +00:21:11,638 --> 00:21:14,041 +有了这个功能 您现在可以 + +382 +00:21:14,074 --> 00:21:16,577 +更好地控制加速结构分配 + +383 +00:21:16,610 --> 00:21:20,047 +它还允许您在分配之间 +重复使用堆内存 + +384 +00:21:20,080 --> 00:21:23,250 +避免了昂贵的缓冲区分配 + +385 +00:21:23,283 --> 00:21:27,054 +使用实例加速结构时 +堆还可以通过减少 + +386 +00:21:27,087 --> 00:21:31,525 +对 useResource: 方法的调用 +来帮助提高性能 + +387 +00:21:31,558 --> 00:21:33,794 +回到示例场景 + +388 +00:21:33,827 --> 00:21:36,430 +实例加速结构间接引用了 + +389 +00:21:36,463 --> 00:21:39,132 +基本加速结构 + +390 +00:21:39,166 --> 00:21:42,870 +这意味着每次您想要使用 +带有指令编码器的实例加速结构时 + +391 +00:21:42,903 --> 00:21:46,507 +需要为每个基本加速结构 + +392 +00:21:46,540 --> 00:21:49,243 +调用 useResource: 方法 + +393 +00:21:49,276 --> 00:21:52,346 +对于大型场景 +每次使用实例加速结构时 + +394 +00:21:52,379 --> 00:21:56,116 +可能需要数千次调用 useResource: + +395 +00:21:56,149 --> 00:21:58,852 +面对如此多的 useResource: 调用 + +396 +00:21:58,886 --> 00:22:02,656 +您可以调用 useResources: 来减少 +API 调用的数量 + +397 +00:22:02,689 --> 00:22:06,260 +但您仍需维护一个加速结构的数组 + +398 +00:22:06,293 --> 00:22:09,062 +Metal 仍需依次通过这个数组 + +399 +00:22:09,096 --> 00:22:11,064 +相反 您可以从同一个堆中 + +400 +00:22:11,098 --> 00:22:14,668 +分配所有这些基本加速结构 + +401 +00:22:14,701 --> 00:22:17,704 +当您想要使用实例加速结构时 + +402 +00:22:17,738 --> 00:22:20,874 +您可以简单地调用 useHeap: 方法 + +403 +00:22:20,908 --> 00:22:24,077 +来引用所有的基本加速结构 + +404 +00:22:24,111 --> 00:22:27,147 +我们只需将对 useResource: 的调用 + +405 +00:22:27,181 --> 00:22:29,816 +替换为对 useHeap: 的单个调用 + +406 +00:22:29,850 --> 00:22:32,186 +就能使 App 的性能得到提升 + +407 +00:22:32,219 --> 00:22:35,455 +让我们看看如何从堆中分配加速结构 + +408 +00:22:35,489 --> 00:22:39,793 +您可以通过在堆上调用一个 +以加速结构描述符为输入的方法 + +409 +00:22:39,826 --> 00:22:43,197 +直接分配一个加速结构 + +410 +00:22:43,230 --> 00:22:46,066 +如果不使用描述符进行分配 + +411 +00:22:46,099 --> 00:22:49,703 +Metal 设备将确定 +从堆中分配加速结构的 + +412 +00:22:49,736 --> 00:22:52,606 +大小和对齐要求 + +413 +00:22:52,639 --> 00:22:55,309 +通过提供描述符或加速结构大小 + +414 +00:22:55,342 --> 00:22:59,012 +您可以从 Metal 设备获得此信息 + +415 +00:22:59,046 --> 00:23:01,148 +一旦确定了最终大小 + +416 +00:23:01,181 --> 00:23:04,351 +就可以从堆中分配加速结构 + +417 +00:23:04,384 --> 00:23:07,621 +在使用堆时 有几个注意事项 + +418 +00:23:07,654 --> 00:23:12,025 +首先 记住调用 useHeap: +使堆中的所有加速结构 + +419 +00:23:12,059 --> 00:23:15,596 +在光线追踪过程中保持驻留 + +420 +00:23:15,629 --> 00:23:20,734 +其次 默认情况下 Metal 不会 +追踪您从堆中分配的资源 + +421 +00:23:20,767 --> 00:23:23,570 +您可以选择加入资源风险追踪 + +422 +00:23:23,604 --> 00:23:27,407 +也可以手动管理自己的同步 + +423 +00:23:27,441 --> 00:23:31,512 +您可以使用 MTLFence +在指令编码器之间进行同步 + +424 +00:23:31,545 --> 00:23:35,215 +使用 MTLEvent +在指令缓冲区之间进行同步 + +425 +00:23:35,249 --> 00:23:38,352 +这些都是今年 +Metal 光线追踪 API 中的 + +426 +00:23:38,385 --> 00:23:40,921 +新功能和性能改进 + +427 +00:23:40,954 --> 00:23:43,991 +接下来 Dominik 将谈一下 Xcode 的 + +428 +00:23:44,024 --> 00:23:47,294 +Metal 工具的改进 +它将提高您在开发 + +429 +00:23:47,327 --> 00:23:49,196 +光线追踪 App 时的效率 + +430 +00:23:49,229 --> 00:23:50,964 +谢谢 Yi + +431 +00:23:50,998 --> 00:23:54,401 +在 Xcode 14 中有很多 +对 Metal 工具的增强 + +432 +00:23:54,434 --> 00:23:57,104 +但在这里 我想强调的是一些 + +433 +00:23:57,137 --> 00:24:00,674 +在开发光线追踪 App 时 +特别有用的工具 + +434 +00:24:01,642 --> 00:24:04,678 +从 Metal 调试器开始 我将介绍 + +435 +00:24:04,711 --> 00:24:09,583 +加速结构查看器 +着色器性能分析和着色器调试的改进 + +436 +00:24:10,551 --> 00:24:14,388 +最后 我会介绍运行时着色器验证 + +437 +00:24:16,523 --> 00:24:21,161 +首先 我们来看看 +加速结构查看器 + +438 +00:24:21,195 --> 00:24:25,999 +Metal 调试器中的 +加速结构查看器 + +439 +00:24:26,033 --> 00:24:29,169 +能够使您非常详细地检查 +组成加速结构的 + +440 +00:24:29,203 --> 00:24:32,573 +所有几何形体和所有网格的实例 + +441 +00:24:34,141 --> 00:24:37,744 +Xcode 14 现在支持调试 + +442 +00:24:37,778 --> 00:24:41,982 +带有基本或实例运动的加速结构 +并支持使用检查器 + +443 +00:24:42,015 --> 00:24:46,954 +对每个图元数据进行可视化的 +新高亮模式 + +444 +00:24:46,987 --> 00:24:48,722 +我们来看看它们的表现 + +445 +00:24:49,523 --> 00:24:52,593 +如果您正在使用带有运动的加速结构 + +446 +00:24:52,626 --> 00:24:55,095 +现在在底部栏中会有一个拖拽条 + +447 +00:24:55,128 --> 00:24:58,899 +用于查看您在不同时间点的加速结构 + +448 +00:24:58,932 --> 00:25:02,135 +在拖拽条的右边是一个“播放”按钮 + +449 +00:25:02,169 --> 00:25:05,339 +您可以用它来循环播放动画 + +450 +00:25:05,372 --> 00:25:08,976 +现在我将展示如何在您的加速结构中 + +451 +00:25:09,009 --> 00:25:11,144 +检查单个图元 + +452 +00:25:11,178 --> 00:25:15,516 +如果您正在使用新的逐图元数据 API +这将特别有用 + +453 +00:25:15,549 --> 00:25:19,853 +这里有一个相应的新的高亮模式 + +454 +00:25:19,887 --> 00:25:23,790 +图元高亮显示模式 +允许您访问所有图元数据 + +455 +00:25:25,292 --> 00:25:29,296 +并允许您选择特定的图元 +进行详细检查 + +456 +00:25:30,631 --> 00:25:34,468 +在左侧边栏中 +可以找到数据行旁边的箭头 + +457 +00:25:35,736 --> 00:25:38,438 +单击箭头将显示一个弹出窗口 + +458 +00:25:38,472 --> 00:25:41,308 +其中显示了该图元的相应数据 + +459 +00:25:41,341 --> 00:25:44,178 +加速结构查看器的这些新增功能 + +460 +00:25:44,211 --> 00:25:47,581 +确保您可以完全访问 + +461 +00:25:47,614 --> 00:25:51,952 +构成加速结构的所有组件 +包括每个图元 + +462 +00:25:51,985 --> 00:25:55,522 +接下来 我们来谈谈 +Shader Profiler 的改进 + +463 +00:25:55,556 --> 00:26:00,160 +Shader Profiler 可让您 +深入了解着色器的性能 + +464 +00:26:00,194 --> 00:26:03,297 +提供每条管道执行计时成本 + +465 +00:26:03,330 --> 00:26:07,968 +在 Apple GPU 上 +它在源代码级别提供了更高的粒度 + +466 +00:26:08,001 --> 00:26:13,240 +显示了分布在指令类别中的 +每行执行成本 + +467 +00:26:13,273 --> 00:26:17,477 +在 Xcode 14 中 +对 GPU 捕获做性能分析已更新的 + +468 +00:26:17,511 --> 00:26:22,516 +支持相交函数 可见函数和动态库 + +469 +00:26:23,884 --> 00:26:28,388 +这里我们有一个使用相交函数的 +光线追踪内核 + +470 +00:26:28,422 --> 00:26:31,091 +现在 您可以在相交函数中 + +471 +00:26:31,124 --> 00:26:33,861 +查看逐行分析的结果 + +472 +00:26:33,894 --> 00:26:36,496 +这包括构成成本的 + +473 +00:26:36,530 --> 00:26:38,365 +指令类别的细目 + +474 +00:26:41,969 --> 00:26:45,005 +分析可见函数的工作方式相同 + +475 +00:26:46,306 --> 00:26:49,409 +同样 现在可以从链接的动态库中 + +476 +00:26:49,443 --> 00:26:53,180 +获取着色器代码的详细性能分析信息 + +477 +00:26:53,213 --> 00:26:56,283 +有了这些附加功能 您现在就可以对 + +478 +00:26:56,316 --> 00:26:59,953 +管道的性能进行全面分解 +直至每一行代码 + +479 +00:27:02,122 --> 00:27:04,024 +接下来再来谈谈 Shader Debugger + +480 +00:27:04,057 --> 00:27:05,158 +Shader Debugger 为调试 + +481 +00:27:05,192 --> 00:27:07,528 +着色器代码的正确性 + +482 +00:27:07,561 --> 00:27:10,397 +提供了一个独特而高效的工作流程 + +483 +00:27:10,430 --> 00:27:13,634 +像 Shader Profiler 一样 +我们还扩展了 + +484 +00:27:13,667 --> 00:27:17,271 +对链接函数 +和动态库的调试支持 + +485 +00:27:17,304 --> 00:27:19,806 +这里有一个光线追踪内核 +它调用了 + +486 +00:27:19,840 --> 00:27:24,011 +一个通过可见函数表 +传递进来的链接可见函数 + +487 +00:27:27,247 --> 00:27:30,250 +现在您可以一直追踪内核的执行 + +488 +00:27:30,284 --> 00:27:32,920 +直到可见函数代码 + +489 +00:27:32,953 --> 00:27:36,123 +以验证代码的行为是否符合预期 + +490 +00:27:37,257 --> 00:27:41,195 +同样 这也适用于调试动态库 + +491 +00:27:41,228 --> 00:27:45,265 +您还可以从管线链接的 + +492 +00:27:45,299 --> 00:27:47,134 +已执行动态库跳入跳出 + +493 +00:27:47,167 --> 00:27:48,802 +有了这些附加功能 现在您可以 + +494 +00:27:48,836 --> 00:27:51,104 +全面了解着色器在管道中的 + +495 +00:27:51,138 --> 00:27:54,141 +链接函数和库的执行情况了 + +496 +00:27:55,943 --> 00:27:59,379 +现在 在捕获并跳转到 +Shader Debugger 之前 + +497 +00:27:59,413 --> 00:28:03,050 +最好在运行时启用着色器验证 + +498 +00:28:05,686 --> 00:28:10,324 +着色器验证是在 GPU 上 +诊断运行时错误的一种很好的方法 + +499 +00:28:10,357 --> 00:28:14,027 +可以捕获诸如超出限制的内存访问 + +500 +00:28:14,061 --> 00:28:16,463 +空纹理读取等问题 + +501 +00:28:16,496 --> 00:28:20,534 +要在 Xcode 中启用着色器验证 +只需转到 + +502 +00:28:20,567 --> 00:28:24,037 +“Edit Scheme” 对话框 +选择 “Run” 操作 + +503 +00:28:24,071 --> 00:28:28,775 +并在 “diagnostics” 选项卡下 +勾选 “Shader Validation” 复选框 + +504 +00:28:28,809 --> 00:28:31,044 +这样就可以了 + +505 +00:28:31,078 --> 00:28:34,748 +在 Metal 3 中 +我们添加了栈溢出检测 + +506 +00:28:34,781 --> 00:28:36,350 +这将帮助您快速发现 + +507 +00:28:36,383 --> 00:28:40,220 +可能导致未定义行为的问题 + +508 +00:28:40,254 --> 00:28:43,524 +我将快速阐述 Metal 着色器中的 + +509 +00:28:43,557 --> 00:28:45,726 +函数堆栈和栈溢出问题 + +510 +00:28:45,759 --> 00:28:48,795 +调用堆栈是设备内存中的一个区域 + +511 +00:28:48,829 --> 00:28:53,267 +Metal 在其中存储 +着色器函数中使用的本地数据值 + +512 +00:28:53,300 --> 00:28:56,103 +如果被调用的函数在编译时是未知的 + +513 +00:28:56,136 --> 00:28:58,405 +Metal 需要您的帮助 + +514 +00:28:58,438 --> 00:29:01,642 +来估计堆栈所需的内存量 + +515 +00:29:01,675 --> 00:29:05,345 +对编译时未知函数的调用示例 + +516 +00:29:05,379 --> 00:29:08,448 +可能是光线追踪相交函数 + +517 +00:29:08,482 --> 00:29:11,051 +如果您在使用自定义相交函数 + +518 +00:29:11,084 --> 00:29:16,123 +则应将最大调用堆栈深度设置为 1 +以便为其分配空间 + +519 +00:29:16,156 --> 00:29:19,826 +这是默认值 因此无需执行其他操作 + +520 +00:29:19,860 --> 00:29:24,231 +但如果您使用函数表调用可见函数 + +521 +00:29:24,264 --> 00:29:28,302 +这是编译时未知函数调用的 +另一个示例 + +522 +00:29:28,335 --> 00:29:31,038 +如果从相交函数执行这样的调用 + +523 +00:29:31,071 --> 00:29:34,708 +如本例中所示 +那么调用堆栈将有两层之深 + +524 +00:29:36,376 --> 00:29:39,813 +另一个例子是调用动态库 + +525 +00:29:39,847 --> 00:29:43,250 +和使用函数指针调用本地函数 + +526 +00:29:43,283 --> 00:29:47,020 +在本例中 +我们的调用堆栈有四个层级 + +527 +00:29:47,054 --> 00:29:48,789 +其中包含对不同类型函数的 + +528 +00:29:48,822 --> 00:29:51,625 +嵌套调用 +这些函数在编译着色器时无法解析 + +529 +00:29:51,658 --> 00:29:55,095 +要正确配置 Metal +以分配正确的内存量 + +530 +00:29:55,128 --> 00:29:59,633 +您需要自己指定最大调用堆栈深度 4 + +531 +00:29:59,666 --> 00:30:02,469 +重要的是要记住 当程序的 + +532 +00:30:02,503 --> 00:30:05,772 +最大调用堆栈深度设置得太低时 + +533 +00:30:05,806 --> 00:30:09,843 +就可能会发生 Stack Overflow +从而导致未定义的行为 + +534 +00:30:09,877 --> 00:30:13,313 +但如果您在运行时 +启用了 + +535 +00:30:13,347 --> 00:30:15,582 +这种情况就会被及早发现 + +536 +00:30:15,616 --> 00:30:20,254 +您会在 Xcode 中看到 +栈溢出发生的信息 + +537 +00:30:20,287 --> 00:30:22,856 +然后 您可以修复着色器代码 + +538 +00:30:22,890 --> 00:30:26,560 +或在管道描述符中 +调整最大堆栈调用深度 + +539 +00:30:26,593 --> 00:30:30,297 +Xcode 14 中 +Metal 工具的所有这些新改进 + +540 +00:30:30,330 --> 00:30:33,133 +确保您对光线追踪 App 的 + +541 +00:30:33,166 --> 00:30:37,304 +性能和正确性有更全面的了解 + +542 +00:30:37,337 --> 00:30:40,340 +有关如何充分利用 Metal 工具 + +543 +00:30:40,374 --> 00:30:43,243 +进行调试和分析的更多信息 +请查看以下其他讲座 + +544 +00:30:45,412 --> 00:30:48,782 +本期讲座旨在最大限度地 +提高您的 App 的 + +545 +00:30:48,815 --> 00:30:50,284 +Metal 光线追踪性能 + +546 +00:30:50,317 --> 00:30:52,953 +我们讨论了如何使用 +逐图元数据等新功能 + +547 +00:30:52,986 --> 00:30:57,558 +来提高性能并简化代码 + +548 +00:30:57,591 --> 00:31:00,627 +我们还讲述了使构建加速结构 + +549 +00:31:00,661 --> 00:31:04,097 +比以往任何时候都更快 更方便的 + +550 +00:31:04,131 --> 00:31:05,832 +优化技术和功能 + +551 +00:31:05,866 --> 00:31:09,236 +最后 我们介绍了 Xcode 14 中 + +552 +00:31:09,269 --> 00:31:11,405 +Metal 工具的所有新的增强功能 + +553 +00:31:11,438 --> 00:31:14,107 +这些功能将在开发过程中 +为您提供更深入的见解 + +554 +00:31:14,141 --> 00:31:15,809 +齐: 感谢观看 + diff --git a/zho/2022 Session 10106 Profile and optimize your game's memory.srt b/zho/2022 Session 10106 Profile and optimize your game's memory.srt new file mode 100644 index 0000000..cd40eff --- /dev/null +++ b/zho/2022 Session 10106 Profile and optimize your game's memory.srt @@ -0,0 +1,2847 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,810 --> 00:00:13,046 +Jack 许: 欢迎来到 +分析并优化您的游戏内存 + +3 +00:00:13,080 --> 00:00:16,149 +我是 Jack 许 +来自 Apple 的 GPU Software 团队 + +4 +00:00:16,183 --> 00:00:18,952 +还有我的同事 Seth 陆 + +5 +00:00:18,986 --> 00:00:21,688 +在过去的几年里 我们团队 + +6 +00:00:21,722 --> 00:00:23,490 +一直和与大家一样的 + +7 +00:00:23,524 --> 00:00:26,560 +游戏开发者们共同协作 +致力于改善游戏内存 + +8 +00:00:26,593 --> 00:00:28,996 +今天 我们将为大家分享成果 + +9 +00:00:29,029 --> 00:00:32,933 +让您在调试游戏内存 +创建精彩的游戏 + +10 +00:00:32,966 --> 00:00:36,803 +设计最佳的游戏体验中 +可抢占先机 + +11 +00:00:37,905 --> 00:00:42,943 +我们从 CPU 和 GPU 对象方面 +来分解您游戏内存使用情况 + +12 +00:00:43,877 --> 00:00:46,680 +另外 分析您游戏的内存分配 + +13 +00:00:46,713 --> 00:00:48,549 +物理内存的实际使用情况 + +14 +00:00:48,582 --> 00:00:51,285 +以及对象间的引用 + +15 +00:00:51,318 --> 00:00:53,554 +因为内存有许多部分 + +16 +00:00:53,587 --> 00:00:58,292 +我们的开发者工具也从 +不同的方面来揭开其面纱 + +17 +00:00:58,325 --> 00:01:02,296 +在这场旅程中 +我们能体验如何使用 + +18 +00:01:02,329 --> 00:01:06,800 +Xcode Instruments 和 +Terminal 中的命令行工具 + +19 +00:01:06,834 --> 00:01:12,039 +今天的旅程将以理解游戏内存 +拉开帷幕 + +20 +00:01:12,072 --> 00:01:15,275 +并开始分析内存和内存增长 + +21 +00:01:15,309 --> 00:01:18,679 +Seth 也会与我们分享 +Instruments 的知识 + +22 +00:01:18,712 --> 00:01:23,383 +了解 Instruments 的时序方案后 +我们继续深入旅行 + +23 +00:01:23,417 --> 00:01:28,488 +用 Xcode 和 Terminal 工具 +来分析您游戏的内存图 + +24 +00:01:28,522 --> 00:01:31,658 +这些工作流主要侧重于 +当前内存使用状态 + +25 +00:01:31,692 --> 00:01:35,329 +以及分解整体游戏内存 + +26 +00:01:35,362 --> 00:01:38,765 +最后 Seth 将与大家分享 +您如何使用 Metal Debugger + +27 +00:01:38,799 --> 00:01:40,734 +来优化 Metal 资源 + +28 +00:01:40,767 --> 00:01:45,739 +虽然从某种程度上说 它在游戏内存中 +相对独立 但仍然是核心领域 + +29 +00:01:45,772 --> 00:01:50,177 +现在 我们先从理解游戏内存开始 + +30 +00:01:51,044 --> 00:01:53,213 +您从 Xcode 启动游戏时 + +31 +00:01:53,247 --> 00:01:56,316 +比如 Metal 的 +示例代码 Modern Rendering + +32 +00:01:56,350 --> 00:02:00,420 +可以打开 Xcode 调试导航器中的 +这份内存报告 + +33 +00:02:00,454 --> 00:02:04,825 +初步展示了您游戏当前和近期 +内存使用情况 + +34 +00:02:04,858 --> 00:02:07,127 +及其在系统中的影响水平 + +35 +00:02:08,862 --> 00:02:12,866 +测量仪中数字展示了 +游戏当前内存使用情况 + +36 +00:02:12,900 --> 00:02:15,002 +内存调试的第一步非常重要 + +37 +00:02:15,035 --> 00:02:17,504 +即理解这些数字的含义 + +38 +00:02:19,173 --> 00:02:20,707 +用一行文字来表示 + +39 +00:02:20,741 --> 00:02:25,979 +游戏中的实际内存使用 +与内存分配并不相同 + +40 +00:02:26,013 --> 00:02:28,682 +实际内存使用是在 +物理内存上的 + +41 +00:02:28,715 --> 00:02:31,952 +而内存分配是游戏在 +虚拟存储地址空间 + +42 +00:02:31,985 --> 00:02:34,221 +所需要的内存 + +43 +00:02:34,254 --> 00:02:38,125 +不同的内存分配是 +自然分开计算的 + +44 +00:02:41,061 --> 00:02:42,896 +当您的游戏分配内存时 + +45 +00:02:42,930 --> 00:02:47,134 +那些新分配的内存并不会 +立即或直接占用 + +46 +00:02:47,167 --> 00:02:48,602 +物理内存的空间 + +47 +00:02:48,635 --> 00:02:53,006 +相反 它们会在虚拟存储地址空间 +预留一定空间 + +48 +00:02:53,040 --> 00:02:56,577 +虚拟地址空间 +是系统为每个进程提供的 + +49 +00:02:56,610 --> 00:02:59,646 +当程序后续 +实际使用该内存分配时 + +50 +00:02:59,680 --> 00:03:02,850 +系统将在物理内存中准备空间 + +51 +00:03:04,518 --> 00:03:08,055 +同类的内存分配会经过分类 + +52 +00:03:08,088 --> 00:03:11,291 +并稀疏地占领虚拟地址空间 + +53 +00:03:11,325 --> 00:03:13,760 +这些分类包括 + +54 +00:03:13,794 --> 00:03:16,363 +程序的可执行二进制文件 + +55 +00:03:16,396 --> 00:03:18,799 +所有库和框架 + +56 +00:03:18,832 --> 00:03:22,002 +栈 为本地和临时变量 + +57 +00:03:22,035 --> 00:03:24,872 +及一些函数参数提供存储 + +58 +00:03:24,905 --> 00:03:27,641 +动态内存区域 也称为堆 + +59 +00:03:27,674 --> 00:03:29,543 +包括类实例存储 + +60 +00:03:29,576 --> 00:03:32,679 +程序手动分配的内存 + +61 +00:03:32,713 --> 00:03:37,017 +从只读资源 如游戏资源文件中 +映射的区域 + +62 +00:03:37,050 --> 00:03:39,620 +当然 还有您游戏的 Metal 对象 + +63 +00:03:39,653 --> 00:03:44,691 +如缓冲区 纹理和管线状态对象 + +64 +00:03:44,725 --> 00:03:48,729 +这些分类是由区域组成的 + +65 +00:03:48,762 --> 00:03:53,767 +在底层 存储操作处理 +的粒度是内存页面 + +66 +00:03:53,800 --> 00:03:57,905 +在现代 Apple 设备中有 16KB + +67 +00:03:57,938 --> 00:04:01,708 +这意味着每个区域会占据 +一个或多个页面 + +68 +00:04:01,742 --> 00:04:04,344 +最少有 16KB 的大小 + +69 +00:04:05,646 --> 00:04:10,017 +随着游戏的持续运行 +其内存状态不断改变 + +70 +00:04:10,050 --> 00:04:11,952 +新对象被分配 + +71 +00:04:11,985 --> 00:04:14,021 +旧项目被销毁 + +72 +00:04:14,054 --> 00:04:16,757 +区域持续变化 + +73 +00:04:16,790 --> 00:04:20,227 +但只有区域中的被使用的页面 +才占用物理内存 + +74 +00:04:20,260 --> 00:04:23,263 +系统会努力计入你的游戏 + +75 +00:04:23,297 --> 00:04:25,332 +如其它 App 一样 + +76 +00:04:27,234 --> 00:04:30,070 +您游戏的内存页面 +可能是以下三者之一 + +77 +00:04:30,103 --> 00:04:32,973 +dirty compressed 和 clean + +78 +00:04:33,006 --> 00:04:35,776 +我们来看看它们分别是什么 + +79 +00:04:35,809 --> 00:04:39,980 +Dirty 内存页面包括 +您游戏写入的内存 + +80 +00:04:40,013 --> 00:04:42,850 +包括堆和框架分配的内存 + +81 +00:04:42,883 --> 00:04:47,888 +只要你的游戏修改过 +这些变量或者符号 + +82 +00:04:47,921 --> 00:04:49,890 +在搭载 Apple 芯片的设备中 + +83 +00:04:49,923 --> 00:04:53,660 +被访问的 Metal 资源 +同样也属于该分类 + +84 +00:04:53,694 --> 00:04:59,132 +这是因为 CPU 和 GPU +共享快速统一内存池 + +85 +00:05:00,501 --> 00:05:04,071 +然而 如果有些 dirty 页面 +长时间未使用 + +86 +00:05:04,104 --> 00:05:07,207 +系统可能会减少它们在物理内存的占用 + +87 +00:05:07,241 --> 00:05:10,944 +通过压缩这些页面的方式 +或将其存储在闪存或者磁盘上 + +88 +00:05:10,978 --> 00:05:12,913 +也被称为交换 (swap) + +89 +00:05:12,946 --> 00:05:17,050 +这让设备可以运行更多 App +和服务 + +90 +00:05:17,084 --> 00:05:20,387 +随后 您的游戏如果再次请求这些页面 + +91 +00:05:20,420 --> 00:05:24,024 +系统会解压或从磁盘换入 + +92 +00:05:24,057 --> 00:05:29,663 +注意 计入您的游戏的 +仍然是未压缩的大小 + +93 +00:05:29,696 --> 00:05:31,598 +而在 clean 内存页面方面 + +94 +00:05:31,632 --> 00:05:34,635 +它们包括从磁盘中映射的只读文件 + +95 +00:05:34,668 --> 00:05:37,804 +如纹理或音频资产 + +96 +00:05:37,838 --> 00:05:40,874 +以及加载到进程中的框架 + +97 +00:05:40,908 --> 00:05:45,279 +该系统可于任何时间对它们 +进行清空或重新加载 + +98 +00:05:45,312 --> 00:05:48,582 +因此不会计入您游戏的内存足迹 + +99 +00:05:48,615 --> 00:05:51,852 +然而 它们可能常驻于内存中 + +100 +00:05:51,885 --> 00:05:57,057 +且过量使用会减缓系统 +和游戏的速度 + +101 +00:05:57,090 --> 00:06:01,361 +通常前面两个部分最值得关注 + +102 +00:06:01,395 --> 00:06:04,064 +这两个部分合在一起称为内存足迹 + +103 +00:06:04,097 --> 00:06:07,868 +系统用它来实施内存限制 + +104 +00:06:09,970 --> 00:06:13,507 +在一些术语系统中 +人们提到 ”dirty 内存” + +105 +00:06:13,540 --> 00:06:18,345 +指的是内存足迹 +因为 dirty 是 clean 的反义词 + +106 +00:06:18,378 --> 00:06:21,281 +但是不用担心 当变得模糊时 + +107 +00:06:21,315 --> 00:06:24,184 +我们会明确所指的是哪一个 + +108 +00:06:24,218 --> 00:06:29,089 +现在您知道内存的工作方式 +以及系统如何在游戏中衡量它 + +109 +00:06:29,990 --> 00:06:32,292 +除了这个 Xcode 内存测量仪 + +110 +00:06:32,326 --> 00:06:36,129 +您还可以在系统的许多地方 +看到内存足迹 + +111 +00:06:36,163 --> 00:06:39,433 +包括 Mac 上的 Activity Monitor App + +112 +00:06:39,466 --> 00:06:43,770 +以及一些 Apple 平台用它来 +作为 App 内存限制 + +113 +00:06:43,804 --> 00:06:47,908 +您的游戏也可以使用这个指标 +来指导内存使用 + +114 +00:06:47,941 --> 00:06:53,413 +有一些有用的 API 可查询 +当前足迹以及可用内存 + +115 +00:06:53,447 --> 00:06:54,915 +我们来快速浏览下 + +116 +00:06:54,948 --> 00:07:00,153 +要为 iOS iPadOS 或 tvOS 游戏 +取得可用系统内存 + +117 +00:07:00,187 --> 00:07:05,459 +调用在 os/proc.h 头文件中声明的 +os_proc_available_memory + +118 +00:07:07,261 --> 00:07:10,264 +而任意 Apple 平台的内存足迹 + +119 +00:07:10,297 --> 00:07:13,100 +均可通过 proc_pid_rusage 来获得 + +120 +00:07:13,133 --> 00:07:15,802 +传入通过 getpid 获得进程 ID + +121 +00:07:15,836 --> 00:07:19,573 +RUSAGE_INFO_CURRENT 当前为版本 6 + +122 +00:07:19,606 --> 00:07:22,543 +以及数据存储结构 + +123 +00:07:22,576 --> 00:07:26,847 +然后获取其物理足迹 +或最大物理足迹属性 + +124 +00:07:28,148 --> 00:07:33,687 +我们来回顾下 在第一部分中 +我们浏览了关于内存的一些概念 + +125 +00:07:33,720 --> 00:07:37,624 +游戏的内存分配在 +虚拟存储地址空间进行 + +126 +00:07:37,658 --> 00:07:42,496 +它们经由游戏访问后 +作为 16KB 页面 + +127 +00:07:42,529 --> 00:07:45,299 +占据物理内存空间 + +128 +00:07:45,332 --> 00:07:50,771 +内存足迹在 Apple 平台中 +作为主要和通用测量指标 + +129 +00:07:50,804 --> 00:07:53,574 +确定游戏实际内存使用 + +130 +00:07:53,607 --> 00:07:58,779 +内存足迹包括 dirty 压缩 +和交换页面 + +131 +00:07:58,812 --> 00:08:03,183 +在 Apple 芯片上 +包括 CPU 和 GPU 对象 + +132 +00:08:03,217 --> 00:08:06,920 +它可用于实施内存限制 + +133 +00:08:06,954 --> 00:08:12,893 +您的游戏可以调用系统 API +来获取其足迹以及可用内存 + +134 +00:08:12,926 --> 00:08:16,063 +现在您知道内存在底层 +是如何工作了 + +135 +00:08:16,096 --> 00:08:18,332 +我们来看看它在您游戏中 +是怎样的 + +136 +00:08:18,365 --> 00:08:21,869 +我们有请 Seth 来分享更多内容 + +137 +00:08:21,902 --> 00:08:23,170 +Seth 陆: 谢谢 Jack + +138 +00:08:23,203 --> 00:08:26,573 +现在 我们开始捕获一个游戏的 +内存增长 + +139 +00:08:26,607 --> 00:08:30,611 +我会继续使用 Modern Renderer +示例项目 + +140 +00:08:30,644 --> 00:08:32,446 +当您从 Xcode 中运行游戏时 + +141 +00:08:32,479 --> 00:08:36,183 +Memory Gauge 能显示 +不同时间下的内存足迹 + +142 +00:08:36,216 --> 00:08:39,286 +然而 您可以通过在 +Instruments 中分析游戏 + +143 +00:08:39,319 --> 00:08:42,289 +获得更详细的内存使用情况 + +144 +00:08:42,322 --> 00:08:46,260 +因为通常来说 游戏在启用期间 +可以分配许多内存 + +145 +00:08:46,293 --> 00:08:48,495 +您可在新游戏启动时就开始分析 + +146 +00:08:48,529 --> 00:08:51,732 +而不是在当前运行期间来分析 + +147 +00:08:51,765 --> 00:08:54,968 +在 Xcode 中 要快速开始 +分析游戏 + +148 +00:08:55,002 --> 00:08:59,206 +按下运行按钮不放 +然后选择 “Profile” + +149 +00:08:59,239 --> 00:09:02,109 +这可以自动跳转到 Instruments + +150 +00:09:02,142 --> 00:09:05,012 +Instruments App 包括一组分析工具 + +151 +00:09:05,045 --> 00:09:07,447 +可在一条时间线内 +从不同方面记录系统 + +152 +00:09:07,481 --> 00:09:10,517 +并将记录数据可视化 + +153 +00:09:10,551 --> 00:09:12,853 +今年全新推出了 +Game Memory 模板 + +154 +00:09:12,886 --> 00:09:15,856 +可以帮助您更好地了解 +您的 Metal 游戏中的内存增长 + +155 +00:09:17,291 --> 00:09:21,428 +该模板附带有 Allocations +和 Metal Resource Events 工具 + +156 +00:09:21,461 --> 00:09:24,531 +来记录内存分配的历史 + +157 +00:09:24,565 --> 00:09:27,801 +VM Tracker 可记录内存足迹 + +158 +00:09:27,835 --> 00:09:31,605 +Virtual Memory Trace 可记录 +虚拟内存活动 + +159 +00:09:31,638 --> 00:09:35,442 +Metal Application 和 GPU +可记录与 Metal 相关的事件 + +160 +00:09:37,477 --> 00:09:40,814 +在这个 demo 中 +我将着重强调前面三个工具 + +161 +00:09:40,848 --> 00:09:44,685 +Allocations Metal Resource Events +和 VM Tracker + +162 +00:09:44,718 --> 00:09:47,955 +但首先 我们先记录一份 +游戏的 trace + +163 +00:09:47,988 --> 00:09:51,391 +您可以按下这里的记录按钮 +开始记录 + +164 +00:09:51,425 --> 00:09:53,193 +随后 停止记录 + +165 +00:09:53,227 --> 00:09:57,130 +您可以按下同样的按钮 +或退出游戏 + +166 +00:09:57,164 --> 00:09:59,399 +趁着 Instruments +在记录 Modern Renderer 时 + +167 +00:09:59,433 --> 00:10:03,036 +我给大家看下另一个 +记录 trace 的方法 + +168 +00:10:03,070 --> 00:10:06,974 +xctrace 指令让您可以 +用编程方式运行记录 + +169 +00:10:07,007 --> 00:10:09,376 +在自动化工作流中可能会有用 + +170 +00:10:10,944 --> 00:10:13,514 +此外 您可以指定设备名称 + +171 +00:10:13,547 --> 00:10:17,751 +选择 iPhone iPad 或 Apple TV +为目标 + +172 +00:10:18,819 --> 00:10:21,021 +现在我已经抓取了 +Instruments trace + +173 +00:10:21,054 --> 00:10:23,624 +首先看看 Allocations + +174 +00:10:23,657 --> 00:10:27,261 +Allocations 为您提供了 +内存分配的详细视图 + +175 +00:10:27,294 --> 00:10:30,330 +包括它们的大小和对象引用计数 + +176 +00:10:30,364 --> 00:10:34,067 +然而 不包括私有 Metal 资源 + +177 +00:10:34,101 --> 00:10:38,338 +Statistics 视图展示了 +所有堆的内存分配以及匿名 VM + +178 +00:10:40,274 --> 00:10:45,779 +All Heap Allocations 包括 +可能包含对象的 malloc 分配的缓冲区 + +179 +00:10:45,812 --> 00:10:50,617 +All Anonymous VM 包括 +值得关注的可能为 dirty 的 VM 区域 + +180 +00:10:50,651 --> 00:10:54,388 +我们稍后会看到这一分类下的 +一些 Metal 资源 + +181 +00:10:56,123 --> 00:10:59,660 +现在 我们来看看 +All Heap Allocations 内部 + +182 +00:10:59,693 --> 00:11:03,964 +通常 大内存空间分配 +更值得关注优化 + +183 +00:11:03,997 --> 00:11:07,634 +要找到单一最大的内存分配 +您可以点击 Size 表列 + +184 +00:11:07,668 --> 00:11:09,837 +来根据内存分配大小排序 + +185 +00:11:11,238 --> 00:11:13,774 +在内存分配中 +您可以点击这个箭头 + +186 +00:11:13,807 --> 00:11:17,878 +来查看 Swift 和 Objective-C +对象的引用计数变化 + +187 +00:11:20,147 --> 00:11:22,583 +在列表中选择这个大内存分配后 + +188 +00:11:22,616 --> 00:11:26,887 +在 inspector 面板有 +内存分配历史的栈踪迹 + +189 +00:11:26,920 --> 00:11:31,592 +点击按钮可以隐藏系统库或框架 + +190 +00:11:31,625 --> 00:11:34,228 +这里 根据栈踪迹 + +191 +00:11:34,261 --> 00:11:37,531 +Modern Renderer 加载资产时 +会进行内存分配 + +192 +00:11:38,866 --> 00:11:43,136 +双击框可进入源代码 + +193 +00:11:43,170 --> 00:11:47,374 +现在 我们返回看下 +“All Anonymous VM” 分类内部 + +194 +00:11:48,809 --> 00:11:52,646 +在 Metal 游戏中 您会看到 +IOAccelerator 和 IOSurface 分类下 + +195 +00:11:52,679 --> 00:11:55,582 +有很多内存分配 + +196 +00:11:55,616 --> 00:11:59,453 +Allocations 中的 IOAccelerator +对应 Metal 资源 + +197 +00:12:00,854 --> 00:12:04,892 +根据栈踪迹 您可以看到 +加载资产时的内存分配 + +198 +00:12:06,493 --> 00:12:10,497 +Allocations 中的 IOSurface +对应 drawable + +199 +00:12:10,531 --> 00:12:14,401 +这里 栈踪迹显示了 +MetalKit 视图请求了 drawable + +200 +00:12:16,036 --> 00:12:20,307 +默认设置下 Allocations 工具 +可将内存分配大小可视化 + +201 +00:12:20,340 --> 00:12:23,544 +但是也会有其它的外观形式 + +202 +00:12:23,577 --> 00:12:26,013 +您可点击 Allocations 轨中的 +箭头按钮 + +203 +00:12:26,046 --> 00:12:29,616 +自定显示模式 +将 Allocation Density 可视化 + +204 +00:12:29,650 --> 00:12:33,520 +这可更新图表 为您展示 +不同时间下内存分配的数量 + +205 +00:12:33,554 --> 00:12:36,657 +显示内存分配的峰值 + +206 +00:12:36,690 --> 00:12:39,726 +这些峰值可能是 +内存增长的来源 + +207 +00:12:39,760 --> 00:12:43,263 +所以 Allocations 中显示的数据 +是很底层的 + +208 +00:12:43,297 --> 00:12:46,300 +要更好地理解分配的 Metal 资源 + +209 +00:12:46,333 --> 00:12:50,003 +我们接着看 Metal Resource Events + +210 +00:12:50,037 --> 00:12:54,775 +Metal Resource Events 工具 +是围绕 Metal 资源来设计的 + +211 +00:12:54,808 --> 00:12:56,310 +在 Resource Events 视图中 + +212 +00:12:56,343 --> 00:13:00,681 +您可以找到 Metal 资源分配 +和释放的历史记录 + +213 +00:13:00,714 --> 00:13:04,218 +这里您可以通过标签 +区分 Metal 资源 + +214 +00:13:04,251 --> 00:13:08,222 +您可通过 Metal API +用编程方式进行指定标签 + +215 +00:13:08,255 --> 00:13:10,290 +与 Allocations 工具类似 + +216 +00:13:10,324 --> 00:13:13,894 +您可以在 inspector 中 +为内存分配历史记录找到栈踪迹 + +217 +00:13:15,929 --> 00:13:19,399 +该工具也会在 Metal 设备下 +添加 Allocation + +218 +00:13:19,433 --> 00:13:21,034 +和 Deallocations 轨 + +219 +00:13:21,068 --> 00:13:23,804 +帮助可视化事件密度 + +220 +00:13:23,837 --> 00:13:26,740 +到目前为止 +Allocations 和 Metal Resource Events + +221 +00:13:26,773 --> 00:13:29,676 +可以帮助理解内存分配 + +222 +00:13:29,710 --> 00:13:33,814 +然而 内存分配并不一定 +会转变为内存足迹 + +223 +00:13:33,847 --> 00:13:37,351 +因此 我们接着到 VM Tracker 下 +查看实际内存使用情况 + +224 +00:13:38,352 --> 00:13:41,154 +VM Tracker 工具展示了 +非压缩 dirty + +225 +00:13:41,188 --> 00:13:44,057 +压缩或交换内存 + +226 +00:13:44,091 --> 00:13:48,061 +Dirty Size 代表了 +非压缩 dirty 内存 + +227 +00:13:48,095 --> 00:13:52,165 +Swapped Size 表示压缩 +或交换内存 + +228 +00:13:52,199 --> 00:13:54,868 +在这条记录中 +Modern Renderer 内 + +229 +00:13:54,902 --> 00:13:57,538 +没有压缩或交换内存使用 + +230 +00:13:57,571 --> 00:14:00,874 +详细的 Summary 视图 +显示了 VM 区域 + +231 +00:14:00,908 --> 00:14:04,244 +在 “mapped file” 区域中 +您可能会看到一些映射内存资源 + +232 +00:14:04,278 --> 00:14:06,280 +比如您的游戏资产 + +233 +00:14:06,313 --> 00:14:10,384 +Modern Renderer 将 bistro 资产 +映射到内存 + +234 +00:14:10,417 --> 00:14:13,320 +这是Instruments 中 Allocations +Metal Resource Events 和 + +235 +00:14:13,353 --> 00:14:17,090 +VM Tracker 的简要概述 + +236 +00:14:17,124 --> 00:14:20,394 +我们快速回顾下您可以 +如何分析内存增长 + +237 +00:14:20,427 --> 00:14:22,930 +首先 选择 Game Memory 模板 + +238 +00:14:22,963 --> 00:14:25,766 +然后 记录和分析 trace + +239 +00:14:25,799 --> 00:14:28,168 +有时 重现或验证 +内存增长模式时 + +240 +00:14:28,202 --> 00:14:31,839 +这个过程可能需要重复多次 + +241 +00:14:31,872 --> 00:14:34,474 +我们希望新的 Game Memory 模板 +可帮助您更好地理解 + +242 +00:14:34,508 --> 00:14:37,945 +您游戏中的内存分配 +或足迹增长 + +243 +00:14:37,978 --> 00:14:42,115 +请查看其它视频来了解更多 +关于 Instruments 的使用方法 + +244 +00:14:42,149 --> 00:14:43,917 +现在 交回给 Jack + +245 +00:14:45,619 --> 00:14:48,055 +Jack: Game Memory 模板看起来 +实在太赞了 + +246 +00:14:48,088 --> 00:14:51,491 +肯定能大大帮助我们理解 +不同时间下 + +247 +00:14:51,525 --> 00:14:53,861 +内存使用情况的变化 + +248 +00:14:53,894 --> 00:14:57,631 +另外 您可能会想抓取 +指定时间内游戏的内存状态 + +249 +00:14:57,664 --> 00:15:01,268 +这样您可以深入研究该内存状态 + +250 +00:15:01,301 --> 00:15:04,571 +并从不同的角度进行审视 + +251 +00:15:04,605 --> 00:15:08,275 +为了实现这一目的 我们有 +内存图和一套工具 + +252 +00:15:09,710 --> 00:15:13,347 +内存图是有效存储 +您游戏内存状态的 + +253 +00:15:13,380 --> 00:15:15,082 +完整快照文件 + +254 +00:15:15,115 --> 00:15:17,150 +包括对象创建历史 + +255 +00:15:17,184 --> 00:15:20,153 +引用 以及所有压缩或交换 + +256 +00:15:21,788 --> 00:15:23,957 +您可以在任意时间生成快照 + +257 +00:15:23,991 --> 00:15:27,160 +如问题发生时 +或生成一对 + +258 +00:15:27,194 --> 00:15:31,865 +分别在问题发生前和发生后 +用来比较 + +259 +00:15:31,899 --> 00:15:35,035 +我们来加点趣味 用菜谱类比法 + +260 +00:15:35,068 --> 00:15:38,739 +来分析内存图的内存 + +261 +00:15:38,772 --> 00:15:41,909 +包括配料和备料 + +262 +00:15:43,710 --> 00:15:47,080 +配料方面 您需要的是您的游戏准备 + +263 +00:15:47,114 --> 00:15:49,550 +被称为 Malloc Stack Logging 的配置 + +264 +00:15:49,583 --> 00:15:52,586 +以及抓取一个内存图 + +265 +00:15:52,619 --> 00:15:55,055 +配置 Malloc Stack Logging + +266 +00:15:55,088 --> 00:15:56,723 +和抓取内存图很便捷 + +267 +00:15:58,592 --> 00:16:03,030 +Malloc Stack Logging 在游戏进程中 +记录分配信息 + +268 +00:16:03,063 --> 00:16:05,299 +您可以在 Scheme 设置中找到 + +269 +00:16:05,332 --> 00:16:08,669 +选择 Run action 进入 Diagnostics + +270 +00:16:08,702 --> 00:16:11,271 +勾选 Malloc Stack Logging +复选框 + +271 +00:16:13,040 --> 00:16:15,642 +如果您想知道这两个选项是什么 + +272 +00:16:15,676 --> 00:16:19,313 +All Allocation and Free History +追踪所有的对象 + +273 +00:16:19,346 --> 00:16:22,049 +即使对象已经释放 + +274 +00:16:22,082 --> 00:16:24,351 +日志数据可能会耗费更多内存 + +275 +00:16:24,384 --> 00:16:28,622 +但调试如分片的问题时会很有用 + +276 +00:16:28,655 --> 00:16:33,160 +另一方面 Live Allocation Only +从它的历史记录中 + +277 +00:16:33,193 --> 00:16:36,263 +丢弃已释放对象 所以更轻 + +278 +00:16:36,296 --> 00:16:39,199 +在这种情况下 我只是研究 + +279 +00:16:39,233 --> 00:16:43,437 +存在对象上的引用 +所以我选择这个选项 + +280 +00:16:43,470 --> 00:16:45,572 +实际上 大部分时间中 + +281 +00:16:45,606 --> 00:16:49,209 +Live Allocation Only 都会是 +您的推荐选项 + +282 +00:16:50,677 --> 00:16:56,049 +或者 如果没有从 Xcode 中启动 +您可以设置环境变量 + +283 +00:16:56,083 --> 00:17:00,187 +查看 malloc 手册页面 +以获得关于记录模式的信息 + +284 +00:17:00,220 --> 00:17:03,190 +随后 准备内存图 + +285 +00:17:03,223 --> 00:17:05,626 +在调试区域点击 + +286 +00:17:05,659 --> 00:17:07,895 +调试内存图按钮 + +287 +00:17:07,928 --> 00:17:09,863 +Xcode 会抓取内存快照 + +288 +00:17:09,897 --> 00:17:13,667 +对其进行处理 进入内存调试器 + +289 +00:17:13,700 --> 00:17:18,505 +Xcode Memory Debugger 为游戏 +内存使用情况提供直观视角 + +290 +00:17:18,539 --> 00:17:22,142 +我们花一分钟来看下其视图 + +291 +00:17:22,176 --> 00:17:25,445 +左边 Debug Navigator 给您 + +292 +00:17:25,479 --> 00:17:28,482 +对象实例的分级列表 + +293 +00:17:30,484 --> 00:17:34,421 +右边 File Inspector 提供 +如内存足迹 运行时间 + +294 +00:17:34,454 --> 00:17:38,625 +和抓取日期的有用信息 + +295 +00:17:40,928 --> 00:17:44,164 +位于中间区域的是 + +296 +00:17:44,198 --> 00:17:47,134 +左边选定对象的内存图视图 + +297 +00:17:47,167 --> 00:17:50,771 +以及引用是如何连接至对象的 + +298 +00:17:50,804 --> 00:17:53,740 +我稍后会再详细解释这个图 + +299 +00:17:56,109 --> 00:17:59,847 +File 菜单给您提供了 +保存内存图的选项 + +300 +00:17:59,880 --> 00:18:03,517 +从而进行进一步分析 +或可以快捷地与您的团队共享 + +301 +00:18:05,118 --> 00:18:07,888 +对于 Mac 游戏 您也可以 +用进程 ID 或名称 + +302 +00:18:07,921 --> 00:18:12,659 +通过 leaks 命令行程序抓取内存图 + +303 +00:18:12,693 --> 00:18:16,163 +这意味着您可以 +通过 ssh 远程操作 + +304 +00:18:16,196 --> 00:18:18,031 +而让光标保留在游戏中 + +305 +00:18:18,065 --> 00:18:23,103 +以使您游戏全屏运行并保持焦点 + +306 +00:18:23,136 --> 00:18:26,907 +这就是您开始内存图分析所需的 + +307 +00:18:28,275 --> 00:18:32,880 +现在来看下在 Terminal 中 +用 Xcode Memory Debugger + +308 +00:18:32,913 --> 00:18:36,083 +和一些多功能命令行工具分析内存图 + +309 +00:18:36,116 --> 00:18:41,121 +来查看内存分配 足迹甚至更多 + +310 +00:18:41,154 --> 00:18:45,759 +第一步最好是按类别 +分解内存使用情况 + +311 +00:18:45,792 --> 00:18:48,629 +footprint 程序正是作为此用 + +312 +00:18:50,430 --> 00:18:56,203 +footprint 使用内存图中的信息 +来重建高度概括 + +313 +00:18:56,236 --> 00:19:01,241 +通常 您首先会关注大一些的类别 + +314 +00:19:01,275 --> 00:19:05,812 +对于如这个来自 Modern Rendering +示例代码的游戏内存图来说 + +315 +00:19:05,846 --> 00:19:09,783 +IOAccelerator 通常是最大的 + +316 +00:19:09,816 --> 00:19:14,988 +如 Seth 所说 它包括 +Metal 资源 + +317 +00:19:15,022 --> 00:19:20,494 +堆内存分配会分为 +几个 MALLOC_ 开头的类别 + +318 +00:19:20,527 --> 00:19:25,899 +系统为了提升性能 +将内存分配按大小分到对应内存池 + +319 +00:19:25,933 --> 00:19:30,170 +这些对象可能会来自许多地方 +如第三方 plugins + +320 +00:19:30,204 --> 00:19:34,875 +或游戏处理音效 +或物理模拟的库 + +321 +00:19:36,343 --> 00:19:39,479 +这个内存图来自一个非常精彩的 +Apple Arcade 游戏 + +322 +00:19:39,513 --> 00:19:43,283 +名为 Manifold Garden +是 William “Cheer” Studio 制作的 + +323 +00:19:43,317 --> 00:19:46,753 +我很高兴他们允许我向您展示 +这款游戏的内存使用情况 + +324 +00:19:46,787 --> 00:19:51,558 +如果您的游戏使用了游戏引擎 +如同 Manifold Garden 使用了 Unity + +325 +00:19:51,592 --> 00:19:54,528 +或基于内存映射使用自定义分配器 + +326 +00:19:54,561 --> 00:19:58,899 +内存像这样显示为 +untagged VM_ALLOCATE + +327 +00:19:58,932 --> 00:20:01,702 +这里有一个专业意见 +在 Apple 平台中 + +328 +00:20:01,735 --> 00:20:04,872 +您的游戏可以使用 +最多 16 个 App 专有标签 + +329 +00:20:04,905 --> 00:20:08,442 +这样您在深入研究内存使用时 +能更清晰 + +330 +00:20:08,475 --> 00:20:11,144 +这和修改一行代码一样简单 + +331 +00:20:12,312 --> 00:20:16,283 +首先 通过 16 个选项之一 +创建标签 + +332 +00:20:16,316 --> 00:20:21,522 +然后 当调用 mmap 时 +用这个新标签作为文件描述符 + +333 +00:20:21,555 --> 00:20:24,091 +来代替这个 -1 + +334 +00:20:24,124 --> 00:20:28,562 +您可以查看 mmap 的手册页面 +以学习如何定义标签和分类 + +335 +00:20:30,597 --> 00:20:32,833 +如果您使用 mach_vm_allocate + +336 +00:20:32,866 --> 00:20:37,171 +在分配时在标记参数中使用 +同样的标记 + +337 +00:20:39,573 --> 00:20:41,642 +在 footprint 程序世界中 + +338 +00:20:41,675 --> 00:20:45,245 +dirty 大小同样包括交换和压缩 + +339 +00:20:45,279 --> 00:20:48,982 +所以要将其作为每个类别的总计量 + +340 +00:20:50,250 --> 00:20:53,754 +这是当前内存使用的组成 + +341 +00:20:53,787 --> 00:20:56,857 +以及它如何组成足迹的简要概念 + +342 +00:20:56,890 --> 00:21:01,361 +有些较少使用的内存 +会压缩或交换 + +343 +00:21:01,395 --> 00:21:04,364 +它们可能是节省内存的来源 + +344 +00:21:04,398 --> 00:21:07,167 +下一步是找到游戏使用了多少 + +345 +00:21:07,201 --> 00:21:10,871 +压缩或交换内存 然后优化 + +346 +00:21:12,773 --> 00:21:16,610 +那您需要对内存图运行 vmmap + +347 +00:21:16,643 --> 00:21:19,580 +它会给您 dirty 和交换的大小 + +348 +00:21:19,613 --> 00:21:22,082 +而不是两者的结合 + +349 +00:21:22,115 --> 00:21:24,985 +该 dirty 列包括当前未交换 + +350 +00:21:25,018 --> 00:21:27,487 +或压缩的常规 dirty 内存 + +351 +00:21:27,521 --> 00:21:30,524 +而交换列包括压缩或交换内存的 + +352 +00:21:30,557 --> 00:21:33,694 +原始大小 + +353 +00:21:33,727 --> 00:21:37,965 +系统将这两列加在一起 +来确定足迹 + +354 +00:21:37,998 --> 00:21:42,636 +但由于交换尺寸列中的内存 +并非经常使用 + +355 +00:21:42,669 --> 00:21:45,772 +这可很好地提示优化游戏内存时 + +356 +00:21:45,806 --> 00:21:48,442 +需要查看的内容是什么 + +357 +00:21:48,475 --> 00:21:51,345 +还有 这是有虚拟尺寸列的 + +358 +00:21:51,378 --> 00:21:54,114 +内存分配大小 + +359 +00:21:54,147 --> 00:21:58,285 +常驻大小包括 clean 页面 +如可执行文件 + +360 +00:21:58,318 --> 00:22:00,521 +和内存映射文件等 + +361 +00:22:02,422 --> 00:22:07,294 +很方便的是 vmmap 会用一个 +不同的表来显示内存分配 + +362 +00:22:07,327 --> 00:22:09,363 +在其输出底部 + +363 +00:22:09,396 --> 00:22:13,300 +vmmap 按区域对内存分组 + +364 +00:22:13,333 --> 00:22:18,172 +这些区域反映了它们在您游戏中的 +使用情况或生命周期 + +365 +00:22:18,205 --> 00:22:20,674 +因为我打开了 MallocStackLogging + +366 +00:22:20,707 --> 00:22:24,811 +堆上的内存分配在工具区域 + +367 +00:22:24,845 --> 00:22:27,714 +不然 它们按内存分配大小 +会在两个默认区域 + +368 +00:22:27,748 --> 00:22:33,887 +MallocHelperZone +和 DefaultMallocZone + +369 +00:22:33,921 --> 00:22:40,594 +通常 您会跳过小一点的 +系统利用区域 如 QuartzCore 区域 + +370 +00:22:42,196 --> 00:22:47,334 +而且 如果您想查看 +高分片大小指示的分片 + +371 +00:22:47,367 --> 00:22:52,439 +或者百分比 如数十或数百兆字节 + +372 +00:22:52,472 --> 00:22:57,411 +WWDC 2021 讲座有更多 +关于分片的问题 + +373 +00:22:58,645 --> 00:23:02,282 +运行没有 --summary 的 vmmap + +374 +00:23:02,316 --> 00:23:04,718 +或在标准模式使用 vmmap + +375 +00:23:04,751 --> 00:23:09,223 +可以在这些分类中逐行显示 +每个 vm 区域 + +376 +00:23:09,256 --> 00:23:14,595 +就好像我们之前谈到的 +虚拟地址空间一样 + +377 +00:23:14,628 --> 00:23:21,068 +所以有 vmmap 您可以将经常使用的 +dirty 内存中与较少使用的部分区分开 + +378 +00:23:21,101 --> 00:23:23,871 +通常游戏中也有很多 + +379 +00:23:23,904 --> 00:23:27,207 +不同大小的动态分配 + +380 +00:23:27,241 --> 00:23:30,010 +或 malloc 分配的堆内存使用 + +381 +00:23:30,043 --> 00:23:32,045 +它们尤其需要关注 + +382 +00:23:32,880 --> 00:23:36,550 +heap 工具按类别分组 +malloc 分配的资源 + +383 +00:23:36,583 --> 00:23:39,253 +根据实例计数来排序 + +384 +00:23:39,286 --> 00:23:43,524 +这些类在 C++ 中由 VTable + +385 +00:23:43,557 --> 00:23:45,993 +或通过 Objective-C 或 Swift 来确定的 + +386 +00:23:47,628 --> 00:23:49,997 +我们使用的是 --quiet 参数 + +387 +00:23:50,030 --> 00:23:53,734 +来跳过关于 +一些元数据的头部信息 + +388 +00:23:53,767 --> 00:23:59,206 +今年新推出的 heap 在 +识别对象类型上更智能 + +389 +00:23:59,239 --> 00:24:02,676 +它使用通过 Malloc Stack Logging +记录的信息 + +390 +00:24:02,709 --> 00:24:05,979 +来展示调用者或相关库 + +391 +00:24:06,013 --> 00:24:09,683 +因此巨大的 non-object 已经是过往 + +392 +00:24:10,584 --> 00:24:14,888 +这个还是 Manifold Garden 的内存图 + +393 +00:24:14,922 --> 00:24:18,392 +这个例子首次揭示了 + +394 +00:24:18,425 --> 00:24:23,463 +如 FMOD Studio 的插件和 +如 GameAssembly.dylib 的游戏组件 + +395 +00:24:23,497 --> 00:24:27,801 +占用了多少堆使用空间 + +396 +00:24:27,835 --> 00:24:32,306 +所以现在您更了解 +内存是如何分布的 + +397 +00:24:32,339 --> 00:24:38,078 +这也可以通过获得这些对象的 +更多信息了解应该往那个方向调查 + +398 +00:24:38,111 --> 00:24:42,216 +在这个例子中 开发者 +打开了 FMOD Studio + +399 +00:24:42,249 --> 00:24:45,919 +来调整游戏中的音轨和音效 + +400 +00:24:45,953 --> 00:24:50,691 +或者到 Unity 中 +查看可优化的游戏代码等等 + +401 +00:24:52,593 --> 00:24:55,295 +有时 按类总大小排序 + +402 +00:24:55,329 --> 00:24:58,765 +而不是类实例计数 +会更为有帮助 + +403 +00:24:58,799 --> 00:25:01,535 +在 Modern Rendering 示例项目的 +内存图中 + +404 +00:25:01,568 --> 00:25:07,641 +顶级贡献者是一个使用了 +超过 258MB 的类 + +405 +00:25:07,674 --> 00:25:11,512 +要继续查看 Modern Rendering 示例中 +较大的对象 + +406 +00:25:11,545 --> 00:25:17,584 +使用 heap 加上 --sortBySize +按类总大小排序对象 + +407 +00:25:17,618 --> 00:25:21,688 +加上 --showSize 列出所有对象 + +408 +00:25:21,722 --> 00:25:24,725 +而不是每个类的概览 + +409 +00:25:24,758 --> 00:25:28,629 +在 Bytes Storage 中 +有一个 NSConcreteMutableData 对象 + +410 +00:25:28,662 --> 00:25:34,201 +大小在 255MB + +411 +00:25:34,234 --> 00:25:37,971 +看起来是值得注意的 + +412 +00:25:38,005 --> 00:25:40,908 +接下来 我想研究下这是什么 + +413 +00:25:40,941 --> 00:25:44,278 +首先 我想知道它的地址 + +414 +00:25:44,311 --> 00:25:49,816 +我添加了 --address +输入 NSConcreteMutableData 匹配符 + +415 +00:25:49,850 --> 00:25:53,153 +然后是通配符 .* + +416 +00:25:53,187 --> 00:25:55,355 +还有括号里的大小过滤器 + +417 +00:25:55,389 --> 00:26:00,093 +只列出 10MB 大小及以上的对象 + +418 +00:26:00,127 --> 00:26:02,796 +这是对象地址 + +419 +00:26:02,829 --> 00:26:07,334 +我会在后续的步骤中使用 +来做进一步的分析 + +420 +00:26:07,367 --> 00:26:13,407 +这是对实例做了对象识别改进的 +heap 工具 + +421 +00:26:13,440 --> 00:26:16,276 +到目前为止 已经看到了三种工具 +来理解 + +422 +00:26:16,310 --> 00:26:18,979 +游戏中什么对象在使用内存 + +423 +00:26:19,012 --> 00:26:21,548 +它们都会提供不同的视图 + +424 +00:26:21,582 --> 00:26:24,351 +我展示的只是一个工作流 + +425 +00:26:24,384 --> 00:26:26,620 +根据您游戏中特定的内存模式 + +426 +00:26:26,653 --> 00:26:28,889 +或使用的技术 + +427 +00:26:28,922 --> 00:26:31,692 +您可以按需求进行使用 + +428 +00:26:33,894 --> 00:26:36,163 +发现我们不确定 + +429 +00:26:36,196 --> 00:26:39,066 +其存在的对象 + +430 +00:26:39,099 --> 00:26:41,835 +下一步就是要找到其来源 + +431 +00:26:41,869 --> 00:26:44,104 +及其分配调用堆栈 + +432 +00:26:45,172 --> 00:26:48,575 +在 Modern Rendering 中的 +200MB 对象中 + +433 +00:26:48,609 --> 00:26:50,944 +我用了 --callTree 模式 + +434 +00:26:50,978 --> 00:26:54,915 +将其地址传到 malloc_history + +435 +00:26:54,948 --> 00:26:57,451 +与额外的 invert 参数一起 + +436 +00:26:57,484 --> 00:27:01,655 +我可以集中于最接近 +内存分配的函数 + +437 +00:27:01,688 --> 00:27:03,156 +然后就好了 + +438 +00:27:03,190 --> 00:27:06,793 +这是内存分配的反向跟踪 + +439 +00:27:06,827 --> 00:27:12,065 +同样的 Xcode Memory Debugger +也展示了 inspector 中一个对象的 + +440 +00:27:12,099 --> 00:27:13,600 +内存分配历史 + +441 +00:27:13,634 --> 00:27:17,371 +选择一个对象 +点击 Memory Inspector + +442 +00:27:17,404 --> 00:27:20,774 +就好了 + +443 +00:27:20,807 --> 00:27:24,344 +另一个例子 +传入 VM_ALLOCATE 作为类模式 + +444 +00:27:24,378 --> 00:27:27,281 +而不是地址 + +445 +00:27:27,314 --> 00:27:31,084 +来检查您游戏或 plugin 中的 +匿名 VM 使用 + +446 +00:27:31,118 --> 00:27:34,888 +如调试自定义分配器 + +447 +00:27:34,922 --> 00:27:37,958 +不管是使用 Xcode +或 malloc_history + +448 +00:27:37,991 --> 00:27:40,294 +您可以知道内存分配反向跟踪 + +449 +00:27:40,327 --> 00:27:43,030 +确定是否想要进一步研究 + +450 +00:27:43,063 --> 00:27:46,800 +包括首先在这行设置断点 + +451 +00:27:48,802 --> 00:27:55,475 +最后 它也可以帮助 +研究对象引用 + +452 +00:27:55,509 --> 00:27:58,846 +内存图总是记录对象引用 + +453 +00:27:58,879 --> 00:28:04,017 +甚至当 MallocStackLogging +由于多种原因未被启用时 + +454 +00:28:04,051 --> 00:28:08,689 +我们在前面使用 leaks +来在 Xcode 外抓取内存图 + +455 +00:28:08,722 --> 00:28:10,190 +leaks 能做的更多 + +456 +00:28:10,224 --> 00:28:12,993 +它检查内存图中所有引用 + +457 +00:28:13,026 --> 00:28:17,431 +所以它了解泄露和保留周期 + +458 +00:28:17,464 --> 00:28:20,634 +leaks 通过使用跟踪树状参数 +和堆中的对象地址 + +459 +00:28:20,667 --> 00:28:24,905 +来获取对象的引用树 + +460 +00:28:24,938 --> 00:28:28,909 +然而 这个例子中 +这是一个很大的树状结构 + +461 +00:28:28,942 --> 00:28:32,679 +从某种程度上说 有比在 Terminal 中 +更好的方式来查看 + +462 +00:28:34,281 --> 00:28:37,751 +通过 Xcode 14 我们重新设计了 +内存图视图 + +463 +00:28:37,784 --> 00:28:42,289 +展示选定对象的入边和出边 + +464 +00:28:43,357 --> 00:28:46,059 +甚至有新的邻居选择弹窗 + +465 +00:28:46,093 --> 00:28:49,396 +来选择您希望 Xcode 绘制的边缘 + +466 +00:28:49,429 --> 00:28:52,132 +在复杂游戏状态中 +尝试理解对象引用时 + +467 +00:28:52,165 --> 00:28:56,603 +会极大的提升效率 + +468 +00:28:58,105 --> 00:29:00,541 +在探索一圈后 + +469 +00:29:00,574 --> 00:29:05,345 +我很确定是纹理管理工具 +在访问这个对象 + +470 +00:29:05,379 --> 00:29:07,814 +对您的游戏来说 +考虑使用 leaks 工具 + +471 +00:29:07,848 --> 00:29:12,386 +和内存图视图来找到 +重要的对象引用关系 + +472 +00:29:12,419 --> 00:29:16,190 +来研究这些对象是如何 +在游戏中被访问的 + +473 +00:29:16,223 --> 00:29:18,992 +这就是如何使用 leaks 或者 Xcode + +474 +00:29:19,026 --> 00:29:22,729 +展示和找到对象的重要引用 + +475 +00:29:22,763 --> 00:29:24,565 +您可查看 leaks 的手册页面 + +476 +00:29:24,598 --> 00:29:28,268 +以及 Xcode 的帮助以获取更多 +关于这些工具的使用信息 + +477 +00:29:29,603 --> 00:29:32,039 +在这个内存图的分析菜谱中 + +478 +00:29:32,072 --> 00:29:35,375 +每步都使用了具体的工具 + +479 +00:29:35,409 --> 00:29:40,047 +它们共同完成内存图的分析 + +480 +00:29:41,548 --> 00:29:45,552 +总的来说 当您希望用 +内存图来抓取和分析内存时 + +481 +00:29:45,586 --> 00:29:50,991 +首先是 +要启用 MallocStackLogging + +482 +00:29:51,024 --> 00:29:54,595 +然后通过 Xcode +为你的游戏抓取内存图 + +483 +00:29:54,628 --> 00:29:58,765 +或给您的 Mac 游戏 +使用 leaks 工具 + +484 +00:29:58,799 --> 00:30:02,870 +接下来 找到尺寸大的惹麻烦的对象 + +485 +00:30:02,903 --> 00:30:07,474 +footprint vmmap 和 heap 工具 +提供从高层面到细节 + +486 +00:30:07,508 --> 00:30:11,111 +的内存分解 + +487 +00:30:11,144 --> 00:30:15,282 +使用 malloc_history +您可以查看对象是在哪里分配 + +488 +00:30:15,315 --> 00:30:19,820 +leaks 可分析对象使用或引用 + +489 +00:30:19,853 --> 00:30:22,756 +之前这些讲座包含了 +这些工具使用情况的 + +490 +00:30:22,789 --> 00:30:26,260 +深入指导和演示 + +491 +00:30:26,293 --> 00:30:30,063 +到目前为止 我们迟迟未开始 +Metal 资源的探索 + +492 +00:30:30,097 --> 00:30:32,533 +现在是时候了 + +493 +00:30:32,566 --> 00:30:35,769 +我们有请 Seth 为我们 +介绍详细内容 + +494 +00:30:35,802 --> 00:30:37,104 +Seth: 大家好 又见面了 + +495 +00:30:37,137 --> 00:30:40,807 +在游戏中 Metal 资源可以使用 +非常大的内存 + +496 +00:30:40,841 --> 00:30:43,310 +但是也是有办法优化 +它们的内存使用的 + +497 +00:30:44,411 --> 00:30:46,513 +这里 我总结了一个 +节省内存的清单 + +498 +00:30:46,547 --> 00:30:50,551 +让您可以优化游戏中 Metal 资源的使用 + +499 +00:30:50,584 --> 00:30:54,254 +我们看下 Metal Debugger +是如何帮助您审计资源 + +500 +00:30:54,288 --> 00:30:58,025 +并学习更多进一步减少游戏内存的 +高级技巧 + +501 +00:30:59,026 --> 00:31:03,230 +Metal Debugger 可一站式 +调试您的 Metal 游戏 + +502 +00:31:03,263 --> 00:31:05,365 +进行 GPU 帧抓取后 + +503 +00:31:05,399 --> 00:31:07,334 +您可以看到一个总结页面 + +504 +00:31:07,367 --> 00:31:10,604 +为您提供关于抓取工作负荷的 +概括数据 + +505 +00:31:12,172 --> 00:31:13,740 +在页面的后半部分 + +506 +00:31:13,774 --> 00:31:17,477 +有一个分为四个类别的 +insights 列表 + +507 +00:31:17,511 --> 00:31:22,115 +Memory 分类中的 Insights +为您游戏中的内存节约提出建议 + +508 +00:31:22,149 --> 00:31:25,752 +针对这一 trace 没有太多的 +内存 insights + +509 +00:31:25,786 --> 00:31:29,356 +访问这些 insights 后 +我们只能节省数兆字节的内存 + +510 +00:31:31,225 --> 00:31:35,095 +然而 您游戏可能有更多 +可节省内存的具体部分 + +511 +00:31:35,128 --> 00:31:38,265 +要获得 Metal 资源 +所使用内存的完整图像 + +512 +00:31:38,298 --> 00:31:41,435 +您可以点击 Show Memory 按钮 +使用 Memory Viewer + +513 +00:31:42,903 --> 00:31:47,441 +Memory Viewer 为您提供 +抓取自游戏的完整资源列表 + +514 +00:31:47,474 --> 00:31:50,844 +上半部分展示了可过滤的不同分类 + +515 +00:31:50,878 --> 00:31:54,681 +您可以用其来快速查看资源 +比方说纹理 + +516 +00:31:54,715 --> 00:31:58,785 +在下半部分中 +表格只展示了纹理 + +517 +00:31:58,819 --> 00:32:01,755 +我们先关掉过滤器 + +518 +00:32:01,788 --> 00:32:06,059 +资源表格有许多列 +来帮助您优化游戏 + +519 +00:32:06,093 --> 00:32:09,329 +我着重介绍可以帮助您快速识别 + +520 +00:32:09,363 --> 00:32:10,964 +一些有趣资源的几列 + +521 +00:32:13,100 --> 00:32:17,337 +Insights 列和我们在总结页面 +看到的类似 + +522 +00:32:17,371 --> 00:32:19,706 +当用该列排序表格时 您可以快速 + +523 +00:32:19,740 --> 00:32:23,343 +用 insights 查看所有资源 + +524 +00:32:23,377 --> 00:32:26,313 +点击 insight 图标 +可以展示弹窗 + +525 +00:32:26,346 --> 00:32:30,717 +解释所发现的内容 +提供一些可能的行动 + +526 +00:32:30,751 --> 00:32:34,288 +旁边列是 Allocated Size + +527 +00:32:34,321 --> 00:32:37,991 +您可以按该列来排序 +查看最大的资源是哪个 + +528 +00:32:38,025 --> 00:32:41,361 +这对于审计有些资源 +是否确实充分利用了它们的内存大小 + +529 +00:32:41,395 --> 00:32:43,397 +可能会有用 + +530 +00:32:43,430 --> 00:32:47,601 +例如 有些纹理可能可以重新调整为 +小一点的分辨率 + +531 +00:32:47,634 --> 00:32:51,305 +有些在缓冲区中加载的模型 +可能可以使用较低的多边形计数 + +532 +00:32:51,338 --> 00:32:55,242 +只要这样做并不会影响 +游戏的视觉品质 + +533 +00:32:55,275 --> 00:32:57,377 +有一些替代方法可以节省 +纹理内存 + +534 +00:32:57,411 --> 00:32:59,680 +我稍后会再提到 + +535 +00:32:59,713 --> 00:33:03,050 +这还有另一个有趣的列 +是 Time Since Last Bound + +536 +00:33:03,083 --> 00:33:08,222 +您可以通过该列来筛选资源 +来查看有哪些是近期没有使用的 + +537 +00:33:08,255 --> 00:33:09,857 +如果资源没有使用过 + +538 +00:33:09,890 --> 00:33:14,428 +最好可以再次检查 +看资产是否值得加载 + +539 +00:33:14,461 --> 00:33:16,763 +有一段时间没有绑定的资源 + +540 +00:33:16,797 --> 00:33:20,734 +且未来不会再使用 +您可能要考虑将其释放 + +541 +00:33:20,767 --> 00:33:24,972 +或者您可以将其可清除状态 +设置为 volatile + +542 +00:33:25,005 --> 00:33:28,475 +Metal 资源可能处于 +以下三种可清除状态之一 + +543 +00:33:28,509 --> 00:33:32,346 +non-volatile volatile 和 empty + +544 +00:33:32,379 --> 00:33:35,949 +在默认设置下 资源是 non-volatile 的 + +545 +00:33:35,983 --> 00:33:37,918 +通过将可清除状态 +设置为 volatile + +546 +00:33:37,951 --> 00:33:39,887 +Metal 可从内存中清理该资源 + +547 +00:33:39,920 --> 00:33:42,656 +应对系统内存压力过高的情况 + +548 +00:33:42,689 --> 00:33:45,325 +一旦资源为空 系统不再需要将其 + +549 +00:33:45,359 --> 00:33:47,995 +计入游戏内存足迹 + +550 +00:33:48,028 --> 00:33:49,663 +当您的游戏再次需要该资源时 + +551 +00:33:49,696 --> 00:33:53,367 +检查内容是否还在该位置 +在需要的时候重新加载 + +552 +00:33:53,400 --> 00:33:56,870 +对于频繁使用的资源 +只考虑使用 volatile + +553 +00:33:56,904 --> 00:33:59,339 +这样可清除状态不会对您不利 + +554 +00:34:01,375 --> 00:34:05,012 +所以这些是针对所有资源的 +通用事项 + +555 +00:34:05,045 --> 00:34:08,015 +现在 我们来详细看看纹理 + +556 +00:34:08,949 --> 00:34:12,219 +Memory Viewer 并不是 +默认显示所有列 + +557 +00:34:12,252 --> 00:34:15,289 +右击表头可选择显示和隐藏列 + +558 +00:34:15,322 --> 00:34:18,158 +如纹理的 Pixel Format + +559 +00:34:18,192 --> 00:34:23,163 +您可以通过优化纹理的像素格式 +获得不同的节省量 + +560 +00:34:23,197 --> 00:34:27,000 +游戏中的许多纹理 +会使用 16 位半像素精度格式 + +561 +00:34:27,034 --> 00:34:29,837 +来减少内存使用和带宽 + +562 +00:34:29,870 --> 00:34:32,940 +在您需要 +单一 alpha 通道的纹理时 + +563 +00:34:32,973 --> 00:34:35,642 +您可以避免多个色彩通道 + +564 +00:34:35,676 --> 00:34:39,146 +最后 一些只读纹理 +可能会得益于块压缩 + +565 +00:34:39,179 --> 00:34:41,615 +来降低内存占用 + +566 +00:34:41,648 --> 00:34:43,717 +对于块压缩像素格式来说 + +567 +00:34:43,750 --> 00:34:46,687 +有如 ASTC 和 BC 的选项 + +568 +00:34:46,720 --> 00:34:49,122 +此外 自 A15 仿生开始 + +569 +00:34:49,156 --> 00:34:51,892 +您可以对纹理和渲染目标 +使用有损压缩 + +570 +00:34:51,925 --> 00:34:55,562 +在尽可能保持画质的同时 +节省内存 + +571 +00:34:55,596 --> 00:34:58,432 +请查看之前的视频 +以获取更多信息 + +572 +00:35:00,634 --> 00:35:03,203 +以上是您使用 Memory Viewer +可快速发现 + +573 +00:35:03,237 --> 00:35:05,172 +一些内存节省的方法 + +574 +00:35:05,205 --> 00:35:07,341 +但您还可以使用一些其它技术 + +575 +00:35:07,374 --> 00:35:09,977 +来进一步优化您的游戏 + +576 +00:35:10,010 --> 00:35:12,546 +如果只有单一通道使用纹理 + +577 +00:35:12,579 --> 00:35:14,648 +您可以将其存储模式 +设置为 memoryless + +578 +00:35:14,681 --> 00:35:16,783 +从而节省内存和带宽 + +579 +00:35:16,817 --> 00:35:19,620 +memoryless 纹理 +非常适合临时渲染目标 + +580 +00:35:19,653 --> 00:35:23,156 +如深度 stencil 或多样本纹理 + +581 +00:35:23,190 --> 00:35:26,293 +另外 如果只有 GPU 使用纹理 + +582 +00:35:26,326 --> 00:35:28,061 +您可以将其存储模式设置为私有 + +583 +00:35:28,095 --> 00:35:31,131 +而不是共享或托管 + +584 +00:35:31,164 --> 00:35:34,601 +提醒下 Apple 芯片 Mac 中 +是不需要托管模式的 + +585 +00:35:34,635 --> 00:35:37,371 +正如在 iPhone 和 iPad 中一样 + +586 +00:35:37,404 --> 00:35:39,473 +以下是示例 + +587 +00:35:39,506 --> 00:35:42,876 +游戏用的是 +Depth32Float_Stencil8 纹理 + +588 +00:35:42,910 --> 00:35:46,079 +深度纹理会跨通道使用 + +589 +00:35:46,113 --> 00:35:48,215 +但 Stencil 纹理内容会被丢弃 + +590 +00:35:48,248 --> 00:35:51,318 +后续在帧中也不会使用 + +591 +00:35:51,351 --> 00:35:54,154 +所以 游戏可以使用两张纹理 + +592 +00:35:54,188 --> 00:35:57,925 +将 Stencil 纹理设置为 memoryless +从而节省内存和带宽 + +593 +00:35:59,359 --> 00:36:02,930 +最后 我要说下另一个充分利用 +您游戏内存的技术 + +594 +00:36:02,963 --> 00:36:05,432 +您可能会感兴趣 + +595 +00:36:05,465 --> 00:36:07,901 +您可以使用堆中的别名资源 + +596 +00:36:07,935 --> 00:36:09,937 +如果您游戏没有 +同时使用它们的话 + +597 +00:36:09,970 --> 00:36:12,973 +它们可以共享在同一内存分配 +支持下的内存 + +598 +00:36:13,006 --> 00:36:17,411 +但是在同步这些资源的访问时 +要格外小心 + +599 +00:36:17,444 --> 00:36:19,780 +您可以查看 +“利用 Metal 3 实现无绑定” 的讲座 + +600 +00:36:19,813 --> 00:36:23,317 +以了解更多关于使用 +堆分配资源的信息 + +601 +00:36:23,350 --> 00:36:26,820 +我们可以总结下节省内存的 +检查清单 + +602 +00:36:26,854 --> 00:36:30,190 +我希望这个清单能帮助您 +审计游戏中的 Metal 资源 + +603 +00:36:31,725 --> 00:36:33,861 +请查看其它 WWDC 讲座 +以了解更多关于 + +604 +00:36:33,894 --> 00:36:38,031 +使用 Metal Debugger +来优化您游戏内存的内容 + +605 +00:36:38,065 --> 00:36:39,499 +再次有请 Jack + +606 +00:36:41,235 --> 00:36:42,503 +Jack: 谢谢 Seth + +607 +00:36:42,536 --> 00:36:46,340 +在今天的旅程中 +我们探索了许多有趣的东西 + +608 +00:36:46,373 --> 00:36:50,177 +让大家可以理解和改进 +游戏的内存使用 + +609 +00:36:50,210 --> 00:36:53,981 +首先 内存足迹是理解 + +610 +00:36:54,014 --> 00:36:56,650 +游戏内存使用的首要指标 + +611 +00:36:56,683 --> 00:37:01,722 +它包括 dirty 和 compressed +和交换内存 + +612 +00:37:01,755 --> 00:37:05,859 +然后 我们体验了强大的 +内存调试工具 + +613 +00:37:05,893 --> 00:37:09,496 +Seth 给我们展示了 +Instruments 如何用有用的 + +614 +00:37:09,530 --> 00:37:11,865 +测量跟踪来助力内存分析 + +615 +00:37:11,899 --> 00:37:16,537 +全新的 Game Memory 模板 +是为这一工作量身定制的 + +616 +00:37:16,570 --> 00:37:22,442 +随后 我展示了用内存图 +来存储游戏内存状态的快照 + +617 +00:37:22,476 --> 00:37:25,712 +有灵活 强大的命令行程序 + +618 +00:37:25,746 --> 00:37:28,315 +来分析内存图中的对象 + +619 +00:37:28,348 --> 00:37:31,652 +引用和分配历史 + +620 +00:37:31,685 --> 00:37:35,822 +heap 工具的改进 +和 Xcode Memory Debugger 的重新设计 + +621 +00:37:35,856 --> 00:37:38,825 +将会强化游戏内存分析 + +622 +00:37:38,859 --> 00:37:42,329 +最后 Seth 与我们共享了 +Metal 资源的 + +623 +00:37:42,362 --> 00:37:44,231 +内存节省检查清单 + +624 +00:37:44,264 --> 00:37:47,334 +以及 Metal Debugger 可以如何 + +625 +00:37:47,367 --> 00:37:51,138 +回答您游戏中关于 Metal +资源使用的问题 + +626 +00:37:51,171 --> 00:37:54,575 +您可以查看其它 +WWDC 讲座 + +627 +00:37:54,608 --> 00:37:57,444 +文件和手册页面以了解更多内容 + +628 +00:37:58,445 --> 00:38:02,349 +我们持续致力于为大家开发 +最灵活的工具 + +629 +00:38:02,382 --> 00:38:04,318 +所以何不尽情一试呢 + +630 +00:38:04,351 --> 00:38:06,720 +它们可能正好就是您需要的 + +631 +00:38:07,955 --> 00:38:11,525 +有任何反馈请随时 + +632 +00:38:11,558 --> 00:38:15,162 +通过多种渠道与我们分享 +如 Feedback Assistant + +633 +00:38:15,195 --> 00:38:17,064 +祝大家有一个愉快的内存 +探索旅程 + +634 +00:38:17,097 --> 00:38:18,465 +感谢大家的观看 + diff --git a/zho/2022 Session 10107 Get it right (to left).srt b/zho/2022 Session 10107 Get it right (to left).srt new file mode 100644 index 0000000..5b31164 --- /dev/null +++ b/zho/2022 Session 10107 Get it right (to left).srt @@ -0,0 +1,2823 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,776 --> 00:00:13,013 +Rich Gillam: 大家好 我是Rich +今天我将帮助大家解决从右到左的 + +3 +00:00:13,046 --> 00:00:14,648 +问题 + +4 +00:00:14,681 --> 00:00:18,418 +您已经将 App 本地化为一系列语言 + +5 +00:00:18,452 --> 00:00:20,521 +包括最常见的欧洲语言 + +6 +00:00:20,554 --> 00:00:22,422 +和最常见的亚洲语言 + +7 +00:00:22,456 --> 00:00:25,225 +所以现在您想将其它本地化为 +阿拉伯语和希伯来语 + +8 +00:00:25,259 --> 00:00:26,793 +会是个不错的选择 + +9 +00:00:26,827 --> 00:00:30,797 +阿拉伯语是我们平台上最常用的 +十种语言之一 + +10 +00:00:30,831 --> 00:00:33,367 +但是它也带来了一些挑战 + +11 +00:00:33,400 --> 00:00:35,569 +这些挑战是您在 +开发其他语言时不会遇到的 + +12 +00:00:35,602 --> 00:00:38,939 +这就是这次演讲的内容 +如何开发您的 App + +13 +00:00:38,972 --> 00:00:44,278 +使其可以本地化为阿拉伯语 +和希伯来语等语言 + +14 +00:00:44,311 --> 00:00:46,980 +阿拉伯语和希伯来语通常被称为 + +15 +00:00:47,014 --> 00:00:49,583 +“从右到左的语言” +“right to left languages.” + +16 +00:00:49,616 --> 00:00:51,285 +为什么叫这个 + +17 +00:00:51,318 --> 00:00:55,589 +英语 法语 中文 泰语 +和许多其他语言的文字 + +18 +00:00:55,622 --> 00:01:00,060 +都是像这样从左到右排列的 + +19 +00:01:00,093 --> 00:01:04,765 +而在希伯来语中 +字符则是像这样从右向左排列的 + +20 +00:01:04,798 --> 00:01:07,067 +阿拉伯语也是一样 + +21 +00:01:07,100 --> 00:01:10,737 +在阿拉伯语中 +字符是粗略地连接在一起的 + +22 +00:01:10,771 --> 00:01:14,808 +“salaam” 中的四个字母 +分开写时是这样的 + +23 +00:01:15,976 --> 00:01:18,846 +顺便说一下 不仅仅是 +阿拉伯语和希伯来语这样排列 + +24 +00:01:18,879 --> 00:01:21,348 +Apple 实际上支持15种 + +25 +00:01:21,381 --> 00:01:24,785 +从右向左的语言的字体和键盘 + +26 +00:01:24,818 --> 00:01:26,887 +这里有一段希伯来文 + +27 +00:01:26,920 --> 00:01:28,488 +这是希伯来文版的 + +28 +00:01:28,522 --> 00:01:32,125 +“Formulas & Functions Help”页面中的 + +29 +00:01:32,159 --> 00:01:35,762 +请注意 这段文本在右边对齐 +在左边参差不齐 + +30 +00:01:35,796 --> 00:01:38,432 +而且许多行 包括最后一行 + +31 +00:01:38,465 --> 00:01:41,168 +在左边都有标点符号 + +32 +00:01:41,201 --> 00:01:43,403 +这一段中还有一个数字 + +33 +00:01:43,437 --> 00:01:45,839 +数字仍然是从左到右排列 + +34 +00:01:45,873 --> 00:01:50,844 +这表明 Numbers 支持超 250 个函数 + +35 +00:01:50,878 --> 00:01:53,881 +如果我们放大视图 +把另一个段落囊括进来 + +36 +00:01:53,914 --> 00:01:56,583 +我们会看到这一段有一些英语单词 + +37 +00:01:56,617 --> 00:01:59,386 +iWork 名称及其组成 App + +38 +00:01:59,419 --> 00:02:01,688 +Pages Numbers 和 Keynote + +39 +00:02:01,722 --> 00:02:03,790 +这些也是从左到右写入的 + +40 +00:02:03,824 --> 00:02:05,659 +甚至在希伯来语段落中也是如此 + +41 +00:02:05,692 --> 00:02:09,329 +因此 对于许多段落来说 +文本是双向的 + +42 +00:02:09,363 --> 00:02:12,165 +这是阿拉伯语和希伯来语的固有属性 + +43 +00:02:12,199 --> 00:02:16,603 +也是为什么它们经常被称为 +“bidi” 语言的原因 + +44 +00:02:17,804 --> 00:02:19,740 +如果我们进一步扩大视图 + +45 +00:02:19,773 --> 00:02:22,709 +会看到整个页面是从右向左布局的 + +46 +00:02:22,743 --> 00:02:25,479 +这里有一个表格 文本在图像的右侧 + +47 +00:02:25,512 --> 00:02:28,048 +而不是左侧 + +48 +00:02:29,183 --> 00:02:32,719 +如果我们进一步放大视图 +会看到 Safari 浏览器的窗口框架 + +49 +00:02:32,753 --> 00:02:35,389 +发现它并没有随着内容而停止 + +50 +00:02:35,422 --> 00:02:39,593 +阿拉伯语和希伯来语文本行 +从右侧开始 向左侧推进 + +51 +00:02:39,626 --> 00:02:43,363 +因此很自然地会期望其他 +UI 元素也这样做 + +52 +00:02:43,397 --> 00:02:47,501 +正如读者希望文本从左边开始 +向右边推进一样 + +53 +00:02:47,534 --> 00:02:50,637 +阿拉伯语和希伯来语的读者 +希望的恰恰相反 + +54 +00:02:50,671 --> 00:02:54,074 +在这里 Safari 浏览器的工具栏 +从右到左运行 + +55 +00:02:54,107 --> 00:02:56,844 +红绿灯按钮在右上角 + +56 +00:02:56,877 --> 00:02:59,379 +按钮向左移动 + +57 +00:03:00,247 --> 00:03:03,483 +如果我们将焦点扩大到整个屏幕 + +58 +00:03:03,517 --> 00:03:05,686 +会发现所有文本都是这样的 + +59 +00:03:05,719 --> 00:03:08,355 +这是 Numbers 的帮助屏幕 +我们看到 + +60 +00:03:08,388 --> 00:03:10,824 +Numbers 的所有元素也改变了方向 + +61 +00:03:10,858 --> 00:03:12,526 +侧边栏在左边 + +62 +00:03:12,559 --> 00:03:16,763 +标签栏从右向左延伸 +甚至文档本身也改变了方向 + +63 +00:03:16,797 --> 00:03:21,802 +Mac 菜单栏和程序坞 +也是从右向左运行的 + +64 +00:03:21,835 --> 00:03:24,471 +做好这一切可能会很复杂 + +65 +00:03:24,505 --> 00:03:27,708 +但好消息是 +我们为您完成了大部分繁重的工作 + +66 +00:03:27,741 --> 00:03:30,344 +大多数对从右到左的支持都是免费的 + +67 +00:03:30,377 --> 00:03:32,646 +但有些事情需要记住 + +68 +00:03:32,679 --> 00:03:36,083 +这就是我们将要讨论的内容 +系统为您做了什么 + +69 +00:03:36,116 --> 00:03:37,985 +您何时需要选择加入或退出 + +70 +00:03:38,018 --> 00:03:41,188 +以及在实现您自己的设备 +从右到左支持时应该考虑什么 + +71 +00:03:41,221 --> 00:03:47,227 +我们将讨论文本 图像 +控件方向和 UI 布局 + +72 +00:03:47,261 --> 00:03:50,697 +我们还将介绍如何用 +阿拉伯语显示数字 + +73 +00:03:50,731 --> 00:03:54,134 +最后 我们将谈一谈如何测试 + +74 +00:03:54,168 --> 00:03:57,604 +您的 App 是否能正确地从右向左操作 + +75 +00:03:57,638 --> 00:03:59,239 +让我们开始吧 + +76 +00:03:59,273 --> 00:04:01,975 +首先 我们将更多地讨论 +文本的工作原理 + +77 +00:04:02,009 --> 00:04:04,878 +并介绍一些术语 + +78 +00:04:04,912 --> 00:04:07,781 +我们先说说写入方向的概念 + +79 +00:04:07,814 --> 00:04:13,120 +正如我们看到的 +英语是从左到右写入的 + +80 +00:04:13,153 --> 00:04:16,723 +希伯来语是从右到左写入的 + +81 +00:04:16,757 --> 00:04:19,393 +但如果我们把它们混在一起会怎么样 + +82 +00:04:21,161 --> 00:04:24,264 +如果您要写这样一句多语种的句子 + +83 +00:04:24,298 --> 00:04:27,801 +每个单独的成分仍然保持 +它们的写入方向 + +84 +00:04:27,835 --> 00:04:30,704 +但这意味着每个句子将由 + +85 +00:04:30,737 --> 00:04:32,439 +三个成分组成 + +86 +00:04:32,472 --> 00:04:35,409 +两个独立的母语文本片段 + +87 +00:04:35,442 --> 00:04:38,545 +中间夹着一个不同语言的文本片段 + +88 +00:04:38,579 --> 00:04:41,281 +当我们讨论一个段落的写入方向时 + +89 +00:04:41,315 --> 00:04:44,852 +我们讨论的是这些片段的顺序 + +90 +00:04:44,885 --> 00:04:48,155 +当我们说英语句子是 +从左到右的写入方向时 + +91 +00:04:48,188 --> 00:04:51,592 +是因为这三个方框从左到右排列 + +92 +00:04:51,625 --> 00:04:55,162 +当我们说希伯来语句子是 +从右到左的写入方向时 + +93 +00:04:55,195 --> 00:04:58,899 +是因为这三个方框从右到左排列 + +94 +00:05:00,200 --> 00:05:03,504 +另一个不同但相关的概念是文本对齐 + +95 +00:05:03,537 --> 00:05:05,639 +如果您阅读的是从左到右的语言 + +96 +00:05:05,672 --> 00:05:09,743 +您的眼睛会转向页面的左边 +然后向右移动 + +97 +00:05:09,776 --> 00:05:13,247 +如果您阅读的是从右到左的语言 +情况正好相反 + +98 +00:05:13,280 --> 00:05:18,051 +因此 文本在从右到左的语言中 +靠右对齐 + +99 +00:05:18,085 --> 00:05:20,521 +好消息是 大多数时候 + +100 +00:05:20,554 --> 00:05:23,023 +您不必担心这些事情 + +101 +00:05:23,056 --> 00:05:25,893 +CoreText 不仅负责在 +一行或一段文本中 + +102 +00:05:25,926 --> 00:05:29,530 +正确地安排所有字符 + +103 +00:05:29,563 --> 00:05:33,534 +包括不同方向的文本混合在一行中时 + +104 +00:05:33,567 --> 00:05:37,137 +而且我们所有的 UI 框架也自动 +设置写入方向 + +105 +00:05:37,171 --> 00:05:38,906 +和对齐方式 + +106 +00:05:38,939 --> 00:05:42,809 +所有 UI 小组件都默认为 +“自然写入方向” + +107 +00:05:42,843 --> 00:05:44,578 +和“自然对齐” + +108 +00:05:44,611 --> 00:05:47,314 +文本小组件的默认写入方向 + +109 +00:05:47,347 --> 00:05:50,551 +与用户 UI 语言的 +正常写入方向相匹配 + +110 +00:05:50,584 --> 00:05:53,520 +也就是说 +如果 UI 是希伯来语或阿拉伯语 + +111 +00:05:53,554 --> 00:05:57,691 +则文本小组件的写入方向 +默认为从右向左 + +112 +00:05:57,724 --> 00:06:00,794 +自然对齐遵循写入方向 + +113 +00:06:00,827 --> 00:06:04,498 +也就是说 如果文本小组件的 +写入方向是从右到左 + +114 +00:06:04,531 --> 00:06:07,134 +它也将右对齐 + +115 +00:06:07,167 --> 00:06:11,205 +大多数情况下 这就是您需要的 +但您可以重写默认值 + +116 +00:06:11,238 --> 00:06:15,576 +我们将在控件方向一节中 +更多地讨论这一点 + +117 +00:06:15,609 --> 00:06:19,713 +现在是时候开始画一个术语图表了 + +118 +00:06:19,746 --> 00:06:22,683 +我们这里说的是 自然对齐 +在从左到右的语言中 + +119 +00:06:22,716 --> 00:06:25,285 +对应于左对齐 +在从右到左的语言中 + +120 +00:06:25,319 --> 00:06:28,322 +对应于右对齐 + +121 +00:06:28,355 --> 00:06:30,858 +我们会在这个图表中添加 + +122 +00:06:30,891 --> 00:06:33,961 +但当然 您要担心的不仅仅是文本 + +123 +00:06:33,994 --> 00:06:36,463 +以相反的方向阅读文本会对 +您的 App 中 + +124 +00:06:36,496 --> 00:06:40,100 +除文本之外的元素产生深远的影响 + +125 +00:06:40,133 --> 00:06:44,638 +我们来谈谈它是如何 +影响图标和其他图形元素的 + +126 +00:06:45,506 --> 00:06:49,276 +这是英语和阿拉伯语的 +Pages 工具栏 + +127 +00:06:49,309 --> 00:06:52,679 +我们仔细看看工具栏中的一些图标 + +128 +00:06:52,713 --> 00:06:55,616 +许多按钮 +在两种语言中看起来是一样的 + +129 +00:06:55,649 --> 00:06:57,818 +如“添加页面”和“媒体”按钮 + +130 +00:06:57,851 --> 00:07:02,189 +这要么是因为它们是对称的 +要么是因为它们的方向性 + +131 +00:07:02,222 --> 00:07:05,425 +与语言无关 +它们在两种语言中都毫无违和感 + +132 +00:07:05,459 --> 00:07:08,629 +其他按钮 如“视图”和“文档”按钮 + +133 +00:07:08,662 --> 00:07:11,231 +可以切换到阿拉伯语的映射 + +134 +00:07:11,265 --> 00:07:14,168 +“视图”按钮会弹出 +Pages 侧边栏 + +135 +00:07:14,201 --> 00:07:17,104 +它出现在窗口的另一侧 +以阿拉伯语显示 + +136 +00:07:17,137 --> 00:07:19,973 +因此图标必须改变以反映这一点 + +137 +00:07:20,007 --> 00:07:24,044 +“文档”按钮会发生变化 +如果用户用阿拉伯语写入 + +138 +00:07:24,077 --> 00:07:27,080 +页面会转向相反的方向 + +139 +00:07:27,114 --> 00:07:30,951 +您可能会遇到图标完全改变的情况 + +140 +00:07:30,984 --> 00:07:34,821 +“插入文本框”按钮上的字母 +更改为不同的字母 + +141 +00:07:34,855 --> 00:07:36,990 +以反映用户的语言 + +142 +00:07:38,091 --> 00:07:42,129 +同样 好消息是 +我们已经为您解决了很多类似问题 + +143 +00:07:42,162 --> 00:07:45,732 +您必须考虑图像方向 +而不是一般的 + +144 +00:07:45,766 --> 00:07:50,337 +文字写入方向 +但要完成这个任务很简单 + +145 +00:07:50,370 --> 00:07:54,241 +这是英语和阿拉伯语的 +Mac Pages 中的 View 菜单 + +146 +00:07:54,274 --> 00:07:57,477 +请注意 “Show Ruler”图标会反转 + +147 +00:07:57,511 --> 00:07:59,179 +在从右向左的语言中 + +148 +00:07:59,213 --> 00:08:02,482 +垂直标尺在右手边 + +149 +00:08:02,516 --> 00:08:04,952 +对于像标尺图标这样的自定义图像 + +150 +00:08:04,985 --> 00:08:08,655 +从右到左的操作是在 +Xcode 图像集编辑器中控制的 + +151 +00:08:08,689 --> 00:08:11,558 +如果您的图像从左到右 +和从右到左是相同的 + +152 +00:08:11,592 --> 00:08:13,560 +那么您不需要做任何特别的操作 + +153 +00:08:13,594 --> 00:08:17,464 +当您的 App 运行在与开发语言相反的 + +154 +00:08:17,497 --> 00:08:20,501 +语言中时 系统还可以通过算法 + +155 +00:08:20,534 --> 00:08:22,336 +来映射您的图像 + +156 +00:08:22,369 --> 00:08:25,539 +您可以在 Xcode 的 +图像集编辑器中请求此功能 + +157 +00:08:25,572 --> 00:08:29,009 +在侧边栏中 您会找到一个 +标记为“Direction”的控件 + +158 +00:08:29,042 --> 00:08:32,246 +如果点击此控件 +您会看到一个有四个选项的菜单 + +159 +00:08:32,279 --> 00:08:36,717 +如果不管使用何种 UI 语言 +图像都是相同的 则选择“Fixed” + +160 +00:08:36,750 --> 00:08:38,785 +如果需要算法映射 + +161 +00:08:38,819 --> 00:08:41,655 +可选择其中一个“Mirrors”选项 + +162 +00:08:41,688 --> 00:08:45,559 +这取决于开发语言的编写方向 + +163 +00:08:45,592 --> 00:08:48,495 +如果图片无法通过算法进行映射 + +164 +00:08:48,529 --> 00:08:51,064 +或者图片有多个元素 +在 UI 改变方向时 + +165 +00:08:51,098 --> 00:08:52,799 +表现方式不同 + +166 +00:08:52,833 --> 00:08:56,436 +又或者您有不想移动的着色 +可选择“Both" + +167 +00:08:56,470 --> 00:08:59,606 +并将三个新的孔添加到 +图像集编辑器中 + +168 +00:08:59,640 --> 00:09:02,009 +使您可以创建单独的图像 + +169 +00:09:02,042 --> 00:09:05,479 +用于从左到右和从右到左的背景中 + +170 +00:09:06,346 --> 00:09:10,450 +但如果您用来自 SF Symbol 的图像 +就像 Pages 工具栏那样 + +171 +00:09:10,484 --> 00:09:12,085 +事情就更简单了 + +172 +00:09:12,119 --> 00:09:14,688 +几乎所有的工作都已为您完成了 + +173 +00:09:14,721 --> 00:09:16,290 +从右到左的语言需要 + +174 +00:09:16,323 --> 00:09:19,326 +更改的符号会自动更改 + +175 +00:09:19,359 --> 00:09:22,462 +以这个项目符号列表图标为例 + +176 +00:09:22,496 --> 00:09:25,299 +对于许多图像 SF Symbol 的侧边栏 + +177 +00:09:25,332 --> 00:09:28,569 +有一个“本地化”部分 +显示所选图像的 + +178 +00:09:28,602 --> 00:09:30,204 +本地化版本 + +179 +00:09:30,237 --> 00:09:32,639 +在这种情况下 项目符号列表图标 + +180 +00:09:32,673 --> 00:09:35,042 +具有不同的从左到右和从右到左版本 + +181 +00:09:35,075 --> 00:09:37,077 +它会自动映射 + +182 +00:09:38,078 --> 00:09:41,081 +本地化功能不仅仅是 + +183 +00:09:41,114 --> 00:09:42,616 +从右向左语言的映射 + +184 +00:09:42,649 --> 00:09:46,253 +这是“插入文本框”图标的本地化标签 + +185 +00:09:46,286 --> 00:09:50,157 +它不仅有拉丁和阿拉伯文字的 +本地化版本 + +186 +00:09:50,190 --> 00:09:52,659 +还有其他语种的版本 + +187 +00:09:53,861 --> 00:09:58,065 +对于阿拉伯语支持来说 +一个特别重要的例子就是问号 + +188 +00:09:58,098 --> 00:10:00,501 +它经常被用作“帮助”图标 + +189 +00:10:00,534 --> 00:10:02,936 +在阿拉伯语中 +问号与拉丁语的问号 + +190 +00:10:02,970 --> 00:10:04,538 +是相反的 + +191 +00:10:04,571 --> 00:10:07,708 +使用 SF Symbol 中的图标 +作为帮助图标 + +192 +00:10:07,741 --> 00:10:10,944 +无需任何额外工作即可获得此版本 + +193 +00:10:11,845 --> 00:10:14,648 +您必须仔细考虑的一类图像是 + +194 +00:10:14,681 --> 00:10:17,651 +箭头和其他方向指示器 + +195 +00:10:17,684 --> 00:10:20,621 +这里我们看到了 +四个圆圈中的箭头图标 + +196 +00:10:20,654 --> 00:10:22,422 +您会发现它们是两对 + +197 +00:10:22,456 --> 00:10:25,826 +有两个指向左边 两个指向右边 + +198 +00:10:25,859 --> 00:10:28,495 +如果我们只看指向左边的两个 + +199 +00:10:28,529 --> 00:10:31,965 +您会看到其中一个叫做 +“arrow.backward.circle.” + +200 +00:10:31,999 --> 00:10:35,402 +这个图表从右向左翻转指向右侧 + +201 +00:10:35,435 --> 00:10:38,672 +另一个叫做 “arrow.left..circle” + +202 +00:10:38,705 --> 00:10:41,008 +而且不是从右向左翻转 + +203 +00:10:41,041 --> 00:10:44,511 +SF Symbol 遵循这个命名惯例 + +204 +00:10:44,545 --> 00:10:48,282 +您可能想要也可能不想要 +从右到左的图标 + +205 +00:10:48,315 --> 00:10:52,586 +“向前”和“向后”的键会翻转 +而“左”和“右”的键不会 + +206 +00:10:52,619 --> 00:10:54,755 +如果使用箭头或其他形状 + +207 +00:10:54,788 --> 00:10:57,024 +传达“向前”或“向后”的概念 + +208 +00:10:57,057 --> 00:10:59,193 +则需要使用翻转版本 + +209 +00:10:59,226 --> 00:11:02,262 +如果使用箭头来传达绝对方向 + +210 +00:11:02,296 --> 00:11:04,932 +则需要使用非翻转版本 + +211 +00:11:06,333 --> 00:11:08,936 +让我们在术语表上加一行 + +212 +00:11:08,969 --> 00:11:12,606 +在 SF Symbol 中选择图像时 +请记住“左”和“右” + +213 +00:11:12,639 --> 00:11:15,843 +总是指向这些方向 +而“向前”和“向后” + +214 +00:11:15,876 --> 00:11:19,513 +则根据 UI 语言的不同 +指向不同的方向 + +215 +00:11:19,546 --> 00:11:23,016 +现在让我们讨论一下控件 +和其他 UI 小组件 + +216 +00:11:23,050 --> 00:11:25,419 +是如何从右到左处理的 + +217 +00:11:25,452 --> 00:11:28,822 +这是英语和阿拉伯语的 +Mac Keynote 侧边栏 + +218 +00:11:28,856 --> 00:11:31,725 +显示形状的格式检查器 + +219 +00:11:31,758 --> 00:11:35,195 +请注意 所有对象的 Appearance +都从右向左翻转 + +220 +00:11:35,229 --> 00:11:38,665 +我们有很多弹出式菜单按钮 + +221 +00:11:38,699 --> 00:11:41,301 +菜单指示器从右向左移动到左侧 + +222 +00:11:41,335 --> 00:11:43,437 +我们有几个复选框 在阿拉伯语中 + +223 +00:11:43,470 --> 00:11:45,706 +复选框位于标签的右侧 + +224 +00:11:45,739 --> 00:11:48,375 +阿拉伯语的不透明度滑块已更改 + +225 +00:11:48,408 --> 00:11:52,179 +因此最小值在右侧 最大值在左侧 + +226 +00:11:52,212 --> 00:11:56,216 +在此检查器中的所有 +其他控件中依此类推 + +227 +00:11:56,250 --> 00:11:59,186 +好消息是这些操作都是免费的 + +228 +00:11:59,219 --> 00:12:02,923 +我们所有 UI 框架中的 +所有标准 UI 控件 + +229 +00:12:02,956 --> 00:12:06,393 +都会自动将它们的外观 +转换为从右到左的语言 + +230 +00:12:06,426 --> 00:12:09,696 +然而 在某些情况下 +您可能不希望发生这种情况 + +231 +00:12:09,730 --> 00:12:12,900 +或者您需要对发生的方式 +有一定的控制 + +232 +00:12:12,933 --> 00:12:15,969 +让我们看几个有趣的例子 + +233 +00:12:16,703 --> 00:12:21,008 +我们来讨论一下上面 +既有文本标签又有图标的按钮 + +234 +00:12:21,041 --> 00:12:24,511 +这是显示“ Move In”动画的 + +235 +00:12:24,545 --> 00:12:26,480 +Keynote 讲演动画检查器 + +236 +00:12:26,513 --> 00:12:30,384 +这个检查器有两个按钮 +既有标签又有图标 + +237 +00:12:30,417 --> 00:12:32,953 +请注意 预览按钮上的箭头 + +238 +00:12:32,986 --> 00:12:34,655 +随着 UI 方向的更改而翻转 + +239 +00:12:34,688 --> 00:12:38,158 +但动画方向菜单上的箭头不会 + +240 +00:12:38,192 --> 00:12:40,794 +这两者都与 UI 方向相反 + +241 +00:12:40,827 --> 00:12:44,398 +但如果方向控件 +是一组按钮而不是菜单 + +242 +00:12:44,431 --> 00:12:47,634 +您可能不希望它改变方向 + +243 +00:12:48,802 --> 00:12:52,039 +为了展示如何控制这个控件 +我将这两个示例分离到 + +244 +00:12:52,072 --> 00:12:54,608 +一个小型玩具 App 中 + +245 +00:12:55,709 --> 00:12:58,979 +下面是在 SwiftUI 中构建该 UI 的代码 + +246 +00:12:59,012 --> 00:13:01,081 +这里有一些有趣的事情需要注意 + +247 +00:13:01,114 --> 00:13:02,749 +我们逐一查看它们 + +248 +00:13:02,783 --> 00:13:06,220 +我们先从图像名称开始 + +249 +00:13:06,253 --> 00:13:08,922 +正如我们之前看到的 +对于 SF Symbol 的图像 + +250 +00:13:08,956 --> 00:13:12,459 +您可以选择一个翻转的图标 +或者一个不翻转的图标 + +251 +00:13:12,492 --> 00:13:15,495 +这里我们使用 +“arrowtriangle.forward.fill” + +252 +00:13:15,529 --> 00:13:16,763 +作为 Preview 按钮 + +253 +00:13:16,797 --> 00:13:20,534 +名字中的“向前”表示 +它是从右向左翻转的 + +254 +00:13:20,567 --> 00:13:24,404 +我们使用“arrow.left” +和“arrow.right”作为方向按钮 + +255 +00:13:24,438 --> 00:13:26,240 +名字中的“左”和“右”表示 + +256 +00:13:26,273 --> 00:13:28,275 +它们不会从右到左翻转 + +257 +00:13:29,443 --> 00:13:33,113 +如果末使用的是 AppKit 或 UIKit +则其工作方式相同 + +258 +00:13:33,146 --> 00:13:37,784 +这是我在 Xcode storyboard +编辑器中的 App 选择了“Preview”按钮 + +259 +00:13:37,818 --> 00:13:40,487 +您可以使用 Attribute 检查器中的 + +260 +00:13:40,521 --> 00:13:42,689 +“Image”控件控制按钮的图标 + +261 +00:13:43,524 --> 00:13:46,860 +在代码中 您可以使用 +按钮的“Image”属性设置它 + +262 +00:13:46,894 --> 00:13:51,632 +它在 AppKit 和 UIKit 中的 +工作方式基本相同 + +263 +00:13:52,566 --> 00:13:56,236 +回到我们的 SwiftUI 示例 +下一个问题是 + +264 +00:13:56,270 --> 00:13:59,473 +如何控制图标位于标签的哪一侧 + +265 +00:13:59,506 --> 00:14:02,276 +您可以通过设置标签样式 +来完成此操作 + +266 +00:14:02,309 --> 00:14:07,047 +内置的 TitleAndIconLabelStyle +将图标放在 + +267 +00:14:07,080 --> 00:14:09,249 +用户阅读方向的标签之前 + +268 +00:14:09,283 --> 00:14:11,752 +我们可以用这个做“左”按钮 + +269 +00:14:11,785 --> 00:14:15,222 +对于另外两个按钮 +我们希望图标位于 + +270 +00:14:15,255 --> 00:14:16,990 +用户阅读方向上的标签之后 + +271 +00:14:17,024 --> 00:14:22,596 +为此 您需要一个自定义标签样式 +但这很容易做到 + +272 +00:14:22,629 --> 00:14:26,466 +您的标签样式的 makeBody() 方法 +只需创建一个 HStack + +273 +00:14:26,500 --> 00:14:28,669 +并将标题和图标添加到其中 + +274 +00:14:28,702 --> 00:14:33,207 +与任何 HStack 一样 您添加它们的 +顺序决定了它们显示的顺序 + +275 +00:14:33,240 --> 00:14:37,477 +并且在适合 UI 方向时 +顺序会自动翻转 + +276 +00:14:37,511 --> 00:14:42,916 +此技术适用于任何可以 +获取标签的视图 而不仅仅是按钮 + +277 +00:14:42,950 --> 00:14:47,154 +当然 您不希望“右”按钮上的 +图标改变方向 + +278 +00:14:47,187 --> 00:14:51,225 +无论 UI 方向如何 +您都希望它始终位于右侧 + +279 +00:14:51,258 --> 00:14:55,028 +这就引出了这段代码片段中 +最后一件有趣的事情 + +280 +00:14:55,062 --> 00:14:57,998 +SwiftUI 中的视图 +从 SwiftUI 环境中 + +281 +00:14:58,031 --> 00:15:01,768 +获取它们的方向性 +您可以对其进行修改 + +282 +00:15:01,802 --> 00:15:05,472 +要实现这一点 可以向视图添加 + +283 +00:15:05,506 --> 00:15:09,743 +“环境”修改器 并为其指定 +要更改的属性的键和新值 + +284 +00:15:09,776 --> 00:15:13,180 +在这里 我们将重写 +环境的 layoutDirection 属性 + +285 +00:15:13,213 --> 00:15:15,182 +使其始终从左到右 + +286 +00:15:15,215 --> 00:15:19,086 +而不管我们可能从父节点继承什么值 + +287 +00:15:19,119 --> 00:15:22,656 +以这种方式改变环境适用于 + +288 +00:15:22,689 --> 00:15:25,792 +所有响应用户 UI 方向的 +SwiftUI 视图 + +289 +00:15:25,826 --> 00:15:28,629 +请注意 我们对包含 +“左”和“右”按钮的 HStack + +290 +00:15:28,662 --> 00:15:31,031 +应用了修改器 +that contains the “Left” + +291 +00:15:31,064 --> 00:15:34,401 +对视图环境的任何改变都会被 + +292 +00:15:34,434 --> 00:15:37,871 +它的子视图继承 所以把它放在这里 + +293 +00:15:37,905 --> 00:15:41,208 +不仅可以防止 HStack +颠倒按钮的顺序 + +294 +00:15:41,241 --> 00:15:45,979 +还可以防止两个按钮颠倒标签的布局 + +295 +00:15:46,013 --> 00:15:49,016 +当然 我们没有将 +环境修改器应用到 + +296 +00:15:49,049 --> 00:15:51,718 +“Preview”按钮的父链中的任何东西 + +297 +00:15:51,752 --> 00:15:56,056 +所以它仍然在适当的时候翻转 +正如我们所希望的那样 + +298 +00:15:57,090 --> 00:16:00,127 +总结一下 “左”按钮的图标在左边 + +299 +00:16:00,160 --> 00:16:04,698 +因为我们使用了内置 +TitleAndIconLabelStyle + +300 +00:16:04,731 --> 00:16:08,235 +而“Preview”和“右”按钮的图标在右边 + +301 +00:16:08,268 --> 00:16:13,640 +因为我们用了一个自定义的标签样式 +我们称之为 IconOnRightLabelStyle + +302 +00:16:13,674 --> 00:16:16,276 +“左”和“左”按钮不会改变它们的顺序 + +303 +00:16:16,310 --> 00:16:18,612 +或它们标签的内部排列 + +304 +00:16:18,645 --> 00:16:20,714 +因为我们在包含它们的 HStack 中 + +305 +00:16:20,747 --> 00:16:22,683 +添加了一个环境修改器 + +306 +00:16:22,716 --> 00:16:25,419 +将布局方向设置为从左到右 + +307 +00:16:25,452 --> 00:16:29,256 +“Preview”按钮改变了 +其标签的内部排列方式 + +308 +00:16:29,289 --> 00:16:31,959 +因为它没有此修改器 + +309 +00:16:32,926 --> 00:16:35,729 +这在 AppKit 和 UIKit 中是不同的 + +310 +00:16:35,762 --> 00:16:39,032 +在这两个框架中 +图标相对于标签的位置 + +311 +00:16:39,066 --> 00:16:42,135 +是由 Xcode 的 Attribute 检查器中的 + +312 +00:16:42,169 --> 00:16:44,538 +“位置”控件控制的 + +313 +00:16:44,571 --> 00:16:46,240 +如果点击这个控件 + +314 +00:16:46,273 --> 00:16:49,176 +您会看到菜单中有两对选项 + +315 +00:16:49,209 --> 00:16:53,080 +它们会将标签和图标水平对齐 + +316 +00:16:53,113 --> 00:16:56,250 +您会看到“前缘”和“左” +还有“后缘”和“右” + +317 +00:16:56,283 --> 00:17:00,254 +“前缘”和“后缘”根据 UI 方向 +改变它们的含义 + +318 +00:17:00,287 --> 00:17:03,023 +“左”和“右”则不会 + +319 +00:17:03,056 --> 00:17:07,227 +在 AppKit 中 您可以用按钮的 +imagePosition 属性来控制它 + +320 +00:17:07,261 --> 00:17:11,798 +在 UIKit 中 则需要按钮配置上的 +imagePlacement 属性来控制它 + +321 +00:17:11,832 --> 00:17:16,403 +这可能意味着您需要 +首先设置按钮的配置 + +322 +00:17:16,436 --> 00:17:19,072 +“Preview”按钮上的图标会改变方向 + +323 +00:17:19,106 --> 00:17:21,341 +因为我们将其位置设置为“后缘” + +324 +00:17:21,375 --> 00:17:24,478 +而“右”按钮上的图标不会改变方向 + +325 +00:17:24,511 --> 00:17:27,881 +因为我们将其位置设置为“右” + +326 +00:17:27,915 --> 00:17:31,718 +这也使得我们填完了 +术语表的最后一行 + +327 +00:17:31,752 --> 00:17:34,121 +在讨论 UI 布局时 + +328 +00:17:34,154 --> 00:17:35,822 +“前缘”和“后缘”这两个术语 +会经常出现 + +329 +00:17:35,856 --> 00:17:37,224 +就像“向前”和“向后”一样 + +330 +00:17:37,257 --> 00:17:40,527 +您经常会看到它们与 +“左”和“右”对比使用 + +331 +00:17:40,561 --> 00:17:44,464 +“前缘”指的是 +最靠近行首一侧的边缘 + +332 +00:17:44,498 --> 00:17:48,402 +或者是读者开始阅读的 +屏幕或窗口的边缘 + +333 +00:17:48,435 --> 00:17:51,605 +从左到右 从右到左 + +334 +00:17:51,638 --> 00:17:53,907 +后缘是相对的一侧 + +335 +00:17:53,941 --> 00:17:55,609 +最接近直线的末端 + +336 +00:17:55,642 --> 00:17:59,046 +从右到右为右 从右到左为左 + +337 +00:17:59,079 --> 00:18:02,649 +大多数时候 您想用这些 +来代替“左”和“右” + +338 +00:18:02,683 --> 00:18:07,120 +只有在与绝对方向相关的事情上 +才使用“左”和“右” + +339 +00:18:08,455 --> 00:18:10,591 +我们来看看另一个有趣的案例 + +340 +00:18:10,624 --> 00:18:14,461 +这是英语和阿拉伯语版的 +iPhone 上 Keynote 中的 + +341 +00:18:14,494 --> 00:18:16,230 +文本格式检查器的一部分 + +342 +00:18:16,263 --> 00:18:20,167 +这个特殊的屏幕截图 +有四个分段的控件 + +343 +00:18:20,200 --> 00:18:23,303 +最上面的两个按钮 +即检查器的页面选择器 + +344 +00:18:23,337 --> 00:18:26,640 +和标准的“粗体/斜体/下划线” +样式按钮 + +345 +00:18:26,673 --> 00:18:30,310 +会根据 UI 语言来颠倒句段的顺序 + +346 +00:18:30,344 --> 00:18:34,381 +如果您不懂阿拉伯语 +就必须相信页面选择器 + +347 +00:18:34,414 --> 00:18:36,517 +与我们所看到的其他控件一样 + +348 +00:18:36,550 --> 00:18:39,987 +这是默认设置 +您可以免费试用此功能 + +349 +00:18:40,020 --> 00:18:43,123 +另外两个分段控件 即对齐控件 + +350 +00:18:43,156 --> 00:18:45,626 +不会颠倒其句段的顺序 + +351 +00:18:45,659 --> 00:18:48,762 +这是因为它们在绝对方向上移动对象 + +352 +00:18:48,795 --> 00:18:50,964 +左对齐就是左对齐 + +353 +00:18:50,998 --> 00:18:54,535 +不管它是行首还是行尾 + +354 +00:18:54,568 --> 00:18:58,305 +让我们看看如何防止这些控件翻转 + +355 +00:18:58,338 --> 00:19:01,008 +我们已经知道如何在 +SwiftUI 中实现这一点 + +356 +00:19:01,041 --> 00:19:02,910 +您只需应用一个“环境”修改器 + +357 +00:19:02,943 --> 00:19:06,947 +将环境的 layoutDirection 属性 +更改为从左到右 + +358 +00:19:06,980 --> 00:19:09,950 +在这里 我们使用这项技术来防止 + +359 +00:19:09,983 --> 00:19:11,451 +对齐控件反转 + +360 +00:19:11,485 --> 00:19:16,323 +但让样式控件像往常一样反转 + +361 +00:19:16,356 --> 00:19:18,792 +在 UIKit 中 工作方式完全不同 + +362 +00:19:18,825 --> 00:19:22,029 +这是 Xcode 中的一个玩具 App +用来模拟 + +363 +00:19:22,062 --> 00:19:24,131 +分段控件的行为 + +364 +00:19:24,164 --> 00:19:26,200 +我有两个分段控件 + +365 +00:19:26,233 --> 00:19:29,203 +一个模仿粗体/斜体/下划线的行为 + +366 +00:19:29,236 --> 00:19:32,172 +另一个模仿对齐控件 + +367 +00:19:32,206 --> 00:19:34,341 +选择对齐控件 + +368 +00:19:34,374 --> 00:19:38,979 +在属性检查器中 您会发现 +一个标签为“Semantic”的菜单 + +369 +00:19:39,012 --> 00:19:42,382 +如果点击这个菜单 会有五个选项 + +370 +00:19:42,416 --> 00:19:46,353 +此菜单控制所谓的语义内容属性 + +371 +00:19:46,386 --> 00:19:49,623 +您用它来说明这是什么类型的控件 + +372 +00:19:49,656 --> 00:19:53,493 +系统用它来决定它是否 + +373 +00:19:53,527 --> 00:19:55,529 +根据 UI 方向翻转其外观 + +374 +00:19:55,562 --> 00:19:57,698 +默认值为“未指定” + +375 +00:19:57,731 --> 00:20:00,767 +这将导致控件翻转其外观 + +376 +00:20:00,801 --> 00:20:04,037 +“Playback”表示该控件是一个 +媒体播放控制面板 + +377 +00:20:04,071 --> 00:20:06,406 +或一组播放控制面板的一部分 + +378 +00:20:06,440 --> 00:20:11,345 +“Spatial”表示控件是一个空间控件 +或一组控件的一部分 + +379 +00:20:11,378 --> 00:20:16,350 +空间控件在空间中 +以绝对方向移动对象 + +380 +00:20:16,383 --> 00:20:18,752 +最后 您可以强制该控件 + +381 +00:20:18,785 --> 00:20:23,290 +始终从左向右或从右向左布局 + +382 +00:20:23,323 --> 00:20:27,895 +因此 粗体/斜体/下划线控件 +从右到左翻转其片段 + +383 +00:20:27,928 --> 00:20:31,765 +因为其语义内容属性 +被设置为“未指定” + +384 +00:20:31,798 --> 00:20:35,102 +而对齐控件不翻转其片段 + +385 +00:20:35,135 --> 00:20:39,306 +因为其语义内容属性 +被设置为“空间的” + +386 +00:20:39,339 --> 00:20:41,808 +它的优点在于它不仅仅适用于 + +387 +00:20:41,842 --> 00:20:43,644 +UISegmentedControl + +388 +00:20:43,677 --> 00:20:46,680 +所有的 UIView +都有一个语义内容属性 + +389 +00:20:46,713 --> 00:20:50,117 +它控制所有控件从右到左的行为 + +390 +00:20:50,150 --> 00:20:53,453 +对于任何具有子组件的 +标准 UIKit 视图 + +391 +00:20:53,487 --> 00:20:56,557 +语义内容属性将确定该视图的 + +392 +00:20:56,590 --> 00:21:01,061 +子组件的位置是否基于 UI 语言翻转 + +393 +00:21:02,196 --> 00:21:05,065 +在 AppKit 中 +这类操作的方式有所不同 + +394 +00:21:05,098 --> 00:21:08,202 +对于所有的 NSControls +Xcode 属性检查器 + +395 +00:21:08,235 --> 00:21:11,805 +都包含两个菜单 分别标记为 +“Layout”和“Mirror.” + +396 +00:21:11,839 --> 00:21:13,674 +“Layout”菜单对应于 + +397 +00:21:13,707 --> 00:21:17,044 +控件的 +userInterfaceLayoutDirection 属性 + +398 +00:21:17,077 --> 00:21:21,181 +该属性指示控件应该使用 +从左到右还是从右到左的布局 + +399 +00:21:21,215 --> 00:21:24,551 +当您使用 Interface Builder 时 +通常不会更改此选项 + +400 +00:21:24,585 --> 00:21:27,087 +相反 您可以使用“Mirror”菜单 + +401 +00:21:27,120 --> 00:21:31,158 +将其设置为“Always”会导致 +userInterfaceLayoutDirection + +402 +00:21:31,191 --> 00:21:35,295 +当 nib 在从右向左的 +用户的 UI 语言中加载时 + +403 +00:21:35,329 --> 00:21:37,898 +控件的布局会被翻转 + +404 +00:21:37,931 --> 00:21:40,300 +而将其设置为“Never” +则会破坏此行为 + +405 +00:21:40,334 --> 00:21:42,336 +从而保持布局不变 + +406 +00:21:42,369 --> 00:21:45,372 +通过将该值设置为“Never” + +407 +00:21:45,405 --> 00:21:47,975 +可以保持对齐控件的布局不变 + +408 +00:21:48,008 --> 00:21:49,910 +如果您没有使用 Interface Builder + +409 +00:21:49,943 --> 00:21:52,112 +则可以通过直接将控件的 + +410 +00:21:52,145 --> 00:21:54,882 +userInterfaceLayoutDirection +设置为从左到右 + +411 +00:21:54,915 --> 00:21:57,484 +来完成相同的操作 + +412 +00:21:57,518 --> 00:22:01,688 +顺便说一句 userInterfaceLayoutDirection +是 NSView 上的一个属性 + +413 +00:22:01,722 --> 00:22:05,492 +但它只出现在 Interface Builder 中的 +NSControl 实例上 + +414 +00:22:05,526 --> 00:22:08,729 +因此 如果您想翻转 +非 NSControl 的内容 + +415 +00:22:08,762 --> 00:22:11,198 +就需要用到此处显示的代码 + +416 +00:22:12,299 --> 00:22:15,335 +在我们继续之前 我想再谈谈文本 + +417 +00:22:15,369 --> 00:22:20,207 +这是 Mac 版 iWork 中的 +“设置文档密码”对话框 + +418 +00:22:20,240 --> 00:22:23,310 +在阿拉伯语版本中 +您会看到一切都颠倒了 + +419 +00:22:23,343 --> 00:22:25,712 +注意标签的变化 + +420 +00:22:25,746 --> 00:22:28,482 +在英语中 它们是右对齐的 +这样它们就会 + +421 +00:22:28,515 --> 00:22:29,950 +靠近编辑文本字段 + +422 +00:22:29,983 --> 00:22:32,152 +在阿拉伯语中 它们是左对齐的 + +423 +00:22:32,186 --> 00:22:35,322 +换句话说 这是与自然对齐相反的 + +424 +00:22:35,355 --> 00:22:38,592 +尾缘对齐 如果您需要的话 + +425 +00:22:38,625 --> 00:22:42,362 +在 Mac 上的 SwiftUI 中 +获得这个布局非常简单 + +426 +00:22:42,396 --> 00:22:45,432 +只需使用一个 Form +将文本字段聚集在一起 + +427 +00:22:45,465 --> 00:22:48,669 +但如果像我们的示例那样 + +428 +00:22:48,702 --> 00:22:51,738 +其中一个标签是多行的 +这就会变得很有趣 + +429 +00:22:51,772 --> 00:22:56,076 +如果我们将最后一个标签扩展为两行 +就会得到这样的结果 + +430 +00:22:56,109 --> 00:22:59,079 +两个单线标签正确对齐 + +431 +00:22:59,112 --> 00:23:01,148 +但双线标签没有对齐 + +432 +00:23:01,181 --> 00:23:04,785 +问题是 底部标签确实是右对齐的 + +433 +00:23:04,818 --> 00:23:07,454 +只有它的边框是右对齐的 + +434 +00:23:07,487 --> 00:23:11,258 +而不是边框内的文本行 + +435 +00:23:11,291 --> 00:23:15,696 +可以通过向最后一个标签添加 +multilineTextAlignment 修改器 + +436 +00:23:15,729 --> 00:23:17,397 +来修复此问题 + +437 +00:23:17,431 --> 00:23:21,134 +SwiftUI 中的文本对齐 +仅在长度超过一行的 + +438 +00:23:21,168 --> 00:23:23,303 +文本对象上起作用 + +439 +00:23:23,337 --> 00:23:25,138 +对于单行文本对象 + +440 +00:23:25,172 --> 00:23:28,375 +其边界框将文本本身紧紧包围 + +441 +00:23:28,408 --> 00:23:32,312 +您可以通过对齐 +整个文本对象来对齐它 + +442 +00:23:32,346 --> 00:23:37,017 +还要注意 无论对齐文本的边界框 + +443 +00:23:37,050 --> 00:23:39,086 +还是边界框内的多行文本 + +444 +00:23:39,119 --> 00:23:41,822 +都可以选择前缘和后缘对齐 + +445 +00:23:41,855 --> 00:23:45,359 +这将根据用户的 UI 方向改变含义 + +446 +00:23:45,392 --> 00:23:48,629 +为了使对齐方式与 UI 方向无关 + +447 +00:23:48,662 --> 00:23:50,497 +可以使用环境修改器 + +448 +00:23:50,531 --> 00:23:54,234 +来更改环境的布局方向 +如我们前面所见 + +449 +00:23:55,202 --> 00:23:58,639 +在 UIKit 中 文本默认是对齐的 + +450 +00:23:58,672 --> 00:24:02,276 +但您可以在必要时 +将其更改为绝对方向 + +451 +00:24:02,309 --> 00:24:05,379 +在 Interface Builder 中 +该控件如下所示 + +452 +00:24:05,412 --> 00:24:08,148 +并对应于 UILabel + +453 +00:24:08,182 --> 00:24:10,517 +和 UITextView 上的 textAlignment 属性 + +454 +00:24:10,551 --> 00:24:13,287 +最右边带虚线的按钮 + +455 +00:24:13,320 --> 00:24:16,256 +可以实现自然或前缘对齐方式 + +456 +00:24:16,290 --> 00:24:17,658 +标签的对齐方式 + +457 +00:24:17,691 --> 00:24:20,360 +将遵循标签的语义内容属性 + +458 +00:24:20,394 --> 00:24:24,298 +其他按钮可实现固定的 +左对齐 右对齐或居中对齐 + +459 +00:24:24,331 --> 00:24:28,869 +而与 UI 方向或标签的 +语义内容属性无关 + +460 +00:24:28,902 --> 00:24:31,738 +没有用于后缘对齐的内置设置 + +461 +00:24:31,772 --> 00:24:34,274 +您需要用代码来实现这一点 + +462 +00:24:34,308 --> 00:24:36,443 +在 AppKit 中 情况略有不同 + +463 +00:24:36,476 --> 00:24:38,345 +您仍然拥有对齐控件 + +464 +00:24:38,378 --> 00:24:41,081 +它的工作原理与 UIKit 中的 +基本相同 + +465 +00:24:41,114 --> 00:24:44,952 +但它与 userInterfaceLayoutDirection +交互的方式不同 + +466 +00:24:44,985 --> 00:24:47,254 +如果您将“Mirror” +设置为“Automatically” + +467 +00:24:47,287 --> 00:24:49,756 +并且系统将 +userInterfaceLayoutDirection + +468 +00:24:49,790 --> 00:24:51,124 +设置为从右到左 + +469 +00:24:51,158 --> 00:24:53,994 +则所有对齐设置的含义将颠倒 + +470 +00:24:54,027 --> 00:24:56,196 +因此 如果将“Mirror” +设置为“Automatically” + +471 +00:24:56,230 --> 00:24:59,132 +则左对齐实际上是前缘对齐 + +472 +00:24:59,166 --> 00:25:03,403 +而右对齐实际上是后缘对齐 + +473 +00:25:03,437 --> 00:25:06,406 +我们已经讨论了所有的 +标准 UI 小组件 + +474 +00:25:06,440 --> 00:25:10,143 +如何自动翻转它们的布局 +来匹配用户的写入方向 + +475 +00:25:10,177 --> 00:25:13,180 +但在必要的时候 +很容易避免这种情况 + +476 +00:25:13,213 --> 00:25:18,185 +这扩展到在屏幕上排列单个 +UI 小组件 + +477 +00:25:18,218 --> 00:25:21,288 +如果您正在使用一个 +标准视图或视图控制器 + +478 +00:25:21,321 --> 00:25:23,657 +来处理它们的子视图的位置 + +479 +00:25:23,690 --> 00:25:26,159 +那么所有的子视图都会在必要的时候 + +480 +00:25:26,193 --> 00:25:29,296 +自动翻转它们的布局 +而无需执行任何操作 + +481 +00:25:29,329 --> 00:25:32,366 +表格视图和集合视图也能正确处理 + +482 +00:25:32,399 --> 00:25:34,501 +从右向左语言的滚动 + +483 +00:25:34,535 --> 00:25:38,105 +UINavigationController +会自动改变它的 + +484 +00:25:38,138 --> 00:25:42,042 +segue 动画的方向 +来反映用户的书写方向 + +485 +00:25:42,075 --> 00:25:45,078 +并更改“后退”按钮以与之匹配 + +486 +00:25:45,112 --> 00:25:49,383 +UIPageViewController +还会自动翻转翻页方向 + +487 +00:25:49,416 --> 00:25:53,187 +和轻扫手势的含义 + +488 +00:25:53,220 --> 00:25:55,856 +除了使用 stack 视图 +定位子视图之外 + +489 +00:25:55,889 --> 00:25:59,393 +您通常不希望重写这些内容 + +490 +00:25:59,426 --> 00:26:02,496 +但所有视图都遵循 +semanticContentAttribute + +491 +00:26:02,529 --> 00:26:06,166 +并使用它来告诉它们 +如何布局子视图 + +492 +00:26:06,200 --> 00:26:09,570 +标准 AppKit 视图也是如此 + +493 +00:26:09,603 --> 00:26:13,106 +表视图和集合视图 +也可以处理从右向左的滚动 + +494 +00:26:13,140 --> 00:26:16,844 +视图都使用它们的 +userInterfaceLayoutDirection 属性 + +495 +00:26:16,877 --> 00:26:19,112 +来决定如何布局它们的子视图 + +496 +00:26:19,146 --> 00:26:21,415 +尽管 Interface Builder 也会如此 + +497 +00:26:21,448 --> 00:26:24,051 +您必须用代码来做 + +498 +00:26:24,084 --> 00:26:26,954 +标准的 SwiftUI 视图也反映了 + +499 +00:26:26,987 --> 00:26:29,890 +环境的 layoutDirection 属性 + +500 +00:26:32,659 --> 00:26:36,063 +如果您使用 Auto Layout +而不是 stack 和网格视图 + +501 +00:26:36,096 --> 00:26:37,164 +来布局您的视图 + +502 +00:26:37,197 --> 00:26:39,933 +Auto Layout 还会根据 + +503 +00:26:39,967 --> 00:26:41,668 +UI 方向自动翻转 + +504 +00:26:41,702 --> 00:26:43,971 +如果您有水平约束 + +505 +00:26:44,004 --> 00:26:46,306 +您将看到它们会自动将事物 + +506 +00:26:46,340 --> 00:26:49,676 +连接到前缘和后缘 +正如我们所看到的 + +507 +00:26:49,710 --> 00:26:53,614 +“前缘”和“后缘”根据 UI 方向 +有不同的含义 + +508 +00:26:53,647 --> 00:26:57,317 +但如果需要 +您可以将 Auto Layout 约束 + +509 +00:26:57,351 --> 00:26:58,952 +设置为绝对左右方向 + +510 +00:26:58,986 --> 00:27:02,823 +您可以点击约束一侧的方向 + +511 +00:27:02,856 --> 00:27:05,325 +并在弹出的菜单中关闭 +“遵循语言方向” + +512 +00:27:05,359 --> 00:27:06,960 +来完成此操作 + +513 +00:27:06,994 --> 00:27:09,930 +这将约束两端的方向 + +514 +00:27:09,963 --> 00:27:13,867 +从“前缘”和“后缘” +更改为“左”和“右” + +515 +00:27:13,901 --> 00:27:17,638 +在代码中设置 +Auto Layout 约束有许多不同的方法 + +516 +00:27:17,671 --> 00:27:19,039 +这是其中之一 + +517 +00:27:19,072 --> 00:27:21,775 +无论您如何操作 要记住的是 + +518 +00:27:21,808 --> 00:27:24,912 +使用“前缘”和“后缘” +而不是“左”和“右” + +519 +00:27:24,945 --> 00:27:28,749 +除非在相对较少的情况下 +无论 UI 语言的 + +520 +00:27:28,782 --> 00:27:34,087 +编写方向如何 +您都希望使用相同的布局方向 + +521 +00:27:34,121 --> 00:27:37,691 +好了 刚才的内容有点多 +我们休息一下 + +522 +00:27:37,724 --> 00:27:40,494 +主要的结论是 我们已经为您 + +523 +00:27:40,527 --> 00:27:42,829 +完成了处理从右到左语言的 +大部分工作 + +524 +00:27:42,863 --> 00:27:45,899 +当您需要重写它时 +有很多方法可以做到这一点 + +525 +00:27:45,933 --> 00:27:48,602 +让我们再来看一下术语幻灯片 + +526 +00:27:48,635 --> 00:27:52,339 +记住 “左”和“右”始终是左和右 + +527 +00:27:52,372 --> 00:27:54,775 +而其他术语的含义 + +528 +00:27:54,808 --> 00:27:57,411 +则取决于整个 UI 方向 + +529 +00:27:58,745 --> 00:28:02,282 +在结束之前 +让我们看一个更重要的问题 + +530 +00:28:02,316 --> 00:28:04,251 +那就是如何显示数字 + +531 +00:28:04,284 --> 00:28:07,888 +严格来说 这不是从右到左的问题 +但对于许多开发者来说 + +532 +00:28:07,921 --> 00:28:10,657 +阿拉伯语是他们本地化的第一种语言 + +533 +00:28:10,691 --> 00:28:15,429 +因为它使用的数字字符 +不同于英语中的数字字符 + +534 +00:28:15,462 --> 00:28:17,631 +这些数字是这样的 + +535 +00:28:17,664 --> 00:28:20,300 +数字的命名有很多不同的约定 + +536 +00:28:20,334 --> 00:28:24,271 +但我将大多数欧洲语言中 +使用的数字称为“拉丁”数字 + +537 +00:28:24,304 --> 00:28:27,608 +而将阿拉伯语中使用的数字 +称为“阿拉伯-印度”数字 + +538 +00:28:27,641 --> 00:28:30,210 +还有其他语言也有自己的数字 + +539 +00:28:30,244 --> 00:28:33,013 +这些是用于印地语的梵文数字 + +540 +00:28:33,046 --> 00:28:36,850 +印地语是另一种 +使用不同数字的通用语言 + +541 +00:28:36,884 --> 00:28:40,087 +需要记住的一件重要的事是 +阿拉伯语和印地语 + +542 +00:28:40,120 --> 00:28:43,490 +都不太使用它们的本地数字 + +543 +00:28:43,524 --> 00:28:45,726 +对于阿拉伯语 它取决于国家 + +544 +00:28:45,759 --> 00:28:50,097 +一些国家 如沙特阿拉伯 +使用本地数字 + +545 +00:28:50,130 --> 00:28:53,634 +而另一些国家 如阿联酋 +使用拉丁数字 + +546 +00:28:53,667 --> 00:28:57,538 +个人用户也可以选择他们喜欢的数字 + +547 +00:28:57,571 --> 00:29:00,774 +对于印地语 我们默认使用拉丁数字 + +548 +00:29:00,807 --> 00:29:04,444 +但是用户可以选择使用本地数字 + +549 +00:29:05,546 --> 00:29:09,716 +您已经知道像这样构造 +UI 字符串不是个好主意 + +550 +00:29:09,750 --> 00:29:12,419 +字符串是硬编码的 无法转换 + +551 +00:29:12,452 --> 00:29:15,856 +消息不会更改为处理复数等等 + +552 +00:29:15,889 --> 00:29:18,525 +但另一个不好的原因是 + +553 +00:29:18,559 --> 00:29:23,163 +“peopleInChat” 的值 +总是用拉丁数字表示 + +554 +00:29:23,197 --> 00:29:26,733 +您可能也已经知道 +解决这个问题的方法是 + +555 +00:29:26,767 --> 00:29:29,436 +对字符串使用“本地化”的 init 方法 + +556 +00:29:29,469 --> 00:29:32,773 +该方法将在 App 包中 +查找实际的字符串 + +557 +00:29:32,806 --> 00:29:36,009 +并在有 stringsdict 文件的情况下 +正确处理复数 + +558 +00:29:36,043 --> 00:29:39,546 +好消息是它还能正确处理数字 + +559 +00:29:39,580 --> 00:29:43,283 +此处的“peopleInChat”插值的值 +将根据用户的区域设置 + +560 +00:29:43,317 --> 00:29:47,354 +和首选项使用正确的 +本地化数字呈现 + +561 +00:29:47,387 --> 00:29:50,591 +这也适用于 SwiftUI 中的文本视图 + +562 +00:29:50,624 --> 00:29:54,328 +文本视图初始值设定项还将使用 +正确本地化的数字 + +563 +00:29:54,361 --> 00:29:57,431 +来呈现任何字符串插值 + +564 +00:29:57,464 --> 00:30:01,768 +构造用户可见字符串时 始终使用 +String(localization:) + +565 +00:30:01,802 --> 00:30:05,372 +许多其他可以格式化数字的 +字符串 API + +566 +00:30:05,405 --> 00:30:08,408 +包括 +stringWithFormat: +和接受数字的 String init 函数 + +567 +00:30:08,442 --> 00:30:12,613 +始终使用拉丁数字 + +568 +00:30:12,646 --> 00:30:16,650 +需要注意的一个问题是 +包含数字的静态字符串 + +569 +00:30:16,683 --> 00:30:17,951 +比如这个 + +570 +00:30:17,985 --> 00:30:19,253 +这有什么大不了的 + +571 +00:30:19,286 --> 00:30:22,990 +您把它发送给翻译 他们翻译 +然后您就会得到这个 + +572 +00:30:23,023 --> 00:30:25,092 +这在很多地方都是正确的 + +573 +00:30:25,125 --> 00:30:27,528 +但在沙特阿拉伯和其他一些国家 + +574 +00:30:27,561 --> 00:30:29,062 +您会看到这个 + +575 +00:30:29,096 --> 00:30:33,233 +除了 3 所使用的字符外 +文本是相同的 + +576 +00:30:33,267 --> 00:30:35,536 +当然 您可以为使用 +阿拉伯-印度数字的 + +577 +00:30:35,569 --> 00:30:38,772 +阿拉伯语地区 +和使用拉丁数字的阿拉伯语地区 + +578 +00:30:38,805 --> 00:30:40,707 +进行单独的本地化 + +579 +00:30:40,741 --> 00:30:43,477 +但是没人这样做 这是一种浪费 + +580 +00:30:43,510 --> 00:30:45,646 +更糟糕的是 在阿拉伯语和印地语中 + +581 +00:30:45,679 --> 00:30:48,415 +用户可以选择他们想要使用的数字 + +582 +00:30:48,448 --> 00:30:50,684 +所以您必须根据用户的偏好 + +583 +00:30:50,717 --> 00:30:55,088 +来选择本地化 +而不仅仅是根据他们的地区 + +584 +00:30:55,122 --> 00:30:59,793 +解决方案是仍然只对 +阿拉伯语或印地语进行本地化 + +585 +00:30:59,826 --> 00:31:02,262 +但要在运行时将数字替换进去 + +586 +00:31:02,296 --> 00:31:04,965 +尽管您在编译时就知道这个值 + +587 +00:31:04,998 --> 00:31:09,002 +在 Swift 中 您可以使用 +字符串插值来完成此操作 + +588 +00:31:10,170 --> 00:31:12,873 +如果有其他元素和数字一起出现 + +589 +00:31:12,906 --> 00:31:16,510 +它们相对于数字的位置也是一个挑战 + +590 +00:31:16,543 --> 00:31:19,413 +甚至不是所有 +从右到左的语言都是一样的 + +591 +00:31:19,446 --> 00:31:21,982 +请注意 在阿拉伯语和希伯来语中 + +592 +00:31:22,015 --> 00:31:25,152 +减号和百分号位于数字的不同侧 + +593 +00:31:25,185 --> 00:31:28,322 +实际上 并不一定是 +从右到左的语言才有这个问题 + +594 +00:31:28,355 --> 00:31:31,358 +注意 在从左向右的土耳其语中 + +595 +00:31:31,391 --> 00:31:34,094 +百分比符号也在左边 + +596 +00:31:34,127 --> 00:31:37,831 +当然 请记住 如果您使用的是 +本地阿拉伯数字 + +597 +00:31:37,865 --> 00:31:41,401 +它们使用的是完全不同的百分比符号 + +598 +00:31:41,435 --> 00:31:44,938 +换言之 您真的不想做这种事情 + +599 +00:31:44,972 --> 00:31:47,875 +您要在后面加上百分号 +或者货币符号 + +600 +00:31:47,908 --> 00:31:51,178 +单位缩写 或者您自己加的任何东西 + +601 +00:31:51,211 --> 00:31:54,748 +相反 使用数字格式化程序 +添加百分号 + +602 +00:31:54,781 --> 00:31:56,850 +货币符号或其他符号 + +603 +00:31:56,884 --> 00:31:59,887 +在 Swift 中 对所有数值类型 +使用 formatted() 方法 + +604 +00:31:59,920 --> 00:32:01,622 +很容易做到这一点 + +605 +00:32:01,655 --> 00:32:04,791 +如果它是更大字符串的一部分 +如本例中所示 + +606 +00:32:04,825 --> 00:32:08,095 +String(localized:) 还将确保 +格式化的数字 + +607 +00:32:08,128 --> 00:32:11,031 +或在运行时代入字符串的 +任何其他内容 + +608 +00:32:11,064 --> 00:32:12,833 +包括其他字符串 + +609 +00:32:12,866 --> 00:32:15,836 +被标记包围 这样可以防止 + +610 +00:32:15,869 --> 00:32:18,539 +格式化数字的书写方向 + +611 +00:32:18,572 --> 00:32:21,141 +和周围消息相互混淆 + +612 +00:32:21,175 --> 00:32:25,179 +最后 我想给您一个提示 +用于测试您的 App + +613 +00:32:25,212 --> 00:32:27,781 +以确保您从右向左的操作是正确的 + +614 +00:32:28,549 --> 00:32:31,518 +您不必在可执行文件中使用 +阿拉伯语 + +615 +00:32:31,552 --> 00:32:34,688 +或希伯来语本地化 +就可以从右向左测试您的 App + +616 +00:32:34,721 --> 00:32:36,957 +实际上 您可以在开发语言中 + +617 +00:32:36,990 --> 00:32:38,926 +测试从右到左的行为 + +618 +00:32:38,959 --> 00:32:42,329 +为此 在 Xcode 中 +打开方案编辑器 + +619 +00:32:42,362 --> 00:32:46,633 +现在转到 Options 选项卡 +寻找“App Language”菜单 + +620 +00:32:46,667 --> 00:32:50,370 +在这个菜单的底部是一堆 +“pseudolanguage”选项 + +621 +00:32:50,404 --> 00:32:54,274 +这些都是假语言 +它们以各种方式转换您的 UI + +622 +00:32:54,308 --> 00:32:56,910 +让您在没有实际本地化的情况下 + +623 +00:32:56,944 --> 00:32:59,112 +检查本地化问题 + +624 +00:32:59,146 --> 00:33:02,382 +选择“Right-to-left Pseudolanguage”选项 +并点击运行 + +625 +00:33:02,416 --> 00:33:06,286 +您的 App 仍然是 +英语或其他开发语言 + +626 +00:33:06,320 --> 00:33:10,190 +但 UI 会将全部从右到左翻转 + +627 +00:33:10,224 --> 00:33:11,758 +这就是我要介绍的全部内容 + +628 +00:33:11,792 --> 00:33:14,728 +从右向左语言的本地化 + +629 +00:33:14,761 --> 00:33:18,031 +需要注意一些 +与书写方向变化相关的问题 + +630 +00:33:18,065 --> 00:33:21,201 +但是系统会为您完成 +大部分繁重的工作 + +631 +00:33:21,235 --> 00:33:24,471 +在某些情况下 通常是在绝对方向上 + +632 +00:33:24,505 --> 00:33:26,640 +您可能希望选择这种行为 + +633 +00:33:26,673 --> 00:33:28,408 +而这始终是可能的 + +634 +00:33:28,442 --> 00:33:33,680 +请记住 并非所有语言 +都使用拉丁数字来表示数字 + +635 +00:33:33,714 --> 00:33:35,449 +记住这些东西 + +636 +00:33:35,482 --> 00:33:37,584 +实现从右到左 + +637 +00:33:37,618 --> 00:33:38,685 +并不难 + +638 +00:33:38,719 --> 00:33:42,990 +[欢快的音乐] + diff --git a/zho/2022 Session 10108 Streamline local authorization flows.srt b/zho/2022 Session 10108 Streamline local authorization flows.srt new file mode 100644 index 0000000..c24ba0a --- /dev/null +++ b/zho/2022 Session 10108 Streamline local authorization flows.srt @@ -0,0 +1,1241 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,843 --> 00:00:12,946 +Felix Acero: 大家好 我叫 Felix Acero +是一名软件工程师 + +3 +00:00:12,980 --> 00:00:15,916 +供职于安全工程与架构团队 + +4 +00:00:15,949 --> 00:00:17,684 +在本视频中 我将向您展示如何使用 + +5 +00:00:17,718 --> 00:00:19,786 +LocalAuthentication 框架 + +6 +00:00:19,820 --> 00:00:23,423 +来改进 App 身份验证和授权流 + +7 +00:00:23,457 --> 00:00:25,659 +我们将首先了解身份验证(Authentication) + +8 +00:00:25,692 --> 00:00:28,262 +和授权(Authorization)的一般概念 + +9 +00:00:28,295 --> 00:00:31,164 +以及它们如何应用于您的 App + +10 +00:00:31,198 --> 00:00:34,902 +然后我们将回顾 +现有的 LocalAuthentication API + +11 +00:00:34,935 --> 00:00:37,004 +尤其是 LAContext + +12 +00:00:37,037 --> 00:00:41,108 +如何帮助您实现广泛的授权方案 + +13 +00:00:41,141 --> 00:00:43,110 +最后我们将看到 今年添加到 + +14 +00:00:43,143 --> 00:00:45,312 +LocalAuthentication 的新 API + +15 +00:00:45,345 --> 00:00:48,348 +如何帮助您进一步简化授权代码 + +16 +00:00:50,017 --> 00:00:53,954 +那么我们先来说说身份验证和授权 + +17 +00:00:53,987 --> 00:00:56,857 +身份验证和授权是不同 + +18 +00:00:56,890 --> 00:00:59,326 +但密切相关的安全概念 + +19 +00:00:59,359 --> 00:01:04,264 +一方面 身份验证 +是验证用户身份的行为 + +20 +00:01:04,298 --> 00:01:08,535 +另一方面 +授权是验证是否允许给定用户 + +21 +00:01:08,569 --> 00:01:13,040 +对具体资源执行特定操作的行为 + +22 +00:01:13,073 --> 00:01:16,410 +综上所述 我们可以看到 +由于我们首先需要验证 + +23 +00:01:16,443 --> 00:01:19,413 +用户是否就是 +他们所说的那个人 然后才能 + +24 +00:01:19,446 --> 00:01:22,149 +评估他们可以使用哪些资源和操作 + +25 +00:01:22,182 --> 00:01:26,587 +因此我们可以说 +身份验证实际上启用了授权 + +26 +00:01:26,620 --> 00:01:28,322 +为了帮助说明这些概念 + +27 +00:01:28,355 --> 00:01:31,124 +我们来看一个具体示例 +其中涉及由您的 App + +28 +00:01:31,158 --> 00:01:34,361 +管理的公共安全资源 +例如 Secure Enclave 密钥 + +29 +00:01:35,562 --> 00:01:38,498 +Secure Enclave 密钥 +是一种特殊类型的非对称密钥 + +30 +00:01:38,532 --> 00:01:41,268 +它绑定到特定设备 并受到 + +31 +00:01:41,301 --> 00:01:46,173 +与主处理器隔离的 +基于硬件的密钥管理器的保护 + +32 +00:01:46,206 --> 00:01:49,042 +这些密钥的特别之处在于 当您在 +Secure Enclave 中存储密钥时 + +33 +00:01:49,076 --> 00:01:51,578 +您实际上从未处理过该密钥 + +34 +00:01:51,612 --> 00:01:56,350 +而是指示 Secure Enclave +使用它执行操作 + +35 +00:01:56,383 --> 00:01:59,486 +Secure Enclave 密钥 +可以与访问控制列表 + +36 +00:01:59,520 --> 00:02:02,322 +或 ACL 相关联 + +37 +00:02:02,356 --> 00:02:05,859 +访问控制列表指定了 +执行特定操作所需满足的要求 + +38 +00:02:05,893 --> 00:02:10,130 +如对 blob 进行签名或解密 + +39 +00:02:11,532 --> 00:02:14,535 +它们可以指定给定项何时可用 + +40 +00:02:14,568 --> 00:02:18,539 +例如在设备解锁后 以及允许执行 + +41 +00:02:18,572 --> 00:02:21,842 +某些操作所需的身份验证要求 + +42 +00:02:21,875 --> 00:02:24,444 +在本例中 假设您的 App + +43 +00:02:24,478 --> 00:02:28,282 +希望通过生物认证 +来保护其密钥的签名 + +44 +00:02:28,315 --> 00:02:31,185 +和解密操作 同时确保密钥 + +45 +00:02:31,218 --> 00:02:33,620 +仅在设备解锁后可用 + +46 +00:02:34,454 --> 00:02:37,224 +现在让我们看看涉及此密钥的 + +47 +00:02:37,257 --> 00:02:39,560 +签名操作的授权流是什么样子的 + +48 +00:02:40,661 --> 00:02:44,731 +首先 App 发出 +使用密钥对 blob 进行签名的请求 + +49 +00:02:45,899 --> 00:02:49,503 +然后在验证 App +是否可以访问密钥后 + +50 +00:02:49,536 --> 00:02:52,773 +系统继续识别签名操作的 + +51 +00:02:52,806 --> 00:02:54,408 +授权要求 + +52 +00:02:54,441 --> 00:02:58,312 +在这种情况下 +签名操作需要当前注册用户 + +53 +00:02:58,345 --> 00:03:01,815 +进行成功的生物认证 + +54 +00:03:01,849 --> 00:03:03,584 +然后系统将通过标准 UI + +55 +00:03:03,617 --> 00:03:07,855 +引导用户完成生物认证 + +56 +00:03:07,888 --> 00:03:09,690 +身份验证成功后 + +57 +00:03:09,723 --> 00:03:10,858 +系统将验证 + +58 +00:03:10,891 --> 00:03:15,195 +是否已满足所有剩余的授权要求 + +59 +00:03:15,229 --> 00:03:18,265 +然后最终执行签名操作 + +60 +00:03:18,298 --> 00:03:20,834 +并将签名的 blob 返回给您的 App + +61 +00:03:21,969 --> 00:03:24,171 +我们来分解一下 +这个流程中涉及的主要组件 + +62 +00:03:24,204 --> 00:03:26,840 +看看它们如何适应我们最初的定义 + +63 +00:03:26,874 --> 00:03:30,811 +首先 我们有一个资源 +Secure Enclave 密钥 + +64 +00:03:30,844 --> 00:03:35,382 +其次 我们有一个 +可以用密钥执行的操作 + +65 +00:03:35,415 --> 00:03:38,685 +第三 我们有一组要求 其中包括 + +66 +00:03:38,719 --> 00:03:41,388 +指定允许执行操作的人员 + +67 +00:03:41,421 --> 00:03:43,690 +以及应用于验证其身份的 + +68 +00:03:43,724 --> 00:03:46,426 +身份验证方法 + +69 +00:03:46,460 --> 00:03:50,764 +将此示例的参数插入到我们的定义中 +我们可以看到 + +70 +00:03:50,797 --> 00:03:54,168 +对于身份验证来说 +是否是正确用户的问题 + +71 +00:03:54,201 --> 00:03:57,571 +是通过生物认证来回答的 + +72 +00:03:57,604 --> 00:04:01,241 +而对于授权 是否允许用户 + +73 +00:04:01,275 --> 00:04:04,611 +使用私钥进行签名操作的问题 + +74 +00:04:04,645 --> 00:04:09,750 +是通过验证访问控制列表中 +指定的要求来回答的 + +75 +00:04:09,783 --> 00:04:12,653 +现在我们已经在较高的层级上 +了解了它是如何工作的 + +76 +00:04:12,686 --> 00:04:15,722 +我们可以看看如何使用当前的 + +77 +00:04:15,756 --> 00:04:18,725 +LocalAuthentication API +来实现这样的流程 + +78 +00:04:18,759 --> 00:04:22,429 +让我们首先快速回顾一下 +LAContext 提供的功能 + +79 +00:04:22,462 --> 00:04:25,699 +它是框架的核心组件之一 + +80 +00:04:25,732 --> 00:04:29,303 +LAContext 可用于评估用户的身份 + +81 +00:04:29,336 --> 00:04:33,907 +它在需要生物特征或密码验证时 +处理用户交互 + +82 +00:04:33,941 --> 00:04:36,143 +它还与 Secure Enclave 连接 + +83 +00:04:36,176 --> 00:04:39,346 +以实现对生物特征数据的安全管理 + +84 +00:04:39,379 --> 00:04:41,648 +从这个角度来看 LAContext 可用于 + +85 +00:04:41,682 --> 00:04:44,785 +支持您的身份验证用例 + +86 +00:04:44,818 --> 00:04:48,355 +LAContext 也可以与其他框架 + +87 +00:04:48,388 --> 00:04:50,924 +结合使用以支持授权流 + +88 +00:04:50,958 --> 00:04:54,094 +例如 您可以用它 +来评估 AccessControl 列表 + +89 +00:04:54,127 --> 00:04:56,630 +就像我们在前面的例子中看到的那样 + +90 +00:04:56,663 --> 00:04:58,732 +我们来仔细看看 + +91 +00:04:58,765 --> 00:05:02,035 +我们需要做的第一件事是 +访问与我们的私钥 + +92 +00:05:02,069 --> 00:05:05,038 +相关联的 ACL + +93 +00:05:05,072 --> 00:05:08,542 +我们可以在 Security 框架提供的 +SecItemCopyMatching API 的 + +94 +00:05:08,575 --> 00:05:10,644 +帮助下做到这一点 + +95 +00:05:10,677 --> 00:05:14,748 +确保在查询中 +提供 ReturnAttributes 密钥 + +96 +00:05:15,782 --> 00:05:18,619 +一旦我们获得 +对访问控制列表的访问权 + +97 +00:05:18,652 --> 00:05:21,455 +我们就可以直接使用 LAContext + +98 +00:05:21,488 --> 00:05:24,958 +和 evaluateAccessControl API +对其进行评估 + +99 +00:05:24,992 --> 00:05:28,128 +这种方法给您带来的最大好处是 +它可以让您在 App 中 + +100 +00:05:28,161 --> 00:05:30,664 +决定提示用户进行此授权的 + +101 +00:05:30,697 --> 00:05:33,700 +正确时机和正确位置 + +102 +00:05:33,734 --> 00:05:36,370 +在这种情况下 +由于访问 AccessControl 列表 + +103 +00:05:36,403 --> 00:05:39,306 +要求对签名操作进行生物认证 + +104 +00:05:39,339 --> 00:05:43,143 +LAContext 将显示 +熟悉的 FaceID 或 TouchID UI + +105 +00:05:44,845 --> 00:05:48,582 +一旦 ACL 在我们的 +LAContext 中得到授权 + +106 +00:05:48,615 --> 00:05:50,918 +我们就可以将其作为查询的一部分 + +107 +00:05:50,951 --> 00:05:53,754 +来获取对密钥的引用 + +108 +00:05:53,787 --> 00:05:57,024 +我们通过将 LAContext 附加到 +UseAuthenticationContext 密钥下的 + +109 +00:05:57,057 --> 00:05:59,293 +SecItem 查询来实现这一点 + +110 +00:06:01,261 --> 00:06:04,131 +通过将 LAContext 绑定到私钥引用 + +111 +00:06:04,164 --> 00:06:06,600 +我们可以确保执行签名操作 + +112 +00:06:06,633 --> 00:06:08,902 +不会触发另一个身份验证 + +113 +00:06:08,936 --> 00:06:13,473 +同时允许操作在没有 +不必要提示的情况下继续进行 + +114 +00:06:13,507 --> 00:06:16,443 +这些绑定还意味着 +在 LAContext 失效之前 + +115 +00:06:16,476 --> 00:06:20,480 +之后的签名不需要额外的用户交互 + +116 +00:06:22,649 --> 00:06:25,252 +LAContext 提供了很大的灵活性 + +117 +00:06:25,285 --> 00:06:27,621 +它允许您控制授权流中 + +118 +00:06:27,654 --> 00:06:30,157 +涉及的每个步骤和参数 + +119 +00:06:30,190 --> 00:06:33,827 +它可以与其他框架 +如 Security 框架 结合使用 + +120 +00:06:33,861 --> 00:06:37,831 +这反过来又解锁了广泛的用例 + +121 +00:06:37,865 --> 00:06:42,169 +然而这种多功能性 +是以更高的代码复杂性为代价的 + +122 +00:06:42,202 --> 00:06:47,040 +需要您仔细编排几个框架提供的 API + +123 +00:06:47,074 --> 00:06:48,242 +根据您的使用情况 + +124 +00:06:48,275 --> 00:06:50,410 +LAContext 可能是适合您的工具 + +125 +00:06:50,444 --> 00:06:53,046 +尤其是当您的 App 的主要价值 + +126 +00:06:53,080 --> 00:06:56,250 +主张要求对密钥 秘密 + +127 +00:06:56,283 --> 00:06:58,652 +上下文和访问控制列表 +进行底层访问时 + +128 +00:06:58,685 --> 00:07:03,824 +然而 如果您的 App 需要的 +只是授权访问内容或敏感资源的方式 + +129 +00:07:03,857 --> 00:07:07,461 +那么您可能想用一个更简单的 API + +130 +00:07:07,494 --> 00:07:09,363 +来权衡这种灵活性 + +131 +00:07:09,396 --> 00:07:13,634 +这就把我们带到了最后一个话题 +简化您的 App + +132 +00:07:13,667 --> 00:07:18,839 +作为 iOS 16 和 macOS 13 的新功能 +LocalAuthentication 引入了 + +133 +00:07:18,872 --> 00:07:22,643 +更高层级的 以授权为中心的 API + +134 +00:07:22,676 --> 00:07:26,747 +新的 API 建立在 +LocalAuthentication 中的现有概念 + +135 +00:07:26,780 --> 00:07:31,118 +例如 LAContext 之上 +旨在简化常见 + +136 +00:07:31,151 --> 00:07:35,289 +授权流的实施 +让您可以将所有精力集中在 + +137 +00:07:35,322 --> 00:07:38,725 +您的 App 的核心价值主张上 + +138 +00:07:38,759 --> 00:07:42,896 +新 API 引入的最重要的 +抽象类是 LARight + +139 +00:07:44,431 --> 00:07:46,333 +您可以给 LARight 提供的 +最简单用例 + +140 +00:07:46,366 --> 00:07:51,405 +是帮助您对 App 定义的 +资源授权操作 + +141 +00:07:51,438 --> 00:07:54,408 +例如 您可以使用权限来帮助您 + +142 +00:07:54,441 --> 00:07:57,010 +访问 App 的用户配置文件部分 + +143 +00:07:57,044 --> 00:08:01,114 +首先 需要您的用户 +进行成功的生物认证 + +144 +00:08:02,950 --> 00:08:06,854 +默认情况下 权限受到 +一组身份验证要求的保护 + +145 +00:08:06,887 --> 00:08:10,257 +允许用户使用 Touch ID + +146 +00:08:10,290 --> 00:08:13,427 +FaceID Apple Watch +或它们的设备密码进行身份验证 + +147 +00:08:13,460 --> 00:08:15,295 +这取决于它们使用的设备 + +148 +00:08:16,997 --> 00:08:19,099 +您还可以选择将您的权限 + +149 +00:08:19,132 --> 00:08:20,868 +与更细粒度的需求相关联 + +150 +00:08:20,901 --> 00:08:24,571 +这允许您进一步限制身份验证的方法 + +151 +00:08:24,605 --> 00:08:27,608 +让我们看看如何 +在代码中使用 LARights + +152 +00:08:29,109 --> 00:08:32,546 +我们需要做的第一件事是 +实例化我们的权利 + +153 +00:08:32,579 --> 00:08:35,782 +我们通过指定它的需求来做到这一点 + +154 +00:08:35,816 --> 00:08:39,253 +在这种情况下 我们的登录权限 +将要求用户 + +155 +00:08:39,286 --> 00:08:43,457 +使用生物特征 +或提供设备密码进行身份验证 + +156 +00:08:43,490 --> 00:08:48,328 +然后我们继续验证当前用户 +是否可以获得登录权限 + +157 +00:08:48,362 --> 00:08:50,430 +我们使用这些信息来确定 + +158 +00:08:50,464 --> 00:08:52,866 +我们是否可以继续登录操作 + +159 +00:08:52,900 --> 00:08:57,971 +或者我们是否需要将用户 +重定向到我们 App 的公共部分 + +160 +00:08:58,005 --> 00:09:01,408 +最后 我们可以继续实际的授权操作 + +161 +00:09:01,441 --> 00:09:04,745 +提供一个本地化的 +用户可以在授权 UI 中 + +162 +00:09:04,778 --> 00:09:06,380 +看到的原因 + +163 +00:09:08,081 --> 00:09:09,850 +当以这种方式授权权利时 + +164 +00:09:09,883 --> 00:09:12,986 +将显示一个全新的 系统驱动的 UI + +165 +00:09:13,020 --> 00:09:15,722 +UI 在 App 窗口中呈现 + +166 +00:09:15,756 --> 00:09:17,991 +并为用户提供相关信息 + +167 +00:09:18,025 --> 00:09:21,461 +帮助他们了解操作的来源和目的 + +168 +00:09:21,495 --> 00:09:25,165 +我们相信 +新的外观将允许您精心设计 + +169 +00:09:25,199 --> 00:09:27,768 +与 App 无缝集成的授权流 + +170 +00:09:27,801 --> 00:09:31,471 +并为用户提供更多上下文和信息 + +171 +00:09:32,573 --> 00:09:35,242 +现在我们已经了解了 +如何创建和授权一个权利 + +172 +00:09:35,275 --> 00:09:38,445 +让我们进一步研究它的生命周期 + +173 +00:09:38,478 --> 00:09:42,249 +权利以未知状态开始其生命周期 + +174 +00:09:42,282 --> 00:09:45,018 +一旦您的 App +发出 authorize() 请求 + +175 +00:09:45,052 --> 00:09:48,255 +权限的状态就会更改为授权 + +176 +00:09:48,288 --> 00:09:51,658 +此时用户将看到我们 +在上一张幻灯片中 + +177 +00:09:51,692 --> 00:09:53,393 +看到的授权 UI + +178 +00:09:54,595 --> 00:09:57,364 +根据操作的成功或失败 + +179 +00:09:57,397 --> 00:10:01,468 +权限可以转换为授权或未授权状态 + +180 +00:10:01,502 --> 00:10:05,305 +这是您的 App 最重要的状态转换 + +181 +00:10:05,339 --> 00:10:07,841 +最后 权限也可以从授权状态 + +182 +00:10:07,875 --> 00:10:09,910 +转移到未授权状态 + +183 +00:10:09,943 --> 00:10:12,279 +当您的 App 在右边显式 +发出取消授权请求时 + +184 +00:10:12,312 --> 00:10:16,583 +或者当右边的实例被释放时 +就会发生这种情况 + +185 +00:10:17,751 --> 00:10:20,187 +请务必保留对您的权利的强引用 + +186 +00:10:20,220 --> 00:10:22,723 +以维护其授权状态 + +187 +00:10:23,924 --> 00:10:27,194 +取消权限授权后 +您的 App 可以继续 + +188 +00:10:27,227 --> 00:10:31,098 +发出授权请求以重新开始该周期 + +189 +00:10:31,131 --> 00:10:34,968 +可以查询和观察之前的所有状态转换 + +190 +00:10:35,002 --> 00:10:37,104 +如果您有权访问 LARight 实例 + +191 +00:10:37,137 --> 00:10:40,274 +则可以直接查询其状态属性 + +192 +00:10:40,307 --> 00:10:44,611 +您还可以使用 KVO 或 Combine +来观察所有状态转换 + +193 +00:10:44,645 --> 00:10:47,514 +此外 如果您的 App +处理多个权限 + +194 +00:10:47,548 --> 00:10:49,983 +那么您可以通过侦听 +didBecomeAuthorized + +195 +00:10:50,017 --> 00:10:52,119 +和 didBecomeUnauthorized 通知 + +196 +00:10:52,152 --> 00:10:54,755 +从一个位置观察所有权限的状态 + +197 +00:10:54,788 --> 00:10:57,357 +这些通知会在检测到授权状态更改后 + +198 +00:10:57,391 --> 00:11:00,294 +发布到默认 NotificationCenter + +199 +00:11:01,728 --> 00:11:04,598 +在继续之前 让我们回到我们的示例 + +200 +00:11:04,631 --> 00:11:08,535 +添加一个注销操作来取消登录权限 + +201 +00:11:08,569 --> 00:11:11,705 +通过这种操作 +我们可以保证用户下次登录时 + +202 +00:11:11,738 --> 00:11:13,974 +需要新的授权 + +203 +00:11:15,909 --> 00:11:19,346 +到目前为止 我们已经了解了 +如何使用正确的实例 + +204 +00:11:19,379 --> 00:11:23,517 +来授权对 App 定义的资源的操作 + +205 +00:11:23,550 --> 00:11:26,687 +我们还了解了这些权限的 +生命周期和状态 + +206 +00:11:26,720 --> 00:11:28,789 +最终是如何与运行时联系在一起的 + +207 +00:11:28,822 --> 00:11:31,725 +这意味着在 App 的每个会话上 + +208 +00:11:31,758 --> 00:11:35,963 +您都需要正确地 +实例化和配置这些权限 + +209 +00:11:35,996 --> 00:11:38,265 +那么让我们看看如何保持权限 + +210 +00:11:38,298 --> 00:11:41,034 +以及这为您的 App +带来了什么样的可能性 + +211 +00:11:42,703 --> 00:11:46,073 +LARights 可以在 +权利存储的帮助下持久化 + +212 +00:11:47,608 --> 00:11:51,245 +持久化后 权限由唯一的 +Secure Enclave 密钥支持 + +213 +00:11:51,278 --> 00:11:54,014 +该密钥受访问控制列表或 ACL 保护 + +214 +00:11:54,047 --> 00:11:57,584 +该列表或 ACL +与权限的授权要求相匹配 + +215 +00:11:57,618 --> 00:12:00,687 +这种方法帮助我们确保授权需求 + +216 +00:12:00,721 --> 00:12:03,757 +在权利被持久化之后仍然是不可变的 + +217 +00:12:05,125 --> 00:12:07,961 +您还可以访问支持您权限的私钥 + +218 +00:12:07,995 --> 00:12:11,331 +并使用它执行受保护的加密操作 + +219 +00:12:11,365 --> 00:12:15,602 +如解密 签名和密钥交换 + +220 +00:12:17,337 --> 00:12:19,773 +相应的公钥也是可访问的 + +221 +00:12:19,806 --> 00:12:21,642 +可以用于执行 + +222 +00:12:21,675 --> 00:12:25,779 +加密和签名验证等操作 + +223 +00:12:25,812 --> 00:12:30,350 +因为这是一个公钥 +所以您还可以导出与其关联的字节 + +224 +00:12:31,885 --> 00:12:33,987 +只有在成功授权权限后 + +225 +00:12:34,021 --> 00:12:36,790 +才允许私钥操作 + +226 +00:12:36,823 --> 00:12:40,194 +相比之下 总是允许公钥操作 + +227 +00:12:42,129 --> 00:12:44,965 +当坚持您的权利时 +您也有机会存储一个 + +228 +00:12:44,998 --> 00:12:48,368 +单一的 不变的秘密 + +229 +00:12:48,402 --> 00:12:51,605 +该秘密还与符合您权限授权要求的 + +230 +00:12:51,638 --> 00:12:54,408 +访问控制列表相关联 + +231 +00:12:54,441 --> 00:12:57,978 +并且只有在权限授权后 +才能访问该秘密 + +232 +00:12:59,146 --> 00:13:01,982 +总之 LAPersistedRights 是在 + +233 +00:13:02,015 --> 00:13:03,917 +权利存储的帮助下创建的 + +234 +00:13:03,951 --> 00:13:05,619 +它们只配置一次 + +235 +00:13:05,652 --> 00:13:08,856 +其授权要求是不变的 + +236 +00:13:08,889 --> 00:13:10,791 +因为它们是存储的 所以可以在 + +237 +00:13:10,824 --> 00:13:13,260 +App 的不同会话中使用 + +238 +00:13:13,293 --> 00:13:15,963 +在内部 它们绑定到特定设备 + +239 +00:13:15,996 --> 00:13:18,665 +并由唯一的 +Secure Enclave 密钥支持 + +240 +00:13:18,699 --> 00:13:21,668 +该密钥可用于执行不同的加密操作 + +241 +00:13:21,702 --> 00:13:25,305 +具体取决于权限的授权状态 + +242 +00:13:25,339 --> 00:13:28,775 +最后 它们可以用来保护一个单一的 +不可更改的秘密 + +243 +00:13:28,809 --> 00:13:32,446 +该秘密只有在授权后才可用 + +244 +00:13:33,313 --> 00:13:36,817 +现在我们已经了解了 +PersistedRights 提供的一些功能 + +245 +00:13:36,850 --> 00:13:38,519 +让我们看看它们如何帮助我们实现 + +246 +00:13:38,552 --> 00:13:41,255 +我们在演示开始时讨论的场景 + +247 +00:13:41,288 --> 00:13:43,891 +我们希望在该场景中授权签名操作 + +248 +00:13:44,691 --> 00:13:49,730 +我们首先实例化一个常规权限 +指定其授权要求 + +249 +00:13:49,763 --> 00:13:52,900 +在这种情况下 我们希望确保该权利 + +250 +00:13:52,933 --> 00:13:56,003 +仅授予在创建我们的权利时 + +251 +00:13:56,036 --> 00:13:58,939 +在设备中具有生物特征注册的用户 + +252 +00:13:58,972 --> 00:14:01,742 +因此我们使用 +biometryCurrentSet 要求 + +253 +00:14:03,177 --> 00:14:06,013 +然后我们可以 +在权利存储的帮助下持久化权限 + +254 +00:14:06,046 --> 00:14:08,615 +提供唯一标识符 + +255 +00:14:08,649 --> 00:14:12,119 +下次我们需要在 App 的 +未来会话中获取权限时 + +256 +00:14:12,152 --> 00:14:14,254 +这个标识符将非常有用 + +257 +00:14:15,622 --> 00:14:19,126 +一旦权限被持久化 +我们就可以立即访问它的公钥 + +258 +00:14:19,159 --> 00:14:22,095 +并开始用它执行不受保护的操作 + +259 +00:14:22,129 --> 00:14:25,199 +而不需要显式授权 + +260 +00:14:25,232 --> 00:14:28,535 +在这个例子中 +我们只是导出它的公共字节 + +261 +00:14:30,437 --> 00:14:33,540 +稍后 当需要执行签名操作时 + +262 +00:14:33,574 --> 00:14:35,642 +我们可以使用在创建过程中 + +263 +00:14:35,676 --> 00:14:39,813 +提供的唯一标识符 +从存储中检索我们的权利 + +264 +00:14:39,847 --> 00:14:42,149 +然后我们可以通过 + +265 +00:14:42,182 --> 00:14:45,085 +我们右边的授权操作 +对当前用户进行授权 + +266 +00:14:45,118 --> 00:14:48,388 +此时 系统将引导用户 +完成身份验证过程 + +267 +00:14:48,422 --> 00:14:52,226 +并验证是否满足所有授权要求 + +268 +00:14:53,227 --> 00:14:55,996 +在权限被授权后 +我们可以使用它的私钥 + +269 +00:14:56,029 --> 00:14:59,299 +来执行受保护的加密操作 + +270 +00:14:59,333 --> 00:15:02,236 +在这种情况下 我们使用私钥 + +271 +00:15:02,269 --> 00:15:05,172 +对 App 后端服务器 +发出的质询进行签名 + +272 +00:15:06,106 --> 00:15:09,376 +总结一下 我们讨论了身份验证 + +273 +00:15:09,409 --> 00:15:13,013 +和授权的通用概念之间存在的关系 + +274 +00:15:13,046 --> 00:15:17,885 +特别是身份验证如何启用授权 + +275 +00:15:17,918 --> 00:15:20,988 +我们讨论了 +LAContext 提供的一些特性 + +276 +00:15:21,021 --> 00:15:23,657 +以及它如何与 Security 等框架结合 + +277 +00:15:23,690 --> 00:15:27,561 +以解锁非常强大和可扩展的授权流程 + +278 +00:15:27,594 --> 00:15:30,697 +最后 我们研究了新添加的 LARight + +279 +00:15:30,731 --> 00:15:32,332 +如何帮助您简化代码 + +280 +00:15:32,366 --> 00:15:35,302 +以实现某些授权用例 + +281 +00:15:35,335 --> 00:15:39,306 +我们邀请您查看 App 中 +LocalAuthentication 的现有用法 + +282 +00:15:39,339 --> 00:15:42,843 +并考虑我们今天讨论的某些功能 + +283 +00:15:42,876 --> 00:15:44,578 +是否可以帮助您简化代码 + +284 +00:15:44,611 --> 00:15:48,215 +同时仍然保护用户的隐私和安全 + +285 +00:15:48,248 --> 00:15:49,249 +谢谢 + diff --git "a/zho/2022 Session 10109 What\342\200\231s new in notarization for Mac apps.srt" "b/zho/2022 Session 10109 What\342\200\231s new in notarization for Mac apps.srt" new file mode 100644 index 0000000..2a040c3 --- /dev/null +++ "b/zho/2022 Session 10109 What\342\200\231s new in notarization for Mac apps.srt" @@ -0,0 +1,770 @@ +1 +00:00:00,000 --> 00:00:03,170 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,170 --> 00:00:10,043 +♪ + +3 +00:00:10,043 --> 00:00:12,312 +大家好 我是 Johnathan + +4 +00:00:12,312 --> 00:00:15,215 +macOS 开发人员将软件 +提交给公证服务 + +5 +00:00:15,215 --> 00:00:16,850 +以帮助保护他们的客户 + +6 +00:00:16,850 --> 00:00:18,852 +免受恶意软件的侵害 + +7 +00:00:18,852 --> 00:00:21,622 +去年我们推出了 +一种更快更简单的方式 + +8 +00:00:21,622 --> 00:00:25,025 +通过 notarytool CLI +(命令行界面) + +9 +00:00:25,025 --> 00:00:27,160 +提交 App 进行公证 + +10 +00:00:27,160 --> 00:00:30,264 +今年 我们很高兴能通过为您与公证服务的交互 + +11 +00:00:30,264 --> 00:00:32,833 +做出的一些重大改进 + +12 +00:00:32,833 --> 00:00:36,403 +继续优化性能和灵活性 + +13 +00:00:36,403 --> 00:00:39,907 +在本讲座中 我们将讨论 +三个主要的主题 + +14 +00:00:39,907 --> 00:00:41,909 +首先 我们将了解 + +15 +00:00:41,909 --> 00:00:45,078 +从使用 altool 转换为使用 +notarytool 进行公证 + +16 +00:00:45,078 --> 00:00:47,814 +的重要截止日期 + +17 +00:00:47,814 --> 00:00:51,118 +接下来 我们将讨论 +即将推出的 Xcode 14 + +18 +00:00:51,118 --> 00:00:53,520 +对 Xcode 集成所做的改进 + +19 +00:00:53,520 --> 00:00:57,457 +这为 Xcode 带来了 +notarytool 的提交速度 + +20 +00:00:57,457 --> 00:00:59,927 +最后 我们将讨论一种灵活的 + +21 +00:00:59,927 --> 00:01:01,995 +与公证服务交互的新方式 + +22 +00:01:01,995 --> 00:01:05,933 +即 REST API +它让您可以在更多地方进行上传 + +23 +00:01:05,933 --> 00:01:09,703 +查看提交状态并检查提交内容 + +24 +00:01:11,705 --> 00:01:14,775 +去年我们推出了 notarytool + +25 +00:01:14,775 --> 00:01:18,212 +这是一个替代 altool +进行公证的工具 + +26 +00:01:18,212 --> 00:01:20,848 +在本讲座的稍后部分 +我将讨论 Xcode + +27 +00:01:20,848 --> 00:01:25,219 +通过 Xcode 14 迁移到 +我们最新的后端 + +28 +00:01:25,219 --> 00:01:27,921 +为通过 altool 和 Xcode 13 +进行的公证 + +29 +00:01:27,921 --> 00:01:30,457 +准备好迁移路径之后 + +30 +00:01:30,457 --> 00:01:32,826 +我们宣布使用这些旧方法进行公证的 + +31 +00:01:32,826 --> 00:01:37,431 +截止日期是 2023 年秋季 + +32 +00:01:37,431 --> 00:01:40,334 +如果您从 altool 迁移到 +notarytool 时需要帮助 + +33 +00:01:40,334 --> 00:01:42,703 +请参考去年的讲座 + +34 +00:01:42,703 --> 00:01:47,140 +“更快更简单的 +Mac App公证方式” + +35 +00:01:47,140 --> 00:01:50,277 +这里还有一些细节要说明 + +36 +00:01:50,277 --> 00:01:53,847 +包括捆绑在 Xcode 13 中的 + +37 +00:01:53,847 --> 00:01:57,184 +notarytool CLI 在 2023 年秋季的 +截止日期之后还能继续工作 + +38 +00:01:57,184 --> 00:01:59,086 +不过 与往常一样 +我们鼓励您进行更新 + +39 +00:01:59,086 --> 00:02:02,990 +以接收最新的改进和修补程序 + +40 +00:02:02,990 --> 00:02:06,393 +但我们将在该截止日期后停止支持 + +41 +00:02:06,393 --> 00:02:09,062 +使用 Xcode 13 UI +上传到公证服务 + +42 +00:02:09,062 --> 00:02:11,298 +请继续关注 Xcode 14 中的 +一些性能改进 + +43 +00:02:11,298 --> 00:02:14,368 +但在很大程度上您可以预期 + +44 +00:02:14,368 --> 00:02:17,337 +您的工作流程不会改变 + +45 +00:02:17,337 --> 00:02:20,507 +最后 +所有形式的 altool 公证 + +46 +00:02:20,507 --> 00:02:23,443 +将在 2023 年秋季停止工作 + +47 +00:02:23,443 --> 00:02:27,214 +有关迁移到 +notarytool 的详细信息 + +48 +00:02:27,214 --> 00:02:30,417 +也请参考去年的 WWDC 讲座 + +49 +00:02:30,417 --> 00:02:34,888 +接下来 我们将谈谈 +Xcode 14 中公证方式的变化 + +50 +00:02:34,888 --> 00:02:37,191 +我们已经迁移了 + +51 +00:02:37,191 --> 00:02:40,160 +Xcode 中内置的公证支持功能 + +52 +00:02:40,160 --> 00:02:44,464 +以使用与我们去年推出的 +notarytool CLI 相同的可靠后端 + +53 +00:02:44,464 --> 00:02:46,700 +因此 我们很高兴 +为 Xcode 14 带来 + +54 +00:02:46,700 --> 00:02:49,970 +大约 4 倍的性能提升 +这与我们去年 + +55 +00:02:49,970 --> 00:02:53,240 +针对 notarytool 宣布的 +性能提升是一致的 + +56 +00:02:53,240 --> 00:02:55,809 +最棒的是 除了更新 + +57 +00:02:55,809 --> 00:02:58,412 +您无需更改项目设置或工作流程 + +58 +00:02:58,412 --> 00:03:01,481 +即可获得这种性能提升 + +59 +00:03:01,481 --> 00:03:03,684 +对于本讲座的最后一个主题 + +60 +00:03:03,684 --> 00:03:05,953 +我们很高兴地宣布一项新服务 + +61 +00:03:05,953 --> 00:03:08,121 +Notary REST API + +62 +00:03:08,121 --> 00:03:10,457 +这项新服务让您可以在更多地方 + +63 +00:03:10,457 --> 00:03:14,361 +更灵活地与公证服务进行交互 + +64 +00:03:14,361 --> 00:03:16,630 +我们看一下几个重要的概念 + +65 +00:03:16,630 --> 00:03:18,465 +这个新的 API 旨在 + +66 +00:03:18,465 --> 00:03:21,735 +为公证服务提供更灵活的界面 + +67 +00:03:21,735 --> 00:03:23,770 +作为基于 JSON 的 +Web 服务 + +68 +00:03:23,770 --> 00:03:27,140 +集成在大多数语言里应该相当简单 + +69 +00:03:27,140 --> 00:03:29,576 +此 API 允许您 + +70 +00:03:29,576 --> 00:03:32,379 +从任何有网络连接的地方 +上传提交文件 + +71 +00:03:32,379 --> 00:03:34,615 +包括持续集成服务器 + +72 +00:03:34,615 --> 00:03:38,452 +在这些地方您目前可能 +没有运行 macOS + +73 +00:03:38,452 --> 00:03:41,188 +此外 该 API 还支持 + +74 +00:03:41,188 --> 00:03:43,557 +与公证服务的其他交互 + +75 +00:03:43,557 --> 00:03:45,392 +例如检索您的提交历史记录 + +76 +00:03:45,392 --> 00:03:48,295 +或过去的提交详情 + +77 +00:03:48,295 --> 00:03:50,197 +我们引入 REST API 的 +目标是 + +78 +00:03:50,197 --> 00:03:52,799 +支持从更多平台提交软件进行公证 + +79 +00:03:52,799 --> 00:03:55,836 +并允许在自动化系统中 + +80 +00:03:55,836 --> 00:03:58,672 +更轻松地与公证人进行交互 + +81 +00:03:58,672 --> 00:04:00,908 +提供了当前的提交方法 +Xcode 和 notarytool 之外的补充方式 + +82 +00:04:00,908 --> 00:04:04,011 +可用于这些方法目前无法运行的地方 + +83 +00:04:04,011 --> 00:04:07,147 +比如基于 Linux 的持续集成 + +84 +00:04:07,147 --> 00:04:09,750 +举个例子 假设您希望部署管道 + +85 +00:04:09,750 --> 00:04:11,485 +在分发之前将您的 App + +86 +00:04:11,485 --> 00:04:13,453 +提交给公证人 + +87 +00:04:13,453 --> 00:04:15,689 +通过这个新的 API +和一些基本的脚本 + +88 +00:04:15,689 --> 00:04:18,926 +您可以轻松地实现该过程的自动化 + +89 +00:04:18,926 --> 00:04:20,227 +在我开始正题之前 + +90 +00:04:20,227 --> 00:04:22,896 +一个重要的主题是身份验证 + +91 +00:04:22,896 --> 00:04:26,366 +您可以通过像其他 +App Store Connect API 一样 + +92 +00:04:26,366 --> 00:04:30,604 +使用 JSON Web Tokens +或 JWT 的 API 进行身份验证 + +93 +00:04:30,604 --> 00:04:32,339 +有关身份验证或我将要展示的代码 + +94 +00:04:32,339 --> 00:04:34,308 +的更多详细信息 + +95 +00:04:34,308 --> 00:04:38,212 +请访问下面链接的 +REST API 文档 + +96 +00:04:38,212 --> 00:04:41,248 +在这些代码片段中 +我假设您将有效的 JWT + +97 +00:04:41,248 --> 00:04:44,284 +作为令牌变量传递给函数 + +98 +00:04:44,284 --> 00:04:46,954 +我们来看一个在 Python 中 + +99 +00:04:46,954 --> 00:04:49,022 +向公证人提交文件的例子 + +100 +00:04:49,022 --> 00:04:50,691 +其他编程语言也适用 + +101 +00:04:50,691 --> 00:04:53,360 +同样的基本流程 + +102 +00:04:53,360 --> 00:04:57,130 +将文件上传给公证人有两个主要步骤 + +103 +00:04:57,130 --> 00:04:58,932 +第一步是通知公证人 + +104 +00:04:58,932 --> 00:05:01,301 +您希望上传文件 + +105 +00:05:01,301 --> 00:05:04,671 +其中包含有关该文件的一些基本信息 + +106 +00:05:04,671 --> 00:05:07,674 +如文件名和 SHA-256 + +107 +00:05:07,674 --> 00:05:09,776 +响应包含上传文件所需的信息 + +108 +00:05:09,776 --> 00:05:13,080 +和通过我们的管道 + +109 +00:05:13,080 --> 00:05:15,415 +跟踪提交文件的 ID + +110 +00:05:15,415 --> 00:05:18,252 +第二步是通过 Amazon S3 + +111 +00:05:18,252 --> 00:05:21,054 +实际上传文件进行公证 + +112 +00:05:21,054 --> 00:05:23,657 +您需要利用 +您最喜欢的 S3 SDK + +113 +00:05:23,657 --> 00:05:24,725 +对于这个例子 + +114 +00:05:24,725 --> 00:05:27,728 +我将使用 boto3 库 + +115 +00:05:27,728 --> 00:05:29,496 +在这里我们使用 + +116 +00:05:29,496 --> 00:05:31,498 +上一次调用中返回的临时凭证 + +117 +00:05:31,498 --> 00:05:34,168 +进行身份验证并创建客户端 + +118 +00:05:34,168 --> 00:05:37,037 +然后 我们使用客户端将文件上传到 + +119 +00:05:37,037 --> 00:05:40,807 +第一步的响应中指定的存储桶和对象 + +120 +00:05:40,807 --> 00:05:43,043 +上传后 提交文件将 + +121 +00:05:43,043 --> 00:05:45,412 +通过公证管道处理 + +122 +00:05:45,412 --> 00:05:47,981 +对于大多数提交文件 + +123 +00:05:47,981 --> 00:05:50,417 +此过程应在 15 分钟内完成 + +124 +00:05:50,417 --> 00:05:52,753 +上传后 您应在分发前确认 + +125 +00:05:52,753 --> 00:05:54,621 +公证服务已成功处理 + +126 +00:05:54,621 --> 00:05:56,757 +您提交的文件 + +127 +00:05:56,757 --> 00:05:59,993 +从广义上讲 +有两种方法可以做到这一点 + +128 +00:05:59,993 --> 00:06:01,662 +第一种方法 也是最简单的方法 + +129 +00:06:01,662 --> 00:06:04,598 +是通过相同的 API 来检查结果 + +130 +00:06:04,598 --> 00:06:06,600 +另一种选择是借助于 +随 notarytool 引入的 + +131 +00:06:06,600 --> 00:06:08,969 +webhook 支持 + +132 +00:06:08,969 --> 00:06:12,506 +首先 我们看一下 API 方法 + +133 +00:06:12,506 --> 00:06:14,675 +查看向公证人提交的文件的状态 + +134 +00:06:14,675 --> 00:06:17,010 +非常简单 + +135 +00:06:17,010 --> 00:06:19,079 +您可以使用在上传过程中收到的 +提交 ID + +136 +00:06:19,079 --> 00:06:22,316 +提出请求 + +137 +00:06:22,316 --> 00:06:24,418 +响应包含提交文件的当前状态 + +138 +00:06:24,418 --> 00:06:27,154 +该状态将一直为“进行中” + +139 +00:06:27,154 --> 00:06:29,957 +直到公证人完成处理 + +140 +00:06:29,957 --> 00:06:32,226 +然后该状态将转换为 + +141 +00:06:32,226 --> 00:06:36,897 +提交文件的最终状态 +例如已接受或无效 + +142 +00:06:36,897 --> 00:06:38,565 +提交完成后 + +143 +00:06:38,565 --> 00:06:39,933 +您可以使用该 API + +144 +00:06:39,933 --> 00:06:43,237 +来检索此次上传的公证日志 + +145 +00:06:43,237 --> 00:06:46,073 +有关这些端点的更多详情 + +146 +00:06:46,073 --> 00:06:49,409 +请参阅 Notary REST API 文档 + +147 +00:06:49,409 --> 00:06:51,512 +接下来 我们将讨论获取状态的 + +148 +00:06:51,512 --> 00:06:53,914 +第二种方法:webhook + +149 +00:06:53,914 --> 00:06:57,351 +在 webhook 工作流程中 +过程大致相同 + +150 +00:06:57,351 --> 00:06:59,887 +但这次您将在初始上传请求中 + +151 +00:06:59,887 --> 00:07:02,422 +提供 webhook URL + +152 +00:07:02,422 --> 00:07:04,992 +有关格式的详细信息 + +153 +00:07:04,992 --> 00:07:07,961 +请参阅 Notary REST API 文档 + +154 +00:07:07,961 --> 00:07:10,364 +和以前一样 这将触发公证服务 + +155 +00:07:10,364 --> 00:07:12,966 +来分析您提交的文件 + +156 +00:07:12,966 --> 00:07:16,403 +当自动分析结束时 会创建工单 + +157 +00:07:16,403 --> 00:07:19,039 +并保存最终状态 + +158 +00:07:19,039 --> 00:07:21,642 +完成后 公证服务将调用 + +159 +00:07:21,642 --> 00:07:23,844 +提供的 webhook URL + +160 +00:07:23,844 --> 00:07:26,547 +此调用的内容包括提交 ID + +161 +00:07:26,547 --> 00:07:32,085 +团队 ID +和证明其来自我们的签名 + +162 +00:07:32,085 --> 00:07:35,956 +收到该通知后 +您可以选择下一步做什么 + +163 +00:07:35,956 --> 00:07:39,026 +例如 您可以通知原始提交者 + +164 +00:07:39,026 --> 00:07:42,496 +或启动自动分发管道 + +165 +00:07:42,496 --> 00:07:44,198 +与使用 +notarytool 等待相比 + +166 +00:07:44,198 --> 00:07:47,201 +这允许您将上传文件的系统 + +167 +00:07:47,201 --> 00:07:51,905 +与公证后自动执行操作的系统分离 + +168 +00:07:51,905 --> 00:07:54,775 +我们很高兴看到 +这个新的 REST API 打开了 + +169 +00:07:54,775 --> 00:07:57,945 +与持续集成系统 +和其他为 macOS 构建软件的工具 + +170 +00:07:57,945 --> 00:08:01,281 +进行更多集成的大门 + +171 +00:08:01,281 --> 00:08:03,750 +在本讲座即将结束时 再次提醒一下 + +172 +00:08:03,750 --> 00:08:07,487 +转换为使用 +Xcode 14、notarytool + +173 +00:08:07,487 --> 00:08:11,458 +或直接使用 REST API 的截止日期 +是 2023 年秋季 + +174 +00:08:11,458 --> 00:08:14,194 +最后 如果您还不能在部署管道中 + +175 +00:08:14,194 --> 00:08:15,929 +使用 notarytool + +176 +00:08:15,929 --> 00:08:18,031 +现在试用 +Notary REST API + +177 +00:08:18,031 --> 00:08:20,734 +将为您带来启动自动化的机会 + +178 +00:08:20,734 --> 00:08:23,337 +您可以在下面找到文档链接 + +179 +00:08:23,337 --> 00:08:26,974 +谢谢 我希望您喜欢 +WWDC 22 的其余部分 + +180 +00:08:26,974 --> 00:08:30,844 +♪ + diff --git a/zho/2022 Session 10110 Build global apps - Localization by example.srt b/zho/2022 Session 10110 Build global apps - Localization by example.srt new file mode 100644 index 0000000..38adea7 --- /dev/null +++ b/zho/2022 Session 10110 Build global apps - Localization by example.srt @@ -0,0 +1,1842 @@ +1 +00:00:09,776 --> 00:00:12,112 +Andreas: 大家好 +欢迎来到全球开发者大会 + +2 +00:00:12,145 --> 00:00:14,481 +我是来自 Apple 本地化团队的 Andreas + +3 +00:00:14,515 --> 00:00:16,917 +今天我想和您分享一些 +关于如何创建高质量的 + +4 +00:00:16,950 --> 00:00:19,820 +本地化 App 的示例 + +5 +00:00:20,988 --> 00:00:23,524 +国际化意味着让您的 App + +6 +00:00:23,557 --> 00:00:26,126 +在世界各地的设备上运行 + +7 +00:00:26,159 --> 00:00:29,696 +如果本地化做得好 +所有人都能享受到同样棒的 + +8 +00:00:29,730 --> 00:00:33,867 +体验和功用 +不管他们说的是什么语言 + +9 +00:00:33,901 --> 00:00:36,303 +使用 Apple 提供的 API + +10 +00:00:36,336 --> 00:00:39,239 +您的 App 的大多数部分 +都会易于国际化 + +11 +00:00:39,273 --> 00:00:41,341 +开箱即用 + +12 +00:00:41,375 --> 00:00:43,744 +在本期演讲中 您将从我们的经验中 + +13 +00:00:43,777 --> 00:00:46,480 +学习如何让 Apple App +吸引不同的受众 + +14 +00:00:46,513 --> 00:00:49,249 +包括存在的一些挑战 +和我们该如何解决它们 + +15 +00:00:49,283 --> 00:00:53,153 +我将从声明和加载本地化文本开始 + +16 +00:00:53,187 --> 00:00:57,558 +字符串中很容易包含 +格式化的日期 时间等 + +17 +00:00:57,591 --> 00:01:02,563 +我将特别强调一些选项 +并将研究一个复杂的示例 + +18 +00:01:02,596 --> 00:01:05,766 +您的 Swift 软件包 +可能也包括本地化文本 + +19 +00:01:05,799 --> 00:01:09,970 +您将会了解到本地化工作流程的改进 + +20 +00:01:10,003 --> 00:01:14,408 +最后 我将谈谈 SwiftUI 的 +布局和新功能 + +21 +00:01:14,441 --> 00:01:18,345 +在 Apple 我们会确保我们的 App + +22 +00:01:18,378 --> 00:01:20,113 +能为世界各地的用户提供卓越的体验 + +23 +00:01:20,147 --> 00:01:22,783 +天气 App 就是一个例子 + +24 +00:01:22,816 --> 00:01:26,486 +每天都有数百万用户打开它 +查看天气预报 + +25 +00:01:26,520 --> 00:01:30,457 +无论他们身在何处 +他们眼中的 App 都是这样的 + +26 +00:01:30,490 --> 00:01:34,094 +注意 UI 中的所有内容是如何 +根据他们的首选项进行调整的 + +27 +00:01:34,127 --> 00:01:37,064 +我们将对当前天气状况的描述本地化 + +28 +00:01:37,097 --> 00:01:39,199 +并格式化数字 + +29 +00:01:39,233 --> 00:01:41,568 +UI 也会根据语言是从左到右的 + +30 +00:01:41,602 --> 00:01:45,305 +还是从右到左的进行适当调整 + +31 +00:01:45,339 --> 00:01:48,909 +让我们从翻译开始仔细看看某个 + +32 +00:01:48,942 --> 00:01:50,611 +自定义的内容 + +33 +00:01:50,644 --> 00:01:54,348 +这个视图用英语写着 +“风让体感更凉爽”(Wind is making it feel cooler.) + +34 +00:01:54,381 --> 00:01:57,317 +这是它在其他语言中的样子 + +35 +00:01:57,351 --> 00:02:00,120 +为了正确地运行它们 +我们所要做的就是使用 + +36 +00:02:00,153 --> 00:02:02,489 +(本地化的)String 声明字符串 + +37 +00:02:02,523 --> 00:02:05,125 +Xcode 会在导出本地化时发现它 + +38 +00:02:05,158 --> 00:02:09,296 +然后我们就可以将结果 +发送给我们的翻译人员 + +39 +00:02:09,329 --> 00:02:11,598 +我将使用 Mac 上的 +Mail App 来做到这一点 + +40 +00:02:11,632 --> 00:02:13,867 +既然我们说到这儿了 +我想给您看样东西 + +41 +00:02:13,901 --> 00:02:16,136 +如果我打开电子邮件的快捷菜单 + +42 +00:02:16,170 --> 00:02:19,273 +我可以把它移动到一个 +名为 Archive 的特殊文件夹 + +43 +00:02:19,306 --> 00:02:22,509 +它位于我的侧边栏中 + +44 +00:02:22,543 --> 00:02:25,812 +注意这两个单词在英语中 +都是 Archive + +45 +00:02:25,846 --> 00:02:28,682 +但是其他语言 如西班牙语 +关于操作和文件夹名称 + +46 +00:02:28,715 --> 00:02:31,018 +有不同的单词 + +47 +00:02:31,051 --> 00:02:33,020 +即使英语单词是相同的 + +48 +00:02:33,053 --> 00:02:35,088 +但是当它们出现在不同的语境中时 + +49 +00:02:35,122 --> 00:02:37,824 +其他语言可能会使用不同的单词 + +50 +00:02:37,858 --> 00:02:40,561 +在这种情况下 +应该在代码中使用两个字符串 + +51 +00:02:40,594 --> 00:02:45,832 +为此 今年我们给字符串初始化器 +添加了新的 API + +52 +00:02:45,866 --> 00:02:50,037 +它现在接受了一个默认值 +我们可以将其用于英语字符串 + +53 +00:02:50,070 --> 00:02:52,539 +然后 我们要修改本地化字符串的键 + +54 +00:02:52,573 --> 00:02:55,542 +使翻译人员清楚地了解区别 + +55 +00:02:55,576 --> 00:02:58,812 +通过这种方式用英语运行 App 时 + +56 +00:02:58,846 --> 00:03:02,349 +会显示相同的单词 +而西班牙语翻译可以提供不同的单词 + +57 +00:03:02,382 --> 00:03:04,918 +去年的演讲 +“Streamline your localized strings” + +58 +00:03:04,952 --> 00:03:07,721 +帮助您理解了管理字符串的基本知识 + +59 +00:03:07,754 --> 00:03:11,458 +并进一步介绍了本地化过程 + +60 +00:03:11,491 --> 00:03:15,929 +我希望您从这个例子中学到 +有时候同一个英文单词 + +61 +00:03:15,963 --> 00:03:20,267 +甚至是一个完整的句子 +会在 UI 里不同的环境中显示 + +62 +00:03:20,300 --> 00:03:25,339 +在这些情况下 请确保在代码中 +使用两个不同的字符串 + +63 +00:03:25,372 --> 00:03:27,708 +天气不仅仅与 App 有关 + +64 +00:03:27,741 --> 00:03:30,477 +它也能很好地集成到系统中 + +65 +00:03:30,511 --> 00:03:33,313 +在这里 我们能看到一个用户活动 +建议打开 App + +66 +00:03:33,347 --> 00:03:36,316 +来检查当前位置的天气 + +67 +00:03:36,350 --> 00:03:39,520 +让我们看看如何实现它 + +68 +00:03:39,553 --> 00:03:41,889 +可以像这样使用字符串插入(String Interpolation) + +69 +00:03:41,922 --> 00:03:45,659 +插入任何位置名称来声明 +加载字符串 + +70 +00:03:45,692 --> 00:03:50,163 +这个名字可以是一个城市 +也可以是当前位置的一个术语 + +71 +00:03:50,197 --> 00:03:51,932 +这个结果在英语中效果很好 + +72 +00:03:51,965 --> 00:03:53,433 +分别是 “Show weather in Cupertino” + +73 +00:03:53,467 --> 00:03:56,970 +和 “Show weather in my location” + +74 +00:03:57,004 --> 00:04:00,741 +但是 在其他语言中 +我们可能会遇到语法问题 + +75 +00:04:00,774 --> 00:04:04,244 +例如 在德语中 +介词可以用于城市名称前 + +76 +00:04:04,278 --> 00:04:07,814 +但插入表示当前位置的词前时 +就错误了 + +77 +00:04:07,848 --> 00:04:10,651 +我们需要一个不同的翻译来代替 + +78 +00:04:10,684 --> 00:04:13,153 +解决方案很简单 + +79 +00:04:13,187 --> 00:04:15,556 +用两个不同的字符串 + +80 +00:04:15,589 --> 00:04:17,925 +在第一个字符串中 +插入城市名称没有问题 + +81 +00:04:17,958 --> 00:04:21,061 +对于当前位 +我们要使用另一个字符串 + +82 +00:04:21,094 --> 00:04:24,231 +这可以确保翻译人员 +能够使用正确的 + +83 +00:04:24,264 --> 00:04:25,666 +语言语法 + +84 +00:04:25,699 --> 00:04:28,435 +这些在英语和德语中都很好用 + +85 +00:04:28,468 --> 00:04:32,439 +我做这个例子是为了向您展示 +插入一个变量 + +86 +00:04:32,472 --> 00:04:34,374 +会对整个句子产生影响 + +87 +00:04:34,408 --> 00:04:38,478 +在其他语言中 连接字符串 +可能会产生令人惊讶的结果 + +88 +00:04:38,512 --> 00:04:43,050 +它们可能需要改变语法 +或者可能在大写方面有问题 + +89 +00:04:43,083 --> 00:04:46,353 +但要在编写代码之前 +想到这一点很困难 + +90 +00:04:46,386 --> 00:04:48,789 +让会说这门语言的人测试 App + +91 +00:04:48,822 --> 00:04:51,491 +是工作流程的重要部分 + +92 +00:04:51,525 --> 00:04:55,295 +当您试图以编程方式构造字符串时 +请记住这一点 + +93 +00:04:57,297 --> 00:05:00,634 +现在我们已经很好地理解了 +字符串是如何在代码中被声明的 + +94 +00:05:00,667 --> 00:05:03,270 +让我们来聊一聊它们的注释 + +95 +00:05:03,303 --> 00:05:07,774 +下面是我们上一个例子中的字符串 +并附有适当的注释 + +96 +00:05:07,808 --> 00:05:10,277 +注释对翻译来说非常非常重要 + +97 +00:05:10,310 --> 00:05:13,647 +您应该确保为它们 +能提供翻译所需的上下文 + +98 +00:05:13,680 --> 00:05:17,851 +使译文与您声明 +字符串时的意图保持一致 + +99 +00:05:17,885 --> 00:05:21,421 +一个好的注释解释了字符串 +显示在哪个界面元素中 + +100 +00:05:21,455 --> 00:05:23,824 +类似于标签或按钮 + +101 +00:05:23,857 --> 00:05:28,629 +它还解释了 UI 元素的上下文 +以及它在屏幕上显示的位置 + +102 +00:05:28,662 --> 00:05:33,567 +它可以是一个段落头 +一个快捷菜单 或者一个用户活动 + +103 +00:05:33,600 --> 00:05:35,002 +如果字符串包含变量 + +104 +00:05:35,035 --> 00:05:37,604 +请确保在运行时解释它们的值 + +105 +00:05:37,638 --> 00:05:40,407 +如我们在例子中看到的 + +106 +00:05:40,440 --> 00:05:42,543 +这对于匹配句子的语法非常重要 + +107 +00:05:42,576 --> 00:05:45,779 +记住 翻译在翻译内容时 + +108 +00:05:45,812 --> 00:05:47,514 +可能不会看到运行时的 App + +109 +00:05:47,548 --> 00:05:50,417 +但是通过这些技巧 +您应该能够在字符串的声明 + +110 +00:05:50,450 --> 00:05:53,253 +和翻译 它在您的 App 中 + +111 +00:05:53,287 --> 00:05:56,256 +扮演的角色之间建立一个共识 + +112 +00:05:56,290 --> 00:05:57,858 +现在 您可能从来没有想过 + +113 +00:05:57,891 --> 00:06:00,827 +但天气 App 实际上 +并不能控制天气 + +114 +00:06:00,861 --> 00:06:03,664 +相反 数据是从服务器下载下来的 + +115 +00:06:03,697 --> 00:06:05,866 +它可能位于世界上的任何地方 + +116 +00:06:05,899 --> 00:06:09,636 +甚至可能不知道用什么语言发送内容 + +117 +00:06:09,670 --> 00:06:11,772 +当内容被下载到用户的设备时 + +118 +00:06:11,805 --> 00:06:15,843 +它应该一直以用户 +更愿意使用的语言呈现 + +119 +00:06:15,876 --> 00:06:19,780 +只本地化应用的某些部分 +可能会让人非常困惑 + +120 +00:06:20,747 --> 00:06:23,717 +在这里 天气 App 显示了 +一个恶劣天气警报 + +121 +00:06:23,750 --> 00:06:26,286 +它是从服务器加载来的 + +122 +00:06:26,320 --> 00:06:27,621 +这看起来真的很严重 + +123 +00:06:27,654 --> 00:06:31,992 +如果它没有翻译成我的语言 +我之后可能会遇到麻烦 + +124 +00:06:32,025 --> 00:06:34,595 +让我们看看可以做些什么 +来确保用户能 + +125 +00:06:34,628 --> 00:06:37,231 +持续读取远程内容 + +126 +00:06:38,999 --> 00:06:42,336 +您的服务器可以向 App +发送支持的语言列表 + +127 +00:06:42,369 --> 00:06:44,738 +这应该是一个语言 ID 的阵列 + +128 +00:06:44,771 --> 00:06:48,308 +设备有关于用户喜欢哪种语言的 +所有数据 + +129 +00:06:48,342 --> 00:06:51,445 +这样您就不必自己检查比较它们 + +130 +00:06:51,478 --> 00:06:55,415 +您可以通过调用 “Bundle.preferredLocalizations” +来利用 Apple 的框架 + +131 +00:06:55,449 --> 00:06:57,818 +它会帮您匹配 + +132 +00:06:57,851 --> 00:07:00,053 +它会返回一个候选语言的数组 + +133 +00:07:00,087 --> 00:07:03,857 +根据它们与用户的语言选择的 +匹配程度排序 + +134 +00:07:03,891 --> 00:07:08,962 +第一个通常是最合适的 +所以您要用这个 + +135 +00:07:08,996 --> 00:07:13,300 +然后 应将该语言用于 +对服务器的任何后续请求 + +136 +00:07:13,333 --> 00:07:16,403 +它会用它生成一个回应 + +137 +00:07:16,436 --> 00:07:19,273 +其内容是用户能够理解的语言 + +138 +00:07:19,306 --> 00:07:21,041 +使用这种技术 +您可以确保来自服务器的字符串 + +139 +00:07:21,074 --> 00:07:24,711 +为更新 UI 和向用户显示警报 + +140 +00:07:24,745 --> 00:07:27,948 +做好了准备 + +141 +00:07:27,981 --> 00:07:30,951 +因此 为了使用户在显示远程内容时 + +142 +00:07:30,984 --> 00:07:34,388 +避免困惑 请下载可用的语言 + +143 +00:07:34,421 --> 00:07:36,490 +将其与用户的语言偏好进行匹配 + +144 +00:07:36,523 --> 00:07:40,594 +并在加载面向用户内容的任何请求时 +使用该结果 + +145 +00:07:40,627 --> 00:07:42,729 +但现在让我们再看看更好的天气 + +146 +00:07:42,763 --> 00:07:45,465 +无论晴雨 +天气 App 的数据都非常丰富 + +147 +00:07:45,499 --> 00:07:48,802 +它的许多方面都包含数字和计数 + +148 +00:07:48,836 --> 00:07:51,238 +让我们关注其中一个 + +149 +00:07:51,271 --> 00:07:56,443 +降水(Precipitation) 下面写着 +“最近 6 小时内会有 0 毫米。” + +150 +00:07:56,476 --> 00:07:58,979 +让我们假设您想要构建类似的内容 + +151 +00:07:59,012 --> 00:08:01,648 +但这里改为 “ 1 小时” + +152 +00:08:01,682 --> 00:08:04,017 +这就是在代码中声明字符串的方式 + +153 +00:08:04,051 --> 00:08:06,286 +在英语中 如果小时数大于 1 + +154 +00:08:06,320 --> 00:08:08,655 +您就需要使用复数形式 + +155 +00:08:08,689 --> 00:08:11,692 +1 小时是 hour 但 2 小时是 hours + +156 +00:08:11,725 --> 00:08:13,794 +在乌克兰语中要使用另一种变体 + +157 +00:08:13,827 --> 00:08:16,330 +其规则更加复杂 + +158 +00:08:16,363 --> 00:08:19,099 +您不会希望在代码中实现这种逻辑 + +159 +00:08:19,132 --> 00:08:22,703 +这就是为什么要利用 Apple 框架 + +160 +00:08:22,736 --> 00:08:25,138 +您所要做的 +就是在代码中声明字符串 + +161 +00:08:25,172 --> 00:08:29,543 +并提供一个 stringsdict 文件 +该文件会对复数规则进行编码 + +162 +00:08:29,576 --> 00:08:33,413 +另一个选择是使用 +自动语法协议(Automatic Grammar Agreement) + +163 +00:08:33,447 --> 00:08:35,549 +您可以在去年的演讲 +“Streamline your localized strings” 中 + +164 +00:08:35,582 --> 00:08:39,219 +了解更多关于这两种技术的内容 + +165 +00:08:39,253 --> 00:08:42,356 +尽管这很简单 +但您不应该总是将复数规则 + +166 +00:08:42,389 --> 00:08:44,992 +应用于所有字符串 + +167 +00:08:45,025 --> 00:08:47,561 +例如 如果您的句子不要计数 + +168 +00:08:47,594 --> 00:08:51,999 +也不包括数字 +您就不应该使用复数规则 + +169 +00:08:52,032 --> 00:08:54,201 +在这里 +“Remove this city from your favorites” + +170 +00:08:54,234 --> 00:08:56,537 +不需要该规则 因为其中没有数字 + +171 +00:08:56,570 --> 00:09:00,007 +而且同样适用于多个城市 + +172 +00:09:00,040 --> 00:09:02,009 +但如果字符串确实包含一个数字 + +173 +00:09:02,042 --> 00:09:05,179 +您应该考虑使用复数变形 + +174 +00:09:05,212 --> 00:09:09,316 +前面示例中的字符串 +计算了未来几个小时的降雨量 + +175 +00:09:09,349 --> 00:09:14,154 +我们刚刚学习了让它依据 +大于 1 的数字改进是多么容易 + +176 +00:09:14,188 --> 00:09:17,491 +但是 如果句子中有一个单位 +比如持续时间 + +177 +00:09:17,524 --> 00:09:21,595 +时间或百分比 +您应该考虑使用格式化器 + +178 +00:09:21,628 --> 00:09:24,364 +所以 现在让我们来聊聊格式化器(Formatter)吧 + +179 +00:09:24,398 --> 00:09:28,368 +气候会在这个视图中 +以百分比显示当前湿度 + +180 +00:09:28,402 --> 00:09:32,239 +要在 SwiftUI 中实现这一点 +只需要一行代码 + +181 +00:09:32,272 --> 00:09:35,609 +您只需在 Text() 中填入您需要的值 + +182 +00:09:35,642 --> 00:09:37,444 +并指定您希望如何格式化这个数字 + +183 +00:09:37,477 --> 00:09:39,479 +等效的 Swift 代码也很简单 + +184 +00:09:39,513 --> 00:09:42,115 +您只需要在值上调用 .formatted + +185 +00:09:43,417 --> 00:09:45,085 +这就是您需要做的全部工作 + +186 +00:09:45,118 --> 00:09:48,222 +而格式化器会处理其他所有事情 + +187 +00:09:48,255 --> 00:09:50,624 +它不仅会将百分号 +放在数字的前面或后面 + +188 +00:09:50,657 --> 00:09:52,960 +并添加空格 + +189 +00:09:52,993 --> 00:09:56,630 +它还会适应用户偏好的编号系统 + +190 +00:09:56,663 --> 00:10:00,601 +这是阿拉伯语和印地语用户所期望的 + +191 +00:10:00,634 --> 00:10:04,972 +但这仅仅是可以格式化的 +数据类型的开始 + +192 +00:10:05,005 --> 00:10:07,474 +几乎所有的东西都有格式化器 + +193 +00:10:07,508 --> 00:10:11,912 +我建议您再看一次讲座 +“Formatters: Make data human-friendly” + +194 +00:10:14,715 --> 00:10:17,417 +正如我们所看到的 +天气并不总是晴朗的 + +195 +00:10:17,451 --> 00:10:19,686 +有些日子会下雨 + +196 +00:10:19,720 --> 00:10:23,357 +当然 天气 App 也不能缺少这个亮点 + +197 +00:10:23,390 --> 00:10:28,462 +降雨(Rainfall) 一栏写着 “50 mm expected +in next 24 hours”(预计未来 24 小时内会有 50 毫米。) + +198 +00:10:28,495 --> 00:10:32,699 +我真的很高兴这不是我的 +所在地的情况 + +199 +00:10:32,733 --> 00:10:34,535 +在英语中 情况很简单 + +200 +00:10:34,568 --> 00:10:38,705 +我们会说 “50 millimeters expected +in next 24 hours.” + +201 +00:10:38,739 --> 00:10:41,241 +但是在西班牙语中 事情要复杂得多 + +202 +00:10:41,275 --> 00:10:44,444 +我们需要依据降水量是单数或复数 + +203 +00:10:44,478 --> 00:10:47,114 +来改变翻译 + +204 +00:10:47,147 --> 00:10:51,652 +我们可以通过结合格式化器 +和复数规则来解决这个问题 + +205 +00:10:51,685 --> 00:10:54,354 +字符串 2mm 是由格式化器生成的 + +206 +00:10:54,388 --> 00:10:59,560 +它被嵌入到了一个在西班牙语中 +需要改为复数形式的句子中 + +207 +00:10:59,593 --> 00:11:03,463 +好的 让我们看看 +如何在代码中做到这一点 + +208 +00:11:03,497 --> 00:11:06,500 +我们首先要声明一个 +带有一个参数 + +209 +00:11:06,533 --> 00:11:10,170 +关于降水量的函数 单位是毫米 + +210 +00:11:10,204 --> 00:11:13,807 +它可能是从服务器上下载的 + +211 +00:11:13,841 --> 00:11:16,376 +首先 我们要向系统请求一个 +UnitLength + +212 +00:11:16,410 --> 00:11:18,512 +它会对用户的配置进行编码 + +213 +00:11:18,545 --> 00:11:23,217 +并为要显示降雨的情况 +选择正确的长度 + +214 +00:11:23,250 --> 00:11:26,253 +如果用户没有将其系统 +配置为使用公制 + +215 +00:11:26,286 --> 00:11:29,890 +那么可以很容易地将 +Measurement 类型转换为偏好单位 + +216 +00:11:31,692 --> 00:11:35,162 +接下来 格式化 API +会让我们能够在一行代码中为值 + +217 +00:11:35,195 --> 00:11:38,031 +生成格式化字符串 + +218 +00:11:38,065 --> 00:11:40,667 +偏好单位已经有了我们想要显示的 + +219 +00:11:40,701 --> 00:11:42,102 +降雨信息 + +220 +00:11:42,135 --> 00:11:45,939 +所以格式化时 我们要 +将用法设置为 asProvided + +221 +00:11:45,973 --> 00:11:49,276 +如果降雨量超过 1 毫米或 1 英寸 + +222 +00:11:49,309 --> 00:11:51,512 +我们希望使用复数形式 + +223 +00:11:51,545 --> 00:11:55,082 +我们要把这个值转换成一个整数 +这样我们就可以检查它了 + +224 +00:11:55,115 --> 00:11:58,085 +接下来 我们要加载一个 +带有给定键的本地化字符串 + +225 +00:11:58,118 --> 00:12:00,988 +并提供一个默认值 + +226 +00:12:01,021 --> 00:12:04,258 +在这里 我们要用字符串插值 +来包含 integerValue + +227 +00:12:04,291 --> 00:12:07,294 +格式化值和数字 24 + +228 +00:12:07,327 --> 00:12:11,365 +这个数字是在代码中定义的 +因为它永远是 24 小时 + +229 +00:12:11,398 --> 00:12:13,734 +使用字符串插值能自动确保 + +230 +00:12:13,767 --> 00:12:17,671 +使用正确的编号系统 + +231 +00:12:17,704 --> 00:12:19,673 +该键在 stringsdict 文件中被声明 + +232 +00:12:19,706 --> 00:12:22,442 +让我们来看看 + +233 +00:12:22,476 --> 00:12:26,780 +stringsdict 以我们刚刚 +在代码中使用的键开始 + +234 +00:12:26,813 --> 00:12:29,449 +在英语中 我们不需要为复数 +改变字符串的形式 + +235 +00:12:29,483 --> 00:12:33,086 +所以我们可以用 +Other 这一类别来表示它 + +236 +00:12:33,120 --> 00:12:36,690 +第一个参数会定义 +在运行时选择哪个类别 + +237 +00:12:36,723 --> 00:12:39,493 +记住 它是整数值 + +238 +00:12:39,526 --> 00:12:43,230 +参数 2 和 3 出现在格式化字符串中 + +239 +00:12:43,263 --> 00:12:47,034 +这定义了句子在运行时的样子 + +240 +00:12:47,067 --> 00:12:49,837 +西班牙语的 stringsdict +具有相同的结构 + +241 +00:12:49,870 --> 00:12:54,007 +只是我们同时提供了 +单数和复数的翻译 + +242 +00:12:56,143 --> 00:13:00,180 +我们现在已经用代码格式化了数据 +并将其放入一个句子中 + +243 +00:13:00,214 --> 00:13:02,449 +stringsdict 文件包含复数规则 + +244 +00:13:02,482 --> 00:13:05,886 +这样西班牙语翻译 +使用的就是正确的语法 + +245 +00:13:05,919 --> 00:13:08,989 +有时候 提供一个适合所有语言的 +完全本地化的 UI + +246 +00:13:09,022 --> 00:13:11,491 +是很有挑战性的 + +247 +00:13:11,525 --> 00:13:15,128 +同样 连接字符串在英语中可以运作 + +248 +00:13:15,162 --> 00:13:18,732 +但在其他语言中可能会产生 +令人惊讶的结果 + +249 +00:13:18,765 --> 00:13:21,401 +这可能需要一些全面的代码来完成 + +250 +00:13:21,435 --> 00:13:24,938 +但现在您知道了该如何 +使它能适合所有用户 + +251 +00:13:24,972 --> 00:13:28,242 +有时候您的字符串会处在依赖关系中 + +252 +00:13:28,275 --> 00:13:30,978 +或者在 App 使用的模块中 + +253 +00:13:31,011 --> 00:13:34,081 +或者您也可以使用 +Swift 软件包将自己的代码 + +254 +00:13:34,114 --> 00:13:36,083 +分发给其他开发人员 + +255 +00:13:36,116 --> 00:13:39,019 +让我们看看本地化的新内容 + +256 +00:13:39,052 --> 00:13:41,922 +要定义一个 Swift 软件包 +您需要通过使用 + +257 +00:13:41,955 --> 00:13:45,025 +Swift 本身来声明结构和构建配置 + +258 +00:13:45,058 --> 00:13:48,061 +如果您有面向用户的内容 +您可以使用参数 + +259 +00:13:48,095 --> 00:13:51,331 +default Localization 来声明 +内容使用英语 + +260 +00:13:51,365 --> 00:13:53,267 +作为主要语言 + +261 +00:13:53,300 --> 00:13:58,272 +这类似于指定 App 项目的 +开发语言 + +262 +00:13:58,305 --> 00:14:01,875 +Xcode 现在会读取这个参数 +并识别出 + +263 +00:14:01,909 --> 00:14:05,445 +您对提供本地化体验感兴趣 + +264 +00:14:05,479 --> 00:14:10,250 +因此 它将向 Product 菜单添加 +Export Localizations 选项 + +265 +00:14:10,284 --> 00:14:13,120 +您可能已习惯于在您的主 App 中 +使用这个功能 + +266 +00:14:13,153 --> 00:14:16,123 +现在它也适用于 Swift 软件包 + +267 +00:14:16,156 --> 00:14:21,161 +如果您点击 Export 那么Xcode就会 +读取您的代码并提取所有的字符串 + +268 +00:14:21,195 --> 00:14:25,532 +它们被放在 .xcloc 文件中 +发送给翻译人员 + +269 +00:14:25,566 --> 00:14:28,702 +要将本地化后的内容导入到包中 +需要使用 + +270 +00:14:28,735 --> 00:14:30,404 +Import Localization + +271 +00:14:30,437 --> 00:14:34,675 +Xcode 会将本地化后的文件 +放到包中正确的文件路径里 + +272 +00:14:34,708 --> 00:14:39,580 +现在 本地化一个 Swift 软件包的 +工作流程和本地化您的 App 是一样的 + +273 +00:14:41,615 --> 00:14:44,451 +但是记住 在 Swift 软件包中 +加载一个字符串 + +274 +00:14:44,484 --> 00:14:47,387 +需要指定 bundle 参数 + +275 +00:14:47,421 --> 00:14:50,357 +您可以在演讲 +“Swift package: + +276 +00:14:50,390 --> 00:14:54,328 +resources and localization”中 +了解到更多 + +277 +00:14:54,361 --> 00:14:58,432 +如果您是一个以 Swift 软件包 +形式发布的库的作者 + +278 +00:14:58,465 --> 00:15:01,635 +您现在有了一个保持项目更新 + +279 +00:15:01,668 --> 00:15:05,572 +并使本地化成为您工作流程的 +常规部分的简单方法 + +280 +00:15:05,606 --> 00:15:08,442 +您在您的项目中投入了 +大量的精力和关注 + +281 +00:15:08,475 --> 00:15:12,513 +将其本地化将为所有客户端 +节省大量的时间 + +282 +00:15:12,546 --> 00:15:14,581 +这一定能让它脱颖而出 + +283 +00:15:14,615 --> 00:15:16,750 +让人们意识到您是在额外付出 + +284 +00:15:16,783 --> 00:15:19,486 +用您的软件为他们提供最好的体验 + +285 +00:15:19,520 --> 00:15:21,221 +所以去大胆地告诉他们吧 + +286 +00:15:21,255 --> 00:15:25,192 +对您所支持的语言保持开放的态度 + +287 +00:15:25,225 --> 00:15:27,928 +作为一名 App 开发人员 +您需要特别考虑 + +288 +00:15:27,961 --> 00:15:29,162 +依赖关系 + +289 +00:15:29,196 --> 00:15:32,065 +不仅仅是从代码质量的角度考虑 + +290 +00:15:32,099 --> 00:15:34,935 +您使用的组件应该支持 +与 App 其他部分 + +291 +00:15:34,968 --> 00:15:39,072 +相同的语言和高质量的翻译 + +292 +00:15:39,106 --> 00:15:42,943 +在第三方代码没有本地化到 +所需语言的情况下 + +293 +00:15:42,976 --> 00:15:45,546 +您仍然可以创建包的本地副本 + +294 +00:15:45,579 --> 00:15:48,448 +并在那里更新本地化 + +295 +00:15:48,482 --> 00:15:53,120 +确保您用了 App 支持的语言 +测试的它所有部分 + +296 +00:15:53,153 --> 00:15:56,023 +这样就可以确保里面没有 + +297 +00:15:56,056 --> 00:15:58,792 +不适合用户语言的 UI 元素 + +298 +00:15:58,825 --> 00:16:00,894 +大多数情况下 翻译后的字符串 + +299 +00:16:00,928 --> 00:16:03,497 +会比对应的英文字符串更长或更短 + +300 +00:16:03,530 --> 00:16:06,400 +这总是会影响 App 的布局 + +301 +00:16:06,433 --> 00:16:08,836 +让我们看看这对天气 App +意味着什么 + +302 +00:16:08,869 --> 00:16:11,071 +这是用英语运行的 App + +303 +00:16:11,104 --> 00:16:14,408 +在右边您可以看到 +它用阿拉伯语运行的情况 + +304 +00:16:14,441 --> 00:16:17,778 +很明显 不仅翻译适应了语言 + +305 +00:16:17,811 --> 00:16:22,616 +布局也遵循了适当的方向性 + +306 +00:16:22,649 --> 00:16:25,319 +如果您想了解更多 + +307 +00:16:25,352 --> 00:16:28,021 +关于如何创建适用于 +所有语言的布局以及哪些类型的符号 + +308 +00:16:28,055 --> 00:16:30,023 +提供了本地化的替代方案 + +309 +00:16:30,057 --> 00:16:32,492 +以及对于从右到左书写的语言 +还需要考虑什么 + +310 +00:16:32,526 --> 00:16:36,363 +请务必观看演讲 +“Get it right... to left” + +311 +00:16:37,731 --> 00:16:40,000 +在这里 右边是用印度语 +运行的 App + +312 +00:16:40,033 --> 00:16:42,302 +让我们放大看看 + +313 +00:16:42,336 --> 00:16:45,639 +这种语言的脚本往往更高 + +314 +00:16:45,672 --> 00:16:48,342 +如果您仔细观察 +您会发现标签的高度 + +315 +00:16:48,375 --> 00:16:50,944 +也相应地调整了 + +316 +00:16:50,978 --> 00:16:52,946 +系统会自动完成这项任务 + +317 +00:16:52,980 --> 00:16:54,615 +您所要做的就是确保您没有 + +318 +00:16:54,648 --> 00:16:57,784 +给 UI 元素一个固定的高度 + +319 +00:16:57,818 --> 00:17:00,621 +不要假定所有文字 +都能在 44 像素点以内 + +320 +00:17:00,654 --> 00:17:03,690 +只是因为它足以放下英文字符串 + +321 +00:17:03,724 --> 00:17:07,661 +请根据不同的情况 +做好您的文字会更高的准备 + +322 +00:17:09,062 --> 00:17:11,398 +回到主视图 滚上去 + +323 +00:17:11,431 --> 00:17:13,333 +天气有一个 10 天的预测视图 + +324 +00:17:13,367 --> 00:17:15,736 +便于查看下个星期的天气 + +325 +00:17:17,304 --> 00:17:20,374 +这个屏幕上最引人注目的 + +326 +00:17:20,407 --> 00:17:24,044 +是它如何根据最长的标签 +动态调整元素的位置 + +327 +00:17:24,077 --> 00:17:28,215 +在英语中 Today 比所有 +工作日名称的缩写都要长 + +328 +00:17:28,248 --> 00:17:31,552 +但是 在西班牙语中 +它们都有三个字符宽 + +329 +00:17:31,585 --> 00:17:36,123 +而在希腊语中 +“今天”一词的长度几乎是两倍 + +330 +00:17:36,156 --> 00:17:40,227 +不过 在所有语言中 +天气图标都是垂直对齐的 + +331 +00:17:40,260 --> 00:17:43,697 +这意味着它们与相邻元素之间 +没有固定的间隔 + +332 +00:17:43,730 --> 00:17:47,534 +而是根据 “最长工作日” 标签流动 + +333 +00:17:47,568 --> 00:17:51,104 +在创建与国际化配合良好的布局时 + +334 +00:17:51,138 --> 00:17:55,008 +您应该始终记住标签需要灵活 + +335 +00:17:55,042 --> 00:17:58,745 +您已经看到了使它们 +在垂直方向上具有灵活性是多么重要 + +336 +00:17:58,779 --> 00:18:03,283 +但同时也准备好标签会随着 +较长的译文在水平方向上增长 + +337 +00:18:03,317 --> 00:18:06,286 +在某些布局中 比如在这个例子中 + +338 +00:18:06,320 --> 00:18:07,921 +要适应这一点可能是一个挑战 + +339 +00:18:07,955 --> 00:18:10,591 +但今年 SwiftUI 增加了对 Grid 的支持 + +340 +00:18:10,624 --> 00:18:15,195 +这是一个新的视图 +可以帮助您更易于构建这种布局 + +341 +00:18:15,229 --> 00:18:18,999 +让我们仔细看看如何使用 Grid + +342 +00:18:19,032 --> 00:18:22,002 +首先 您要先用前导对齐来声明 Grid + +343 +00:18:22,035 --> 00:18:25,405 +这意味着 UI 元素在从左到右 +书写的语言中 + +344 +00:18:25,439 --> 00:18:26,940 +会从屏幕的左边开始 + +345 +00:18:26,974 --> 00:18:31,512 +在从右到左的书写语言中 +会从屏幕的右边开始 + +346 +00:18:31,545 --> 00:18:35,382 +然后 为每个水平组 +添加一个 GridRow + +347 +00:18:35,415 --> 00:18:38,752 +最后 要声明行内容 + +348 +00:18:38,785 --> 00:18:41,622 +这就是创建这个高级布局 +所需要的全部内容 + +349 +00:18:41,655 --> 00:18:43,557 +当标签需要更多的空间时 + +350 +00:18:43,590 --> 00:18:48,061 +Capsule 可以缩小大小 +因为它是最灵活的元素 + +351 +00:18:48,095 --> 00:18:50,964 +SwiftUI 完成了所有繁重的工作 +如测量 + +352 +00:18:50,998 --> 00:18:55,569 +改变大小 定位视图 这完全是自动的 + +353 +00:18:55,602 --> 00:18:58,672 +另一个挑战是在有限的空间内 +比如在 Apple Watch 上 + +354 +00:18:58,705 --> 00:19:02,576 +使用较长的翻译作品制作视图 + +355 +00:19:02,609 --> 00:19:05,045 +在这里 Tip Function 的 +德语翻译太长了 + +356 +00:19:05,078 --> 00:19:07,581 +无法放在一行里 + +357 +00:19:07,614 --> 00:19:11,685 +我们不用为解决这个问题删除 +文本旁的图标 以腾出更多空间 + +358 +00:19:11,718 --> 00:19:15,556 +解决方案是在需要时 +使用两行或两行以上的文本 + +359 +00:19:15,589 --> 00:19:17,958 +这是默认行为 + +360 +00:19:17,991 --> 00:19:19,660 +如果没有足够的空间 我们不鼓励您 + +361 +00:19:19,693 --> 00:19:22,896 +改变或者隐藏界面元素 + +362 +00:19:22,930 --> 00:19:25,365 +通常会有一种调整布局的方法 + +363 +00:19:25,399 --> 00:19:28,902 +使其能够适应语言的需要 + +364 +00:19:28,936 --> 00:19:31,205 +邮件 App 以一种创造性的方式 +做到了这一点 + +365 +00:19:32,206 --> 00:19:37,077 +在表单演示中 有四个按钮 +能对这封电子邮件执行行动 + +366 +00:19:37,110 --> 00:19:40,247 +当一个按钮标题的翻译太长时 + +367 +00:19:40,280 --> 00:19:43,050 +我们不用剪切文本或换行 + +368 +00:19:43,083 --> 00:19:45,819 +这会让视图看起来不平衡 + +369 +00:19:45,853 --> 00:19:49,089 +相反 整个布局从水平堆(Horizontal Stack) + +370 +00:19:49,122 --> 00:19:51,758 +过渡为了两行垂直堆 + +371 +00:19:53,060 --> 00:19:55,662 +今年 SwiftUI 增加了另一个 + +372 +00:19:55,696 --> 00:19:58,098 +很棒的工具 +使创建动态布局更容易 + +373 +00:19:58,131 --> 00:20:00,033 +它就是 ViewThatFits + +374 +00:20:00,067 --> 00:20:02,469 +本质上 它会允许您在空间受限和 + +375 +00:20:02,503 --> 00:20:05,939 +视图不适合的情况下提供替代的布局 + +376 +00:20:07,608 --> 00:20:10,277 +您只需声明您的视图彼此独立 + +377 +00:20:10,310 --> 00:20:12,980 +并把它们放在 ViewThatFits 中 + +378 +00:20:13,013 --> 00:20:16,383 +SwiftUI 会自动检测视图 +是否不适合 但不会进行剪切 + +379 +00:20:16,416 --> 00:20:19,486 +并切换到提供的下一个视图 + +380 +00:20:19,520 --> 00:20:22,389 +记住 您应该只切换布局 + +381 +00:20:22,422 --> 00:20:26,627 +仅仅因为翻译太长而隐藏视图 +是一种糟糕的做法 + +382 +00:20:26,660 --> 00:20:30,430 +这会使得用户更难使用 UI + +383 +00:20:30,464 --> 00:20:33,400 +通过灵活的布局 +尽量为所有界面元素 + +384 +00:20:33,433 --> 00:20:34,868 +腾出空间 + +385 +00:20:36,303 --> 00:20:38,672 +这不仅有助于本地化 + +386 +00:20:38,705 --> 00:20:41,875 +当用户喜欢更小或更大的文本 + +387 +00:20:41,909 --> 00:20:45,412 +并且使用不同的设备时 +这种布局也会很有效 + +388 +00:20:45,445 --> 00:20:48,882 +如果您想要了解更多今年 +SwiftUI 出色的新布局功能 + +389 +00:20:48,916 --> 00:20:53,787 +我建议您观看演讲 +“Compose custom layouts with SwiftUI” + +390 +00:20:53,820 --> 00:20:56,123 +拥有不同的辅助功能偏好设置 + +391 +00:20:56,156 --> 00:20:59,560 +和本地化文本对布局来说是一个挑战 + +392 +00:20:59,593 --> 00:21:02,496 +界面元素可以更高更宽 + +393 +00:21:02,529 --> 00:21:05,599 +调整布局以适应它可能是一项挑战 + +394 +00:21:05,632 --> 00:21:08,335 +但今年有了 SwiftUI 就容易多了 + +395 +00:21:09,770 --> 00:21:13,273 +我希望您从这次演讲中了解到 +在支持其他语言时 + +396 +00:21:13,307 --> 00:21:16,143 +在代码中构造字符串 +是很有挑战性的 + +397 +00:21:16,176 --> 00:21:18,612 +要听取全球用户和测试人员的反馈 + +398 +00:21:18,645 --> 00:21:23,183 +确保所有人都能顺利使用 + +399 +00:21:23,217 --> 00:21:25,252 +在 Swift 中格式化值很简单 + +400 +00:21:25,285 --> 00:21:27,921 +通常只需要一行代码 + +401 +00:21:27,955 --> 00:21:30,290 +这样 格式化的值 + +402 +00:21:30,324 --> 00:21:32,426 +就会自动地顺应用户的偏好设置 + +403 +00:21:33,727 --> 00:21:35,529 +当您提供一个 Swift 软件包时 + +404 +00:21:35,562 --> 00:21:38,165 +利用新的 Xcode 本地化工作流程 + +405 +00:21:38,198 --> 00:21:42,336 +为您的客户端提供完全本地化的体验 + +406 +00:21:42,369 --> 00:21:44,538 +现在 无论使用 SwiftUI 与否 + +407 +00:21:44,571 --> 00:21:47,407 +您的布局都应该能够适应翻译文本 + +408 +00:21:47,441 --> 00:21:49,476 +和辅助功能的设置 + +409 +00:21:49,510 --> 00:21:52,312 +使用您的布局工具使布局灵活 + +410 +00:21:52,346 --> 00:21:55,315 +而不隐藏界面元素 + +411 +00:21:55,349 --> 00:21:57,818 +最后 您的用户会对此感到庆幸的 + +412 +00:21:57,851 --> 00:22:00,954 +因为他们会希望您的 App +能融入他们的生活 + +413 +00:22:00,988 --> 00:22:03,857 +这包括尊重他们的语言 + +414 +00:22:03,891 --> 00:22:06,093 +现在 我正期待着一个 +阳光灿烂的星期 + +415 +00:22:06,126 --> 00:22:07,728 +请享受余下的 WWDC + +416 +00:22:07,761 --> 00:22:09,630 +感谢观看 + diff --git "a/zho/2022 Session 10115 What\342\200\231s new in CloudKit Console.srt" "b/zho/2022 Session 10115 What\342\200\231s new in CloudKit Console.srt" new file mode 100644 index 0000000..46a1410 --- /dev/null +++ "b/zho/2022 Session 10115 What\342\200\231s new in CloudKit Console.srt" @@ -0,0 +1,633 @@ +1 +00:00:00,000 --> 00:00:03,036 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,036 --> 00:00:10,143 +♪ + +3 +00:00:10,143 --> 00:00:12,045 +嗨 我是 Alex Young + +4 +00:00:12,045 --> 00:00:15,516 +我是 iCloud 开发者 +体验团队的工程师 + +5 +00:00:15,516 --> 00:00:18,418 +CloudKit 是一种 +打造完美体验的简单方法 + +6 +00:00:18,418 --> 00:00:21,321 +它让用户可以轻松地在设备之间 + +7 +00:00:21,321 --> 00:00:23,624 +同步数据 + +8 +00:00:23,624 --> 00:00:26,460 +CloudKit Console 提供了可让您 +使用 App 的架构和数据 + +9 +00:00:26,460 --> 00:00:30,731 +的工具 从而让这一切变得更加简单 + +10 +00:00:30,731 --> 00:00:33,600 +我将分享 +CloudKit Console 的一些更新 + +11 +00:00:33,600 --> 00:00:35,369 +这些更新有助于您了解和调试 + +12 +00:00:35,369 --> 00:00:38,172 +App 的架构和数据 + +13 +00:00:38,172 --> 00:00:41,909 +首先 我将介绍如何使用隐藏容器 + +14 +00:00:41,909 --> 00:00:44,311 +然后深入探讨 +一种使用 iCloud 帐户 + +15 +00:00:44,311 --> 00:00:46,713 +查看记录的新方法 + +16 +00:00:46,713 --> 00:00:48,415 +最后 对于使用共享区域 + +17 +00:00:48,415 --> 00:00:51,151 +有一些很棒的更新 + +18 +00:00:51,151 --> 00:00:54,054 +常见的做法是在开发过程中 +创建大量容器 + +19 +00:00:54,054 --> 00:00:56,657 +而以后只关注其中的少数几个 + +20 +00:00:56,657 --> 00:00:57,891 +通过新的隐藏容器功能 + +21 +00:00:57,891 --> 00:01:00,694 +您可以更好地组织这个过程 + +22 +00:01:00,694 --> 00:01:02,629 +在 CloudKit Console 中 + +23 +00:01:02,629 --> 00:01:05,499 +您可以选择 +哪些容器是隐藏的或可见的 + +24 +00:01:05,499 --> 00:01:07,234 +隐藏容器不仅 + +25 +00:01:07,234 --> 00:01:09,403 +在 Console 内的列表中不可见 + +26 +00:01:09,403 --> 00:01:11,538 +在所有开发者工具中也不可见 + +27 +00:01:11,538 --> 00:01:13,740 +包括 Xcode + +28 +00:01:13,740 --> 00:01:16,009 +更妙之处在于 当一个容器被隐藏时 + +29 +00:01:16,009 --> 00:01:17,878 +它适用于团队级别 + +30 +00:01:17,878 --> 00:01:20,681 +这意味着您的所有测试和原型容器 + +31 +00:01:20,681 --> 00:01:24,084 +不再乱放在队友的视图上 + +32 +00:01:24,084 --> 00:01:28,655 +现在我将打开 Console +并使用这个新功能 + +33 +00:01:28,655 --> 00:01:30,424 +登录 Console 后 + +34 +00:01:30,424 --> 00:01:34,428 +从顶级导航栏打开容器选择器 + +35 +00:01:34,428 --> 00:01:36,830 +然后单击 +“Manage Containers”(管理容器) + +36 +00:01:36,830 --> 00:01:39,466 +这将显示一个新菜单 允许您切换 + +37 +00:01:39,466 --> 00:01:43,704 +当前团队中每个容器的可见性 + +38 +00:01:43,704 --> 00:01:46,773 +对于隶属于多个团队的用户 您可以 + +39 +00:01:46,773 --> 00:01:49,576 +使用右上角的帐户菜单 +在各团队之间切换 + +40 +00:01:49,576 --> 00:01:51,378 +然后 您还可以 + +41 +00:01:51,378 --> 00:01:54,381 +继续在其他团队中隐藏容器 + +42 +00:01:54,381 --> 00:01:57,351 +这是来自 WWDC 21 的容器 + +43 +00:01:57,351 --> 00:01:59,052 +我们不再需要它了 + +44 +00:01:59,052 --> 00:02:01,655 +我可以把它隐藏 就像这样 + +45 +00:02:01,655 --> 00:02:04,691 +如果您在 Xcode 中 +刷新容器列表 + +46 +00:02:04,691 --> 00:02:08,962 +您会看到这些容器在那里也隐藏起来 + +47 +00:02:08,962 --> 00:02:11,565 +我将告诉您 +Console 的一个新增功能 + +48 +00:02:11,565 --> 00:02:13,901 +此功能让您可以 +使用 iCloud 帐户查看数据 + +49 +00:02:13,901 --> 00:02:16,236 +而不是使用开发者帐户 + +50 +00:02:16,236 --> 00:02:19,806 +这称为 Act As iCloud + +51 +00:02:19,806 --> 00:02:23,010 +有时 可能很难理解为什么某些用户 + +52 +00:02:23,010 --> 00:02:27,814 +在处理其私人数据库中的数据时 +会遇到问题 + +53 +00:02:27,814 --> 00:02:29,650 +现在您可以 + +54 +00:02:29,650 --> 00:02:34,087 +用单独的 iCloud 帐户登录 +以查看私人数据 + +55 +00:02:34,087 --> 00:02:36,156 +当您使用 iCloud +帐户登录时 + +56 +00:02:36,156 --> 00:02:39,226 +CloudKit Console 的 +查询工具会 + +57 +00:02:39,226 --> 00:02:42,229 +按照您从该帐户的角度 +所期望的那样工作 + +58 +00:02:42,229 --> 00:02:43,497 +这有助于您 + +59 +00:02:43,497 --> 00:02:47,868 +代表用户排查开发和生产问题 + +60 +00:02:47,868 --> 00:02:49,503 +我将在 Console 中 +演示这个过程 + +61 +00:02:49,503 --> 00:02:52,573 +以说明此功能是如何工作的 + +62 +00:02:52,573 --> 00:02:55,709 +这个查询 +是使用我的开发者帐户执行的 + +63 +00:02:55,709 --> 00:02:57,778 +我要切换到 iCloud 帐户 + +64 +00:02:57,778 --> 00:03:01,014 +以显示查询结果如何变化 + +65 +00:03:01,014 --> 00:03:05,052 +首先 导航到 +Act As iCloud 帐户菜单项 + +66 +00:03:05,052 --> 00:03:07,254 +这将打开一个对话框 + +67 +00:03:07,254 --> 00:03:09,256 +允许您以 iCloud 帐户登录 + +68 +00:03:09,256 --> 00:03:13,393 +当我登录时 +Console 的上下文将会改变 + +69 +00:03:13,393 --> 00:03:15,729 +现在您会在页面顶部看到一个横幅 + +70 +00:03:15,729 --> 00:03:17,965 +所有后续操作都将 + +71 +00:03:17,965 --> 00:03:22,402 +使用 iCloud 帐户 +而不是开发者帐户执行 + +72 +00:03:22,402 --> 00:03:24,705 +您可以查询记录并查看区域 + +73 +00:03:24,705 --> 00:03:28,909 +但不能执行架构操作 + +74 +00:03:28,909 --> 00:03:30,911 +如您所见 此查询的结果 + +75 +00:03:30,911 --> 00:03:34,882 +是 iCloud 帐户的查询结果 +而不是开发者帐户的查询结果 + +76 +00:03:34,882 --> 00:03:36,950 +如切换到另一个容器或环境 + +77 +00:03:36,950 --> 00:03:39,586 +则将停止充当 iCloud 帐户 + +78 +00:03:39,586 --> 00:03:41,555 +您也可以单击横幅中的按钮 + +79 +00:03:41,555 --> 00:03:45,325 +来停止 Act As 会话 + +80 +00:03:45,325 --> 00:03:48,228 +请记住 充当 iCloud 帐户的功能 +适用于记录 + +81 +00:03:48,228 --> 00:03:50,597 +而不是架构 因此该功能仅适用于 + +82 +00:03:50,597 --> 00:03:53,100 +Console 的数据部分 + +83 +00:03:53,100 --> 00:03:57,371 +尝试访问架构 +将停止 Act As 会话 + +84 +00:03:57,371 --> 00:03:59,273 +此功能有助于您更好地了解 + +85 +00:03:59,273 --> 00:04:01,375 +数据在生产中的使用方式 + +86 +00:04:01,375 --> 00:04:06,280 +更有效地调查与数据相关的错误 + +87 +00:04:06,280 --> 00:04:08,615 +充当另一个帐户时 + +88 +00:04:08,615 --> 00:04:10,851 +加密字段对您来说仍然不可读 + +89 +00:04:10,851 --> 00:04:14,721 +只有拥有数据的原始用户 +才能解密这些字段 + +90 +00:04:14,721 --> 00:04:16,490 +这是设计使然 +有助于 iCloud + +91 +00:04:16,490 --> 00:04:19,193 +保持高水平的安全性和隐私性 + +92 +00:04:19,193 --> 00:04:23,163 +并确保敏感数据的安全 + +93 +00:04:23,163 --> 00:04:27,234 +接下来 我将展示 +如何在 Console 中共享区域 + +94 +00:04:27,234 --> 00:04:29,303 +CloudKit 共享是 + +95 +00:04:29,303 --> 00:04:33,006 +一种在 App 用户之间 +安全共享记录的方式 + +96 +00:04:33,006 --> 00:04:34,808 +这是安全的共享方式 + +97 +00:04:34,808 --> 00:04:36,577 +其使用的权限允许 App + +98 +00:04:36,577 --> 00:04:40,914 +确定参与者的读写访问权限 + +99 +00:04:40,914 --> 00:04:42,883 +将共享定义为公共或私人 + +100 +00:04:42,883 --> 00:04:47,888 +可进一步控制参与者访问 + +101 +00:04:47,888 --> 00:04:52,192 +区域共享的工作方式是 +将规则应用于区域中的每一条记录 + +102 +00:04:52,192 --> 00:04:54,862 +共享区域 +具有 CloudKit 共享记录 + +103 +00:04:54,862 --> 00:04:57,431 +其中包含访问区域中每条记录 + +104 +00:04:57,431 --> 00:04:59,600 +的选项 + +105 +00:04:59,600 --> 00:05:03,604 +共享区域不能有现存的共享记录 + +106 +00:05:03,604 --> 00:05:06,240 +共享区域支持标准的 + +107 +00:05:06,240 --> 00:05:10,210 +公共和私人区域共享选项 + +108 +00:05:10,210 --> 00:05:13,113 +公共共享区域使拥有共享代码的 + +109 +00:05:13,113 --> 00:05:15,616 +每个用户都可以看到所有记录 + +110 +00:05:15,616 --> 00:05:19,019 +任何拥有短共享代码的用户 +都可以加入此共享 + +111 +00:05:19,019 --> 00:05:21,688 +对于应该易于在用户之间共享 + +112 +00:05:21,688 --> 00:05:25,459 +且没有严格访问控制的记录 +这是最理想的 + +113 +00:05:25,459 --> 00:05:28,595 +私人共享区域具有额外的安全层 + +114 +00:05:28,595 --> 00:05:30,898 +因为成员必须在参与者列表中 + +115 +00:05:30,898 --> 00:05:33,667 +才能加入共享 + +116 +00:05:33,667 --> 00:05:36,036 +CloudKit Console 有几个 + +117 +00:05:36,036 --> 00:05:38,005 +创建和查看区域共享的新工具 + +118 +00:05:38,005 --> 00:05:40,240 +可帮助您更好地了解共享区域 + +119 +00:05:40,240 --> 00:05:43,844 +并在开发和生产过程中使用它们 + +120 +00:05:43,844 --> 00:05:48,582 +现在让我们创建一个区域共享 +以便您了解它是如何工作的 + +121 +00:05:48,582 --> 00:05:52,186 +导航到 Zones (区域) +然后选择要共享的区域 + +122 +00:05:52,186 --> 00:05:54,588 +单击详细信息视图中的 + +123 +00:05:54,588 --> 00:05:56,356 +“Configure zone wide sharing...” +(配置区域范围的共享…) 按钮 + +124 +00:05:56,356 --> 00:05:58,091 +这将显示一个表单 可让您决定 + +125 +00:05:58,091 --> 00:06:01,461 +是选择公共共享还是私人共享 + +126 +00:06:01,461 --> 00:06:03,964 +公共区域有一个额外的权限选项 + +127 +00:06:03,964 --> 00:06:07,301 +可用于创建只读或读写共享 + +128 +00:06:07,301 --> 00:06:09,403 +对于私人共享 + +129 +00:06:09,403 --> 00:06:11,505 +权限是在参与者级别定义的 + +130 +00:06:11,505 --> 00:06:14,508 +我要创建一个私人共享 就像这样 + +131 +00:06:16,510 --> 00:06:19,146 +共享区域后 +您将会看到一个简短的唯一 ID + +132 +00:06:19,146 --> 00:06:23,951 +可将其发送给要加入共享的参与者 + +133 +00:06:23,951 --> 00:06:26,153 +可以使用 Records (记录) +页面中的 + +134 +00:06:26,153 --> 00:06:28,555 +“Accept Shared Record” +(接受共享记录) 菜单选项 + +135 +00:06:28,555 --> 00:06:31,058 +在控制台中加入共享区域 + +136 +00:06:31,058 --> 00:06:32,860 +现在 在此区域中创建的任何记录 + +137 +00:06:32,860 --> 00:06:35,996 +都将自动共享 + +138 +00:06:35,996 --> 00:06:38,765 +现在您已经看到了 +CloudKit Console 的这些更新 + +139 +00:06:38,765 --> 00:06:42,269 +请通过隐藏容器来整理您的容器列表 + +140 +00:06:42,269 --> 00:06:44,938 +试用 Act As iCloud +来查看 + +141 +00:06:44,938 --> 00:06:48,342 +不同 iCloud 帐户的记录 +并尝试进行区域共享 + +142 +00:06:48,342 --> 00:06:51,945 +以更轻松地共享多个记录 + +143 +00:06:51,945 --> 00:06:54,581 +我们希望这些工具能让您 +更好地了解您的架构 + +144 +00:06:54,581 --> 00:06:57,518 +并排查 App 中的问题 + +145 +00:06:57,518 --> 00:07:01,188 +从而使 CloudKit 更容易使用 + +146 +00:07:01,188 --> 00:07:03,624 +谢谢 祝您在 WWDC +度过愉快的时光 + +147 +00:07:03,624 --> 00:07:07,661 +♪ + diff --git a/zho/2022 Session 10117 Enhance voice communication with Push to Talk.srt b/zho/2022 Session 10117 Enhance voice communication with Push to Talk.srt new file mode 100644 index 0000000..f218397 --- /dev/null +++ b/zho/2022 Session 10117 Enhance voice communication with Push to Talk.srt @@ -0,0 +1,1905 @@ +1 +00:00:00,000 --> 00:00:03,403 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,403 --> 00:00:09,476 +♪ + +3 +00:00:09,476 --> 00:00:11,111 +Kevin Ferrell: +嗨 我是 Kevin + +4 +00:00:11,111 --> 00:00:14,348 +是研究 PushToTalk +新框架的工程师 + +5 +00:00:14,348 --> 00:00:16,950 +该框架能使 iOS 上的 App + +6 +00:00:16,950 --> 00:00:19,052 +体验对讲机式的系统 + +7 +00:00:19,052 --> 00:00:21,188 +稍后我的同事 +Trevor 会加入进来 + +8 +00:00:21,188 --> 00:00:24,057 +介绍如何在您的 App 中 +使用这个新框架 + +9 +00:00:24,057 --> 00:00:27,261 +增强语音交流的方法 + +10 +00:00:27,261 --> 00:00:29,496 +首先我来介绍一下 +PushToTalk 框架 + +11 +00:00:29,496 --> 00:00:32,432 +并解释它如何适配您的 App + +12 +00:00:32,432 --> 00:00:34,935 +其次 我们会介绍 +如何为 PushToTalk + +13 +00:00:34,935 --> 00:00:37,237 +配置您的 App + +14 +00:00:37,237 --> 00:00:38,972 +随后 Trevor 将详细介绍 + +15 +00:00:38,972 --> 00:00:43,010 +使用此框架传输和接收音频的方法 + +16 +00:00:43,010 --> 00:00:46,013 +最后 Trevor 将总结增强 + +17 +00:00:46,013 --> 00:00:48,582 +一键通用户体验的最佳实践 + +18 +00:00:48,582 --> 00:00:52,486 +同时如何为您的用户节省电量 + +19 +00:00:52,486 --> 00:00:54,588 +我先从 +PushToTalk 新框架的 + +20 +00:00:54,588 --> 00:00:57,457 +关键功能讲起 + +21 +00:00:57,457 --> 00:00:59,693 +PushToTalk 框架能使您 + +22 +00:00:59,693 --> 00:01:03,197 +在 iOS 上构建一类 +新的音频通信 App + +23 +00:01:03,197 --> 00:01:07,768 +为您的用户提供对讲机式的体验 + +24 +00:01:07,768 --> 00:01:09,603 +一键通 App + +25 +00:01:09,603 --> 00:01:12,739 +在需要快速沟通的领域有很多用途 + +26 +00:01:12,739 --> 00:01:15,976 +如医疗保健和紧急服务 + +27 +00:01:15,976 --> 00:01:18,412 +为了实现良好的一键通体验 + +28 +00:01:18,412 --> 00:01:20,347 +用户需要某种方法来快速访问 + +29 +00:01:20,347 --> 00:01:23,784 +音频传输功能 同时还能看到 + +30 +00:01:23,784 --> 00:01:26,186 +谁在回应他们 + +31 +00:01:26,186 --> 00:01:28,222 +与此同时 一键通 App + +32 +00:01:28,222 --> 00:01:30,824 +必须节能 确保用户 + +33 +00:01:30,824 --> 00:01:35,195 +在使用 App 时 +能保持一整天的电量 + +34 +00:01:35,195 --> 00:01:38,098 +PushToTalk 框架 +为您提供 API + +35 +00:01:38,098 --> 00:01:39,833 +以利用系统 UI + +36 +00:01:39,833 --> 00:01:42,436 +用户无需直接启动您的 App + +37 +00:01:42,436 --> 00:01:45,572 +就可访问系统的任何位置 + +38 +00:01:45,572 --> 00:01:48,509 +系统 UI 允许用户快速激活 + +39 +00:01:48,509 --> 00:01:51,111 +音频传输 +这将在后台启动您的 App + +40 +00:01:51,111 --> 00:01:55,616 +录制并将音频传输到您的服务器 + +41 +00:01:55,616 --> 00:01:58,252 +当您的 App 从服务器 +播放音频时 + +42 +00:01:58,252 --> 00:01:59,586 +该系统会显示说话人 + +43 +00:01:59,586 --> 00:02:02,523 +从而为用户增加透明度 + +44 +00:02:02,523 --> 00:02:04,625 +PushToTalk 框架 +实现这一点的方法 + +45 +00:02:04,625 --> 00:02:07,628 +是通过引入新的推送通知类型 + +46 +00:02:07,628 --> 00:02:11,965 +当有新的音频 +可供播放时就会通知您的 App + +47 +00:02:11,965 --> 00:02:14,368 +您的 App 收到此通知后 + +48 +00:02:14,368 --> 00:02:15,903 +它就会在后台启动 + +49 +00:02:15,903 --> 00:02:19,273 +以便传输和播放音频 + +50 +00:02:19,273 --> 00:02:22,075 +PushToTalk 框架可与 + +51 +00:02:22,075 --> 00:02:25,012 +现有的端到端通信方法 + +52 +00:02:25,012 --> 00:02:27,147 +以及后端基础设施兼容 + +53 +00:02:27,147 --> 00:02:28,649 +如果您已在 + +54 +00:02:28,649 --> 00:02:30,851 +您的 App 中实施了 +一键通工作流程 + +55 +00:02:30,851 --> 00:02:32,386 +那么应该很容易 + +56 +00:02:32,386 --> 00:02:36,590 +将 PushToTalk 框架 +集成到您现有的代码中 + +57 +00:02:36,590 --> 00:02:38,525 +该框架允许您的 App 使用 + +58 +00:02:38,525 --> 00:02:41,261 +自己的音频编码和传输程序 + +59 +00:02:41,261 --> 00:02:43,897 +从而在用户之间传输音频 + +60 +00:02:43,897 --> 00:02:46,400 +这为您的 App +处理音频传输方式 + +61 +00:02:46,400 --> 00:02:49,536 +提供了灵活性 + +62 +00:02:49,536 --> 00:02:51,905 +并能与其他平台兼容 + +63 +00:02:51,905 --> 00:02:53,907 +最后 许多一键通 App + +64 +00:02:53,907 --> 00:02:56,043 +依赖无线蓝牙配件 + +65 +00:02:56,043 --> 00:02:59,146 +触发录音和传输功能 + +66 +00:02:59,146 --> 00:03:02,015 +您的 App 可使用 +CoreBluetooth 框架 + +67 +00:03:02,015 --> 00:03:04,151 +持续与上述配件集成使用 + +68 +00:03:04,151 --> 00:03:07,654 +并且可以在 +PushToTalk 中触发录音 + +69 +00:03:07,654 --> 00:03:10,123 +如果您正在构建 +您的第一个一键通 App + +70 +00:03:10,123 --> 00:03:12,426 +在开始构建代码时请牢记 + +71 +00:03:12,426 --> 00:03:15,262 +以上集成注意事项 + +72 +00:03:15,262 --> 00:03:17,164 +在开始详细介绍 + +73 +00:03:17,164 --> 00:03:18,999 +PushToTalk +新框架的代码之前 + +74 +00:03:18,999 --> 00:03:21,435 +我们想先展示一键通 + +75 +00:03:21,435 --> 00:03:24,771 +在您 App 中的运行方式 + +76 +00:03:24,771 --> 00:03:26,240 +我和 Trevor +构建了一个演示 App + +77 +00:03:26,240 --> 00:03:28,509 +来展示 +PushToTalk 的工作原理 + +78 +00:03:28,509 --> 00:03:30,344 +首先 我将点击加入按钮 + +79 +00:03:30,344 --> 00:03:32,179 +连接到一键通会话 + +80 +00:03:32,179 --> 00:03:36,316 +我们称之为频道 + +81 +00:03:36,316 --> 00:03:37,618 +加入频道后 + +82 +00:03:37,618 --> 00:03:41,588 +我可以接收或将音频 +发送给频道上的其他成员 + +83 +00:03:41,588 --> 00:03:42,990 +Trevor 和我们的同事 + +84 +00:03:42,990 --> 00:03:44,658 +加入了同一频道 + +85 +00:03:44,658 --> 00:03:47,628 +这样我们就可全天候交流 + +86 +00:03:47,628 --> 00:03:49,963 +使用麦克风按钮 我可以直接 + +87 +00:03:49,963 --> 00:03:52,566 +从 App 传输音频 +而 PushToTalk 框架 + +88 +00:03:52,566 --> 00:03:54,868 +可允许我从系统中的任何位置 + +89 +00:03:54,868 --> 00:03:59,072 +访问传输功能 + +90 +00:03:59,072 --> 00:04:00,974 +当有激活的一键通频道时 + +91 +00:04:00,974 --> 00:04:03,644 +一个蓝色药丸状图标 +就会出现在状态栏中 + +92 +00:04:03,644 --> 00:04:08,949 +点击该图标可显示系统 UI + +93 +00:04:08,949 --> 00:04:11,919 +系统 UI 会显示 +我所加入的一键通频道的名称 + +94 +00:04:11,919 --> 00:04:14,721 +以及 App 提供的用于 + +95 +00:04:14,721 --> 00:04:18,892 +帮助用户快速识别频道的图像 + +96 +00:04:18,892 --> 00:04:20,561 +我可以按住通话按钮 + +97 +00:04:20,561 --> 00:04:22,729 +向频道传输音频 + +98 +00:04:22,729 --> 00:04:24,998 +然后等待系统提示音 + +99 +00:04:24,998 --> 00:04:27,267 +我就可以开始说话了 + +100 +00:04:29,069 --> 00:04:32,072 +[铃声] 嘿 Trevor + +101 +00:04:32,072 --> 00:04:37,444 +您准备好展示您的 +WWDC 幻灯片了吗?完毕 + +102 +00:04:37,444 --> 00:04:39,746 +Trevor Sheridan: +当我的设备收到 Kevin 的信息时 + +103 +00:04:39,746 --> 00:04:42,716 +就显示出一个包含 +他的名字和图像的通知 + +104 +00:04:42,716 --> 00:04:48,789 +公开透明地显示谁向我发送了消息 + +105 +00:04:48,789 --> 00:04:50,724 +一旦我启动系统 UI + +106 +00:04:50,724 --> 00:04:52,860 +我就可以快速回复 +Kevin 的消息 + +107 +00:04:52,860 --> 00:04:56,196 +或者继续做我手头的事 先不回复 + +108 +00:04:56,196 --> 00:05:01,001 +我不想让 Kevin 久等 +所以我现在就回复 + +109 +00:05:01,001 --> 00:05:04,104 +[铃声]嘿 Kevin +再有几分钟就准备好了 + +110 +00:05:04,104 --> 00:05:07,241 +完毕 + +111 +00:05:07,241 --> 00:05:09,810 +Kevin:PushToTalk +系统 UI 也可 + +112 +00:05:09,810 --> 00:05:13,213 +从锁屏界面访问 用户无需解锁设备 + +113 +00:05:13,213 --> 00:05:16,316 +即可接收回复消息 + +114 +00:05:21,288 --> 00:05:27,160 +[铃声]好的 +一会儿见 完毕 [铃声] + +115 +00:05:27,160 --> 00:05:29,429 +我们已经讨论了 +PushToTalk 的工作原理 + +116 +00:05:29,429 --> 00:05:33,100 +现在来介绍一下如何 +将框架集成到您自己的 App 中 + +117 +00:05:33,100 --> 00:05:35,335 +您需要对您的 Xcode 项目 + +118 +00:05:35,335 --> 00:05:39,439 +进行一些修改以支持 +PushToTalk 框架 + +119 +00:05:39,439 --> 00:05:43,177 +首先 您需要添加 +新的一键通后台模式 + +120 +00:05:43,177 --> 00:05:45,379 +这能让您的 App +在响应一键通事件时 + +121 +00:05:45,379 --> 00:05:48,982 +可以在后台运行 + +122 +00:05:48,982 --> 00:05:52,019 +接下来 您还需 +为您的 App 添加 + +123 +00:05:52,019 --> 00:05:55,689 +一键通功能以启用框架功能 + +124 +00:05:55,689 --> 00:05:59,293 +需要推送通知功能 +才能允许 APNS + +125 +00:05:59,293 --> 00:06:01,028 +在后台唤醒您的 App + +126 +00:06:01,028 --> 00:06:04,097 +播放接收到的音频 + +127 +00:06:04,097 --> 00:06:06,834 +最后 您的 App +必须向用户请求 + +128 +00:06:06,834 --> 00:06:10,137 +录音许可 并在其 +Info.plist 文件中 + +129 +00:06:10,137 --> 00:06:12,973 +包含麦克风用途字符串 + +130 +00:06:12,973 --> 00:06:16,076 +现在我们准备开始集成代码 + +131 +00:06:16,076 --> 00:06:18,212 +一键通工作流程的第一步 + +132 +00:06:18,212 --> 00:06:19,947 +是加入一个频道 + +133 +00:06:19,947 --> 00:06:21,882 +频道代表并描述了 + +134 +00:06:21,882 --> 00:06:24,785 +到系统的一键通会话 + +135 +00:06:24,785 --> 00:06:28,388 +您的 App 通过 +频道管理器与频道交互 + +136 +00:06:28,388 --> 00:06:31,425 +频道管理器是 +您的 App 加入频道 + +137 +00:06:31,425 --> 00:06:33,861 +执行发送和接收音频等操作的 + +138 +00:06:33,861 --> 00:06:37,231 +主要界面 + +139 +00:06:37,231 --> 00:06:39,867 +您加入频道后 一键通系统 UI + +140 +00:06:39,867 --> 00:06:43,904 +立即启用 您的 App +也会收到一个 APNS 设备令牌 + +141 +00:06:43,904 --> 00:06:47,207 +可在频道的整个生命周期中使用 + +142 +00:06:47,207 --> 00:06:49,943 +您必须先加入频道 +然后才能开始传输 + +143 +00:06:49,943 --> 00:06:52,579 +和接收音频 + +144 +00:06:52,579 --> 00:06:54,882 +第一步是使用类初始化器 + +145 +00:06:54,882 --> 00:06:57,451 +创建频道管理器 + +146 +00:06:57,451 --> 00:06:59,453 +该初始化器要求您提供 + +147 +00:06:59,453 --> 00:07:04,057 +频道管理器委托和频道恢复委托 + +148 +00:07:04,057 --> 00:07:05,993 +多次调用初始化器 + +149 +00:07:05,993 --> 00:07:08,795 +会导致相同的共享实例被返回 + +150 +00:07:08,795 --> 00:07:11,131 +但我们建议您在实例变量中 + +151 +00:07:11,131 --> 00:07:13,233 +存储频道管理器 + +152 +00:07:13,233 --> 00:07:15,636 +App 在您 ApplicationDelegate 的 + +153 +00:07:15,636 --> 00:07:17,871 +didFinishLaunchingWithOptions 方法中 + +154 +00:07:17,871 --> 00:07:19,573 +启动期间 +尽快初始化您的频道管理器 + +155 +00:07:19,573 --> 00:07:22,776 +非常重要 + +156 +00:07:22,776 --> 00:07:26,213 +这样可以确保快速初始化频道管理器 + +157 +00:07:26,213 --> 00:07:28,415 +以便恢复现有频道 + +158 +00:07:28,415 --> 00:07:30,751 +推送通知也会在您的 App + +159 +00:07:30,751 --> 00:07:33,654 +后台启动时发送过来 + +160 +00:07:33,654 --> 00:07:35,722 +现在我们准备加入一个频道 + +161 +00:07:35,722 --> 00:07:37,558 +当有人通过 +您的 App 加入频道时 + +162 +00:07:37,558 --> 00:07:40,527 +您必须提供一个 +识别频道的 UUID + +163 +00:07:40,527 --> 00:07:44,298 +和一个描述系统频道的描述符 + +164 +00:07:44,298 --> 00:07:47,701 +在该频道的 +整个生命周期中 与管理器交互时 + +165 +00:07:47,701 --> 00:07:50,103 +使用的是相同的 UUID + +166 +00:07:50,103 --> 00:07:53,340 +描述符包括名称和图像 + +167 +00:07:53,340 --> 00:07:56,143 +提供独特的图像来代表频道 + +168 +00:07:56,143 --> 00:07:58,879 +可让您的用户在与系统交互时 + +169 +00:07:58,879 --> 00:08:01,615 +更易识别频道 + +170 +00:08:01,615 --> 00:08:04,818 +您的 App 通过 +在频道管理器上调用 + +171 +00:08:04,818 --> 00:08:06,720 +requestJoin 方法加入频道 + +172 +00:08:06,720 --> 00:08:09,022 +请注意 只有当您的 App + +173 +00:08:09,022 --> 00:08:12,125 +在前台运行时才可加入频道 + +174 +00:08:12,125 --> 00:08:15,028 +当您的 App 加入频道时 +频道管理器委托的 + +175 +00:08:15,028 --> 00:08:18,198 +didJoinChannel 方法将被调用 + +176 +00:08:18,198 --> 00:08:20,367 +这个委托方法是您的指示 + +177 +00:08:20,367 --> 00:08:23,070 +表明您的 App 已加入频道 + +178 +00:08:23,070 --> 00:08:24,471 +此外 该委托的 + +179 +00:08:24,471 --> 00:08:27,608 +receivedEphemeralPushToken +方法也将被调用 + +180 +00:08:27,608 --> 00:08:30,277 +同时 APNS 推送令牌可用于 + +181 +00:08:30,277 --> 00:08:34,181 +将一键通通知发送到该设备 + +182 +00:08:34,181 --> 00:08:35,849 +此令牌只在 + +183 +00:08:35,849 --> 00:08:38,685 +一键通频道的生命周期内有效 + +184 +00:08:38,685 --> 00:08:41,889 +请注意 APNS 推送令牌 +长度可变 + +185 +00:08:41,889 --> 00:08:45,859 +但您不应将其长度 +硬编码到您的 App 中 + +186 +00:08:45,859 --> 00:08:49,129 +频道加入请求可能会失败 + +187 +00:08:49,129 --> 00:08:51,031 +例如在另一个频道处于激活状态时 + +188 +00:08:51,031 --> 00:08:53,834 +尝试加入频道 + +189 +00:08:53,834 --> 00:08:56,637 +若发生此类情况 +错误处理程序将被调用 + +190 +00:08:56,637 --> 00:09:00,374 +错误会指明失败原因 + +191 +00:09:00,374 --> 00:09:01,942 +当用户离开频道时 + +192 +00:09:01,942 --> 00:09:04,945 +将调用 +委托的 didLeaveChannel 方法 + +193 +00:09:04,945 --> 00:09:07,314 +您的用户可通过您的 App + +194 +00:09:07,314 --> 00:09:10,250 +以编程方式请求离开频道 + +195 +00:09:10,250 --> 00:09:12,553 +或者用户可以点击系统 UI 中的 + +196 +00:09:12,553 --> 00:09:14,321 +“离开频道”按钮离开 + +197 +00:09:14,321 --> 00:09:16,657 +通道管理器委托有一个关联的 + +198 +00:09:16,657 --> 00:09:19,626 +LeaveChannel +错误处理方法将被调用 + +199 +00:09:19,626 --> 00:09:23,230 +来应对请求离开频道失败的情况 + +200 +00:09:23,230 --> 00:09:25,632 +每当您的 App 被终止 +或在设备重启后 + +201 +00:09:25,632 --> 00:09:28,202 +再次启动时 +PushToTalk 都支持恢复 + +202 +00:09:28,202 --> 00:09:30,771 +之前打开的频道 + +203 +00:09:30,771 --> 00:09:33,006 +为让系统实现这一点 + +204 +00:09:33,006 --> 00:09:37,077 +您必须提供频道描述符来更新系统 + +205 +00:09:37,077 --> 00:09:39,146 +这里我们可以用一个辅助方法来获取 + +206 +00:09:39,146 --> 00:09:43,517 +在恢复后的委托中缓存的频道描述符 + +207 +00:09:43,517 --> 00:09:45,853 +为保持系统响应 + +208 +00:09:45,853 --> 00:09:48,722 +您应尽快从该方法返回 + +209 +00:09:48,722 --> 00:09:51,892 +且不应执行 +任何长时间运行或阻塞的任务 + +210 +00:09:51,892 --> 00:09:53,360 +比如检索您 + +211 +00:09:53,360 --> 00:09:56,230 +频道描述符的网络请求 + +212 +00:09:56,230 --> 00:09:59,166 +在您的一键通会话的 +整个生命周期中 + +213 +00:09:59,166 --> 00:10:01,068 +您应在频道信息发生变化时 + +214 +00:10:01,068 --> 00:10:04,905 +为描述符提供更新 + +215 +00:10:04,905 --> 00:10:06,974 +您还应使用服务状态对象 + +216 +00:10:06,974 --> 00:10:09,576 +告知系统您的网络连接或 + +217 +00:10:09,576 --> 00:10:12,312 +服务器是否可用 + +218 +00:10:12,312 --> 00:10:15,549 +这里 我们正在更新频道的描述符 + +219 +00:10:15,549 --> 00:10:16,717 +您可在您需要 + +220 +00:10:16,717 --> 00:10:20,654 +更新频道名称或图像时调用此方法 + +221 +00:10:20,654 --> 00:10:22,856 +在此示例中 我们向系统提供更新 + +222 +00:10:22,856 --> 00:10:25,259 +以表明 App 与其服务器的 + +223 +00:10:25,259 --> 00:10:28,462 +连接处于重新连接状态 + +224 +00:10:28,462 --> 00:10:30,731 +这也会相应更新系统 UI + +225 +00:10:30,731 --> 00:10:32,833 +阻止用户在服务状态为 + +226 +00:10:32,833 --> 00:10:37,104 +正在连接或断开时传输音频 + +227 +00:10:37,104 --> 00:10:38,939 +重新建立连接后 + +228 +00:10:38,939 --> 00:10:42,242 +您应将服务状态更新为“就绪” + +229 +00:10:42,242 --> 00:10:44,845 +现在我们来看 +使用 PushToTalk + +230 +00:10:44,845 --> 00:10:46,780 +发送和接收音频的方法 + +231 +00:10:46,780 --> 00:10:49,583 +[铃声] Trevor +您准备好讲解 + +232 +00:10:49,583 --> 00:10:51,451 +该 API 的其余内容了吗? + +233 +00:10:51,451 --> 00:10:52,653 +完毕 + +234 +00:10:55,088 --> 00:10:59,326 +[铃声] Trevor:准备好了 +发送 完毕 + +235 +00:10:59,326 --> 00:11:00,327 +[铃声] + +236 +00:11:01,862 --> 00:11:03,463 +我们已经看到了配置 + +237 +00:11:03,463 --> 00:11:05,098 +PushToTalk 框架的方法 + +238 +00:11:05,098 --> 00:11:09,670 +现在我们来探索 +传输和接收音频的方法 + +239 +00:11:09,670 --> 00:11:12,172 +PushToTalk 框架的 +核心功能 + +240 +00:11:12,172 --> 00:11:16,210 +是让您的用户快速传输音频 + +241 +00:11:16,210 --> 00:11:18,045 +用户可以从您的 App 中 + +242 +00:11:18,045 --> 00:11:19,580 +或从系统一键通 UI 中 + +243 +00:11:19,580 --> 00:11:22,616 +开始音频传输 + +244 +00:11:22,616 --> 00:11:25,152 +如果您的 App 可通过 +CoreBluetooth + +245 +00:11:25,152 --> 00:11:26,753 +支持蓝牙配件 + +246 +00:11:26,753 --> 00:11:29,656 +您也可在后台开始传输 + +247 +00:11:29,656 --> 00:11:33,927 +响应外围设备的特性变化 + +248 +00:11:33,927 --> 00:11:36,663 +传输时 +PushToTalk 框架 + +249 +00:11:36,663 --> 00:11:39,032 +会解锁设备麦克风 + +250 +00:11:39,032 --> 00:11:41,668 +并激活您 App 的音频会话 + +251 +00:11:41,668 --> 00:11:44,771 +在后台启用音频录制 + +252 +00:11:44,771 --> 00:11:48,108 +我们再来详细研究一下这个过程 + +253 +00:11:48,108 --> 00:11:51,311 +要从您的 App 中 +开始传输 您可调用 + +254 +00:11:51,311 --> 00:11:54,815 +requestBeginTransmitting 函数 + +255 +00:11:54,815 --> 00:11:57,951 +每当您的 App 在前台运行 +或对蓝牙外围设备特性的变化 + +256 +00:11:57,951 --> 00:11:59,720 +做出反应时 + +257 +00:11:59,720 --> 00:12:03,490 +都可以调用该函数 + +258 +00:12:03,490 --> 00:12:06,426 +若系统无法开始传输 + +259 +00:12:06,426 --> 00:12:07,661 +委托的 + +260 +00:12:07,661 --> 00:12:11,198 +failedToBeginTransmittingInChannel 方法 + +261 +00:12:11,198 --> 00:12:13,467 +将被调用并说明失败原因 + +262 +00:12:13,467 --> 00:12:17,738 +例如 若用户正在进行蜂窝呼叫 + +263 +00:12:17,738 --> 00:12:22,409 +他们就无法开启一键通传输 + +264 +00:12:22,409 --> 00:12:23,944 +要停止传输 + +265 +00:12:23,944 --> 00:12:28,248 +可调用频道管理器的 +stopTransmitting 方法 + +266 +00:12:28,248 --> 00:12:31,785 +为处理尝试停止传输时的失败情况 + +267 +00:12:31,785 --> 00:12:34,888 +例如当用户未处于传输状态时 + +268 +00:12:34,888 --> 00:12:37,758 +频道管理器委托有一个关联的 + +269 +00:12:37,758 --> 00:12:41,528 +failedToStopTransmittingInChannel 方法 + +270 +00:12:41,528 --> 00:12:44,898 +无论您是从 App 内开始传输 + +271 +00:12:44,898 --> 00:12:48,068 +还是用户从系统 UI 开始传输 + +272 +00:12:48,068 --> 00:12:50,470 +您的频道管理器委托都将收到 + +273 +00:12:50,470 --> 00:12:53,674 +“已开始传输”回调 + +274 +00:12:53,674 --> 00:12:56,577 +传输源将传递给方法 + +275 +00:12:56,577 --> 00:12:58,545 +并指明传输 + +276 +00:12:58,545 --> 00:13:00,347 +是从系统 UI + +277 +00:13:00,347 --> 00:13:04,685 +编程 API 还是 +硬件按钮事件开始 + +278 +00:13:04,685 --> 00:13:06,486 +一旦开始传输 + +279 +00:13:06,486 --> 00:13:10,123 +系统将为您的 App +激活音频会话 + +280 +00:13:10,123 --> 00:13:13,660 +这就是可以开始录制的信号 + +281 +00:13:13,660 --> 00:13:19,433 +您不应开始或停止自己的音频会话 + +282 +00:13:19,433 --> 00:13:23,103 +传输结束时 您的频道管理器委托 + +283 +00:13:23,103 --> 00:13:25,172 +将收到结束传输 + +284 +00:13:25,172 --> 00:13:29,109 +和音频会话停用事件 + +285 +00:13:29,109 --> 00:13:32,312 +请记住 当您的传输处于激活状态时 + +286 +00:13:32,312 --> 00:13:36,016 +您的音频会话可能会被其他来源中断 + +287 +00:13:36,016 --> 00:13:38,852 +例如电话和 FaceTime 通话 + +288 +00:13:38,852 --> 00:13:42,456 +这需要您在 App 内进行处理 + +289 +00:13:42,456 --> 00:13:45,225 +PushToTalk 框架 +还允许您的 App + +290 +00:13:45,225 --> 00:13:48,061 +在后台接收和播放来自 + +291 +00:13:48,061 --> 00:13:49,963 +其他用户的音频 + +292 +00:13:49,963 --> 00:13:53,767 +此过程依赖一种新的 +专门针对一键通 App 的 + +293 +00:13:53,767 --> 00:13:56,937 +Apple 推送通知类型 + +294 +00:13:56,937 --> 00:13:59,740 +当您的一键通服务器有新的音频 + +295 +00:13:59,740 --> 00:14:02,643 +供用户接收时 +它应使用您在加入频道时 + +296 +00:14:02,643 --> 00:14:06,446 +接收到的设备推送令牌 + +297 +00:14:06,446 --> 00:14:09,583 +向用户发送一键通通知 + +298 +00:14:09,583 --> 00:14:12,953 +当您的 App 收到推送通知时 + +299 +00:14:12,953 --> 00:14:16,423 +必须向框架报告有源扬声器 + +300 +00:14:16,423 --> 00:14:18,192 +这将导致系统激活 + +301 +00:14:18,192 --> 00:14:23,297 +您 App 的音频会话 +并允许其开始播放 + +302 +00:14:23,297 --> 00:14:25,032 +新的一键通通知 + +303 +00:14:25,032 --> 00:14:28,569 +类似于 iOS 上的其他通知类型 + +304 +00:14:28,569 --> 00:14:31,438 +而且您必须设置某些具体属性 + +305 +00:14:31,438 --> 00:14:34,942 +以启用您的 +一键通 App 推送功能 + +306 +00:14:34,942 --> 00:14:39,613 +首先 APNS 推送类型 +必须在请求头中 + +307 +00:14:39,613 --> 00:14:41,949 +设置为“pushtotalk” + +308 +00:14:41,949 --> 00:14:45,352 +其次 APNS 主题头必须设置为 + +309 +00:14:45,352 --> 00:14:47,554 +您 App 的捆绑标识符 + +310 +00:14:47,554 --> 00:14:52,292 +并在末尾加上 +“.voip-ptt”后缀 + +311 +00:14:52,292 --> 00:14:55,128 +推送负载可以包含 + +312 +00:14:55,128 --> 00:14:57,297 +与您 App 相关的自定义密钥 + +313 +00:14:57,297 --> 00:14:59,399 +比如有源扬声器的名称 + +314 +00:14:59,399 --> 00:15:02,336 +或会话已结束 App 应退出 + +315 +00:15:02,336 --> 00:15:05,539 +一键通频道的标识 + +316 +00:15:05,539 --> 00:15:10,010 +“aps”属性的主体可以留空 + +317 +00:15:10,010 --> 00:15:13,013 +此外 与其他与通信相关的 + +318 +00:15:13,013 --> 00:15:14,214 +推送类型一样 + +319 +00:15:14,214 --> 00:15:18,619 +一键通有效负载的 +APNS 优先级应为 10 + +320 +00:15:18,619 --> 00:15:20,821 +以便要求立即推送 + +321 +00:15:20,821 --> 00:15:25,626 +APNS 到期时间应为零 以阻止 + +322 +00:15:25,626 --> 00:15:29,563 +与未来推送不再相关的陈旧推送 + +323 +00:15:29,563 --> 00:15:32,699 +当您的服务器发送一键通通知时 + +324 +00:15:32,699 --> 00:15:35,135 +您的 App 将在后台启动 + +325 +00:15:35,135 --> 00:15:39,173 +传入的推送委托方法将被调用 + +326 +00:15:39,173 --> 00:15:41,108 +当您收到推送有效负载时 + +327 +00:15:41,108 --> 00:15:43,944 +您需构建一个推送结果类型 + +328 +00:15:43,944 --> 00:15:46,480 +指示推送通知后 + +329 +00:15:46,480 --> 00:15:50,017 +应该执行的操作 + +330 +00:15:50,017 --> 00:15:52,819 +为表明远程用户正在讲话 + +331 +00:15:52,819 --> 00:15:54,555 +需返回一个推送结果 其中包含 + +332 +00:15:54,555 --> 00:15:57,124 +活跃参与者的信息 + +333 +00:15:57,124 --> 00:16:01,128 +包括他们的名称和可选图像 + +334 +00:16:01,128 --> 00:16:02,429 +这会让系统 + +335 +00:16:02,429 --> 00:16:05,098 +设置频道的活跃参与者 + +336 +00:16:05,098 --> 00:16:08,735 +表明频道处于接收模式 + +337 +00:16:08,735 --> 00:16:11,572 +然后系统将激活您的音频会话 + +338 +00:16:11,572 --> 00:16:13,907 +调用 didActivateaudioSession + +339 +00:16:13,907 --> 00:16:15,342 +委托方法 + +340 +00:16:15,342 --> 00:16:17,544 +您应在开始播放之前 + +341 +00:16:17,544 --> 00:16:19,847 +等待该方法被调用 + +342 +00:16:19,847 --> 00:16:21,849 +如果您的服务器决定 + +343 +00:16:21,849 --> 00:16:24,284 +不应再让用户加入频道 + +344 +00:16:24,284 --> 00:16:27,054 +它可能会在推送 +有效负载时表明这一点 + +345 +00:16:27,054 --> 00:16:31,558 +您可为其返回 +leaveChannel 推送结果 + +346 +00:16:31,558 --> 00:16:33,594 +务必注意 您应尽快 + +347 +00:16:33,594 --> 00:16:36,029 +从此方法中返回 +PTPushResult + +348 +00:16:36,029 --> 00:16:40,434 +而非阻塞线程 + +349 +00:16:40,434 --> 00:16:43,203 +如果您尝试设置 +正在活跃的远程参与者 + +350 +00:16:43,203 --> 00:16:45,873 +但却没有将参与者的图像存储在本地 + +351 +00:16:45,873 --> 00:16:48,609 +您可返回一个只有说话者名称的 + +352 +00:16:48,609 --> 00:16:50,911 +activeRemoteParticipant + +353 +00:16:50,911 --> 00:16:53,747 +然后在单独的线程上下载其图像 + +354 +00:16:53,747 --> 00:16:55,782 +一旦检索到图像 + +355 +00:16:55,782 --> 00:16:57,951 +即可在频道管理器上 + +356 +00:16:57,951 --> 00:17:00,787 +调用 setActiveRemoteParticipant + +357 +00:17:00,787 --> 00:17:03,323 +以更新 activeRemoteParticipant + +358 +00:17:03,323 --> 00:17:05,726 +当远程参与者说完话后 + +359 +00:17:05,726 --> 00:17:08,695 +您应将 +activeRemoteParticipant 设置为 nil + +360 +00:17:08,695 --> 00:17:11,665 +这会向系统表明您不再 + +361 +00:17:11,665 --> 00:17:13,767 +在频道上接收音频 + +362 +00:17:13,767 --> 00:17:17,771 +且系统应该停用您的音频会话 + +363 +00:17:17,771 --> 00:17:20,941 +这也会更新系统一键通 UI + +364 +00:17:20,941 --> 00:17:24,278 +允许用户再次发送 + +365 +00:17:24,278 --> 00:17:25,712 +现在我们已经介绍了 + +366 +00:17:25,712 --> 00:17:28,782 +将 PushToTalk +集成到您 App 中的基本操作 + +367 +00:17:28,782 --> 00:17:30,784 +我们再来看优化用户体验 + +368 +00:17:30,784 --> 00:17:32,819 +以及保存电量的 + +369 +00:17:32,819 --> 00:17:35,489 +最佳操作 + +370 +00:17:37,291 --> 00:17:39,993 +PushToTalk 框架 +提供了一个系统 UI + +371 +00:17:39,993 --> 00:17:42,396 +供用户开始传输 + +372 +00:17:42,396 --> 00:17:46,066 +并从系统内的任何地方离开频道 + +373 +00:17:46,066 --> 00:17:50,003 +此外 该框架非常灵活 允许您 + +374 +00:17:50,003 --> 00:17:52,673 +在您的 App 前台运行时 + +375 +00:17:52,673 --> 00:17:56,143 +使用自定义的一键通 UI + +376 +00:17:56,143 --> 00:17:57,344 +PushToTalk 框架 + +377 +00:17:57,344 --> 00:18:00,147 +可利用共享系统资源 + +378 +00:18:00,147 --> 00:18:02,549 +系统上一次只能激活一个 + +379 +00:18:02,549 --> 00:18:04,384 +一键通 App + +380 +00:18:04,384 --> 00:18:07,621 +且一键通通信可被 + +381 +00:18:07,621 --> 00:18:11,758 +蜂窝电话 FaceTime 通话 +和 VoIP 通话取代 + +382 +00:18:11,758 --> 00:18:14,461 +您的 App 应妥善处理 +PushToTalk 失败情况 + +383 +00:18:14,461 --> 00:18:18,832 +并相应做出响应 + +384 +00:18:18,832 --> 00:18:21,201 +如前所述 PushToTalk 框架 + +385 +00:18:21,201 --> 00:18:23,337 +为您激活和停用 + +386 +00:18:23,337 --> 00:18:25,639 +音频会话 + +387 +00:18:25,639 --> 00:18:27,708 +但是 您仍应配置 + +388 +00:18:27,708 --> 00:18:30,944 +音频会话类别 +以便在您的 App 启动时 + +389 +00:18:30,944 --> 00:18:33,981 +播放和录制音频 + +390 +00:18:33,981 --> 00:18:36,383 +系统提供了内置音效 + +391 +00:18:36,383 --> 00:18:39,620 +以便在传输时提醒用户 + +392 +00:18:39,620 --> 00:18:42,389 +麦克风已激活还是已停用 + +393 +00:18:42,389 --> 00:18:44,191 +您不应 + +394 +00:18:44,191 --> 00:18:46,693 +自定义音效 + +395 +00:18:46,693 --> 00:18:49,396 +监控您的 App 并响应 + +396 +00:18:49,396 --> 00:18:53,133 +AVAudioSession 通知也很重要 + +397 +00:18:53,133 --> 00:18:54,902 +例如会话中断 + +398 +00:18:54,902 --> 00:18:57,471 +路线变化和故障等 + +399 +00:18:57,471 --> 00:18:59,806 +同系统上的其他音频 App 一样 + +400 +00:18:59,806 --> 00:19:01,775 +您的一键通 App 也可能会受到 + +401 +00:19:01,775 --> 00:19:05,612 +这些音频会话事件的影响 + +402 +00:19:05,612 --> 00:19:07,614 +优化您的 App + +403 +00:19:07,614 --> 00:19:09,583 +以保存电量非常重要 + +404 +00:19:09,583 --> 00:19:11,785 +PushToTalk 框架 +在需要时会 + +405 +00:19:11,785 --> 00:19:13,887 +为您的 App 提供后台运行时间 + +406 +00:19:13,887 --> 00:19:17,191 +比如在传输和接收音频时就会如此 + +407 +00:19:17,191 --> 00:19:19,459 +当用户没有使用您的 App 时 + +408 +00:19:19,459 --> 00:19:24,031 +它将被系统暂停以保存电量 + +409 +00:19:24,031 --> 00:19:26,633 +您不应自己激活或停用 + +410 +00:19:26,633 --> 00:19:28,569 +您的音频会话 + +411 +00:19:28,569 --> 00:19:32,039 +系统将适时为您处理 + +412 +00:19:32,039 --> 00:19:34,341 +音频会话激活程序 + +413 +00:19:34,341 --> 00:19:36,143 +这可确保您的音频会话 + +414 +00:19:36,143 --> 00:19:38,946 +在系统内有适当的优先级 + +415 +00:19:38,946 --> 00:19:43,383 +可在不使用时暂停 + +416 +00:19:43,383 --> 00:19:45,085 +您的一键通服务器 + +417 +00:19:45,085 --> 00:19:47,621 +应该使用新的推送通知类型 + +418 +00:19:47,621 --> 00:19:51,158 +提醒您的 App +有新的音频要播放 + +419 +00:19:51,158 --> 00:19:54,561 +或一键通会话已结束 + +420 +00:19:54,561 --> 00:19:56,530 +有关延长您的 +App 电池续航时间的 + +421 +00:19:56,530 --> 00:19:59,066 +更多信息 请参考 + +422 +00:19:59,066 --> 00:20:03,537 +“断电:减少电池消耗”讲解视频 + +423 +00:20:03,537 --> 00:20:05,906 +当您的一键通 App 在后台运行 + +424 +00:20:05,906 --> 00:20:09,276 +且 App 没有传输或接收音频时 + +425 +00:20:09,276 --> 00:20:11,945 +它将被系统暂停 + +426 +00:20:11,945 --> 00:20:13,480 +您的 App 被暂停后 + +427 +00:20:13,480 --> 00:20:17,251 +任何网络连接都将断开 + +428 +00:20:17,251 --> 00:20:19,786 +您应考虑采用 +Network.framework + +429 +00:20:19,786 --> 00:20:22,689 +和 QUIC 以减少 + +430 +00:20:22,689 --> 00:20:25,559 +建立 TLS 安全连接 + +431 +00:20:25,559 --> 00:20:28,896 +以及提高初始化连接速度所需的步骤 + +432 +00:20:28,896 --> 00:20:31,865 +Network.framework 内置支持 QUIC + +433 +00:20:31,865 --> 00:20:32,900 +想了解更多信息 请观看 + +434 +00:20:32,900 --> 00:20:36,904 +“减少网络延迟 +使 App 更灵敏”的讲解 + +435 +00:20:36,904 --> 00:20:40,674 +以了解使用 QUIC 的方法 + +436 +00:20:40,674 --> 00:20:43,043 +PushToTalk 框架能让您 + +437 +00:20:43,043 --> 00:20:44,878 +在 App 中构建 + +438 +00:20:44,878 --> 00:20:47,514 +稳固 省电 对讲机式的 + +439 +00:20:47,514 --> 00:20:49,449 +交流体验 + +440 +00:20:49,449 --> 00:20:51,652 +如果您已经拥有一个 App + +441 +00:20:51,652 --> 00:20:54,788 +可在 iOS 上实现对讲机式体验 + +442 +00:20:54,788 --> 00:20:57,124 +您可更新现有 App + +443 +00:20:57,124 --> 00:20:59,893 +以使用新的 API + +444 +00:20:59,893 --> 00:21:02,095 +如果您正在使用 +对讲机式的新 App + +445 +00:21:02,095 --> 00:21:05,999 +您应该立即使用 +PushToTalk 框架 + +446 +00:21:05,999 --> 00:21:07,968 +最后 您在开始测试新框架 + +447 +00:21:07,968 --> 00:21:10,037 +将其集成到您的 App 上时 + +448 +00:21:10,037 --> 00:21:12,639 +可向我们提交反馈 + +449 +00:21:12,639 --> 00:21:15,809 +谢谢 祝您体验 WWDC 愉快 + +450 +00:21:15,809 --> 00:21:17,344 +完毕 退出 + +451 +00:21:17,344 --> 00:21:21,815 +♪ + diff --git a/zho/2022 Session 10119 Optimize your use of Core Data and CloudKit.srt b/zho/2022 Session 10119 Optimize your use of Core Data and CloudKit.srt new file mode 100644 index 0000000..ec6c840 --- /dev/null +++ b/zho/2022 Session 10119 Optimize your use of Core Data and CloudKit.srt @@ -0,0 +1,1868 @@ +1 +00:00:01,401 --> 00:00:07,407 +[古怪的音乐] + +2 +00:00:09,309 --> 00:00:13,580 +Nick: 大家好 我叫 Gillett +是 Apple Core Data 团队的一名工程师 + +3 +00:00:14,147 --> 00:00:18,218 +在本期讲座中 我将向你展示如何 +使用开发者工具了解更多关于使用 + +4 +00:00:18,252 --> 00:00:21,722 +NSPersistentCloudKitContainer 的 +App 信息 + +5 +00:00:21,755 --> 00:00:25,492 +首先 我们将详细介绍 +如何以一种富有成效 + +6 +00:00:25,526 --> 00:00:27,761 +和具有教育意义的方式 +来探索应用程序 + +7 +00:00:28,795 --> 00:00:33,800 +然后 我们将使用一些我最喜欢的 +工具来分析应用程序的行为 + +8 +00:00:33,834 --> 00:00:37,037 +最后 我们将研究如何就使用 +NSPersistentCloudKitContainer 的 + +9 +00:00:37,070 --> 00:00:41,408 +体验提供详细的 可操作的反馈 + +10 +00:00:42,509 --> 00:00:46,313 +我喜欢把工程学想象成水循环 + +11 +00:00:46,346 --> 00:00:49,983 +通常 我从探索功能所在的空间 + +12 +00:00:50,017 --> 00:00:51,852 +开始研究其功能 + +13 +00:00:51,885 --> 00:00:57,057 +然后 根据我学到的东西 +我会使用工具和测试的组合 + +14 +00:00:57,090 --> 00:00:59,993 +在可复制的环境中分析我的工作 + +15 +00:01:00,794 --> 00:01:05,098 +最后 我会与同事和合作者 +一起回顾结果 + +16 +00:01:05,132 --> 00:01:06,400 +并收集他们的反馈 + +17 +00:01:07,134 --> 00:01:10,938 +这个循环的目标是持久地捕捉到 +我在工作中 + +18 +00:01:10,971 --> 00:01:12,506 +学到的东西 + +19 +00:01:12,539 --> 00:01:16,877 +Apple 平台包括很多工具 比如 Xcode + +20 +00:01:16,910 --> 00:01:21,949 +Instruments 和 XCTest +我用它们来获取我所学的内容 + +21 +00:01:21,982 --> 00:01:24,885 +这些工具还可以收集大量的诊断信息 + +22 +00:01:24,918 --> 00:01:28,989 +我可以用这些信息 +来提供可操作的反馈 + +23 +00:01:30,858 --> 00:01:34,628 +本讲座参考了过去几年的许多知识 + +24 +00:01:34,661 --> 00:01:37,731 +我已经讨论过 +NSPersisentCloudKitContainer + +25 +00:01:37,764 --> 00:01:41,168 +和 Core Data CloudKit 示例应用程序 +我今天将在 + +26 +00:01:41,201 --> 00:01:46,840 +“Build Apps that +share data through CloudKit and Core Data” + +27 +00:01:46,874 --> 00:01:51,211 +和 “Using Core Data with CloudKit.” +这两个讲座中详细介绍这两个应用程序 + +28 +00:01:51,245 --> 00:01:56,483 +我还将演示如何使用 +Xcode 和 Instruments 来运行测试 + +29 +00:01:56,517 --> 00:02:00,254 +以及如何使用 Device Organizer +从设备中捕获数据 + +30 +00:02:00,287 --> 00:02:03,490 +如果需要 我建议你查看讲座 + +31 +00:02:03,524 --> 00:02:05,392 +“Getting Started With Instruments” + +32 +00:02:05,425 --> 00:02:09,763 +和 “Diagnose performance issues +with the Xcode Organizer” + +33 +00:02:09,796 --> 00:02:14,735 +以更多地了解工具链的 +这两个重要部分 + +34 +00:02:14,768 --> 00:02:19,873 +好了 让我们开始本循环的 +第一部分 探索 + +35 +00:02:19,907 --> 00:02:24,178 +对我来说 探索的首要目标是学习 + +36 +00:02:24,211 --> 00:02:27,814 +我想挑战并验证 + +37 +00:02:27,848 --> 00:02:29,816 +应用程序工作原理的所有假设 + +38 +00:02:30,617 --> 00:02:34,087 +我可能会问 +如果我点击这个按钮会发生什么 + +39 +00:02:34,121 --> 00:02:39,493 +当我将数据保存到永久存储时 +NSPersistentCloudKitContainer 是否同步 + +40 +00:02:39,526 --> 00:02:43,630 +在处理大型数据集时 +应用程序是否会耗尽内存 + +41 +00:02:44,498 --> 00:02:48,669 +从 Core Data 的角度来看 +所有这些问题都受到 + +42 +00:02:48,702 --> 00:02:51,038 +应用程序处理的数据的影响 + +43 +00:02:51,071 --> 00:02:56,743 +例如 Core Data CloudKit +示例应用程序使用这个数据模型 + +44 +00:02:58,245 --> 00:03:03,383 +它管理一组帖子 其中包含 +一些标题和内容的文本字段 + +45 +00:03:04,284 --> 00:03:07,688 +帖子可以与附件 通常是图像 相关 + +46 +00:03:07,721 --> 00:03:08,889 +这些附件可能非常大 + +47 +00:03:10,324 --> 00:03:14,728 +因此 ImageData 存储在 +一组对一关系中 + +48 +00:03:14,761 --> 00:03:17,698 +以便按需加载 + +49 +00:03:17,731 --> 00:03:21,768 +我将重点研究该数据集 + +50 +00:03:21,802 --> 00:03:24,872 +特别是当我改变该数据的形状 + +51 +00:03:24,905 --> 00:03:29,443 +结构和变化时 +该示例应用程序会发生什么 + +52 +00:03:30,677 --> 00:03:36,216 +自从发布以来 该示例应用程序 +已经包含了一个内置的方法来探索它 + +53 +00:03:36,250 --> 00:03:40,487 +Generate 1000 Posts 按钮 +完全按照标签上的内容执行 + +54 +00:03:41,355 --> 00:03:44,157 +点击后 它会生成一个 +包含 1000 篇短文标题的 + +55 +00:03:44,191 --> 00:03:47,060 +样本数据集 + +56 +00:03:47,094 --> 00:03:50,931 +帖子的表格视图可以轻松处理 +这种级别的数据 + +57 +00:03:50,964 --> 00:03:54,835 +因此 我要问的下一个问题是 +如何在这个应用程序中 + +58 +00:03:54,868 --> 00:03:58,138 +探索不同形状或大小的数据集 + +59 +00:03:59,006 --> 00:04:02,376 +Generate 1000 Posts 按钮运行的是 + +60 +00:04:02,409 --> 00:04:05,078 +我所说的算法数据生成器 + +61 +00:04:05,112 --> 00:04:08,982 +算法数据生成器遵循 +一组预先确定的规则 + +62 +00:04:09,016 --> 00:04:11,852 +如 “插入 1000 个对象” + +63 +00:04:11,885 --> 00:04:17,224 +或“确保每个字段都有值 +或者没有字段有值” + +64 +00:04:17,858 --> 00:04:21,395 +事实证明 我们也是数据生成者 + +65 +00:04:21,428 --> 00:04:25,499 +我们可以在代码中 在 SQL 中 + +66 +00:04:25,532 --> 00:04:28,869 +或通过直接与应用程序交互 +来手工创建特定的数据集 + +67 +00:04:28,902 --> 00:04:31,705 +这些生成的数据集可以被保留 + +68 +00:04:31,738 --> 00:04:33,740 +以供以后使用或分析 + +69 +00:04:34,508 --> 00:04:39,213 +为了探索更大的数据集 +我可以定义一个新的数据生成器 + +70 +00:04:39,246 --> 00:04:42,850 +LargeDataGenerator +并提供一个方法 + +71 +00:04:42,883 --> 00:04:46,086 +来构建我的新数据集 +即 generateData + +72 +00:04:46,119 --> 00:04:49,890 +只需两个 for 循环 +我就可以生成一组 60 个帖子 + +73 +00:04:49,923 --> 00:04:54,094 +每个帖子都有 11 个关联的图片附件 + +74 +00:04:54,127 --> 00:04:57,231 +总共有 660 张图片 + +75 +00:04:57,264 --> 00:05:00,601 +每个图像的平均大小为 10 到 15 MB + +76 +00:05:00,634 --> 00:05:06,073 +生成的数据集消耗了近 10 GB 的数据 + +77 +00:05:06,106 --> 00:05:10,143 +通过这样一个简单的接口 +数据生成器很容易 + +78 +00:05:10,177 --> 00:05:12,246 +在这样的测试中调用 + +79 +00:05:12,279 --> 00:05:17,184 +这一行代码生成了超过 10 GB 的 +代表性数据 + +80 +00:05:17,217 --> 00:05:18,685 +供该测试使用 + +81 +00:05:20,721 --> 00:05:24,391 +此外 我们可以在测试中 +构建验证方法 + +82 +00:05:24,424 --> 00:05:27,828 +以验证数据生成器的行为是否正确 + +83 +00:05:27,861 --> 00:05:31,899 +比如断言每个帖子确实有 +11 个图像附件 + +84 +00:05:33,433 --> 00:05:37,604 +当然 如果我们不同步这些数据 + +85 +00:05:37,638 --> 00:05:39,673 +这就不是 +NSPersistentCloudKitContainer + +86 +00:05:39,706 --> 00:05:42,409 +所以让我们设计一个新的测试 +来完成这个任务 + +87 +00:05:43,911 --> 00:05:49,183 +我首先需要使用 +NSPersistentCloudKitContainer 的一个实例 + +88 +00:05:49,216 --> 00:05:52,753 +我已经创建了一个助手方法 +来简化这一过程 + +89 +00:05:52,786 --> 00:05:55,422 +接下来 +我使用 LargeDataGenerator + +90 +00:05:55,455 --> 00:05:58,559 +用所需的数据集填充容器 + +91 +00:05:59,526 --> 00:06:03,997 +最后 我等待容器完成数据导出 + +92 +00:06:04,031 --> 00:06:07,467 +在这个特定的测试中 +我最多等待 20 分钟 + +93 +00:06:07,501 --> 00:06:09,736 +以便为大数据集提供上传时间 + +94 +00:06:11,338 --> 00:06:15,108 +你们当中目光敏锐的人 +可能已经注意到 + +95 +00:06:15,142 --> 00:06:18,378 +这个测试似乎在等待不同类型的事件 + +96 +00:06:18,412 --> 00:06:21,381 +在这里 当我创建容器时 + +97 +00:06:21,415 --> 00:06:23,750 +我等待容器完成设置 + +98 +00:06:24,551 --> 00:06:29,323 +在这里 我使用我编写的助手方法 + +99 +00:06:29,356 --> 00:06:31,558 +为容器中的导出事件 +创建 XctestExpections + +100 +00:06:32,159 --> 00:06:33,493 +我们来详细了解一下 + +101 +00:06:34,494 --> 00:06:38,165 +此方法将所需的事件类型和 + +102 +00:06:38,198 --> 00:06:41,568 +NSPersistentCloudKitContainer 的 +实例作为参数 + +103 +00:06:41,602 --> 00:06:45,939 +它使用 XCTestCase 的 +expectationForNotification 方法 + +104 +00:06:45,973 --> 00:06:50,511 +来观察 NSPersistentCloudKitContainer 的 +eventChanged 通知 + +105 +00:06:50,544 --> 00:06:55,749 +从而为容器中的每个持久性存储 +创建一个预期 + +106 +00:06:55,782 --> 00:06:57,951 +在通知处理程序模块中 + +107 +00:06:57,985 --> 00:06:59,953 +我验证传入事件的类型 + +108 +00:06:59,987 --> 00:07:01,388 +是否与这个预期所针对的 + +109 +00:07:01,421 --> 00:07:04,358 +特定存储的类型一致 + +110 +00:07:04,391 --> 00:07:06,727 +并通过检查 endDate + +111 +00:07:06,760 --> 00:07:08,195 +不等于 nil 来完成 + +112 +00:07:08,962 --> 00:07:10,731 +通过使用这种技术 + +113 +00:07:10,764 --> 00:07:14,501 +我们可以将测试中的控制点与来自 + +114 +00:07:14,535 --> 00:07:17,471 +NSPersistentCloudKitContainer 的 +事件紧密关联起来 + +115 +00:07:17,504 --> 00:07:24,011 +回到测试中 我添加了一个新容器 +来导入刚刚导出的数据 + +116 +00:07:24,044 --> 00:07:26,446 +这项技术使用了一种技巧 + +117 +00:07:26,480 --> 00:07:27,848 +它使用空存储文件创建 + +118 +00:07:27,881 --> 00:07:31,919 +NSPersistentCloudKitContainer 的 +新实例 + +119 +00:07:31,952 --> 00:07:33,954 +这使得测试可以利用 + +120 +00:07:33,987 --> 00:07:37,157 +NSPersisentCloudKitContainer 的 +第一次导入 + +121 +00:07:37,191 --> 00:07:42,296 +来探索当设备下载 +所有这些数据时会发生什么 + +122 +00:07:42,329 --> 00:07:45,966 +现在 测试很顺利 但有时我想知道 + +123 +00:07:45,999 --> 00:07:48,702 +数据集在应用程序中是如何工作的 + +124 +00:07:48,735 --> 00:07:52,806 +为此 我可以将数据生成器 +绑定到用户界面 + +125 +00:07:52,840 --> 00:07:55,375 +就像我们在示例应用程序中 +所做的那样 + +126 +00:07:56,076 --> 00:07:59,479 +当我点击 Generate Large Data +按钮时 我可以看到 + +127 +00:07:59,513 --> 00:08:02,482 +数据生成器填充数据集 + +128 +00:08:02,516 --> 00:08:06,186 +在另一个设备上 +当 NSPersistentCloudKitContainer + +129 +00:08:06,220 --> 00:08:12,226 +下载生成的数据时 +我可以看到表视图被填充 + +130 +00:08:12,259 --> 00:08:16,697 +点击单个帖子 我可以看到附件下载 + +131 +00:08:16,730 --> 00:08:18,799 +和增量填充 + +132 +00:08:18,832 --> 00:08:22,102 +就像该应用程序用户所做的那样 + +133 +00:08:22,669 --> 00:08:26,440 +此特定用户界面由警报控制器驱动 + +134 +00:08:27,107 --> 00:08:30,644 +LargeDataGenerator 的简单接口 +使得仅使用这两行代码 + +135 +00:08:30,677 --> 00:08:34,781 +就可以轻松地添加新的警报操作 + +136 +00:08:34,815 --> 00:08:38,018 +清晰 简洁 易理解 + +137 +00:08:39,753 --> 00:08:43,290 +在这个部分 +我们使用数据生成器的概念 + +138 +00:08:43,323 --> 00:08:45,726 +探索了应用程序的行为 + +139 +00:08:46,593 --> 00:08:51,098 +数据生成器可在我们的应用程序中 +以我们选择的任何方式驱动 + +140 +00:08:51,131 --> 00:08:55,102 +无论是通过测试或自定义 UI +如我所演示的那样 + +141 +00:08:55,135 --> 00:08:57,571 +或是通过命令行参数之类的东西 + +142 +00:08:57,604 --> 00:09:01,375 +或任何针对特定用例的东西 + +143 +00:09:01,408 --> 00:09:05,112 +现在我们已经知道 +如何用数据填充应用程序 + +144 +00:09:05,145 --> 00:09:08,849 +那么我们就可以分析 +数据如何改变应用程序的行为了 + +145 +00:09:08,882 --> 00:09:12,586 +在这个部分 +我们将了解一些工具和技术 + +146 +00:09:12,619 --> 00:09:14,555 +来分析应用程序如何处理 + +147 +00:09:14,588 --> 00:09:15,822 +大型数据集 + +148 +00:09:16,890 --> 00:09:21,562 +具体来说 我们将使用工具 +分析 LargeDataGenerator 创建的 + +149 +00:09:21,595 --> 00:09:24,665 +数据集的时间和内存复杂性 + +150 +00:09:25,465 --> 00:09:29,069 +然后 我们将查看系统日志中 + +151 +00:09:29,102 --> 00:09:30,571 +丰富的可用信息 + +152 +00:09:30,604 --> 00:09:35,075 +这样 我们就可以从 +NSPersistentCloudKitContainer + +153 +00:09:35,108 --> 00:09:39,713 +CloudKit 系统调度器和推送通知中 +找到活动记录 + +154 +00:09:39,746 --> 00:09:42,449 +我们先从 Instruments 开始 + +155 +00:09:42,482 --> 00:09:46,420 +我喜欢测试的一个原因是 + +156 +00:09:46,453 --> 00:09:49,156 +Xcode 使分析测试行为变得很容易 + +157 +00:09:49,189 --> 00:09:52,860 +在我的测试用例中 +我可以在 gutter 区域点击右键 + +158 +00:09:52,893 --> 00:09:55,229 +显示并选择 Profile + +159 +00:09:55,262 --> 00:09:59,433 +Xcode 将构建测试 +然后自动启动工具 + +160 +00:10:00,234 --> 00:10:02,769 +我可以双击 Time Profiler 工具 + +161 +00:10:02,803 --> 00:10:05,939 +来检查我的测试在哪里花费了时间 + +162 +00:10:07,508 --> 00:10:11,612 +当我点击记录按钮时 +Instruments 将启动应用程序 + +163 +00:10:11,645 --> 00:10:14,681 +并执行所选的测试 + +164 +00:10:14,715 --> 00:10:18,785 +这个测试似乎要花很长时间来运行 + +165 +00:10:18,819 --> 00:10:20,787 +我们跳过这一步 看看为什么 + +166 +00:10:21,688 --> 00:10:24,758 +Instruments 已经选择了主线程 + +167 +00:10:24,791 --> 00:10:28,795 +在右边 我可以看到测试运行中 +最重的堆栈轨迹 + +168 +00:10:30,063 --> 00:10:31,865 +我们让它更易阅读 + +169 +00:10:36,203 --> 00:10:38,172 +好了 + +170 +00:10:38,205 --> 00:10:42,876 +现在 如果我滚动到底部 +可以看到 LargeDataGenerator + +171 +00:10:42,910 --> 00:10:45,546 +正在花费大量时间来生成缩略图 + +172 +00:10:45,579 --> 00:10:48,582 +我们如何判断这是一个漏洞 +还是一个功能呢 + +173 +00:10:50,050 --> 00:10:53,687 +在 LargeDataGenerator 中 +我用这行代码 + +174 +00:10:53,720 --> 00:10:56,623 +为每个附件生成一个新的缩略图 + +175 +00:10:56,657 --> 00:11:01,361 +但我从应用程序的数据模型中知道 +缩略图是特殊的 + +176 +00:11:01,395 --> 00:11:05,432 +它们是根据相关的 imageData +按需计算的 + +177 +00:11:05,465 --> 00:11:09,803 +这意味着这一行代码不是必要的 +我的数据生成器在这上面 + +178 +00:11:09,837 --> 00:11:11,605 +浪费了很多时间 + +179 +00:11:11,638 --> 00:11:14,074 +所以我可以把它删除掉 + +180 +00:11:14,107 --> 00:11:16,643 +我们来看看这会如何改变测试的性能 + +181 +00:11:17,578 --> 00:11:20,781 +在使用更新的数据生成器 +重新构建应用程序后 + +182 +00:11:20,814 --> 00:11:23,617 +我可以在 Instruments 中 +重新运行测试 + +183 +00:11:23,650 --> 00:11:29,223 +老实说 我看不出有什么变化 + +184 +00:11:29,256 --> 00:11:32,326 +但再过几秒钟 测试就完成了 + +185 +00:11:32,359 --> 00:11:35,195 +这比上一次运行快得多 + +186 +00:11:35,229 --> 00:11:37,998 +我们看看测试大部分时间花在哪里 + +187 +00:11:43,504 --> 00:11:46,907 +在右侧的边栏抽屉型菜单中 +我现在看到最重的堆栈轨迹 + +188 +00:11:46,940 --> 00:11:49,977 +是将图像保存到持久存储中 + +189 +00:11:50,010 --> 00:11:54,081 +这正是我对管理这么多 +数据的测试所期望的 + +190 +00:11:55,582 --> 00:11:59,720 +这一改变将 generateData 测试的 +运行时间从这么多 + +191 +00:11:59,753 --> 00:12:02,322 +减少到这么多 + +192 +00:12:02,356 --> 00:12:05,959 +它的执行时间只有十分之一 + +193 +00:12:05,993 --> 00:12:09,496 +以这种方式分析测试 +并不总能发现漏洞 + +194 +00:12:09,530 --> 00:12:11,198 +有时 我们只是进一步了解了 + +195 +00:12:11,231 --> 00:12:13,400 +应用程序在处理特定数据集时 + +196 +00:12:13,433 --> 00:12:16,003 +将时间花在哪里 + +197 +00:12:16,036 --> 00:12:18,472 +但不管怎样 这都是有价值的学习 + +198 +00:12:19,473 --> 00:12:23,043 +这就是 Time Profiler 工具 +如何帮助探索 + +199 +00:12:23,076 --> 00:12:26,413 +应用程序在数据集上花费的时间 + +200 +00:12:26,446 --> 00:12:31,618 +现在 由于这个数据集的大小 +我也很好奇这个测试 + +201 +00:12:31,652 --> 00:12:33,720 +使用了多少内存 + +202 +00:12:33,754 --> 00:12:37,558 +让我们使用 Allocations 工具 +来试一试 + +203 +00:12:37,591 --> 00:12:41,328 +我将使用 Xcode 启动 Instruments +来分析我的测试 + +204 +00:12:42,062 --> 00:12:44,765 +我将双击 Allocations 而不是选择 + +205 +00:12:44,798 --> 00:12:47,301 +Time Profiler 工具 + +206 +00:12:51,205 --> 00:12:52,873 +然后点击 Record + +207 +00:13:02,916 --> 00:13:05,719 +尽管此测试执行速度很快 + +208 +00:13:05,752 --> 00:13:10,057 +但它使用了大量内存 +实际上超过 10 GB + +209 +00:13:10,090 --> 00:13:13,026 +这告诉我 在测试运行期间 + +210 +00:13:13,060 --> 00:13:15,495 +几乎整个数据集都保存在内存中 + +211 +00:13:15,529 --> 00:13:17,264 +让我们来找出原因 + +212 +00:13:19,199 --> 00:13:22,102 +我可以选择要查看的分配范围 + +213 +00:13:22,135 --> 00:13:26,573 +在底部窗格中 +我可以看到有许多大的分配 + +214 +00:13:27,407 --> 00:13:31,211 +我可以通过单击这个公开信息 +来深入研究这些内容 + +215 +00:13:31,245 --> 00:13:33,647 +然后单击分配给测试的 + +216 +00:13:33,680 --> 00:13:36,250 +一个大数据团 + +217 +00:13:36,283 --> 00:13:41,288 +此特定 blob 已分配 +但在将近两秒钟内未释放 + +218 +00:13:41,321 --> 00:13:45,292 +这是一个永恒的测试时间 +为什么它能存在这么久呢 + +219 +00:13:46,894 --> 00:13:49,930 +我可以通过展开右边的 +堆栈轨迹来探究这一点 + +220 +00:13:53,834 --> 00:13:57,404 +根据经验 +分配和解除堆栈轨迹告诉我 + +221 +00:13:57,437 --> 00:14:00,807 +此对象是由于 CoreData +而出现了故障 + +222 +00:14:00,841 --> 00:14:05,145 +然后在托管对象上下文 +完成其工作时释放 + +223 +00:14:05,179 --> 00:14:09,283 +这通常表示对象是由提取 +autoreleasepool + +224 +00:14:09,316 --> 00:14:12,486 +或测试中的对象保留的 + +225 +00:14:15,155 --> 00:14:19,126 +代码中有问题的部分在我的验证器中 + +226 +00:14:19,159 --> 00:14:22,563 +我从附件中加载图像并进行验证 + +227 +00:14:22,596 --> 00:14:26,600 +但这会将附件和关联的图像数据 + +228 +00:14:26,633 --> 00:14:28,969 +注册到托管对象上下文中 + +229 +00:14:29,736 --> 00:14:33,106 +我们可以通过多种方式 +来解决这个问题 + +230 +00:14:33,140 --> 00:14:37,177 +例如 在表格视图中 +当表格滚动到帖子上时 + +231 +00:14:37,211 --> 00:14:41,615 +我们可以使用批处理提取 +来释放图像 + +232 +00:14:41,648 --> 00:14:46,286 +然而 此测试执行得太快 +无法有效执行 + +233 +00:14:46,320 --> 00:14:48,922 +我需要改变方法 + +234 +00:14:48,956 --> 00:14:54,228 +我可以提取附件 +而不是通过提取帖子来验证 + +235 +00:14:54,261 --> 00:14:57,931 +如果我也只提取 objectID +那么托管对象上下文 + +236 +00:14:57,965 --> 00:15:01,368 +将不会捕获任何加载的对象 +除非我要求它这样做 + +237 +00:15:03,237 --> 00:15:07,040 +在进行验证时 我可以使用 +NSManagedObjectContext 的 + +238 +00:15:07,074 --> 00:15:11,178 +objectWithID 方法提取附件 + +239 +00:15:11,211 --> 00:15:16,250 +最后 对于我验证的每 10 个附件 +我会重置上下文 + +240 +00:15:16,283 --> 00:15:19,653 +释放所有缓存状态和相关内存 + +241 +00:15:21,555 --> 00:15:25,459 +如果我用这个变化重新运行测试 +我可以看到它将引起 + +242 +00:15:25,492 --> 00:15:29,229 +更可预测和更可调的内存消耗水平 + +243 +00:15:30,063 --> 00:15:32,900 +事实上 在插入这些对象时 + +244 +00:15:32,933 --> 00:15:34,868 +验证器使用的内存 + +245 +00:15:34,902 --> 00:15:36,770 +甚至比 LargeDataGenerator 更少 + +246 +00:15:38,272 --> 00:15:41,141 +让我们深入了解特定的分配 + +247 +00:15:41,175 --> 00:15:42,976 +以了解修复的工作方式 + +248 +00:15:44,344 --> 00:15:47,681 +首先 我将选择一系列要使用的分配 + +249 +00:15:47,714 --> 00:15:50,951 +然后 我将选择一个 +特定的大小进行检查 + +250 +00:15:54,755 --> 00:16:00,227 +我需要启用已销毁的对象 +来查找在此期间释放的对象 + +251 +00:16:00,260 --> 00:16:03,530 +然后我可以选择一个 +特定的分配进行检查 + +252 +00:16:05,732 --> 00:16:10,237 +在右侧 Instruments 向我显示了 +一个分配堆栈轨迹 + +253 +00:16:10,270 --> 00:16:15,742 +但我想知道它在哪里被释放 +所以我将选择 deallocation 事件 + +254 +00:16:15,776 --> 00:16:18,011 +我碰巧知道这个堆栈轨迹意味着 + +255 +00:16:18,045 --> 00:16:21,849 +NSManagedObjectContext +正在异步释放 + +256 +00:16:21,882 --> 00:16:26,320 +保留此 blob 的对象 +从而释放已使用的内存 + +257 +00:16:27,054 --> 00:16:31,191 +这种技术使我能够为测试 +建立一个高水位线 + +258 +00:16:31,225 --> 00:16:33,994 +使其能够在内存较少的系统上运行 + +259 +00:16:35,028 --> 00:16:38,932 +通过将测试 +与 Instruments 相结合 + +260 +00:16:38,966 --> 00:16:43,637 +我发现这个特定的测试有一些 +不太理想的行为 + +261 +00:16:43,670 --> 00:16:46,940 +我做了有针对性的改变 +来直接解决这种行为 + +262 +00:16:46,974 --> 00:16:49,610 +然后验证结果 + +263 +00:16:49,643 --> 00:16:52,713 +此外 系统日志还包含 + +264 +00:16:52,746 --> 00:16:55,682 +大量关于应用程序及其依赖的 + +265 +00:16:55,716 --> 00:16:57,918 +系统服务的信息 + +266 +00:16:57,951 --> 00:17:01,922 +如 CloudKit 进程表 和推送通知 + +267 +00:17:02,890 --> 00:17:08,295 +我将在我的 MacBook Pro +和 iPhone 之间同步一篇帖子 + +268 +00:17:08,328 --> 00:17:12,399 +当我在 Mac 上插入一篇新帖子 +给它一个简短的标题 + +269 +00:17:12,432 --> 00:17:14,801 +并将其上传到 iCloud 时 + +270 +00:17:14,835 --> 00:17:17,237 +系统日志会捕获一些事件 + +271 +00:17:18,338 --> 00:17:21,375 +当它与我的 iPhone 同步时 +有时甚至会捕获 + +272 +00:17:21,408 --> 00:17:23,076 +中间状态 + +273 +00:17:23,110 --> 00:17:27,181 +系统日志会捕获相应的一组事件 + +274 +00:17:27,214 --> 00:17:31,618 +在 MacBook Pro上 +NSPersistentCloudKitContainer + +275 +00:17:31,652 --> 00:17:37,357 +在应用程序进程内部工作 在本例中 +它是 CoreDataCloudKitDemo + +276 +00:17:37,391 --> 00:17:39,826 +当数据被写入持久存储时 + +277 +00:17:39,860 --> 00:17:43,330 +它会询问名为 DASD 的系统服务 + +278 +00:17:43,363 --> 00:17:47,234 +现在是否适合将数据导出到 CloudKit + +279 +00:17:47,267 --> 00:17:51,605 +如果是 那么DASD 将通知 +NSPersistentCloudKitContainer + +280 +00:17:51,638 --> 00:17:53,607 +运行任务 + +281 +00:17:53,640 --> 00:17:57,044 +然后 NSPersistentCloudKitContainer +将使用一个 + +282 +00:17:57,077 --> 00:17:59,046 +名为 cloudd 的进程来调度工作 + +283 +00:17:59,079 --> 00:18:02,216 +以将更改后的对象导出到 CloudKit + +284 +00:18:02,249 --> 00:18:07,020 +我们可以使用 Console app +观察每个进程的日志 + +285 +00:18:07,721 --> 00:18:11,792 +对于应用程序日志 +我们只需查找应用程序进程 + +286 +00:18:11,825 --> 00:18:13,994 +CoreDataCloudKitDemo + +287 +00:18:14,027 --> 00:18:18,131 +在这里 我选择了一个 +显示导出完成的选项 + +288 +00:18:18,165 --> 00:18:23,237 +对于调度日志 +我们希望查看来自进程 dasd + +289 +00:18:23,270 --> 00:18:26,707 +和来自应用程序特定存储的日志 + +290 +00:18:26,740 --> 00:18:29,977 +在这里 我为应用程序的私有存储 + +291 +00:18:30,010 --> 00:18:32,613 +选择了导出任务开始 + +292 +00:18:32,646 --> 00:18:35,215 +让我们更详细地检查一下这个日志 + +293 +00:18:36,116 --> 00:18:39,653 +NSPersistentCloudKitContainer +使用 dasd 创建的任务 + +294 +00:18:39,686 --> 00:18:43,257 +遵循特定的格式 + +295 +00:18:43,290 --> 00:18:47,127 +任务标识符由 +NSPersistentCloudKitContainer + +296 +00:18:47,160 --> 00:18:52,266 +使用的特定前缀以及任务所属存储的 + +297 +00:18:52,299 --> 00:18:55,369 +存储标识符组成 + +298 +00:18:55,402 --> 00:18:59,506 +dasd 日志包含有关服务如何决定 + +299 +00:18:59,540 --> 00:19:01,675 +任务是否可以运行的信息 + +300 +00:19:01,708 --> 00:19:05,312 +影响应用程序工作能力的策略 + +301 +00:19:05,345 --> 00:19:08,949 +将与最终决策一起列在日志中 + +302 +00:19:10,017 --> 00:19:14,555 +最后 流程 cloudd 记录 +来自 CloudKit 的信息 + +303 +00:19:14,588 --> 00:19:16,757 +我喜欢根据正在处理的 + +304 +00:19:16,790 --> 00:19:19,860 +容器标识符过滤这些日志 + +305 +00:19:19,893 --> 00:19:23,463 +在这里 我为前面提到的导出内容 + +306 +00:19:23,497 --> 00:19:25,499 +选择了相应的修改记录操作 + +307 +00:19:26,633 --> 00:19:29,937 +当在接收设备上导入更改时 + +308 +00:19:29,970 --> 00:19:33,440 +还有一个额外的过程需要观察 + +309 +00:19:33,473 --> 00:19:38,278 +apsd 进程负责接收推送通知 + +310 +00:19:38,312 --> 00:19:40,614 +并将其转发给应用程序 + +311 +00:19:41,248 --> 00:19:44,017 +这会导致 +NSPersistentCloudKitContainer + +312 +00:19:44,051 --> 00:19:48,856 +启动一系列类似于导出过程的任务 + +313 +00:19:48,889 --> 00:19:52,392 +它询问 dasd 执行导入的时间 + +314 +00:19:52,426 --> 00:19:56,530 +然后使用 cloudd 从 CloudKit 提取 + +315 +00:19:56,563 --> 00:19:59,299 +所有更新的对象 +并将它们导入本地存储 + +316 +00:20:00,601 --> 00:20:05,739 +Apsd 在收到应用程序的推送通知时 + +317 +00:20:05,772 --> 00:20:09,142 +会进行日志记录 +该日志记录了许多重要的细节 + +318 +00:20:10,010 --> 00:20:13,680 +日志消息包括这里的容器标识符 + +319 +00:20:13,714 --> 00:20:16,884 +以及触发推送通知的 + +320 +00:20:16,917 --> 00:20:19,319 +订阅名称和区域标识符 + +321 +00:20:19,353 --> 00:20:22,422 +这些由 +NSPersistentCloudKitContainer 管理 + +322 +00:20:22,456 --> 00:20:27,728 +并将始终以前缀 +com.apple.coredata.cloudkit 开头 + +323 +00:20:29,296 --> 00:20:31,498 +现在 console app 很棒 + +324 +00:20:31,532 --> 00:20:35,235 +但当我在 Mac 上开发时 我喜欢 +使用终端中的 log stream 命令 + +325 +00:20:35,269 --> 00:20:38,672 +将这些日志显示在我的 App 旁边 + +326 +00:20:40,007 --> 00:20:44,478 +我为以下每个 predicate +打开一个终端窗口或选项卡 + +327 +00:20:44,511 --> 00:20:46,947 +首先是应用程序 + +328 +00:20:46,980 --> 00:20:52,519 +接下来是 cloudd 中的日志 这样我就 +可以看到 CloudKit 服务器发生了什么 + +329 +00:20:52,553 --> 00:20:56,657 +接下来 是用于推送通知日志的 apsd + +330 +00:20:56,690 --> 00:21:00,661 +最后是 dasd 这样我就可以看到 +NSPersistentCloudKitContainer + +331 +00:21:00,694 --> 00:21:04,898 +为我安排的任务发生了什么 + +332 +00:21:04,932 --> 00:21:09,469 +这些 predicate 还可以用于 +指导 console app 中的查询 + +333 +00:21:11,205 --> 00:21:15,475 +在我们使用的设备上 +有很多信息可供我们使用 + +334 +00:21:15,509 --> 00:21:19,646 +真正的挑战是知道使用什么工具 +来发现和分析信息 + +335 +00:21:19,680 --> 00:21:24,318 +仅使用 Instruments +我们就可以了解许多主题 + +336 +00:21:24,351 --> 00:21:27,054 +如运行时间和内存性能等 + +337 +00:21:27,087 --> 00:21:31,325 +系统日志捕获事件 +这些事件描述应用程序所做的工作 + +338 +00:21:31,358 --> 00:21:33,861 +以及系统在幕后为它所做的工作 + +339 +00:21:34,828 --> 00:21:37,531 +开发周期的最后阶段 + +340 +00:21:37,564 --> 00:21:40,868 +是收集和提供可操作的反馈 + +341 +00:21:40,901 --> 00:21:44,671 +在这个部分 我将演示如何从设备收集 + +342 +00:21:44,705 --> 00:21:45,939 +诊断信息 + +343 +00:21:45,973 --> 00:21:48,275 +我们的目标是利用这些信息 + +344 +00:21:48,308 --> 00:21:52,846 +来产生可行的反馈 +并与特定的目标保持一致 + +345 +00:21:52,880 --> 00:21:55,115 +这些技术可以帮助你 +从任何设备收集反馈 + +346 +00:21:55,148 --> 00:21:59,253 +无论是你自己的设备还是客户的设备 + +347 +00:21:59,286 --> 00:22:04,391 +从设备收集诊断信息有三个步骤 + +348 +00:22:04,424 --> 00:22:07,661 +首先 我们需要安装 CloudKit +日志记录配置文件 + +349 +00:22:07,694 --> 00:22:10,764 +该文件允许使用日志来识别问题 + +350 +00:22:10,797 --> 00:22:13,000 +并对其进行有效分类 + +351 +00:22:13,033 --> 00:22:17,404 +接下来 我们将从受影响的设备 +收集 sysdiagnose + +352 +00:22:17,437 --> 00:22:21,141 +最后 如果我们对设备有物理访问权 + +353 +00:22:21,175 --> 00:22:24,611 +我们还可以从 Xcode +收集持久存储文件 + +354 +00:22:25,145 --> 00:22:29,716 +要安装日志配置文件 我们只需访问 + +355 +00:22:29,750 --> 00:22:31,818 +开发人员网站上的 +Profile and Logs 页面 + +356 +00:22:31,852 --> 00:22:36,790 +我可以搜索 CloudKit 配置文件 +然后点击配置文件链接进行下载 + +357 +00:22:36,823 --> 00:22:41,328 +在某些设备上 +会显示安装配置文件的通知 + +358 +00:22:41,361 --> 00:22:44,498 +然而 在 iOS 上 我们需要通过 + +359 +00:22:44,531 --> 00:22:45,465 +Settings app 手动安装 + +360 +00:22:47,267 --> 00:22:52,639 +在 Settings 中 我可以导航到 +点击 Profile Downloaded 单元格 + +361 +00:22:52,673 --> 00:22:56,610 +然后我可以点击下载的 +配置文件进行安装 + +362 +00:22:56,643 --> 00:23:00,514 +按照步骤完成安装 + +363 +00:23:00,547 --> 00:23:02,516 +配置文件安装完成后 + +364 +00:23:02,549 --> 00:23:05,619 +重启设备即可生效 + +365 +00:23:09,022 --> 00:23:12,459 +一旦设备重新启动 我们就可以重现 + +366 +00:23:12,492 --> 00:23:15,395 +我们想要捕获的行为 +然后进行系统诊断 + +367 +00:23:16,096 --> 00:23:21,702 +进行系统诊断是通过 keychord +即一系列特殊的按钮来完成的 + +368 +00:23:21,735 --> 00:23:25,506 +这些在配置文件的说明页面中 +进行了描述 + +369 +00:23:25,539 --> 00:23:29,076 +我碰巧知道 在 iPhone 中 +我们按住音量键 + +370 +00:23:29,109 --> 00:23:31,645 +和侧边按钮几秒钟 + +371 +00:23:31,678 --> 00:23:33,480 +然后松开 + +372 +00:23:33,514 --> 00:23:37,784 +稍后 sysdiagnose 便在 +Settings 中可用 + +373 +00:23:37,818 --> 00:23:41,255 +查找它的说明包含在概要文件的 + +374 +00:23:41,288 --> 00:23:42,256 +说明文件中 + +375 +00:23:43,190 --> 00:23:48,562 +在 Settings 中 +我导航到 Privacy & Security + +376 +00:23:48,595 --> 00:23:50,564 +Analytics and Improvements + +377 +00:23:50,597 --> 00:23:52,833 +然后选择 Analytics Data + +378 +00:23:52,866 --> 00:23:56,170 +在日志中滚动 +直到找到 sysdiagnose + +379 +00:23:57,437 --> 00:24:01,308 +如果我点击 sysdiagnose +然后点击 Share 按钮 + +380 +00:24:01,341 --> 00:24:03,310 +我可以选择多种方式来分享它 + +381 +00:24:04,077 --> 00:24:08,081 +例如 我喜欢将它们隔空投送到 +我的 Mac 上进行分析 + +382 +00:24:08,715 --> 00:24:11,752 +最后 如果可能的话 +我可以使用 Device Organizer + +383 +00:24:11,785 --> 00:24:13,921 +从 Xcode 收集存储文件 + +384 +00:24:14,721 --> 00:24:16,924 +我可以从这台 iPhone 上收集文件 + +385 +00:24:16,957 --> 00:24:18,792 +方法是单击已安装 App 列表中的 + +386 +00:24:18,825 --> 00:24:20,394 +示例应用程序 + +387 +00:24:20,427 --> 00:24:22,262 +单击公开信息按钮 + +388 +00:24:22,296 --> 00:24:24,164 +选择 Download Container + +389 +00:24:24,198 --> 00:24:26,733 +并将其保存到我的 +Downloads 目录中 + +390 +00:24:30,470 --> 00:24:34,174 +完成所有这些操作后 +现在可以对系统日志 + +391 +00:24:34,208 --> 00:24:36,343 +和存储文件进行分析了 + +392 +00:24:36,376 --> 00:24:38,946 +我们已经讨论了 log stream 命令 + +393 +00:24:38,979 --> 00:24:40,047 +但使用 sysdiagnose 时 + +394 +00:24:40,080 --> 00:24:44,985 +我可以使用 log show 命令 +打印出系统诊断中的日志 + +395 +00:24:45,018 --> 00:24:49,389 +在这里 我复制了我们前面谈到的 +apsd 日志的 predicate + +396 +00:24:51,925 --> 00:24:56,530 +log show 命令的最后一个参数 +是要使用的 logarchive + +397 +00:24:56,563 --> 00:24:59,466 +如果未指定任何内容 它将显示 + +398 +00:24:59,499 --> 00:25:01,502 +其运行所在机器的系统日志 + +399 +00:25:01,535 --> 00:25:05,105 +这里 我指定了 system_logs.logarchive + +400 +00:25:05,138 --> 00:25:08,308 +以便读取我从 +sysdiagnose 中获取的日志 + +401 +00:25:08,342 --> 00:25:11,912 +例如 我可以指定一个精确的 +时间范围 + +402 +00:25:11,945 --> 00:25:15,382 +以关注我感兴趣的事件发生的时间 + +403 +00:25:16,884 --> 00:25:20,120 +我还可以将我们前面讨论的 +许多 predicate 组合起来 + +404 +00:25:20,153 --> 00:25:25,492 +形成一个与应用程序相关的 +所有任务的统一日志 + +405 +00:25:25,526 --> 00:25:28,562 +首先是这里的应用程序日志 + +406 +00:25:28,595 --> 00:25:33,200 +这里的 cloudd 日志 +这里的 apsd 日志 + +407 +00:25:33,233 --> 00:25:35,869 +最后是这里的 dasd 日志 + +408 +00:25:36,703 --> 00:25:40,073 +这个强大的命令可以包含在 +反馈报告中 + +409 +00:25:40,107 --> 00:25:41,408 +也可以与队友共享 + +410 +00:25:41,441 --> 00:25:45,445 +让每个人都可以专注于一组 +特定的日志进行分析 + +411 +00:25:46,947 --> 00:25:50,918 +在本讲座中 +我们讨论了如何使用数据生成器 + +412 +00:25:50,951 --> 00:25:52,920 +来探索应用程序的行为 + +413 +00:25:52,953 --> 00:25:56,690 +如何使用工具和系统日志 +来分析应用程序 + +414 +00:25:56,723 --> 00:25:59,193 +以及如何从使用 +NSPersistentCloudKitContainer 的 + +415 +00:25:59,226 --> 00:26:02,663 +应用程序中提供或收集可操作的反馈 + +416 +00:26:03,964 --> 00:26:04,932 +我是 Nick Gillett + +417 +00:26:04,965 --> 00:26:08,101 +很高兴为大家带来这个演讲 + +418 +00:26:08,135 --> 00:26:13,106 +感谢收看 保持活跃 双手合十 +祝你余下的 WWDC 之旅一切顺利 + +419 +00:26:14,408 --> 00:26:16,476 +[古怪的音乐] + diff --git a/zho/2022 Session 10120 Evolve your Core Data schema.srt b/zho/2022 Session 10120 Evolve your Core Data schema.srt new file mode 100644 index 0000000..f20625c --- /dev/null +++ b/zho/2022 Session 10120 Evolve your Core Data schema.srt @@ -0,0 +1,1371 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,309 --> 00:00:13,113 +David Stites: 嗨 欢迎来到 +发展您的 Core Data 架构 + +3 +00:00:13,146 --> 00:00:17,718 +我叫 David Stites +是 Core Data 团队的一名工程师 + +4 +00:00:17,751 --> 00:00:20,187 +在本期讲座中 我很高兴与您讨论 + +5 +00:00:20,220 --> 00:00:24,658 +如何在您的 App 中更新和迁移 +Core Data 架构 + +6 +00:00:24,691 --> 00:00:29,229 +本期讲座的议程是 +了解什么是架构迁移 + +7 +00:00:29,263 --> 00:00:33,700 +为什么您的 App 必须在更新 +其数据模型后执行架构迁移 + +8 +00:00:33,734 --> 00:00:37,070 +如何迁移现有架构 + +9 +00:00:37,104 --> 00:00:41,275 +以及 CloudKit 和架构迁移如何交互 + +10 +00:00:41,308 --> 00:00:45,812 +首先 什么是架构迁移 +以及为什么在更新数据模型时 + +11 +00:00:45,846 --> 00:00:47,681 +App 必须迁移 + +12 +00:00:49,049 --> 00:00:54,788 +由于涉及到 App +可能有必要更改您的数据模型 + +13 +00:00:54,821 --> 00:00:58,592 +更新数据模型需要在底层存储架构中 + +14 +00:00:58,625 --> 00:01:00,861 +具体化这些更改 + +15 +00:01:00,894 --> 00:01:02,763 +考虑一下这个数据模型 + +16 +00:01:02,796 --> 00:01:06,200 +这有一个 Aircraft 实体 它有两个属性 + +17 +00:01:06,233 --> 00:01:09,136 +即类型和发动机数量 + +18 +00:01:09,169 --> 00:01:13,440 +这些属性反映在底层存储中 + +19 +00:01:13,473 --> 00:01:16,677 +如果我添加了“乘客数量”属性 + +20 +00:01:16,710 --> 00:01:20,147 +那我需要添加相应的存储 + +21 +00:01:20,180 --> 00:01:25,285 +迁移后 更改完全反映在底层存储中 + +22 +00:01:25,319 --> 00:01:28,488 +如果不迁移底层存储中的更改 + +23 +00:01:28,522 --> 00:01:31,792 +Core Data 将拒绝打开您的持久存储 + +24 +00:01:31,825 --> 00:01:36,897 +因为新更改的模型 +与用于存储的模型不匹配 + +25 +00:01:36,930 --> 00:01:40,868 +试图打开不兼容的存储将导致代码 + +26 +00:01:40,901 --> 00:01:45,873 +NSPersistentStore- +IncompatibleVersionHashError出错 + +27 +00:01:45,906 --> 00:01:48,675 +如果您收到此错误 +这应该是在指示您 + +28 +00:01:48,709 --> 00:01:51,512 +需要进行迁移 + +29 +00:01:51,545 --> 00:01:54,548 +现在我已经解释了什么是架构迁移 + +30 +00:01:54,581 --> 00:01:56,850 +以及为什么它对开发 App 至关重要 + +31 +00:01:56,884 --> 00:01:59,553 +让我来告诉您迁移是如何完成的 + +32 +00:01:59,586 --> 00:02:02,523 +Core Data 具有内置的数据迁移工具 + +33 +00:02:02,556 --> 00:02:08,028 +可帮助您的 App 进行数据存储 +使其与当前数据模型保持同步 + +34 +00:02:08,061 --> 00:02:12,566 +这些工具统称为“轻量级迁移” + +35 +00:02:14,067 --> 00:02:17,905 +轻量级迁移是首选的迁移方法 + +36 +00:02:17,938 --> 00:02:22,643 +轻量级迁移从源 +和目标托管对象模型之间的 + +37 +00:02:22,676 --> 00:02:27,581 +差异自动分析和推断迁移 + +38 +00:02:27,614 --> 00:02:31,518 +在运行时 +Core Data 在 NSBundle 类的 + +39 +00:02:31,552 --> 00:02:36,757 +.allBundles 和 .allFrameworks 方法 +返回的包中查找模型 + +40 +00:02:36,790 --> 00:02:39,760 +然后轻量级迁移 +会生成一个映射模型 + +41 +00:02:39,793 --> 00:02:44,231 +将您在 App 中所做的更改 +具体化到您的数据库架构中 + +42 +00:02:45,966 --> 00:02:49,803 +使用轻量级迁移需要 +对数据模型进行更改 + +43 +00:02:49,837 --> 00:02:52,239 +以适应明显的迁移架构 + +44 +00:02:54,041 --> 00:02:57,110 +涉及属性的轻量级操作 + +45 +00:02:57,144 --> 00:03:00,614 +包括添加属性 移除属性 + +46 +00:03:00,647 --> 00:03:04,084 +将非可选属性变为可选 + +47 +00:03:04,117 --> 00:03:07,087 +将可选属性变为非可选 + +48 +00:03:07,120 --> 00:03:09,423 +并定义默认值 + +49 +00:03:09,456 --> 00:03:11,391 +以及重命名属性 + +50 +00:03:11,425 --> 00:03:15,062 +如果您想要重命名属性 +请将目标模型中的 + +51 +00:03:15,095 --> 00:03:16,864 +重命名标识符 + +52 +00:03:16,897 --> 00:03:19,366 +设置为源模型中相应属性的名称 + +53 +00:03:20,534 --> 00:03:22,236 +重命名标识符位于 + +54 +00:03:22,269 --> 00:03:25,973 +Xcode 数据模型编辑器的 +属性检查器中 + +55 +00:03:26,006 --> 00:03:28,575 +例如 您可以将 + +56 +00:03:28,609 --> 00:03:32,713 +Aircraft 实体的颜色属性 +重命名为 paintColor + +57 +00:03:32,746 --> 00:03:35,749 +重命名标识符要创建一个规范名称 + +58 +00:03:35,782 --> 00:03:38,719 +因此将重命名标识符 +设置为源模型中属性的名称 + +59 +00:03:38,752 --> 00:03:43,490 +除非该属性已经具有重命名标识符 + +60 +00:03:43,524 --> 00:03:47,661 +这意味着您可以在模型的 +版本 2 中重命名一个属性 + +61 +00:03:47,694 --> 00:03:50,497 +然后在版本 3 中再次重命名它 + +62 +00:03:50,531 --> 00:03:55,002 +重命名将从版本 2 到版本 3 +或者从版本 1 到版本 3 + +63 +00:03:55,035 --> 00:03:58,539 +正确工作 + +64 +00:04:00,240 --> 00:04:03,544 +轻量级迁移还可以毫不费力地 + +65 +00:04:03,577 --> 00:04:05,479 +处理关系的变化 + +66 +00:04:05,512 --> 00:04:10,150 +您可以添加新关系或删除现有关系 + +67 +00:04:10,184 --> 00:04:13,787 +您还可以通过使用重命名标识符 +来重命名关系 + +68 +00:04:13,820 --> 00:04:15,989 +就跟属性一样 + +69 +00:04:16,023 --> 00:04:19,259 +此外 您还可以更改关系基数 + +70 +00:04:19,293 --> 00:04:23,630 +例如 从一对一迁移到一对多 + +71 +00:04:23,664 --> 00:04:27,668 +或者从无序的一对多 +迁移到有序的一对多 反之亦然 + +72 +00:04:29,236 --> 00:04:32,539 +如果您猜测实体也有资格 +进行轻量级迁移 + +73 +00:04:32,573 --> 00:04:33,974 +那么您是对的 + +74 +00:04:34,007 --> 00:04:38,145 +您可以添加新实体 删除现有实体 + +75 +00:04:38,178 --> 00:04:40,547 +以及重命名实体 + +76 +00:04:40,581 --> 00:04:43,750 +您还可以创建新的父实体或子实体 + +77 +00:04:43,784 --> 00:04:48,488 +并在实体层次结构中上下移动属性 + +78 +00:04:48,522 --> 00:04:53,594 +您可以将实体移入或移出层次结构 + +79 +00:04:53,627 --> 00:04:56,530 +但是不能合并实体层次结构 + +80 +00:04:56,563 --> 00:05:00,534 +如果两个现有实体 +在源中不共享公共父级 + +81 +00:05:00,567 --> 00:05:03,237 +则它们无法在目标中共享公共父级 + +82 +00:05:03,270 --> 00:05:07,841 +轻量级迁移由两个选项键控制 + +83 +00:05:07,875 --> 00:05:11,545 +NSMigratePersistent- +StoresAutomaticallyOption + +84 +00:05:11,578 --> 00:05:16,383 +和 NSInferMappingModelAutomaticallyOption + +85 +00:05:16,416 --> 00:05:19,386 +将存储添加到持久性协调器时 + +86 +00:05:19,419 --> 00:05:23,056 +如果检测到持久性存储 +不再匹配当前模型 + +87 +00:05:23,090 --> 00:05:26,727 +这两个将值设置为真的键的存在 + +88 +00:05:26,760 --> 00:05:31,031 +将导致核心数据自动执行轻量级迁移 + +89 +00:05:31,064 --> 00:05:33,667 +如果您使用 NSPersistentContainer + +90 +00:05:33,700 --> 00:05:36,203 +或 NSPersistentStoreDescription + +91 +00:05:36,236 --> 00:05:38,605 +这些选项会自动为您设置 + +92 +00:05:38,639 --> 00:05:41,275 +您无需执行任何操作 + +93 +00:05:41,308 --> 00:05:43,443 +如果您使用的是替代 API + +94 +00:05:43,477 --> 00:05:47,648 +例如 .NSPersistentStoreCoordinator +.addPersistentStore + +95 +00:05:47,681 --> 00:05:50,918 +(type:configuration:at:options:) + +96 +00:05:50,951 --> 00:05:56,857 +可以通过设置和传递带有能够将 +NSMigratePersistent-StoresAutomaticallyOption + +97 +00:05:56,890 --> 00:06:02,496 +和 NSInferMappingModelAutomaticallyOption 的值 +设置为 YES 的键的 + +98 +00:06:02,529 --> 00:06:07,968 +选项字典 NSMigratePersistent-StoresAutomaticallyOption +来请求轻量级迁移 + +99 +00:06:08,001 --> 00:06:11,138 +如果 Core Data 检测到持久存储 +不再匹配当前模型 + +100 +00:06:11,171 --> 00:06:15,676 +它将自动执行轻量级迁移 + +101 +00:06:16,910 --> 00:06:19,379 +以下是它在代码中的工作方式 + +102 +00:06:19,413 --> 00:06:23,684 +首先我将导入 CoreData +并创建一个托管对象模型 + +103 +00:06:23,717 --> 00:06:27,020 +然后我将使用刚刚创建的模型 + +104 +00:06:27,054 --> 00:06:29,923 +创建一个持久存储协调器 + +105 +00:06:29,957 --> 00:06:33,527 +请注意我创建的选项字典 +当我将存储添加到持久协调器时 + +106 +00:06:33,560 --> 00:06:36,663 +我将传递这个字典 + +107 +00:06:36,697 --> 00:06:39,333 +最后 我将把存储添加到协调器中 + +108 +00:06:39,366 --> 00:06:43,604 +如果需要 迁移将自动进行 + +109 +00:06:43,637 --> 00:06:48,876 +不管您使用什么 API +对数据模型的更改都可以直接 + +110 +00:06:48,909 --> 00:06:52,579 +在 App 附带的同一个模型中进行 + +111 +00:06:52,613 --> 00:06:56,617 +无需创建模型的新版本即可进行更改 + +112 +00:06:56,650 --> 00:07:00,087 +如果您想提前确定 Core Data +是否可以推断 + +113 +00:07:00,120 --> 00:07:04,157 +源模型和目标模型之间的映射模型 + +114 +00:07:04,191 --> 00:07:06,593 +而不需要实际进行迁移工作 + +115 +00:07:06,627 --> 00:07:11,465 +那么可以使用 +NSMappingModel.inferredMappingModel 方法 + +116 +00:07:11,498 --> 00:07:16,036 +如果 Core Data 能够创建推断模型 +则该方法将返回该模型 + +117 +00:07:16,069 --> 00:07:18,071 +否则 它将返回 nil + +118 +00:07:19,339 --> 00:07:22,176 +有时 对模式的组合更改 + +119 +00:07:22,209 --> 00:07:25,212 +可能会超出轻量级迁移的能力 + +120 +00:07:25,245 --> 00:07:28,282 +我将向您描述如何处理该问题 + +121 +00:07:28,315 --> 00:07:30,751 +并仍然使用轻量级迁移 + +122 +00:07:31,518 --> 00:07:36,089 +回到我们之前的示例模型 +假设我们之前添加了 + +123 +00:07:36,123 --> 00:07:42,095 +一个名为 flightData 的属性 该属性 +使用外部存储来存储二进制数据 + +124 +00:07:42,129 --> 00:07:46,233 +由存储在 FLIGHT_DATA 中的 +文件路径来指示 + +125 +00:07:46,266 --> 00:07:49,503 +此外 假设需要更改该属性 + +126 +00:07:49,536 --> 00:07:53,707 +以在内部存储数据并删除外部存储 + +127 +00:07:53,740 --> 00:07:57,177 +检查此迁移是否符合 +轻量级迁移的任何功能 + +128 +00:07:57,211 --> 00:08:00,948 +然后发现它不符合 + +129 +00:08:00,981 --> 00:08:03,317 +从表面上看 我们似乎陷入了困境 + +130 +00:08:03,350 --> 00:08:04,985 +无法进行此更改 + +131 +00:08:05,018 --> 00:08:06,453 +但是不要害怕 + +132 +00:08:06,486 --> 00:08:10,591 +轻量级迁移仍可用于执行更复杂 +且不一致的迁移 + +133 +00:08:10,624 --> 00:08:14,761 +尽管需要多个步骤 + +134 +00:08:16,330 --> 00:08:20,434 +目标是将不符合轻量级迁移条件的 + +135 +00:08:20,467 --> 00:08:23,070 +迁移任务分解为 + +136 +00:08:23,103 --> 00:08:28,242 +符合轻量级迁移条件的最小迁移系列 + +137 +00:08:28,275 --> 00:08:33,981 +通常 如果原始模型为 A +目标模型为 B + +138 +00:08:34,014 --> 00:08:36,817 +但模型 B 的变更不符合 + +139 +00:08:36,850 --> 00:08:40,721 +轻量级迁移的条件 +则可以通过引入一个或多个 + +140 +00:08:40,754 --> 00:08:45,158 +分解这些变更的模型版本来创建桥梁 + +141 +00:08:46,827 --> 00:08:51,331 +每一个引入的模型 +都将具有一个或多个操作 + +142 +00:08:51,365 --> 00:08:55,802 +这些操作在组成不一致变更的 +能力范围之内 + +143 +00:08:55,836 --> 00:08:58,205 +这导致了一系列的迁移 + +144 +00:08:58,238 --> 00:09:01,575 +其中每个模型现在是轻量级可迁移的 + +145 +00:09:01,608 --> 00:09:05,279 +但是等同于不一致的迁移 + +146 +00:09:05,312 --> 00:09:07,781 +回到不适合轻量级迁移的 + +147 +00:09:07,814 --> 00:09:11,752 +示例 我们的原始模型是模型 A + +148 +00:09:11,785 --> 00:09:16,957 +我将通过引入新模型版本 A' +来开始分解任务 + +149 +00:09:16,990 --> 00:09:20,794 +并添加一个新属性 tmpStorage + +150 +00:09:20,827 --> 00:09:25,199 +该属性将临时用于存储 +从外部文件导入的数据 + +151 +00:09:26,333 --> 00:09:29,303 +接下来我将 +把数据从外部文件导入到 + +152 +00:09:29,336 --> 00:09:31,371 +我们的新属性中 + +153 +00:09:31,405 --> 00:09:33,674 +导入此数据的代码 + +154 +00:09:33,707 --> 00:09:37,010 +与 Core Data 提供的功能是分开的 + +155 +00:09:37,044 --> 00:09:41,715 +该导入的执行介于两次迁移之间 + +156 +00:09:42,683 --> 00:09:45,185 +安全导入数据后 + +157 +00:09:45,219 --> 00:09:50,657 +我将从 A' 创建 +另一个新版本的模型 A'' + +158 +00:09:50,691 --> 00:09:55,028 +在 A'' 中 我将删除旧的外部存储属性 + +159 +00:09:55,062 --> 00:09:58,232 +同时重命名新属性 + +160 +00:09:58,265 --> 00:10:03,470 +我描述的每个步骤 +都在轻量级迁移的能力范围内 + +161 +00:10:04,438 --> 00:10:09,076 +直观地说 可以构建一个事件循环 + +162 +00:10:09,109 --> 00:10:11,478 +使用轻量级迁移选项集打开持久存储 + +163 +00:10:11,512 --> 00:10:16,216 +并以串行顺序迭代地 +遍历每个未处理的模型 + +164 +00:10:16,250 --> 00:10:19,253 +Core Data 将迁移存储 + +165 +00:10:19,286 --> 00:10:22,723 +如果您在迁移期间 +执行特定于 App 的逻辑 + +166 +00:10:22,756 --> 00:10:26,927 +例如在上一个示例中 +我是如何从外部文件导入数据的 + +167 +00:10:26,960 --> 00:10:31,832 +那么在迁移因进程终止 +而中断的情况下 + +168 +00:10:31,865 --> 00:10:33,800 +该逻辑必须是可重启的 + +169 +00:10:34,668 --> 00:10:36,904 +如果您的 App +使用 Core Data 和 CloudKit + +170 +00:10:36,937 --> 00:10:39,373 +那么在使用 Core Data +设计数据模型时 + +171 +00:10:39,406 --> 00:10:42,142 +您应该牢记一些要点 + +172 +00:10:42,176 --> 00:10:46,914 +要在 Core Data 存储和 +CloudKit 数据库之间传递记录 + +173 +00:10:46,947 --> 00:10:51,285 +它们需要对数据模型有共同的理解 + +174 +00:10:51,318 --> 00:10:55,389 +您可以在 Core Data 模型编辑器中 +定义此模型 + +175 +00:10:55,422 --> 00:10:59,860 +该模型随后用于生成 CloudKit 架构 + +176 +00:10:59,893 --> 00:11:04,264 +生成的架构最初 +是在开发环境中创建的 + +177 +00:11:04,298 --> 00:11:07,067 +然后升级到生产环境 + +178 +00:11:07,100 --> 00:11:10,504 +您应该意识到了 CloudKit 并不支持 +Core Data 模型的 + +179 +00:11:10,537 --> 00:11:12,406 +所有功能 + +180 +00:11:12,439 --> 00:11:16,109 +设计模型时 请注意以下限制 + +181 +00:11:16,143 --> 00:11:18,612 +并创建兼容的数据模型 + +182 +00:11:18,645 --> 00:11:23,417 +例如 不支持对实体的唯一约束 + +183 +00:11:23,450 --> 00:11:28,856 +不支持将 undefined 和 objectID +属性类型作为其属性类型 + +184 +00:11:28,889 --> 00:11:34,461 +并且关系必须是可选的 +并且具有反向关系 + +185 +00:11:34,494 --> 00:11:38,899 +此外 CloudKit 不支持拒绝删除规则 + +186 +00:11:38,932 --> 00:11:43,937 +在开发 App 时 您将使用开发环境 + +187 +00:11:43,971 --> 00:11:48,475 +CloudKit 架构可以在此环境中 +自由修改 + +188 +00:11:48,509 --> 00:11:51,612 +但是 将架构升级到生产模式后 + +189 +00:11:51,645 --> 00:11:54,882 +记录类型及其字段是不可变的 + +190 +00:11:54,915 --> 00:11:58,919 +虽然轻量级迁移 +可以处理许多不同的场景 + +191 +00:11:58,952 --> 00:12:02,523 +但 CloudKit 在它支持的内容上 +受到更多限制 + +192 +00:12:02,556 --> 00:12:07,561 +我之前描述的许多轻量级操作 +都不受支持 + +193 +00:12:07,594 --> 00:12:10,998 +具体来说 CloudKit 支持 + +194 +00:12:11,031 --> 00:12:16,203 +向现有记录类型添加新字段 +和添加新记录类型 + +195 +00:12:16,236 --> 00:12:21,441 +您不能修改或删除 +现有的记录类型或字段 + +196 +00:12:21,475 --> 00:12:25,245 +修改模型架构时 请考虑这些限制 + +197 +00:12:26,680 --> 00:12:28,949 +当需要更新数据模型时 + +198 +00:12:28,982 --> 00:12:33,153 +请记住轻量级迁移 +仅在本地存储文件中实现 + +199 +00:12:33,187 --> 00:12:35,155 +架构更改 + +200 +00:12:35,189 --> 00:12:38,859 +无论 CloudKit 是否使用特定存储 + +201 +00:12:38,892 --> 00:12:42,162 +迁移只会更改磁盘上的存储 + +202 +00:12:42,196 --> 00:12:45,799 +而不会更改 CloudKit 架构 + +203 +00:12:45,832 --> 00:12:48,001 +您仍然需要通过运行架构初始化程序 + +204 +00:12:48,035 --> 00:12:52,172 +在开发数据库中使这些更改具体化 + +205 +00:12:52,206 --> 00:12:55,042 +然后使用 CloudKit 控制台 + +206 +00:12:55,075 --> 00:12:58,212 +将开发中的这些更改提升到生产中 + +207 +00:12:58,245 --> 00:13:02,216 +请记住 您的 App 用户 +将同时使用旧版本 + +208 +00:13:02,249 --> 00:13:04,384 +和新版本 + +209 +00:13:04,418 --> 00:13:06,954 +最新版 App 当然会知道 + +210 +00:13:06,987 --> 00:13:09,823 +架构中所有新添加的功能 + +211 +00:13:09,857 --> 00:13:14,127 +旧版 App 不会知道 +新字段或记录类型 + +212 +00:13:15,863 --> 00:13:18,866 +由于 CloudKit 架构本质上是附加的 + +213 +00:13:18,899 --> 00:13:22,069 +因此请考虑将架构迁移到 + +214 +00:13:22,102 --> 00:13:24,938 +运行旧版 App 设备上的影响 + +215 +00:13:24,972 --> 00:13:29,743 +例如 一个常见的缺陷是 +忘记更新旧版 App + +216 +00:13:29,776 --> 00:13:33,747 +从而使用新版本已不使用的旧字段 + +217 +00:13:33,780 --> 00:13:37,885 +下面是一些 +迁移 CloudKit 架构的策略 + +218 +00:13:37,918 --> 00:13:43,090 +第一种选择是以增量方式 +向现有记录类型添加新字段 + +219 +00:13:43,123 --> 00:13:47,227 +如果您采用这种方法 +旧版 App 将可以访问 + +220 +00:13:47,261 --> 00:13:50,964 +用户创建的每条记录 +但不能访问每个字段 + +221 +00:13:52,332 --> 00:13:55,102 +第二个选项是通过包含版本属性 + +222 +00:13:55,135 --> 00:13:59,006 +来对实体进行版本设置 +然后使用提取请求 + +223 +00:13:59,039 --> 00:14:03,110 +仅选择与 App 当前版本兼容的记录 + +224 +00:14:04,077 --> 00:14:07,714 +如果您采用这种方法 旧版 App + +225 +00:14:07,748 --> 00:14:11,752 +将无法获取 +用户使用较新版本创建的记录 + +226 +00:14:11,785 --> 00:14:15,122 +从而有效地将它们隐藏在该设备上 + +227 +00:14:15,155 --> 00:14:18,525 +最后一个策略是使用 + +228 +00:14:18,559 --> 00:14:21,595 +NSPersistentCloudKitContainerOptions +创建一个全新的容器 + +229 +00:14:21,628 --> 00:14:25,032 +将新的存储与新的容器相关联 + +230 +00:14:25,065 --> 00:14:28,068 +请注意 如果用户有一个大型数据集 + +231 +00:14:28,101 --> 00:14:33,106 +将数据集上传到 +iCloud 可能需要很长时间 + +232 +00:14:33,140 --> 00:14:37,244 +无论您使用哪种方法 +都要小心设计您的数据模型 + +233 +00:14:37,277 --> 00:14:40,948 +一定要考虑跨版本的兼容性问题 + +234 +00:14:40,981 --> 00:14:44,518 +并一起测试不同版本的数据模型 + +235 +00:14:44,551 --> 00:14:47,020 +既然我们已经彻底讨论了数据模型 + +236 +00:14:47,054 --> 00:14:51,124 +迁移和 CloudKit +那么我来实际演示一下 + +237 +00:14:51,158 --> 00:14:54,161 +您可能已经猜到了 我是一名飞行员 + +238 +00:14:54,194 --> 00:14:57,264 +我创建了一个小 App +来记录我的飞行时间 + +239 +00:14:57,297 --> 00:14:59,499 +这是该 App 的数据模型 + +240 +00:14:59,533 --> 00:15:04,037 +我有一个名为 LogEntry 的实体 +并添加了许多属性 + +241 +00:15:04,071 --> 00:15:09,443 +例如飞机类型 飞行时间 +始发地 目的地和尾号 + +242 +00:15:09,476 --> 00:15:14,414 +可以让我记录需要的体验信息 + +243 +00:15:14,448 --> 00:15:16,817 +当我第一次运行这个 App 时 + +244 +00:15:16,850 --> 00:15:21,455 +Core Data 将创建存储 +并在该存储中实现架构 + +245 +00:15:21,488 --> 00:15:23,190 +在运行 App 之前 + +246 +00:15:23,223 --> 00:15:28,128 +我将打开 +com.Apple.CoreData.SQLDebug + +247 +00:15:28,161 --> 00:15:34,001 +和 com.apple.CoreData.MigrationDebug +环境变量 + +248 +00:15:34,034 --> 00:15:37,704 +这会使 Core Data 记录 +它正在执行的步骤 + +249 +00:15:37,738 --> 00:15:40,574 +有了这些参数 我将运行该 App + +250 +00:15:42,342 --> 00:15:46,180 +随着 App 启动 +Core Data 在记录它正在执行的步骤 + +251 +00:15:46,213 --> 00:15:49,716 +创建文件 为存储创建元数据 + +252 +00:15:49,750 --> 00:15:52,019 +以及实现架构 + +253 +00:15:52,052 --> 00:15:56,623 +SQLite 使用我们的架构创建了 +表 ZLOGENTRY + +254 +00:15:56,657 --> 00:15:59,526 +这也可以通过使用 +sqlite3 命令行工具 + +255 +00:15:59,560 --> 00:16:02,262 +查看存储文件来确认 + +256 +00:16:02,296 --> 00:16:07,201 +在这里 我有一个 LogEntry 表 +它有与我在 + +257 +00:16:07,234 --> 00:16:09,970 +数据模型中创建的属性对应的列 + +258 +00:16:10,003 --> 00:16:12,973 +现在我要做一些轻量级的改动 + +259 +00:16:14,341 --> 00:16:18,445 +我正在添加一些新的实体 +Aircraft Pilot 和 Airport + +260 +00:16:18,478 --> 00:16:21,081 +这会帮助我规范化架构 + +261 +00:16:21,114 --> 00:16:26,086 +我正在将 LogEntry 实体中的 +一些属性更改为关系 + +262 +00:16:26,119 --> 00:16:30,958 +例如 目的地和始发地 +从字符串属性转变为 + +263 +00:16:30,991 --> 00:16:34,061 +机场一对一关系 + +264 +00:16:34,094 --> 00:16:37,164 +Airport 实体还有两个新属性 + +265 +00:16:37,197 --> 00:16:40,534 +即 icaoIdentifier 和 faaIdentifier + +266 +00:16:40,567 --> 00:16:44,304 +type 属性被提升为 +一个新实体 Aircraft + +267 +00:16:44,338 --> 00:16:49,343 +我添加了两个新属性 +tailNumber 和 registrationNumber + +268 +00:16:49,376 --> 00:16:55,249 +在 LogEntry 上 我正在从 LogEntry +创建与飞机的一对一关系 + +269 +00:16:56,416 --> 00:17:01,522 +最后 我添加了一个具有名称 +和证书 ID 的 Pilot 实体 + +270 +00:17:02,589 --> 00:17:06,393 +每个日志条目 +将与一个 Pilot 实体相关 + +271 +00:17:06,426 --> 00:17:09,296 +现在我已经完成了对数据模型的更改 + +272 +00:17:09,329 --> 00:17:10,998 +我将再次运行该 App + +273 +00:17:15,235 --> 00:17:19,039 +噢 我在运行 App 时收到一个错误 + +274 +00:17:19,072 --> 00:17:20,774 +检查一下代码 + +275 +00:17:20,807 --> 00:17:24,845 +是 NSPersistentStore- +IncompatibleVersionHashError + +276 +00:17:24,878 --> 00:17:28,448 +该错误意味着我当前模型的架构 +不再与存储中的模型 + +277 +00:17:28,482 --> 00:17:30,184 +相匹配 + +278 +00:17:30,217 --> 00:17:32,719 +我需要迁移存储架构 + +279 +00:17:32,753 --> 00:17:35,355 +我可以通过以下三种方式中的一种 +来做到这一点 + +280 +00:17:35,389 --> 00:17:40,761 +使用第一种方法 我可以将我的代码 +转换为使用 NSPersistentContainer + +281 +00:17:40,794 --> 00:17:45,799 +因为轻量级迁移选项会自动为我设置 + +282 +00:17:45,832 --> 00:17:50,337 +第二种方法 我可以使用 +NSPersistentStoreDescription + +283 +00:17:50,370 --> 00:17:55,375 +因为轻量级迁移选项 +也会自动为我设置 + +284 +00:17:55,409 --> 00:17:58,812 +最后 使用第三种方法 我可以 + +285 +00:17:58,846 --> 00:18:02,115 +在选项字典上 +手动设置轻量级迁移选项 + +286 +00:18:02,149 --> 00:18:06,119 +并在打开存储时 +将该字典传递给协调器 + +287 +00:18:06,987 --> 00:18:11,225 +我想我会选择第一个选项 +使用 NSPersistentContainer + +288 +00:18:11,258 --> 00:18:15,295 +现在我已将代码转换为使用 +NSPersistentContainer + +289 +00:18:15,329 --> 00:18:17,431 +我将启动 App 并再次观察到 + +290 +00:18:17,464 --> 00:18:20,467 +Core Data 正在迁移 +存储文件中的架构 + +291 +00:18:32,012 --> 00:18:36,850 +同样这可以使用 +sqlite3 命令行工具来确认 + +292 +00:18:36,884 --> 00:18:40,621 +请注意 Core Data 使用轻量级迁移 + +293 +00:18:40,654 --> 00:18:42,256 +自动实现了新架构 + +294 +00:18:42,289 --> 00:18:44,525 +还有什么比这更容易呢 + +295 +00:18:44,558 --> 00:18:48,562 +在结束演示之前 +我想展示第 3 个选项 + +296 +00:18:48,595 --> 00:18:50,931 +回想一下 在此选项中 + +297 +00:18:50,964 --> 00:18:54,168 +我在选项字典上手动设置 +轻量级迁移选项 + +298 +00:18:54,201 --> 00:18:58,739 +然后在打开存储时 +将该字典传递给协调器 + +299 +00:18:58,772 --> 00:19:00,073 +最终结果是相同的 + +300 +00:19:00,107 --> 00:19:02,976 +因为存储迁移到了新架构 + +301 +00:19:03,010 --> 00:19:07,748 +当对数据模型进行更改时 +请使用轻量级迁移来帮助您 + +302 +00:19:07,781 --> 00:19:11,385 +对于绝大多数数据模型更改来说 + +303 +00:19:11,418 --> 00:19:14,788 +轻量级迁移非常灵活且易于使用 + +304 +00:19:14,821 --> 00:19:18,692 +如果您有更复杂的数据模型 + +305 +00:19:18,725 --> 00:19:22,062 +请将该模型分解成 +由轻量级变化组成的模型 + +306 +00:19:22,095 --> 00:19:24,965 +最后如果您在 App 中使用 CloudKit + +307 +00:19:24,998 --> 00:19:29,303 +请仔细考虑数据模型更改的影响 + +308 +00:19:29,336 --> 00:19:32,506 +彻底测试所有数据模型更改 + +309 +00:19:32,539 --> 00:19:34,808 +我希望您会发现这些信息很有用 + +310 +00:19:34,842 --> 00:19:37,611 +并且会考虑更新项目中的模型 + +311 +00:19:37,644 --> 00:19:40,047 +来构建一些很棒的新功能 + +312 +00:19:40,080 --> 00:19:43,884 +感谢您与我一起飞行 +祝您的 WWDC 之旅一切顺利 + diff --git a/zho/2022 Session 10121 Meet Focus filters.srt b/zho/2022 Session 10121 Meet Focus filters.srt new file mode 100644 index 0000000..53b3a65 --- /dev/null +++ b/zho/2022 Session 10121 Meet Focus filters.srt @@ -0,0 +1,1231 @@ +1 +00:00:00,033 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,943 +♪ + +3 +00:00:09,943 --> 00:00:14,748 +大家好 我是 iOS 系统 +体验团队的工程师 Teja + +4 +00:00:14,748 --> 00:00:18,318 +本次讲座 +我们会来看看专注模式过滤器 + +5 +00:00:18,318 --> 00:00:24,291 +我们在 iOS 15 macOS Monterey +和 watchOS 8 中引入了专注模式 + +6 +00:00:24,291 --> 00:00:27,528 +用户可以通过 +设置系统在一段时间内的行为 + +7 +00:00:27,528 --> 00:00:31,532 +来帮助自己专注于当下最重要的事 + +8 +00:00:31,532 --> 00:00:34,968 +要启用专注模式 只需进入控制中心 + +9 +00:00:34,968 --> 00:00:39,806 +选择默认或是自定义的专注模式即可 + +10 +00:00:39,806 --> 00:00:42,342 +当专注模式启用时 + +11 +00:00:42,342 --> 00:00:45,078 +用户可以自定义通知行为 + +12 +00:00:45,078 --> 00:00:48,482 +比如 在工作模式下 您也许会 + +13 +00:00:48,482 --> 00:00:51,919 +只允许来自同事的通知 + +14 +00:00:51,919 --> 00:00:55,355 +或者只允许来自某些与工作相关的 + +15 +00:00:55,355 --> 00:00:57,524 +特定 App 的通知 + +16 +00:00:57,524 --> 00:01:01,094 +每种专注模式的系统行为 + +17 +00:01:01,094 --> 00:01:04,264 +都可以在设置中调整 + +18 +00:01:04,264 --> 00:01:08,669 +iOS 16 和 macOS Ventura +引入了专注模式过滤器 + +19 +00:01:08,669 --> 00:01:10,704 +来增强专注模式 + +20 +00:01:10,704 --> 00:01:13,273 +首先 +我会为您介绍专注模式过滤器 + +21 +00:01:13,273 --> 00:01:15,475 +以及它的行为模式 + +22 +00:01:15,475 --> 00:01:20,814 +其次 要如何在您的 App 中 +定义专注模式过滤器 + +23 +00:01:20,814 --> 00:01:25,285 +然后 我也介绍 +专注模式的过滤器要怎么实现 + +24 +00:01:25,285 --> 00:01:28,155 +最后 您的 App 可以怎样 + +25 +00:01:28,155 --> 00:01:31,825 +把额外的上下文返回给系统 + +26 +00:01:31,825 --> 00:01:34,027 +专注模式过滤器可以让用户 + +27 +00:01:34,027 --> 00:01:39,666 +根据当前启用的 +专注模式自定 App 的行为模式 + +28 +00:01:39,666 --> 00:01:41,902 +一些系统 App +已经适配了专注模式过滤器 + +29 +00:01:41,902 --> 00:01:44,938 +可以用做范例 + +30 +00:01:44,938 --> 00:01:46,940 +日历 App 允许用户 + +31 +00:01:46,940 --> 00:01:50,511 +根据启用的专注模式 + +32 +00:01:50,511 --> 00:01:53,146 +设定默认显示的日历 + +33 +00:01:53,146 --> 00:01:55,883 +通常状态下 我的日历是这样的 + +34 +00:01:55,883 --> 00:01:57,551 +如您所见 在这里 + +35 +00:01:57,551 --> 00:02:01,488 +个人和工作上的日程是混在一起的 + +36 +00:02:01,488 --> 00:02:04,324 +我可以给日历 +设置一个专注模式过滤器 + +37 +00:02:04,324 --> 00:02:08,896 +让它在个人模式下 +只显示我的个人日程 + +38 +00:02:08,896 --> 00:02:10,731 +设置好专注模式过滤器后 + +39 +00:02:10,731 --> 00:02:13,300 +我的日历就变成了这样 + +40 +00:02:13,300 --> 00:02:16,670 +日历 App 会显示 +这是经过专注模式过滤的 + +41 +00:02:16,670 --> 00:02:19,740 +还提供了开关这个过滤器的选项 + +42 +00:02:19,740 --> 00:02:22,709 +现在我终于不会在个人时间 + +43 +00:02:22,709 --> 00:02:26,280 +被这些工作日程打扰了 + +44 +00:02:26,280 --> 00:02:28,649 +Mail App 的收件箱 +可以根据过滤器 + +45 +00:02:28,649 --> 00:02:32,853 +在专注模式下只显示相关的邮箱 + +46 +00:02:32,853 --> 00:02:35,422 +还可以过滤 Mail 通知 + +47 +00:02:35,422 --> 00:02:40,027 +使其只突出显示相关的通知 + +48 +00:02:40,027 --> 00:02:42,162 +也就是说我可以让 Mail + +49 +00:02:42,162 --> 00:02:45,265 +在工作模式下只推送 + +50 +00:02:45,265 --> 00:02:48,235 +工作相关的邮件通知 + +51 +00:02:48,235 --> 00:02:52,439 +这样个人邮件通知就不会打扰到我 + +52 +00:02:52,439 --> 00:02:53,507 +为您的 App + +53 +00:02:53,507 --> 00:02:56,510 +加入专注模式过滤器的好处有很多 + +54 +00:02:56,510 --> 00:02:59,179 +也许您的 App 管理着多个账户 + +55 +00:02:59,179 --> 00:03:01,615 +一个账户会需要 + +56 +00:03:01,615 --> 00:03:04,084 +关联一个专注模式 + +57 +00:03:04,084 --> 00:03:07,654 +有大量数据的 App +也许需要为了专注模式 + +58 +00:03:07,654 --> 00:03:09,656 +过滤内容 + +59 +00:03:09,656 --> 00:03:11,325 +如果您想帮助用户 + +60 +00:03:11,325 --> 00:03:13,794 +在专注状态下免受打扰 + +61 +00:03:13,794 --> 00:03:16,196 +您可以通过减少标记 + +62 +00:03:16,196 --> 00:03:18,632 +App 提醒以及通知的数量 + +63 +00:03:18,632 --> 00:03:23,303 +来突出专注模式下最重要的信息 + +64 +00:03:23,303 --> 00:03:26,673 +在外观上 也许您的 App +可以根据启用的专注模式 + +65 +00:03:26,673 --> 00:03:30,110 +展示特定的主题或布局 + +66 +00:03:30,110 --> 00:03:34,281 +从本质上讲 只要您的 App +可以根据不同情况 + +67 +00:03:34,281 --> 00:03:38,151 +展示不同内容 +您就可以利用专注模式过滤器 + +68 +00:03:38,151 --> 00:03:41,388 +改善用户体验 + +69 +00:03:41,388 --> 00:03:44,491 +我来说明一下 +专注模式过滤器的运作方式 + +70 +00:03:44,491 --> 00:03:49,596 +您的 App 定义了 +用户可以根据专注模式自定哪些内容 + +71 +00:03:49,596 --> 00:03:52,733 +这会通过 AppIntent 实现 + +72 +00:03:52,733 --> 00:03:57,237 +系统会暴露出 +可根据专注模式设置的部分 + +73 +00:03:57,237 --> 00:04:00,774 +您的 AppIntent +定义的属性可通过 UI 设置 + +74 +00:04:00,774 --> 00:04:05,579 +它会在专注模式设置中 +作为过滤器显示出来 + +75 +00:04:05,579 --> 00:04:09,216 +用户可以进入 +专注模式设置 设置过滤器 + +76 +00:04:09,216 --> 00:04:13,320 +来设定您的 App 的 + +77 +00:04:13,320 --> 00:04:15,589 +运作方式 + +78 +00:04:15,589 --> 00:04:17,925 +现在 让我来讲解 +如何把专注模式过滤器 + +79 +00:04:17,925 --> 00:04:21,128 +加入您的代码库中 + +80 +00:04:21,128 --> 00:04:24,164 +定义专注模式过滤器分为几步 + +81 +00:04:24,164 --> 00:04:28,168 +首先是启用 +SetFocusFilterIntent + +82 +00:04:28,168 --> 00:04:30,537 +这会向系统表明您的 App + +83 +00:04:30,537 --> 00:04:35,008 +愿意根据专注模式提供自定设置 + +84 +00:04:35,008 --> 00:04:38,679 +第二步是定义 App 的参数 + +85 +00:04:38,679 --> 00:04:42,516 +即用户可以在您的 App 中 + +86 +00:04:42,516 --> 00:04:44,218 +调节哪些设置 + +87 +00:04:44,218 --> 00:04:47,788 +最后一步是设置显示内容 + +88 +00:04:47,788 --> 00:04:50,858 +这样您的过滤器才会在系统设置中 + +89 +00:04:50,858 --> 00:04:52,893 +显示正确的内容 + +90 +00:04:52,893 --> 00:04:57,397 +用户才能明白自己设置了什么 + +91 +00:04:57,397 --> 00:04:59,233 +用代码举例 + +92 +00:04:59,233 --> 00:05:02,836 +首先您需要 import AppIntents + +93 +00:05:02,836 --> 00:05:07,541 +定义一个实施了 +SetFocusFilterIntent 的 struct + +94 +00:05:07,541 --> 00:05:10,110 +这就是您的专注模式过滤器 + +95 +00:05:10,110 --> 00:05:12,179 +设置标题和描述 + +96 +00:05:12,179 --> 00:05:17,651 +让用户知道您的专注模式有什么效果 + +97 +00:05:17,651 --> 00:05:22,089 +过滤器在设置中以网格状展示 + +98 +00:05:22,089 --> 00:05:24,691 +在专注模式过滤器设置完成之前 + +99 +00:05:24,691 --> 00:05:28,529 +这就是用户会看到的界面 + +100 +00:05:28,529 --> 00:05:31,665 +这里就是您的 App 的图标 + +101 +00:05:31,665 --> 00:05:34,535 +主要文本是 App 名 + +102 +00:05:34,535 --> 00:05:37,704 +次要文本则与您在过滤器中 + +103 +00:05:37,704 --> 00:05:40,874 +设置的标题对应 + +104 +00:05:40,874 --> 00:05:44,211 +当用户点击配置您的过滤器时 + +105 +00:05:44,211 --> 00:05:46,847 +会显示出同样的内容 + +106 +00:05:46,847 --> 00:05:50,517 +这时 系统还会展示您提供的 + +107 +00:05:50,517 --> 00:05:54,555 +描述字符串 以供参考 + +108 +00:05:54,555 --> 00:05:57,658 +标题和描述字符串都是静态的 + +109 +00:05:57,658 --> 00:05:59,326 +系统在安装您的 App 时 + +110 +00:05:59,326 --> 00:06:02,563 +就读取了它们 + +111 +00:06:02,563 --> 00:06:05,832 +定义您的专注模式过滤器时 + +112 +00:06:05,832 --> 00:06:08,802 +您必须提供一系列修饰为参数的属性 + +113 +00:06:08,802 --> 00:06:13,006 +用于指定用户可以自定的内容 + +114 +00:06:13,006 --> 00:06:16,009 +指定参数时 必须为其命名 + +115 +00:06:16,009 --> 00:06:17,911 +并确定数据类型 + +116 +00:06:17,911 --> 00:06:19,980 +这些参数可以是标准数据类型 + +117 +00:06:19,980 --> 00:06:23,684 +比如 Bool, string, float 等等 + +118 +00:06:23,684 --> 00:06:25,619 +如果您希望设置某种 + +119 +00:06:25,619 --> 00:06:28,922 +自定义的数据类型 +您可以将其设为实体 + +120 +00:06:28,922 --> 00:06:32,392 +这样您就可以 +把它修饰为一个参数使用 + +121 +00:06:32,392 --> 00:06:35,229 +要学习更多关于 +实体和 App 意图的内容 + +122 +00:06:35,229 --> 00:06:38,632 +请观看“详解 App 意图”讲座 + +123 +00:06:38,632 --> 00:06:41,768 +定义专注模式过滤器时 +您只需要指定 + +124 +00:06:41,768 --> 00:06:44,771 +数据类型以及各参数名 + +125 +00:06:44,771 --> 00:06:48,775 +应用于各专注模式的参数值 + +126 +00:06:48,775 --> 00:06:52,145 +是由用户决定的 + +127 +00:06:52,145 --> 00:06:54,381 +可以把参数标记为可选项 + +128 +00:06:54,381 --> 00:06:57,718 +这样用户就不一定要设置它们 + +129 +00:06:57,718 --> 00:07:03,123 +非可选项的参数必须有一个默认值 + +130 +00:07:03,123 --> 00:07:06,326 +在代码中 指定一个参数 + +131 +00:07:06,326 --> 00:07:09,596 +或可选参数的方法是:定义 + +132 +00:07:09,596 --> 00:07:12,499 +您希望出现在过滤器中的变量类型 + +133 +00:07:12,499 --> 00:07:15,435 +并将其修饰为一个参数 + +134 +00:07:15,435 --> 00:07:19,206 +在这里 +我创建了一个必选的 Bool 参数 + +135 +00:07:19,206 --> 00:07:23,377 +代表我的专注模式 +是否总是使用深色模式 + +136 +00:07:23,377 --> 00:07:25,779 +我把它的默认值设置为否 + +137 +00:07:25,779 --> 00:07:29,116 +我还创建了一个 +可选的 string 参数 + +138 +00:07:29,116 --> 00:07:33,987 +代表此专注模式下的用户状态 + +139 +00:07:33,987 --> 00:07:37,524 +最后 我添加了一个可选的账户参数 + +140 +00:07:37,524 --> 00:07:40,527 +这是我的 App 定义的一个实体 + +141 +00:07:40,527 --> 00:07:44,932 +其包含了特定账户的信息 + +142 +00:07:44,932 --> 00:07:48,635 +这三个参数都设置了标题 + +143 +00:07:48,635 --> 00:07:51,805 +用于描述这些参数 + +144 +00:07:51,805 --> 00:07:54,274 +会在设置中展示给用户 + +145 +00:07:54,274 --> 00:07:55,509 +在专注模式设置中 + +146 +00:07:55,509 --> 00:07:58,345 +用户设置您的 App 的 +专注模式过滤器时 + +147 +00:07:58,345 --> 00:08:00,781 +设置界面会以类似我刚才展示过的 + +148 +00:08:00,781 --> 00:08:02,583 +网格的样子呈现 + +149 +00:08:02,583 --> 00:08:04,051 +但这次 因为过滤器 + +150 +00:08:04,051 --> 00:08:07,955 +已经设置好了 其内容会动态反映 + +151 +00:08:07,955 --> 00:08:11,625 +之前设置的内容 + +152 +00:08:11,625 --> 00:08:14,795 +这里仍然是您的 App 的图标 + +153 +00:08:14,795 --> 00:08:17,331 +主要文本和次要文本 + +154 +00:08:17,331 --> 00:08:21,535 +可以根据 +FocusFilterIntent 中的 + +155 +00:08:21,535 --> 00:08:24,471 +显示内容属性自定义 + +156 +00:08:24,471 --> 00:08:27,574 +主要文本会显示出 + +157 +00:08:27,574 --> 00:08:31,278 +设置好了的参数 比如选择账户 + +158 +00:08:31,278 --> 00:08:34,181 +设置状态 等等 + +159 +00:08:34,181 --> 00:08:37,417 +次要文本会显示出 + +160 +00:08:37,417 --> 00:08:43,557 +设置好了的参数 +比如工作账户或工作中 + +161 +00:08:43,557 --> 00:08:46,527 +在我的代码中 我设置了 + +162 +00:08:46,527 --> 00:08:49,229 +动态生成显示内容 + +163 +00:08:49,229 --> 00:08:53,367 +因为账户和状态都是可选参数 + +164 +00:08:53,367 --> 00:08:56,036 +它们只在用户设置之后 + +165 +00:08:56,036 --> 00:08:59,840 +才会出现在动态主次文本中 + +166 +00:08:59,840 --> 00:09:03,343 +由于 alwaysUseDarkMode +是一个必选参数 + +167 +00:09:03,343 --> 00:09:09,116 +它会始终包含在主要和次要文本中 + +168 +00:09:09,116 --> 00:09:11,718 +好了 现在您定义好了 +专注模式过滤器 + +169 +00:09:11,718 --> 00:09:13,854 +用户可以在专注模式设置中 + +170 +00:09:13,854 --> 00:09:17,457 +为某个专注模式自定特定值了 + +171 +00:09:17,457 --> 00:09:20,494 +但您的 App +怎么知道用户自定了什么呢? + +172 +00:09:20,494 --> 00:09:23,297 +您的 App 要如何适当更新自己? + +173 +00:09:23,297 --> 00:09:26,667 +它必须根据系统的变化采取行动 + +174 +00:09:26,667 --> 00:09:29,703 +当专注模式发生了变化 系统认为 + +175 +00:09:29,703 --> 00:09:32,840 +您的 App 有必要知道这个变化时 + +176 +00:09:32,840 --> 00:09:36,376 +它会用 +两种方式之一向您传达这个信息 + +177 +00:09:36,376 --> 00:09:39,246 +如果 App 正在运行 +而您已经部署了 + +178 +00:09:39,246 --> 00:09:42,149 +FocusFilterIntent 它就会收到 + +179 +00:09:42,149 --> 00:09:44,017 +perform 方法的调用 + +180 +00:09:44,017 --> 00:09:47,988 +如果 App 没有运行 您可以部署 + +181 +00:09:47,988 --> 00:09:49,523 +一个扩展 + +182 +00:09:49,523 --> 00:09:51,725 +这样 如果您已经 + +183 +00:09:51,725 --> 00:09:55,095 +在 FocusFilterIntent 中 +部署了 perform + +184 +00:09:55,095 --> 00:09:58,732 +它就会在扩展中被调用 + +185 +00:09:58,732 --> 00:10:01,668 +您的 App 和扩展 +都可以调用 perform + +186 +00:10:01,668 --> 00:10:06,006 +所以并非每个 App 都需要扩展 + +187 +00:10:06,006 --> 00:10:09,776 +一般来说 如果您的 App 只是 + +188 +00:10:09,776 --> 00:10:12,446 +随着专注模式的改变更新界面外观 + +189 +00:10:12,446 --> 00:10:18,018 +那只在 App 内 +实现 perform 就足够了 + +190 +00:10:18,018 --> 00:10:21,221 +如果您的 App 的 +小组件、通知或标记 + +191 +00:10:21,221 --> 00:10:24,725 +都需要随着专注模式改变 + +192 +00:10:24,725 --> 00:10:29,563 +那您也许会需要部署一个扩展 + +193 +00:10:29,563 --> 00:10:31,665 +基本上 如果您的 App + +194 +00:10:31,665 --> 00:10:34,601 +想要更新任何内部视图之外的东西 + +195 +00:10:34,601 --> 00:10:37,671 +您就需要部署扩展了 + +196 +00:10:37,671 --> 00:10:40,741 +在后面 +我会用“您的 App”这个词 + +197 +00:10:40,741 --> 00:10:44,511 +根据上下文不同 +它可能说的是您的 App + +198 +00:10:44,511 --> 00:10:47,781 +也可能是您的扩展 + +199 +00:10:47,781 --> 00:10:52,119 +要响应一个专注模式过滤器 +请部署 perform 函数 + +200 +00:10:52,119 --> 00:10:54,688 +访问设置中提供的 + +201 +00:10:54,688 --> 00:10:58,525 +参数的填充值 + +202 +00:10:58,525 --> 00:11:02,196 +依此更新您的 App 的外观与行为 + +203 +00:11:02,196 --> 00:11:04,631 +当系统认为您的 App + +204 +00:11:04,631 --> 00:11:06,800 +需要响应专注模式的变化时 + +205 +00:11:06,800 --> 00:11:10,537 +就会调用您的 perform 部署 + +206 +00:11:10,537 --> 00:11:13,807 +当系统认为先前提供的值 + +207 +00:11:13,807 --> 00:11:18,212 +不再有效时 也会调用 perform + +208 +00:11:18,212 --> 00:11:21,014 +这种情况下 您的过滤器参数 + +209 +00:11:21,014 --> 00:11:24,451 +会被设置成默认值 + +210 +00:11:24,451 --> 00:11:27,387 +当系统根据您的 App 的 +过滤器调用 perform 时 + +211 +00:11:27,387 --> 00:11:30,257 +所有参数会根据 + +212 +00:11:30,257 --> 00:11:32,860 +设置中设定的值填满 + +213 +00:11:32,860 --> 00:11:35,896 +要读取参数名的值 + +214 +00:11:35,896 --> 00:11:39,399 +可以调用 self.“参数名” + +215 +00:11:39,399 --> 00:11:41,635 +这个示例中 +在 perform 的最后 + +216 +00:11:41,635 --> 00:11:46,173 +我让 App 根据我收到的数据更新 + +217 +00:11:46,173 --> 00:11:47,708 +有时候 您也许会需要询问 + +218 +00:11:47,708 --> 00:11:50,043 +当前的过滤器参数 + +219 +00:11:50,043 --> 00:11:51,111 +在我的案例中 + +220 +00:11:51,111 --> 00:11:55,315 +因为我的过滤器名叫 +ExampleChatAppFocusFilter + +221 +00:11:55,315 --> 00:11:59,520 +我就要访问 +ExampleChatAppFocusFilter.current + +222 +00:12:02,122 --> 00:12:04,925 +现在您的 App +可以根据专注模式过滤器行动了 + +223 +00:12:04,925 --> 00:12:08,262 +接下来就是进一步提升用户体验 + +224 +00:12:08,262 --> 00:12:11,999 +把您的 App +行为变化的额外上下文 + +225 +00:12:11,999 --> 00:12:14,701 +返回给系统 + +226 +00:12:16,570 --> 00:12:19,339 +通过提供额外上下文 + +227 +00:12:19,339 --> 00:12:22,910 +您可以在 App 视图 +之外影响其行为 + +228 +00:12:22,910 --> 00:12:26,013 +比如 过滤通知信息 + +229 +00:12:26,013 --> 00:12:30,250 +设定您的 App 的通知标记的数量 + +230 +00:12:30,250 --> 00:12:32,452 +一个给系统提供信息的方法 + +231 +00:12:32,452 --> 00:12:35,088 +是通过 AppContext 对象 + +232 +00:12:35,088 --> 00:12:37,090 +这个对象可以作为 + +233 +00:12:37,090 --> 00:12:41,028 +perform 函数结果的一部分返回 + +234 +00:12:41,028 --> 00:12:43,664 +或者 您可以在专注模式过滤器中 + +235 +00:12:43,664 --> 00:12:46,400 +随时返回 AppContext + +236 +00:12:46,400 --> 00:12:50,604 +并通过调用 invalidate +强制系统获取更新值 + +237 +00:12:50,604 --> 00:12:53,807 +当有专注模式过滤器启用时 + +238 +00:12:53,807 --> 00:12:57,811 +您的 App 也许有 +额外的上下文 用来决定某个通知 + +239 +00:12:57,811 --> 00:13:00,314 +是否应该打断用户 + +240 +00:13:00,314 --> 00:13:03,617 +为了传递这个信息 +您的 App 必须 + +241 +00:13:03,617 --> 00:13:08,555 +在 AppContext 中 +设置 filterPredicate 属性 + +242 +00:13:08,555 --> 00:13:11,325 +这个“过滤器谓词”与一个 + +243 +00:13:11,325 --> 00:13:15,295 +叫做 filterCriteria +的新字符串属性 + +244 +00:13:15,295 --> 00:13:17,965 +共同工作在 UNNotification 上 + +245 +00:13:17,965 --> 00:13:21,835 +如果通知的过滤器与过滤器谓词(Predicate) + +246 +00:13:21,835 --> 00:13:26,406 +不符合 该通知就会被静音 + +247 +00:13:26,406 --> 00:13:30,010 +要在 FocusFilterIntent 中 +设置过滤器谓词 + +248 +00:13:30,010 --> 00:13:32,713 +请把它加入您的 App 上下文中 + +249 +00:13:32,713 --> 00:13:35,649 +假如一台设备开启了个人专注模式 + +250 +00:13:35,649 --> 00:13:38,652 +用户在设置中只选中了 + +251 +00:13:38,652 --> 00:13:40,454 +个人账户 + +252 +00:13:40,454 --> 00:13:42,956 +在这种情况下 我把过滤器谓词 + +253 +00:13:42,956 --> 00:13:46,093 +设置成个人账户的标识符 + +254 +00:13:46,093 --> 00:13:49,530 +如果收到的通知不是来自个人账户 + +255 +00:13:49,530 --> 00:13:53,100 +它就不会打断用户 + +256 +00:13:53,100 --> 00:13:56,403 +这里 当我设置这个通知时 + +257 +00:13:56,403 --> 00:14:00,874 +我把 filterCriteria +设置成了工作账户的标识符 + +258 +00:14:00,874 --> 00:14:03,810 +因为我知道这个通知 + +259 +00:14:03,810 --> 00:14:06,146 +是要发送给工作账户的 + +260 +00:14:06,146 --> 00:14:09,249 +这个通知应该会被静音 + +261 +00:14:09,249 --> 00:14:13,053 +因为它的账户标识符与我刚刚设置的 + +262 +00:14:13,053 --> 00:14:14,555 +谓词不符 + +263 +00:14:14,555 --> 00:14:19,092 +它只和个人账户的标识符相符 + +264 +00:14:19,092 --> 00:14:22,029 +这是一个本地通知的示例 + +265 +00:14:22,029 --> 00:14:25,899 +但远程通知也可以通过 JSON 载荷 + +266 +00:14:25,899 --> 00:14:29,770 +来设置过滤器 + +267 +00:14:29,770 --> 00:14:32,372 +另一个给系统提供 +额外上下文的方法是 + +268 +00:14:32,372 --> 00:14:35,609 +更新您的 App 的标记数量 + +269 +00:14:35,609 --> 00:14:39,580 +以反映当前启用的 +专注模式下什么最重要 + +270 +00:14:39,580 --> 00:14:42,616 +这样可以防止您的用户分心 + +271 +00:14:42,616 --> 00:14:45,219 +在 UserNotifications 中 + +272 +00:14:45,219 --> 00:14:47,087 +有一个新的 API 为此设计 + +273 +00:14:47,087 --> 00:14:52,092 +在 UNUserNotificationCenter 上 +您只需用一个代表新标记值的 + +274 +00:14:52,092 --> 00:14:57,164 +无符号整数 +调用 setBadgeCount 即可 + +275 +00:14:57,164 --> 00:14:59,399 +现在 您已经学会如何提供上下文 + +276 +00:14:59,399 --> 00:15:02,736 +以过滤通知 或是设置标记数量了 + +277 +00:15:02,736 --> 00:15:05,372 +记住 这个功能的目标是为了 + +278 +00:15:05,372 --> 00:15:08,509 +在用户需要专注时 +展示最有用的信息 + +279 +00:15:08,509 --> 00:15:12,112 +有时候 +这需要尽量减少展示不相关的内容 + +280 +00:15:12,112 --> 00:15:16,283 +以防止用户在启用专注模式时分心 + +281 +00:15:16,283 --> 00:15:18,952 +接下来 请您思考一下 + +282 +00:15:18,952 --> 00:15:22,656 +您的 App 的哪些部分 +可以从专注模式过滤器中受益 + +283 +00:15:22,656 --> 00:15:25,559 +确定哪些属性可以配置 + +284 +00:15:25,559 --> 00:15:29,029 +设置好您的 App 和扩展来处理这些 + +285 +00:15:29,029 --> 00:15:30,697 +然后更进一步 + +286 +00:15:30,697 --> 00:15:34,568 +看看您是否需要提供额外上下文 + +287 +00:15:34,568 --> 00:15:36,436 +这就是专注模式过滤器! + +288 +00:15:36,436 --> 00:15:38,172 +感谢您参加这次讲座 + +289 +00:15:38,172 --> 00:15:40,440 +祝您愉快度过 +接下来的 WWDC 时光 + +290 +00:15:40,440 --> 00:15:44,578 +♪ + diff --git a/zho/2022 Session 10129 Understand USD fundamentals.srt b/zho/2022 Session 10129 Understand USD fundamentals.srt new file mode 100644 index 0000000..c95f88a --- /dev/null +++ b/zho/2022 Session 10129 Understand USD fundamentals.srt @@ -0,0 +1,1632 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,510 +♪ + +3 +00:00:09,510 --> 00:00:12,145 +您好 欢迎来到 WWDC + +4 +00:00:12,145 --> 00:00:14,047 +我是 Kacey + +5 +00:00:14,047 --> 00:00:16,617 +您可能已经见到过“通用场景描述” + +6 +00:00:16,617 --> 00:00:18,218 +或者简称为 USD + +7 +00:00:18,218 --> 00:00:21,555 +您可能已经在增强现实中 +与 USD 文件进行了交互 + +8 +00:00:21,555 --> 00:00:25,058 +您也可能已经有将资产 +从其他格式转换为 USD 的经验 + +9 +00:00:25,058 --> 00:00:28,195 +但是 USD 文件里究竟有什么呢? + +10 +00:00:28,195 --> 00:00:31,365 +USD 是一项 +具有独特功能的重要技术 + +11 +00:00:31,365 --> 00:00:32,933 +就让我们一起揭开它的神秘面纱 + +12 +00:00:32,933 --> 00:00:36,370 +来探讨 USD 的基本原理吧 + +13 +00:00:36,370 --> 00:00:39,139 +我们将了解 USD 是什么 + +14 +00:00:39,139 --> 00:00:42,843 +介绍一些基础的 USD 概念 + +15 +00:00:42,843 --> 00:00:46,113 +学习如何用 USD 构建场景 + +16 +00:00:46,113 --> 00:00:50,684 +并了解 USD 的文件格式 + +17 +00:00:50,684 --> 00:00:53,921 +首先 什么是 USD? + +18 +00:00:53,921 --> 00:00:56,924 +USD 由 Pixar 动画工作室开发 + +19 +00:00:56,924 --> 00:00:59,693 +帮助工作室创作出 +那些深受我们喜爱的精彩电影 + +20 +00:00:59,693 --> 00:01:02,696 +它也在影视、娱乐 + +21 +00:01:02,696 --> 00:01:04,665 +和其他行业中有着广泛应用 + +22 +00:01:04,665 --> 00:01:07,201 +它被设计为可扩展的 +并且正在迅速作为一种 + +23 +00:01:07,201 --> 00:01:10,370 +具备协作性的关键工作流技术崛起 + +24 +00:01:10,370 --> 00:01:12,506 +它是一个建立在数十年 + +25 +00:01:12,506 --> 00:01:14,908 +电影行业制作经验基础上的开源项目 + +26 +00:01:14,908 --> 00:01:17,211 +并且越来越多地被用于游戏 + +27 +00:01:17,211 --> 00:01:22,416 +模拟、增强现实、制造业和电子商务 + +28 +00:01:22,416 --> 00:01:24,818 +USD 有三个核心要素 + +29 +00:01:24,818 --> 00:01:27,921 +场景描述规范、API + +30 +00:01:27,921 --> 00:01:30,824 +和渲染系统 + +31 +00:01:30,824 --> 00:01:35,529 +您的 App 使用 API 与 USD 进行交互 + +32 +00:01:35,529 --> 00:01:36,964 +渲染系统为使用不同 + +33 +00:01:36,964 --> 00:01:41,468 +渲染器进行场景可视化提供支持 + +34 +00:01:41,468 --> 00:01:44,605 +Apple 有多种多样的 USD 渲染系统 + +35 +00:01:44,605 --> 00:01:47,341 +请查看“探讨 USD 工具与渲染”讲座 + +36 +00:01:47,341 --> 00:01:50,677 +了解更多信息 + +37 +00:01:50,677 --> 00:01:51,879 +在今天的讲座中 + +38 +00:01:51,879 --> 00:01:54,381 +我们将集中了解场景描述规范 + +39 +00:01:54,381 --> 00:01:56,617 +它说明了如何描述场景数据 + +40 +00:01:56,617 --> 00:01:58,018 +如何组织这些数据 + +41 +00:01:58,018 --> 00:02:02,155 +以及如何用文件格式来对其进行表述 + +42 +00:02:02,155 --> 00:02:04,958 +究其本质 +这些 USD 文件中包含了 + +43 +00:02:04,958 --> 00:02:07,628 +描述场景应有外观的数据 + +44 +00:02:07,628 --> 00:02:09,763 +渲染 App 解译这些数据 + +45 +00:02:09,763 --> 00:02:12,633 +并在屏幕上生成图像 + +46 +00:02:12,633 --> 00:02:15,936 +比如说 在去年的 WWDC 讲座中 + +47 +00:02:15,936 --> 00:02:19,940 +我们创建了这个 USD 场景 +并用 Octane 对它进行了渲染 + +48 +00:02:19,940 --> 00:02:22,242 +现在让我们深入探讨基本概念 + +49 +00:02:22,242 --> 00:02:24,811 +并了解渲染背后的数据 + +50 +00:02:24,811 --> 00:02:26,246 +为了简单起见 + +51 +00:02:26,246 --> 00:02:29,550 +我们将使用文本 USD 表述 + +52 +00:02:29,550 --> 00:02:32,386 +USD 有很多很酷的功能 +我们都想一一谈到 + +53 +00:02:32,386 --> 00:02:33,787 +但因为时间有限 + +54 +00:02:33,787 --> 00:02:35,255 +我们将集中讲解您在使用 USD 时 + +55 +00:02:35,255 --> 00:02:36,723 +可能最常遇到的必要功能 + +56 +00:02:36,723 --> 00:02:41,361 +比如舞台、基元和层级 + +57 +00:02:41,361 --> 00:02:43,297 +它们只是其中的几个例子 + +58 +00:02:43,297 --> 00:02:45,832 +让我们从舞台开始 + +59 +00:02:45,832 --> 00:02:48,969 +想象一下 我们正在剧院观看戏剧 + +60 +00:02:48,969 --> 00:02:51,371 +作为观众 我们观察着舞台上 + +61 +00:02:51,371 --> 00:02:54,341 +演员的表演 留意环境 + +62 +00:02:54,341 --> 00:02:56,877 +灯光和道具 + +63 +00:02:56,877 --> 00:03:01,281 +这很好地类比了舞台 +在 USD 中运作的方式 + +64 +00:03:01,281 --> 00:03:04,051 +一个舞台就是一个场景图表 +或者数据结构 + +65 +00:03:04,051 --> 00:03:06,086 +用于以分等级的方式 + +66 +00:03:06,086 --> 00:03:07,487 +在所有场景元素集中之处 + +67 +00:03:07,487 --> 00:03:10,624 +对图像信息进行组织 + +68 +00:03:10,624 --> 00:03:13,293 +一个舞台是单个或多个层级的组合 + +69 +00:03:13,293 --> 00:03:18,298 +它们通常是包含场景信息的文件 + +70 +00:03:18,298 --> 00:03:20,767 +一般来说舞台是由基元组成的 + +71 +00:03:20,767 --> 00:03:24,104 +基元是场景的主要容器对象 + +72 +00:03:24,104 --> 00:03:25,606 +基元可以通过包含其他基元 + +73 +00:03:25,606 --> 00:03:28,108 +来创建场景元素的层级结构 + +74 +00:03:28,108 --> 00:03:30,844 +我们来看一个例子 + +75 +00:03:30,844 --> 00:03:33,780 +左侧是一个示例 USD 分层 + +76 +00:03:33,780 --> 00:03:36,650 +在右侧 我们可以看到舞台的 + +77 +00:03:36,650 --> 00:03:38,352 +预览视觉表述 + +78 +00:03:38,352 --> 00:03:43,624 +我们可以看到两个基元 +一个球体和一个立方体 + +79 +00:03:43,624 --> 00:03:45,526 +每个基元都有特定的类型 + +80 +00:03:45,526 --> 00:03:48,662 +来定义它在舞台中代表什么 + +81 +00:03:48,662 --> 00:03:50,230 +构成一个舞台的基元类型有很多 + +82 +00:03:50,230 --> 00:03:55,068 +比如网格、灯光和材质 + +83 +00:03:55,068 --> 00:03:56,303 +在这个例子当中 + +84 +00:03:56,303 --> 00:03:59,406 +球体基元有一个 +名为 Sphere 的类型 + +85 +00:03:59,406 --> 00:04:03,710 +立方体基元有一个 +名为 Cube 的类型 + +86 +00:04:03,710 --> 00:04:06,280 +这提出了一个很好的问题 + +87 +00:04:06,280 --> 00:04:10,017 +USD 怎么知道这些 +基元类型代表的含义呢? + +88 +00:04:10,017 --> 00:04:12,419 +USD 是通过使用模式来了解的 + +89 +00:04:12,419 --> 00:04:14,021 +模式是用于定义基元 + +90 +00:04:14,021 --> 00:04:16,957 +在舞台上角色的结构化数据 + +91 +00:04:16,957 --> 00:04:19,293 +它们为常见的场景概念提供意义 + +92 +00:04:19,293 --> 00:04:22,529 +比如几何、材料等等 + +93 +00:04:22,529 --> 00:04:23,797 +在这个例子中 + +94 +00:04:23,797 --> 00:04:26,466 +这就是一个球体的模式定义 + +95 +00:04:26,466 --> 00:04:28,435 +它定义了每个球体都有半径 + +96 +00:04:28,435 --> 00:04:31,104 +和边界框范围 + +97 +00:04:31,104 --> 00:04:34,174 +使用现有的模式 +USD 为您提供了丰富的 + +98 +00:04:34,174 --> 00:04:38,011 +内置类型基础 用于描述您的场景 + +99 +00:04:38,011 --> 00:04:41,849 +自定义模式使您 +能够进一步扩展 USD + +100 +00:04:41,849 --> 00:04:44,852 +您可以提供自己的模式 +来表述您的自定义数据 + +101 +00:04:44,852 --> 00:04:47,421 +用于您自己的案例和工作流程中 + +102 +00:04:47,421 --> 00:04:49,890 +模式不需要具备视觉表述 + +103 +00:04:49,890 --> 00:04:52,125 +它们可以只是您想在舞台上 + +104 +00:04:52,125 --> 00:04:54,428 +以结构化且有意义的方式 +保有的数据 + +105 +00:04:54,428 --> 00:04:55,529 +举例来说 + +106 +00:04:55,529 --> 00:04:59,433 +我在这里创建了一个 +名为“WWDC”的新模式 + +107 +00:04:59,433 --> 00:05:01,268 +它定义了一个含有标题和 + +108 +00:05:01,268 --> 00:05:03,370 +相关年份的基元 + +109 +00:05:03,370 --> 00:05:06,373 +这个名为“WWDC22”的基元 + +110 +00:05:06,373 --> 00:05:07,908 +就使用了该模式 + +111 +00:05:07,908 --> 00:05:09,877 +它已将年份设定为 2022 年 + +112 +00:05:09,877 --> 00:05:12,613 +并将标题设为“调用代码” + +113 +00:05:12,613 --> 00:05:14,982 +年份和标题被称作 + +114 +00:05:14,982 --> 00:05:16,183 +基元的“属性” + +115 +00:05:16,183 --> 00:05:18,519 +基元可以有各种各样的属性 + +116 +00:05:18,519 --> 00:05:21,622 +每种属性都由类型和值构成 + +117 +00:05:21,622 --> 00:05:24,024 +属性也可以带有创建的默认值 + +118 +00:05:24,024 --> 00:05:25,826 +这样它们就不必在使用此 + +119 +00:05:25,826 --> 00:05:28,395 +模式的基元中进行明确定义 + +120 +00:05:28,395 --> 00:05:30,163 +回到我们的 Sphere 模式 + +121 +00:05:30,163 --> 00:05:31,899 +您可以看到我们是如何为 + +122 +00:05:31,899 --> 00:05:34,902 +半径和范围属性定义默认值的 + +123 +00:05:34,902 --> 00:05:37,638 +这一层级中有一个 +单独的 Sphere 基元 + +124 +00:05:37,638 --> 00:05:39,840 +由于未设置 Radius 属性 + +125 +00:05:39,840 --> 00:05:42,042 +它就从 Sphere 模式中衍生出值 + +126 +00:05:42,042 --> 00:05:43,911 +默认半径为 1 + +127 +00:05:43,911 --> 00:05:47,281 +我们当然也可以明确地设置半径属性 + +128 +00:05:47,281 --> 00:05:48,749 +球体看起来和之前一样 + +129 +00:05:48,749 --> 00:05:50,951 +因为设置值与模式中 + +130 +00:05:50,951 --> 00:05:52,686 +默认设置的值“1”匹配 + +131 +00:05:52,686 --> 00:05:57,124 +现在让我们添加第二个球体 +并将半径设置为 0.5 + +132 +00:05:57,124 --> 00:05:58,825 +我们可以看到 +它确实只有另一个球体的 + +133 +00:05:58,825 --> 00:06:00,694 +一半那么大 + +134 +00:06:00,694 --> 00:06:04,865 +属性、基元和舞台也可以包含元数据 + +135 +00:06:04,865 --> 00:06:07,234 +元数据是可以为场景中某些部分 + +136 +00:06:07,234 --> 00:06:10,604 +提供辅助数据的信息的键值对 + +137 +00:06:10,604 --> 00:06:13,807 +元数据在它适用的级别中设置 + +138 +00:06:13,807 --> 00:06:15,809 +影响整个舞台的元数据 + +139 +00:06:15,809 --> 00:06:19,246 +和其中的所有基元 +都设置在舞台这一级 + +140 +00:06:19,246 --> 00:06:21,215 +特定于单个基元的元数据 + +141 +00:06:21,215 --> 00:06:23,584 +则设置在基元上 + +142 +00:06:23,584 --> 00:06:26,019 +属性也可以含有元数据 + +143 +00:06:26,019 --> 00:06:30,224 +比如说 这是典型的舞台元数据 + +144 +00:06:30,224 --> 00:06:33,760 +metersPerUnit +定义场景的比例单位 + +145 +00:06:33,760 --> 00:06:36,830 +upAxis 定义 X、 Y 或 Z 轴中哪一个 + +146 +00:06:36,830 --> 00:06:41,168 +是对场景中相机而言朝上的方向 + +147 +00:06:41,168 --> 00:06:43,170 +doc 字符串存储有用的文档 + +148 +00:06:43,170 --> 00:06:46,807 +用于工作流的跟踪 + +149 +00:06:46,807 --> 00:06:48,742 +现在我们已经定义了基础信息 + +150 +00:06:48,742 --> 00:06:51,545 +就可以开始使用 USD 了 + +151 +00:06:51,545 --> 00:06:53,347 +让我们看看仅使用这些概念 + +152 +00:06:53,347 --> 00:06:55,849 +是怎么做出煎饼的场景的 + +153 +00:06:55,849 --> 00:06:56,917 +在这个层级中 + +154 +00:06:56,917 --> 00:07:00,654 +我们创建了名为 +Pancakes 的转换基元 + +155 +00:07:00,654 --> 00:07:03,690 +再添加一个名为 +Blueberry_01 的转换基元 + +156 +00:07:03,690 --> 00:07:06,894 +它是 Pancakes 基元的子基元 + +157 +00:07:06,894 --> 00:07:11,632 +在 Blueberry_01 基元中 +我们加入了 Mesh 基元 + +158 +00:07:11,632 --> 00:07:14,001 +Mesh 基元中保存着蓝莓的几何形状 + +159 +00:07:14,001 --> 00:07:17,037 +并将其与材料绑定 + +160 +00:07:17,037 --> 00:07:18,539 +让我们通过添加其他基元 + +161 +00:07:18,539 --> 00:07:21,275 +完成剩余资产的构建 + +162 +00:07:21,275 --> 00:07:23,243 +这是我们仅使用基本概念 + +163 +00:07:23,243 --> 00:07:25,245 +完成的煎饼场景 + +164 +00:07:28,849 --> 00:07:30,684 +基础知识可以让您走得很远 + +165 +00:07:30,684 --> 00:07:32,386 +但在以生产为中心的项目中 + +166 +00:07:32,386 --> 00:07:34,388 +我们需要与许多不同的团队成员 + +167 +00:07:34,388 --> 00:07:36,290 +和组织进行协作 + +168 +00:07:36,290 --> 00:07:38,425 +USD 有很多可以满足这一需求的功能 + +169 +00:07:38,425 --> 00:07:41,662 +通过“组合”来实现 + +170 +00:07:41,662 --> 00:07:43,697 +组合使通过不同场景描述单元 + +171 +00:07:43,697 --> 00:07:46,733 +创建舞台成为可能 + +172 +00:07:46,733 --> 00:07:48,836 +它允许在实现协作和 + +173 +00:07:48,836 --> 00:07:51,138 +快速迭代的场景中 + +174 +00:07:51,138 --> 00:07:53,574 +有效地重复使用 3D 元素 + +175 +00:07:53,574 --> 00:07:56,510 +我们将讨论最常见的组合类型 + +176 +00:07:56,510 --> 00:08:01,181 +分层、引用、有效负载和变体集 + +177 +00:08:01,181 --> 00:08:03,217 +不过 让我们用有趣 +一点的方式来探讨吧 + +178 +00:08:03,217 --> 00:08:05,586 +想玩国际象棋吗? + +179 +00:08:05,586 --> 00:08:07,788 +就让我们来构建 +一套国际象棋的场景吧 + +180 +00:08:07,788 --> 00:08:09,089 +在场景中 + +181 +00:08:09,089 --> 00:08:12,159 +我们将在目录层级中使用资产目录 + +182 +00:08:12,159 --> 00:08:14,695 +它指的是我们的棋子 + +183 +00:08:14,695 --> 00:08:16,864 +然后我们将这些棋子在布局层中 + +184 +00:08:16,864 --> 00:08:19,399 +排列在棋盘上 得到最终结果 + +185 +00:08:19,399 --> 00:08:22,536 +结果可以通过 +ChessSet 层级查看 + +186 +00:08:22,536 --> 00:08:25,572 +首先要制作我们的棋子 + +187 +00:08:25,572 --> 00:08:28,442 +在国际象棋中 有六类主要的棋子 + +188 +00:08:28,442 --> 00:08:35,015 +士兵、城堡、主教 +骑士、王后和国王 + +189 +00:08:35,015 --> 00:08:37,584 +我们将使用这些 +通过 Object Capture 创建的资产 + +190 +00:08:37,584 --> 00:08:40,487 +来构建一套完整的国际象棋 + +191 +00:08:40,487 --> 00:08:42,656 +让我们先使用一个 USD 概念 + +192 +00:08:42,656 --> 00:08:45,893 +来把棋子带入舞台 这就是引用 + +193 +00:08:45,893 --> 00:08:49,463 +引用是指一个舞台 +中的基元引用另一个 + +194 +00:08:49,463 --> 00:08:51,932 +在同一舞台或不同层级的基元 + +195 +00:08:51,932 --> 00:08:54,535 +而无需复制数据 + +196 +00:08:54,535 --> 00:08:56,904 +这有助于最大限度地减少数据重复 + +197 +00:08:56,904 --> 00:08:58,872 +并允许不同的人和 App + +198 +00:08:58,872 --> 00:09:01,675 +分别更新数据 + +199 +00:09:01,675 --> 00:09:06,380 +让我们将士兵棋子资产引用到场景中 + +200 +00:09:06,380 --> 00:09:10,150 +在目录层级中 +我们定义了一个名为 Pawn 的基元 + +201 +00:09:10,150 --> 00:09:15,556 +到目前为止它还没有任何数据 +所以我们的舞台仍然是空的 + +202 +00:09:15,556 --> 00:09:19,459 +接下来 我们要添加 +对 Pawn.usda 层级的引用 + +203 +00:09:19,459 --> 00:09:20,994 +这会将士兵棋子资产引入 + +204 +00:09:20,994 --> 00:09:24,097 +我们可以在目录层级看到它 + +205 +00:09:24,097 --> 00:09:26,166 +但 USD 是怎么知道 +应该从您引用的 + +206 +00:09:26,166 --> 00:09:28,368 +文件中带入哪个基元呢? + +207 +00:09:28,368 --> 00:09:32,439 +我们可以使用 defaultPrim +元数据指定这个基元 + +208 +00:09:32,439 --> 00:09:35,409 +defaultPrim 元数据在舞台上定义 + +209 +00:09:35,409 --> 00:09:37,477 +并指定在另一舞台使用此场景时 + +210 +00:09:37,477 --> 00:09:40,280 +应该引用哪个基元 + +211 +00:09:40,280 --> 00:09:44,418 +我们建议始终 +为 USD 资产创建 defaultPrim + +212 +00:09:44,418 --> 00:09:45,719 +让我们检查一下士兵棋子资产 + +213 +00:09:45,719 --> 00:09:48,422 +确保创建了 defaultPrim + +214 +00:09:48,422 --> 00:09:50,691 +我们可以在资产的舞台这一级 + +215 +00:09:50,691 --> 00:09:51,892 +看到 defaultPrim 元数据 + +216 +00:09:51,892 --> 00:09:53,894 +很好 + +217 +00:09:53,894 --> 00:09:57,097 +在其他情况下 +如果没有创建 defaultPrim + +218 +00:09:57,097 --> 00:09:58,699 +或者您想引用一个 + +219 +00:09:58,699 --> 00:10:00,767 +与 defaultPrim 不同的基元 + +220 +00:10:00,767 --> 00:10:02,436 +您可以在引用层级明确指定 + +221 +00:10:02,436 --> 00:10:04,338 +基元的路径 + +222 +00:10:04,338 --> 00:10:08,342 +在等级结构中的任何位置均可 + +223 +00:10:08,342 --> 00:10:12,579 +USD 中的路径 +用于标识舞台上的元素 + +224 +00:10:12,579 --> 00:10:16,049 +基元路径是基元的唯一标识符 + +225 +00:10:16,049 --> 00:10:19,820 +举例来说 在这个舞台中 +我们可以看到三个基元 + +226 +00:10:19,820 --> 00:10:23,323 +“世界”基元的基元路径为 /World + +227 +00:10:23,323 --> 00:10:24,691 +“士兵”和“骑士”基元 + +228 +00:10:24,691 --> 00:10:27,361 +被认为是“世界”的子基元 + +229 +00:10:27,361 --> 00:10:31,131 +因此 通往“士兵” 的 +路径将是 /World/Pawn + +230 +00:10:31,131 --> 00:10:36,737 +而通往“骑士”的路径 +则是 /World/Knight + +231 +00:10:36,737 --> 00:10:39,806 +有了这个概念后 我们可以明确 + +232 +00:10:39,806 --> 00:10:44,211 +基元路径设置到 +我们引用中的 Pawn 基元 + +233 +00:10:44,211 --> 00:10:46,180 +对于较大的场景 一次性加载 + +234 +00:10:46,180 --> 00:10:49,049 +所有场景信息可能代价过高 + +235 +00:10:49,049 --> 00:10:51,251 +因此 USD 允许使用一种 + +236 +00:10:51,251 --> 00:10:52,953 +名为“有效负载”的引用类型 + +237 +00:10:52,953 --> 00:10:56,290 +对将场景描述搬上舞台的 +动作进行延迟加载 + +238 +00:10:56,290 --> 00:10:58,258 +在引用大型数据集时推荐使用 + +239 +00:10:58,258 --> 00:11:00,827 +有效负载 例如复杂的几何图形 + +240 +00:11:00,827 --> 00:11:02,162 +或其他表示道具和角色的 + +241 +00:11:02,162 --> 00:11:04,164 +大型场景图 + +242 +00:11:07,434 --> 00:11:10,003 +由于我们会将这些 +资产引用转换为有效负载 + +243 +00:11:10,003 --> 00:11:14,541 +所以可以选择延迟加载棋子 + +244 +00:11:14,541 --> 00:11:16,577 +如果我们选择不加载有效负载 + +245 +00:11:16,577 --> 00:11:20,247 +则场景在最初打开时显示为空 + +246 +00:11:20,247 --> 00:11:22,182 +一旦启用了加载有效负载 + +247 +00:11:22,182 --> 00:11:24,518 +就可以重新看到我们的棋子 + +248 +00:11:24,518 --> 00:11:26,453 +现在我们的场景中有了棋子 + +249 +00:11:26,453 --> 00:11:28,889 +现在可以开始把它们排列在棋盘上 + +250 +00:11:28,889 --> 00:11:30,424 +我们可以使用 USD 的 + +251 +00:11:30,424 --> 00:11:33,260 +分层概念 在另一个层级上完成 + +252 +00:11:33,260 --> 00:11:35,929 +通过分层 层级可以堆叠起来 + +253 +00:11:35,929 --> 00:11:38,265 +原理类似于流行的图像编辑软件 + +254 +00:11:38,265 --> 00:11:41,535 +例如 Photoshop 和 Affinity Photo + +255 +00:11:41,535 --> 00:11:43,537 +位于一个层级上方 +另一个层级中的基元 + +256 +00:11:43,537 --> 00:11:46,540 +被视为更强 可以添加或覆盖 + +257 +00:11:46,540 --> 00:11:49,076 +较低层级中的数据 + +258 +00:11:49,076 --> 00:11:50,377 +正如您所看到的 + +259 +00:11:50,377 --> 00:11:53,180 +棋子目前的位置都是错误的 + +260 +00:11:53,180 --> 00:11:55,082 +但是不用担心 我们可以使用分层 + +261 +00:11:55,082 --> 00:11:58,719 +对其他层级进行非破坏性修改 + +262 +00:11:58,719 --> 00:12:00,454 +这非常适合在无需编辑 + +263 +00:12:00,454 --> 00:12:04,091 +目录层级的情况下 +将棋子移动到正确的位置 + +264 +00:12:04,091 --> 00:12:06,660 +让我们来看看这应该如何完成 + +265 +00:12:06,660 --> 00:12:09,596 +首先创建一个 +名为 ChessSet 的新舞台 + +266 +00:12:09,596 --> 00:12:12,132 +它将是我们最后的场景 + +267 +00:12:12,132 --> 00:12:13,834 +在层级的顶部 它包含了一个 + +268 +00:12:13,834 --> 00:12:15,802 +名为“子层级”的元数据 + +269 +00:12:15,802 --> 00:12:20,574 +现在我们将棋子与目录层级一起引入 + +270 +00:12:20,574 --> 00:12:23,777 +接下来 我们新建一个层级 +Layout.usda + +271 +00:12:23,777 --> 00:12:27,781 +用来移动棋子 + +272 +00:12:27,781 --> 00:12:29,983 +这个布局层级将包含 + +273 +00:12:29,983 --> 00:12:31,818 +棋子的位置信息 + +274 +00:12:31,818 --> 00:12:34,922 +让我们开始覆盖棋子在场景中的位置 + +275 +00:12:34,922 --> 00:12:37,858 +我们先从 Pawn_01 开始 + +276 +00:12:37,858 --> 00:12:39,860 +我们通过更改士兵棋子资产的 + +277 +00:12:39,860 --> 00:12:42,663 +平移属性 来修改它的位置 + +278 +00:12:42,663 --> 00:12:46,767 +让我们来看看这将如何更新场景 + +279 +00:12:46,767 --> 00:12:50,003 +这是没有布局层级的国际象棋盘 + +280 +00:12:50,003 --> 00:12:53,407 +所以士兵棋子仍在它原来的位置上 + +281 +00:12:53,407 --> 00:12:55,976 +一旦我们添加了布局层级 +士兵棋子就被移动到了 + +282 +00:12:55,976 --> 00:12:59,213 +它在棋盘上的预期位置 + +283 +00:12:59,213 --> 00:13:00,948 +让我们对其他棋子进行同样的操作 + +284 +00:13:00,948 --> 00:13:03,250 +将它们移动到正确的位置上 + +285 +00:13:04,952 --> 00:13:06,286 +我们摆放其他棋子的方法 + +286 +00:13:06,286 --> 00:13:09,056 +和摆放士兵棋子一样 + +287 +00:13:09,056 --> 00:13:12,226 +这里我们移动了 Pawn_02 + +288 +00:13:12,226 --> 00:13:16,530 +然后是 Pawn_03 以此类推 + +289 +00:13:16,530 --> 00:13:18,398 +我们完成了对布局层级的更改 + +290 +00:13:18,398 --> 00:13:21,535 +将棋子放置在了正确的位置上 + +291 +00:13:23,904 --> 00:13:26,206 +我们的国际象棋已经完成了半套 + +292 +00:13:26,206 --> 00:13:29,676 +我们使用层级将 +资产与目录层级一起引入 + +293 +00:13:29,676 --> 00:13:32,045 +并通过布局层级的覆盖将它们 + +294 +00:13:32,045 --> 00:13:33,680 +放置在棋盘上 + +295 +00:13:35,716 --> 00:13:37,451 +剩下的就是为对手方 + +296 +00:13:37,451 --> 00:13:39,520 +设置棋子 + +297 +00:13:39,520 --> 00:13:41,622 +需要注意的是对手的棋子 + +298 +00:13:41,622 --> 00:13:43,557 +颜色不同 + +299 +00:13:43,557 --> 00:13:45,526 +无需重新制作一套新的资产 + +300 +00:13:45,526 --> 00:13:47,227 +我们可以使用另一个 USD 概念 + +301 +00:13:47,227 --> 00:13:50,864 +“变体集”来更新我们的棋子资产 + +302 +00:13:50,864 --> 00:13:53,233 +变体集允许舞台上的 + +303 +00:13:53,233 --> 00:13:56,170 +离散替代物进行动态交换 + +304 +00:13:56,170 --> 00:13:57,871 +变体集中包含的变体 + +305 +00:13:57,871 --> 00:14:00,440 +可以是不同的材料、几何形状、 + +306 +00:14:00,440 --> 00:14:03,944 +以及一切 +可以用 USD 表述的东西 + +307 +00:14:03,944 --> 00:14:06,079 +在舞台上进行不同变体之间的切换 + +308 +00:14:06,079 --> 00:14:08,348 +是非破坏性的 + +309 +00:14:08,348 --> 00:14:10,217 +我们将设置变体集 + +310 +00:14:10,217 --> 00:14:14,321 +在棋子的不同材料之间进行切换 + +311 +00:14:14,321 --> 00:14:17,658 +在“士兵”资产中 +我们添加名为“color”的变量集 + +312 +00:14:17,658 --> 00:14:21,195 +这样就可以在士兵棋子的 +不同颜色之间进行切换 + +313 +00:14:21,195 --> 00:14:24,198 +现在我们将两个变体添加到变体集 + +314 +00:14:24,198 --> 00:14:30,571 +Dark 使用深色材质 +Light 使用浅色材质 + +315 +00:14:30,571 --> 00:14:33,473 +最后 我们设置默认变体来指定 + +316 +00:14:33,473 --> 00:14:38,245 +将士兵棋子加载到 +舞台上时具体使用哪一个 + +317 +00:14:38,245 --> 00:14:40,914 +现在 我们回到目录层级 + +318 +00:14:40,914 --> 00:14:42,850 +所有的棋子都已经摆好了 + +319 +00:14:42,850 --> 00:14:45,652 +但它们都使用了浅色材料 + +320 +00:14:45,652 --> 00:14:47,154 +那是因为默认变体 + +321 +00:14:47,154 --> 00:14:49,690 +设置为浅色材质 + +322 +00:14:49,690 --> 00:14:51,558 +让我们将其中一个棋子的变体 + +323 +00:14:51,558 --> 00:14:54,561 +更改为深色材料 + +324 +00:14:54,561 --> 00:14:56,363 +我们将变体设置为 Dark + +325 +00:14:56,363 --> 00:14:58,532 +我们可以看到对方阵营中的一个棋子 + +326 +00:14:58,532 --> 00:15:00,634 +现在变成了深色 + +327 +00:15:00,634 --> 00:15:04,872 +让我们也将更改应用于其他棋子 + +328 +00:15:04,872 --> 00:15:07,608 +我们的这套国际象棋终于完成了 + +329 +00:15:09,209 --> 00:15:13,013 +我们还可以使用另一个 +USD 概念来优化我们的场景 + +330 +00:15:13,013 --> 00:15:15,415 +场景图实例化 + +331 +00:15:15,415 --> 00:15:17,017 +场景图实例化允许我们 + +332 +00:15:17,017 --> 00:15:20,020 +在舞台上多次重复使用场景图的局部 + +333 +00:15:20,020 --> 00:15:21,221 +用于表述任何包含 + +334 +00:15:21,221 --> 00:15:24,691 +不止一种元素的物件 +例如树叶、家具 + +335 +00:15:24,691 --> 00:15:27,661 +还有我们案例中的棋子 + +336 +00:15:27,661 --> 00:15:29,863 +使用场景图实例化 +将同时为您的 App + +337 +00:15:29,863 --> 00:15:33,267 +提供内存和性能的提升 + +338 +00:15:33,267 --> 00:15:35,102 +要使用场景图实例化 + +339 +00:15:35,102 --> 00:15:37,571 +我们可以在基元或场景图的局部 + +340 +00:15:37,571 --> 00:15:40,140 +指定实例元数据 + +341 +00:15:40,140 --> 00:15:42,176 +所有实例化的基元都可以 + +342 +00:15:42,176 --> 00:15:44,578 +共享同一个场景图 + +343 +00:15:44,578 --> 00:15:48,348 +让我们在场景中 +添加对基元实例化的支持 + +344 +00:15:48,348 --> 00:15:51,385 +在目录文件中 我们将 +元数据 instanceable + +345 +00:15:51,385 --> 00:15:55,022 +添加到棋子基元 并将值设置为真 + +346 +00:15:55,022 --> 00:15:57,925 +通过添加此元数据 +USD 现在将把这些资产 + +347 +00:15:57,925 --> 00:16:01,495 +看作共享相同数据的 +潜在可实例化基元 + +348 +00:16:01,495 --> 00:16:05,199 +而不再去为每个基元复制数据 + +349 +00:16:05,199 --> 00:16:07,000 +我们的国际象棋盘看起来还是一样 + +350 +00:16:07,000 --> 00:16:10,070 +但现在 它的性能和 +内存效率都提高了 + +351 +00:16:10,070 --> 00:16:12,573 +这样一来 我们的 +这套国际象棋就完成了! + +352 +00:16:12,573 --> 00:16:16,009 +它看起来很棒 我们也练习了 +各种 USD 功能的使用 + +353 +00:16:17,311 --> 00:16:21,215 +分层、引用、有效负载和变体集 + +354 +00:16:21,215 --> 00:16:25,452 +只是 USD 定义的几个组合类型 + +355 +00:16:25,452 --> 00:16:26,854 +USD 对场景图的创建 + +356 +00:16:26,854 --> 00:16:28,822 +有特定的强度顺序 + +357 +00:16:28,822 --> 00:16:32,292 +以确保一致的场景表述 + +358 +00:16:32,292 --> 00:16:34,127 +有关组合的更多信息 + +359 +00:16:34,127 --> 00:16:36,363 +和首字母缩写为 LIVRPS 的命令 + +360 +00:16:36,363 --> 00:16:40,467 +您都可以在 Pixar 的 +USD 文档中进一步了解 + +361 +00:16:40,467 --> 00:16:41,768 +在今天的讲座中 + +362 +00:16:41,768 --> 00:16:44,238 +我们探讨了 USD 文件中的内容 + +363 +00:16:44,238 --> 00:16:46,340 +现在让我们来谈谈文件本身 + +364 +00:16:46,340 --> 00:16:48,909 +以及它们出现在磁盘上的方式 + +365 +00:16:48,909 --> 00:16:51,745 +USD 文件的类型有以下几种 + +366 +00:16:51,745 --> 00:16:53,947 +包含可读 ASCII 文本的 USD 文件 + +367 +00:16:53,947 --> 00:16:56,283 +使用 .usda 扩展名 + +368 +00:16:56,283 --> 00:16:59,953 +在今天的讲座中 +我们一直在使用这些文件 + +369 +00:16:59,953 --> 00:17:02,789 +更紧凑、更高效的二进制表述 + +370 +00:17:02,789 --> 00:17:07,227 +是箱格式 扩展名为 .usdc + +371 +00:17:07,227 --> 00:17:10,497 +您可能还会看到 +使用 .usd 扩展名的文件 + +372 +00:17:10,497 --> 00:17:15,035 +它们既可以是 ASCII 文本 +也可能是二进制箱文件 + +373 +00:17:15,035 --> 00:17:18,539 +最后 USD 还有一个打包格式 + +374 +00:17:18,539 --> 00:17:21,542 +可以将多个 USD 文件 +和相关的辅助文件 + +375 +00:17:21,542 --> 00:17:24,111 +比如纹理 囊括在 +一个未压缩的 zip 存档中 + +376 +00:17:24,111 --> 00:17:27,681 +使用 .usdz 扩展名 + +377 +00:17:27,681 --> 00:17:31,318 +今天我们了解了 USD 的基本概念 + +378 +00:17:31,318 --> 00:17:38,358 +舞台、层级、基元 +模式、属性和元数据 + +379 +00:17:38,358 --> 00:17:40,427 +我们使用这些概念 +来构建了一套国际象棋 + +380 +00:17:40,427 --> 00:17:44,264 +并使用了引用、有效负载、默认基元 + +381 +00:17:44,264 --> 00:17:48,202 +基元路径、分层和实例化 + +382 +00:17:48,202 --> 00:17:51,905 +最后 我们讨论了 +不同的 USD 文件格式 + +383 +00:17:51,905 --> 00:17:57,344 +.usda, .usdc +.usd 和 .usdz + +384 +00:17:57,344 --> 00:17:59,646 +我们鼓励您 +通过 Pixar 的 USD 文档 + +385 +00:17:59,646 --> 00:18:02,749 +更深入地了解这些概念 +并在您的 App 中 + +386 +00:18:02,749 --> 00:18:05,919 +充分利用 USD 的功能 + +387 +00:18:05,919 --> 00:18:07,387 +谢谢! + +388 +00:18:07,387 --> 00:18:11,391 +♪ + diff --git a/zho/2022 Session 10131 Qualities of great AR experiences.srt b/zho/2022 Session 10131 Qualities of great AR experiences.srt new file mode 100644 index 0000000..fd01e65 --- /dev/null +++ b/zho/2022 Session 10131 Qualities of great AR experiences.srt @@ -0,0 +1,1289 @@ +1 +00:00:00,033 --> 00:00:03,203 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,203 --> 00:00:09,510 +♪ + +3 +00:00:09,510 --> 00:00:12,646 +欢迎来到“卓越 AR 体验品质” + +4 +00:00:12,646 --> 00:00:15,282 +我是 Alli Dryer +是 Apple 设计团队的一员 + +5 +00:00:15,282 --> 00:00:18,485 +致力于增强现实技术 + +6 +00:00:18,485 --> 00:00:21,688 +AR 可以给您将虚拟物体 +与现实世界相融合的 + +7 +00:00:21,688 --> 00:00:22,956 +惊人体验 + +8 +00:00:22,956 --> 00:00:26,527 +让您认为这些虚拟物体真实存在 + +9 +00:00:26,527 --> 00:00:28,629 +AR 可以让您身处奇境 + +10 +00:00:28,629 --> 00:00:30,097 +同时 + +11 +00:00:30,097 --> 00:00:33,267 +又总是基于真实的事件和环境 + +12 +00:00:33,267 --> 00:00:34,735 +它能将现实角度看来 + +13 +00:00:34,735 --> 00:00:37,204 +不可能的、有风险的 +或难以做到的事物 + +14 +00:00:37,204 --> 00:00:39,640 +真实的展现在眼前 + +15 +00:00:39,640 --> 00:00:42,176 +它模糊了想象与现实的界限 + +16 +00:00:42,176 --> 00:00:45,345 +AR 体验真的像感受魔法一样 + +17 +00:00:45,345 --> 00:00:47,548 +您可以通过视觉和声音 +彻底改变周遭环境 + +18 +00:00:47,548 --> 00:00:51,084 +让人们体验前所未见的事物 + +19 +00:00:51,084 --> 00:00:54,087 +您还可以在 AR 环境中 +添加新的信息层 + +20 +00:00:54,087 --> 00:00:57,724 +以实现快速和轻量级的交互 + +21 +00:00:57,724 --> 00:01:00,494 +增强现实的设计模式可能与 + +22 +00:01:00,494 --> 00:01:02,596 +设计 2D App 有很大不同 + +23 +00:01:02,596 --> 00:01:04,998 +但别担心 我们会细致的讲解它 + +24 +00:01:04,998 --> 00:01:08,035 +今天我将分享 +您能用到的 AR 标准 + +25 +00:01:08,035 --> 00:01:11,238 +您可以考虑 +能否通过它增强您的程序体验 + +26 +00:01:11,238 --> 00:01:14,208 +以及当您设计第一个 AR 体验时 + +27 +00:01:14,208 --> 00:01:16,210 +处理增强现实功能的 + +28 +00:01:16,210 --> 00:01:18,912 +一些独特技巧 + +29 +00:01:18,912 --> 00:01:21,315 +好的 您正在设计 +一个 App 或功能 + +30 +00:01:21,315 --> 00:01:24,017 +并想知道 AR 是否对您有用 + +31 +00:01:24,017 --> 00:01:26,220 +这里有几点需要您考虑 + +32 +00:01:26,220 --> 00:01:29,857 +AR 可以帮助您 +呈现事物真实的样貌 + +33 +00:01:29,857 --> 00:01:31,091 +为了表明我的意思 + +34 +00:01:31,091 --> 00:01:34,361 +让我们看一个 +用 AR 实现很好的例子 + +35 +00:01:34,361 --> 00:01:37,231 +即呈现虚拟物体在真实世界内的大小 + +36 +00:01:37,231 --> 00:01:38,866 +假设您 正在尝试给人们介绍 + +37 +00:01:38,866 --> 00:01:41,168 +关于恐龙有多大的问题 + +38 +00:01:41,168 --> 00:01:44,171 +您可以直接写出来 + +39 +00:01:44,171 --> 00:01:47,574 +或展示一张图片 + +40 +00:01:47,574 --> 00:01:51,411 +或者可以在现场 +放出一个虚拟的霸王龙 + +41 +00:01:51,411 --> 00:01:53,447 +在那种情况下 没有必要想象 + +42 +00:01:53,447 --> 00:01:55,282 +恐龙究竟有多大 + +43 +00:01:55,282 --> 00:01:57,050 +AR 会即刻以 +一种身临其境的方式 + +44 +00:01:57,050 --> 00:01:59,353 +让观众发自内心的体验到 + +45 +00:01:59,353 --> 00:02:01,655 +这种真实的规模感 + +46 +00:02:01,655 --> 00:02:04,091 +这个例子来自“怪物公园”App + +47 +00:02:04,091 --> 00:02:06,493 +一款让人们探索和控制 + +48 +00:02:06,493 --> 00:02:09,897 +3D 恐龙的休闲游戏 + +49 +00:02:09,897 --> 00:02:11,398 +整个 App 都充满 + +50 +00:02:11,398 --> 00:02:14,501 +这种栩栩如生的 AR 体验 + +51 +00:02:14,501 --> 00:02:20,007 +游戏还同时强调 +恐龙的照片和视频的分享 + +52 +00:02:20,007 --> 00:02:23,177 +当 AR 对您周围的事物 +产生影响并做出反应时 + +53 +00:02:23,177 --> 00:02:25,312 +这是令人非常兴奋的 + +54 +00:02:25,312 --> 00:02:28,415 +它以一种有意义的方式涉及物理空间 + +55 +00:02:28,415 --> 00:02:30,017 +假设您正在尝试设计一个 App + +56 +00:02:30,017 --> 00:02:32,920 +您想帮助人们在室内设计中 + +57 +00:02:32,920 --> 00:02:35,122 +为他们的墙壁选择一种油漆颜色 + +58 +00:02:35,122 --> 00:02:38,425 +您可以用色卡或者图片 + +59 +00:02:38,425 --> 00:02:40,327 +但那些都不是很准确 + +60 +00:02:40,327 --> 00:02:42,095 +好一点的办法是 +您可以直接向人们展示 + +61 +00:02:42,095 --> 00:02:43,864 +他们的房间在粉刷之后 + +62 +00:02:43,864 --> 00:02:46,166 +是什么样子 + +63 +00:02:46,166 --> 00:02:48,435 +Color Snap App 就是这样做的 + +64 +00:02:48,435 --> 00:02:50,304 +它允许人们选择油漆颜色 + +65 +00:02:50,304 --> 00:02:52,973 +然后点击墙壁预览效果 + +66 +00:02:52,973 --> 00:02:55,309 +因为它是 AR +人们可以通过软件四处查看 + +67 +00:02:55,309 --> 00:02:57,444 +从不同的角度查看新的粉刷效果 + +68 +00:02:57,444 --> 00:02:59,313 +将如何影响他们的房间 + +69 +00:02:59,313 --> 00:03:02,983 +接下来 增强现实 +让您创造以 3D 形式 + +70 +00:03:02,983 --> 00:03:05,919 +构建的可视化虚拟物体体验 + +71 +00:03:05,919 --> 00:03:09,256 +这可以对目标更容易理解和评估效果 + +72 +00:03:09,256 --> 00:03:12,793 +借助 AR 您可以构建一种 +虚拟但又足够真实的方式 + +73 +00:03:12,793 --> 00:03:15,128 +构建出帮助人们尝试新事物的功能 + +74 +00:03:15,128 --> 00:03:18,165 +帮助人们做出自信的购买决定 + +75 +00:03:18,165 --> 00:03:20,067 +例如 Warby Parker App + +76 +00:03:20,067 --> 00:03:22,236 +让人们试戴虚拟眼镜 + +77 +00:03:22,236 --> 00:03:24,004 +这样他们就可以为 +真正适合他们的镜框 + +78 +00:03:24,004 --> 00:03:25,606 +准确地下订单 + +79 +00:03:25,606 --> 00:03:28,175 +在 AR 中更换镜框的速度 + +80 +00:03:28,175 --> 00:03:31,144 +比在现实生活中换镜框快多了 + +81 +00:03:31,144 --> 00:03:32,946 +将虚拟物体放置在 现实中的地面 + +82 +00:03:32,946 --> 00:03:34,948 +这个功能也很重要 + +83 +00:03:34,948 --> 00:03:37,951 +物体在现实位置表现出的光影质量 + +84 +00:03:37,951 --> 00:03:40,454 +会对人们的感觉 + +85 +00:03:40,454 --> 00:03:42,055 +产生巨大的影响 + +86 +00:03:42,055 --> 00:03:44,958 +即使对象看起来不太真实 + +87 +00:03:44,958 --> 00:03:47,094 +IKEA Place App 允许人们 + +88 +00:03:47,094 --> 00:03:49,429 +在他们的家中放置一件虚拟家具 + +89 +00:03:49,429 --> 00:03:50,531 +借此对放置新家具的房间 + +90 +00:03:50,531 --> 00:03:52,599 +有了更准确直观的感受 + +91 +00:03:52,599 --> 00:03:55,536 +IKEA Place 利用 +ARKit 的内置照明系统 + +92 +00:03:55,536 --> 00:03:57,905 +解决了虚拟家具摆放到房间后 + +93 +00:03:57,905 --> 00:04:00,874 +如何呈现逼真阴影的问题 + +94 +00:04:00,874 --> 00:04:03,143 +3D 可视化可以描述物体对象 + +95 +00:04:03,143 --> 00:04:05,345 +但不要忘记人们会利用周围环境 + +96 +00:04:05,345 --> 00:04:08,482 +作为体验您软件的画布 + +97 +00:04:08,482 --> 00:04:11,418 +您可以创建具有 +高级视觉效果的新功能 + +98 +00:04:11,418 --> 00:04:14,254 +提供适合您品牌产品的 +地图和 3D 模型 + +99 +00:04:14,254 --> 00:04:17,157 +甚至可以使用 iOS 新的 +RoomPlan API + +100 +00:04:17,157 --> 00:04:20,394 +将人们的现实环境空间 +带入您正在构建的游戏中 + +101 +00:04:20,394 --> 00:04:22,696 +如果您想了解更多信息 + +102 +00:04:22,696 --> 00:04:24,398 +您可以观看我们另一个 +关于创建 3D 房间扫描的课程 + +103 +00:04:24,398 --> 00:04:26,400 +那里会详细介绍 RoomPlan + +104 +00:04:26,400 --> 00:04:28,535 +AR 可以通过将数字功能 +附加到物理事物上来 + +105 +00:04:28,535 --> 00:04:31,638 +让您简化操作 + +106 +00:04:31,638 --> 00:04:34,408 +使您的 App 和功能更加高效 + +107 +00:04:34,408 --> 00:04:35,776 +如果您曾经在餐馆使用过扫码点餐 + +108 +00:04:35,776 --> 00:04:38,679 +那么您可能已经体验过 +使用真实环境作为输入项 + +109 +00:04:38,679 --> 00:04:42,482 +是如何提高速度的 + +110 +00:04:42,482 --> 00:04:45,919 +您可以使用 AR 构建 +紧凑但非常有用的功能 + +111 +00:04:45,919 --> 00:04:47,721 +从而节省人们的时间 + +112 +00:04:47,721 --> 00:04:51,024 +在 iOS 版的 Measure App 中 +将相机对准一个人 + +113 +00:04:51,024 --> 00:04:54,595 +系统自动在正确的位置显示她的身高 + +114 +00:04:54,595 --> 00:04:58,232 +它的体验感觉很轻巧 +因为用户界面非常简单 + +115 +00:04:58,232 --> 00:05:00,567 +交互是基于设备移动的 + +116 +00:05:00,567 --> 00:05:04,671 +并且您看到测量信息后 +消息就会消失 + +117 +00:05:04,671 --> 00:05:07,508 +它的增强现实体验非常有限 + +118 +00:05:07,508 --> 00:05:10,210 +不能作为一个独立 App + +119 +00:05:10,210 --> 00:05:13,280 +但它确实填补了 +Measure App 的其他功能 + +120 +00:05:13,280 --> 00:05:16,683 +所以 现在您知道 +当您想要提供真实的表现 + +121 +00:05:16,683 --> 00:05:19,520 +以有意义的方式涉及物理空间 + +122 +00:05:19,520 --> 00:05:22,322 +或以 3D 形式可视化 + +123 +00:05:22,322 --> 00:05:24,925 +或利用环境中的东西简化操作时 + +124 +00:05:24,925 --> 00:05:27,961 +您可以将 AR 用于 +您的 App 和功能 + +125 +00:05:27,961 --> 00:05:30,664 +正如您所看到的 有很多不同的方法 + +126 +00:05:30,664 --> 00:05:33,967 +将 AR 融入您正在创造的体验中 + +127 +00:05:33,967 --> 00:05:36,036 +无论是作为 App 的主要功能 + +128 +00:05:36,036 --> 00:05:39,573 +或使用他们作为增光添彩的讨巧工具 + +129 +00:05:39,573 --> 00:05:42,809 +所以 您已经明白 AR +对您的目标是一个正确选择 + +130 +00:05:42,809 --> 00:05:45,846 +那么现在是时候开始做程序设计了 + +131 +00:05:45,846 --> 00:05:47,414 +当您设计 AR 功能时 + +132 +00:05:47,414 --> 00:05:49,483 +您需要考虑一些 + +133 +00:05:49,483 --> 00:05:53,287 +有别与传统 2D 界面的地方 + +134 +00:05:53,287 --> 00:05:57,024 +AR 是有空间的 + +135 +00:05:57,024 --> 00:06:00,894 +AR 是基于运动的 + +136 +00:06:00,894 --> 00:06:05,265 +AR 是与物理环境相关联的 + +137 +00:06:05,265 --> 00:06:07,968 +您需要考虑如何将 + +138 +00:06:07,968 --> 00:06:10,470 +虚拟元素融入场景 考虑人体工程学 + +139 +00:06:10,470 --> 00:06:13,473 +以及在有限的视野范围内工作 + +140 +00:06:13,473 --> 00:06:15,475 +现在我将向您介绍一些要点 + +141 +00:06:15,475 --> 00:06:18,712 +在您设计 AR 时请牢记他们 + +142 +00:06:18,712 --> 00:06:20,814 +使用您的 App 的人可能 + +143 +00:06:20,814 --> 00:06:22,649 +身处在一个 AR 难以顺利运用的地方 + +144 +00:06:22,649 --> 00:06:24,651 +所以您要做的就是指导用户 + +145 +00:06:24,651 --> 00:06:27,721 +通过不同的方式获得更好的体验 + +146 +00:06:27,721 --> 00:06:29,823 +火星任务 App 做得很好 + +147 +00:06:29,823 --> 00:06:31,692 +它具有强大的指导课程 + +148 +00:06:31,692 --> 00:06:33,727 +让人们为成功完成任务做好准备 + +149 +00:06:33,727 --> 00:06:37,664 +让我们仔细看看这个例子 + +150 +00:06:37,664 --> 00:06:38,899 +在您开始的时候 + +151 +00:06:38,899 --> 00:06:41,235 +火星任务强调 +如果想获得优质的体验 + +152 +00:06:41,235 --> 00:06:44,271 +那么您的环境需要的三个不同要求 + +153 +00:06:44,271 --> 00:06:47,107 +首先 软件提醒 AR 是可以提供 +身临其境的感觉的 + +154 +00:06:47,107 --> 00:06:50,277 +所以找到一个安全的地方 +进行体验是明智的 + +155 +00:06:50,277 --> 00:06:51,812 +这对于涉及寻路的体验可能是 + +156 +00:06:51,812 --> 00:06:54,181 +一个特别值得关注的问题 + +157 +00:06:54,181 --> 00:06:55,749 +您需要格外小心 + +158 +00:06:55,749 --> 00:06:57,918 +不要将人们的注意力 + +159 +00:06:57,918 --> 00:07:01,021 +长时间吸引到屏幕上 + +160 +00:07:01,021 --> 00:07:03,457 +接下来 App 建议 + +161 +00:07:03,457 --> 00:07:05,225 +最佳的 AR 体验 +是在有纹理的表面上 + +162 +00:07:05,225 --> 00:07:09,363 +而不是在玻璃或 +光滑白色无特征的平面上 + +163 +00:07:09,363 --> 00:07:10,631 +LiDAR 技术可以帮助 + +164 +00:07:10,631 --> 00:07:13,000 +克服一些具有挑战性的环境条件 + +165 +00:07:13,000 --> 00:07:15,035 +所以对于某些设备 + +166 +00:07:15,035 --> 00:07:17,070 +您可以忽略这个建议 + +167 +00:07:17,070 --> 00:07:19,273 +最后 火星任务建议用户 +寻找明亮的空间 + +168 +00:07:19,273 --> 00:07:21,975 +因为在光线充足的环境中 + +169 +00:07:21,975 --> 00:07:25,012 +AR 的效果最好 + +170 +00:07:25,012 --> 00:07:27,748 +这种训练课程的好处在于 +它快速简短 + +171 +00:07:27,748 --> 00:07:30,284 +且易于引导 并帮助人们理解 + +172 +00:07:30,284 --> 00:07:33,921 +如何选择和调整他们的真实环境 +以获得最佳的 AR 体验 + +173 +00:07:33,921 --> 00:07:36,924 +下一个技巧是利用屏幕空间 + +174 +00:07:36,924 --> 00:07:39,226 +您会惊讶于它在 AR 体验设计中 + +175 +00:07:39,226 --> 00:07:41,395 +可以发挥多大的作用 + +176 +00:07:41,395 --> 00:07:43,597 +那么 什么是屏幕空间 + +177 +00:07:43,597 --> 00:07:45,499 +将屏幕空间视为 + +178 +00:07:45,499 --> 00:07:47,768 +通过您的相机视图捕获的 + +179 +00:07:47,768 --> 00:07:49,970 +位于三维世界之上的 2D 图层 + +180 +00:07:49,970 --> 00:07:52,472 +最好将文本元素 +像按钮等交互元素一样 + +181 +00:07:52,472 --> 00:07:54,474 +放置在屏幕空间里 + +182 +00:07:54,474 --> 00:07:56,777 +而不是放置在 +相机拍摄的 3D 世界中 + +183 +00:07:56,777 --> 00:07:58,812 +以保持可读性 + +184 +00:07:58,812 --> 00:08:01,181 +这是火星任务 App 里 +一个很好的例子 + +185 +00:08:01,181 --> 00:08:04,818 +这说明了如何处理屏幕空间中的文本 + +186 +00:08:04,818 --> 00:08:08,488 +高对比度文本和按钮位于 + +187 +00:08:08,488 --> 00:08:11,024 +下面的 3D 场景之上的 2D 图层中 + +188 +00:08:11,024 --> 00:08:14,261 +文字会随着相机的移动而更新 + +189 +00:08:14,261 --> 00:08:17,865 +以帮助您理解它如何 +与场景中的 3D 对象相关联 + +190 +00:08:17,865 --> 00:08:20,667 +如果您确实需要将文本 +锁定到世界的某样东西上 + +191 +00:08:20,667 --> 00:08:23,170 +若有可能 请尝试让这个显示框 + +192 +00:08:23,170 --> 00:08:24,838 +与屏幕平行 + +193 +00:08:24,838 --> 00:08:26,840 +注意增加对比度 + +194 +00:08:26,840 --> 00:08:29,643 +增加字体大小并将文本放在背景上 + +195 +00:08:29,643 --> 00:08:32,513 +这样您就可以保持程序的可读性 + +196 +00:08:32,513 --> 00:08:34,648 +为持续运动而设计 + +197 +00:08:34,648 --> 00:08:36,250 +人们理解如何 +以及何时移动他们的设备 + +198 +00:08:36,250 --> 00:08:38,719 +这一点很重要 + +199 +00:08:38,719 --> 00:08:40,754 +有时他们也会为了感受 AR 体验 + +200 +00:08:40,754 --> 00:08:43,524 +而需要移动身体 + +201 +00:08:43,524 --> 00:08:45,292 +尝试随着人们移动的视觉效果和声音 + +202 +00:08:45,292 --> 00:08:47,995 +提供实时反馈 + +203 +00:08:47,995 --> 00:08:50,364 +这样即使动作发生在视线之外 + +204 +00:08:50,364 --> 00:08:54,535 +人们仍然可以与体验联系起来 + +205 +00:08:54,535 --> 00:08:57,204 +用使用简单、一目了然的 +说明和指导动画 + +206 +00:08:57,204 --> 00:08:59,273 +指导人们如何移动 + +207 +00:08:59,273 --> 00:09:01,775 +有助于合理的 +将说明放置在屏幕空间 + +208 +00:09:01,775 --> 00:09:05,812 +并根据需要显示它们 +而不是全部预先显示出来 + +209 +00:09:05,812 --> 00:09:08,815 +利用内置的指导动画是很棒的 + +210 +00:09:08,815 --> 00:09:11,552 +但您也可以创建与 App 相关的 + +211 +00:09:11,552 --> 00:09:12,886 +自己的指导动画 + +212 +00:09:12,886 --> 00:09:15,088 +像 DoodleLens App +中的这个示例 + +213 +00:09:15,088 --> 00:09:17,191 +提示用户将 iPhone 在涂鸦前 + +214 +00:09:17,191 --> 00:09:19,493 +来回移动 + +215 +00:09:19,493 --> 00:09:23,997 +人体工程学因素 +对于 AR 来说非常重要 + +216 +00:09:23,997 --> 00:09:25,899 +伸出手臂很长的时间 + +217 +00:09:25,899 --> 00:09:27,668 +可能会很累 + +218 +00:09:27,668 --> 00:09:29,269 +并且在不适合单手操作的位置 + +219 +00:09:29,269 --> 00:09:33,307 +触控按键会很不舒服 + +220 +00:09:33,307 --> 00:09:37,144 +所以强调整个界面的可读性 +并简化操作 + +221 +00:09:37,144 --> 00:09:39,780 +以便于用户通过最小的努力 + +222 +00:09:39,780 --> 00:09:41,648 +即可完成操作 + +223 +00:09:41,648 --> 00:09:44,618 +使用带有高对比度图标的超大按钮 + +224 +00:09:44,618 --> 00:09:47,387 +使拇指很容易完成操作 + +225 +00:09:47,387 --> 00:09:49,389 +这是在 DoodleLens 中 + +226 +00:09:49,389 --> 00:09:52,092 +在屏幕底部布置按钮 +的一个很好例子 + +227 +00:09:52,092 --> 00:09:54,061 +人们正在通过手持设备的 + +228 +00:09:54,061 --> 00:09:55,596 +有限视野 + +229 +00:09:55,596 --> 00:09:57,631 +进行 AR 体验 + +230 +00:09:57,631 --> 00:09:59,766 +所以他们很有可能看不到 + +231 +00:09:59,766 --> 00:10:02,169 +体积较大对象的全貌 + +232 +00:10:02,169 --> 00:10:04,872 +也有可能是虚拟物体 + +233 +00:10:04,872 --> 00:10:07,875 +可能位于视线之外的情况 + +234 +00:10:07,875 --> 00:10:10,444 +所以要允许人们调整对象的比例 + +235 +00:10:10,444 --> 00:10:12,646 +以便于他们无法后退到足够远的距离 + +236 +00:10:12,646 --> 00:10:14,748 +而看到物体的全貌 + +237 +00:10:14,748 --> 00:10:16,783 +这个例子来自 AR 快速查看 + +238 +00:10:16,783 --> 00:10:20,087 +使用收缩手势进行直接操作 + +239 +00:10:20,087 --> 00:10:22,489 +当您将物体扩大到 100% 以上时 + +240 +00:10:22,489 --> 00:10:26,426 +还需要给用户一个反馈 + +241 +00:10:26,426 --> 00:10:29,363 +当物体超过视图的左右界限 +而无法看到时 + +242 +00:10:29,363 --> 00:10:32,299 +要使用声音和触觉反馈 +并提供简单的指示 + +243 +00:10:32,299 --> 00:10:35,569 +或在屏幕中提供文本说明 + +244 +00:10:35,569 --> 00:10:37,771 +提供一张地图或鸟瞰图 + +245 +00:10:37,771 --> 00:10:40,607 +显示某人的方位 + +246 +00:10:40,607 --> 00:10:42,743 +并说明物体位于相反的方向 + +247 +00:10:42,743 --> 00:10:44,978 +这也很有帮助 + +248 +00:10:44,978 --> 00:10:47,347 +在 RoomPlan 的体验示例中 + +249 +00:10:47,347 --> 00:10:49,983 +视图底部的小型 3D 模型 + +250 +00:10:49,983 --> 00:10:51,885 +会帮助您预览结果 + +251 +00:10:51,885 --> 00:10:55,289 +并跟踪到截止目前已浏览过的内容 + +252 +00:10:55,289 --> 00:10:57,824 +人们通过屏幕观察 + +253 +00:10:57,824 --> 00:11:00,827 +很难理解虚拟物体在空间中的位置 + +254 +00:11:00,827 --> 00:11:03,197 +除非他们表现得足够真实 + +255 +00:11:03,197 --> 00:11:06,066 +深度提示可以帮助人们 +观察到事物的远近 + +256 +00:11:06,066 --> 00:11:07,968 +从而解决这个问题 + +257 +00:11:07,968 --> 00:11:10,537 +物体大小、透视效果 + +258 +00:11:10,537 --> 00:11:12,639 +就像向地平线递减的效果 + +259 +00:11:12,639 --> 00:11:14,541 +逼真的阴影和照明 + +260 +00:11:14,541 --> 00:11:16,777 +纹理中适当的细节 + +261 +00:11:16,777 --> 00:11:19,213 +以上叠加出具有深度的空间感觉 + +262 +00:11:19,213 --> 00:11:22,749 +帮助人们感知空间关系 + +263 +00:11:22,749 --> 00:11:25,485 +我想重点说明一个 +很难使用的深度提示方法 + +264 +00:11:25,485 --> 00:11:27,321 +但真的可以帮助人们理解 + +265 +00:11:27,321 --> 00:11:30,057 +物体的相对位置 + +266 +00:11:30,057 --> 00:11:33,460 +重叠 也称为遮挡 + +267 +00:11:33,460 --> 00:11:37,097 +这是您可以在 +AR 快速查看中看到的重叠示例 + +268 +00:11:37,097 --> 00:11:39,266 +虚拟飞机看起来像 + +269 +00:11:39,266 --> 00:11:41,368 +是放在桌子上的木块后面 + +270 +00:11:41,368 --> 00:11:44,004 +因为它的下半部分被隐藏了 + +271 +00:11:44,004 --> 00:11:46,540 +最后 程序的体验时间 + +272 +00:11:46,540 --> 00:11:48,575 +请不要超过一到两分钟 + +273 +00:11:48,575 --> 00:11:51,111 +这是出于 +我前面提到的人体工程学的原因 + +274 +00:11:51,111 --> 00:11:55,048 +还因为 AR 是一种 +资源密集型的超级功能 + +275 +00:11:55,048 --> 00:11:59,353 +这对电池和散热都有很大影响 + +276 +00:11:59,353 --> 00:12:02,055 +如果您最终设计的体验时间更长 + +277 +00:12:02,055 --> 00:12:04,358 +请确保休息时间 + +278 +00:12:04,358 --> 00:12:07,160 +For All Mankind:时间返回舱 +是能让您 + +279 +00:12:07,160 --> 00:12:10,697 +探索 For All Mankind +宇宙的 AR 体验 + +280 +00:12:10,697 --> 00:12:12,499 +该 App 通过 +互动对象讲故事的方式 + +281 +00:12:12,499 --> 00:12:15,936 +补充了电视剧的剧情内容 + +282 +00:12:15,936 --> 00:12:17,938 +时间返回舱在每个章节中间 + +283 +00:12:17,938 --> 00:12:19,573 +提供休息的时间和暂停的位置 + +284 +00:12:19,573 --> 00:12:23,377 +可以返回体验 + +285 +00:12:23,377 --> 00:12:26,313 +今天 我分享了一些技巧 + +286 +00:12:26,313 --> 00:12:28,849 +来帮助解决 AR 功能的一些挑战 + +287 +00:12:28,849 --> 00:12:31,251 +您学会了引导人们进入正确的环境 + +288 +00:12:31,251 --> 00:12:33,220 +充分利用屏幕空间 + +289 +00:12:33,220 --> 00:12:35,022 +为持续运动而设计 + +290 +00:12:35,022 --> 00:12:38,158 +考虑人体工程学和有限的视野 + +291 +00:12:38,158 --> 00:12:41,328 +使用深度提示 +并限制体验的持续时间 + +292 +00:12:41,328 --> 00:12:43,830 +以免人们感到疲倦 + +293 +00:12:43,830 --> 00:12:46,700 +当增强现实对体验可用 +使用起来赏心悦目 + +294 +00:12:46,700 --> 00:12:49,636 +并与物理世界相关联时 +您真的会像体验魔法一样 + +295 +00:12:49,636 --> 00:12:51,772 +AR 让您看到虚拟物体 + +296 +00:12:51,772 --> 00:12:54,141 +即便您甚至改变了您的周围环境 + +297 +00:12:54,141 --> 00:12:57,177 +您可以将数字功能附加到物理物体上 + +298 +00:12:57,177 --> 00:13:00,480 +创建有用的信息和操作层 + +299 +00:13:00,480 --> 00:13:02,583 +您创建的 AR 功能和 App + +300 +00:13:02,583 --> 00:13:05,819 +将改变人们工作、学习、娱乐、购物 + +301 +00:13:05,819 --> 00:13:07,688 +和与世界的联系方式 + +302 +00:13:07,688 --> 00:13:09,223 +我迫不及待地想看看 + +303 +00:13:09,223 --> 00:13:10,691 +未来您会在增强现实中创造什么 + +304 +00:13:10,691 --> 00:13:12,159 +谢谢! + +305 +00:13:12,159 --> 00:13:16,163 +♪ + diff --git a/zho/2022 Session 10132 Discover PhotoKit change history.srt b/zho/2022 Session 10132 Discover PhotoKit change history.srt new file mode 100644 index 0000000..27bc2f5 --- /dev/null +++ b/zho/2022 Session 10132 Discover PhotoKit change history.srt @@ -0,0 +1,820 @@ +1 +00:00:00,000 --> 00:00:03,070 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,070 --> 00:00:09,843 +♪ + +3 +00:00:09,843 --> 00:00:11,411 +您好我叫 Mindy + +4 +00:00:11,411 --> 00:00:14,248 +我是相册团队的工程师 + +5 +00:00:14,248 --> 00:00:16,850 +今天我将介绍 +如何在您的 App 中 + +6 +00:00:16,850 --> 00:00:20,754 +获得图片变更的历史记录 + +7 +00:00:20,754 --> 00:00:23,457 +PhotoKit 提供了一组 +丰富的 API + +8 +00:00:23,457 --> 00:00:27,828 +用于对照片库中的照片、视频和相册 + +9 +00:00:27,828 --> 00:00:29,930 +进行访问和更新 + +10 +00:00:29,930 --> 00:00:33,133 +PhotoKit 是专为需要深层 +访问和集成相册 + +11 +00:00:33,133 --> 00:00:36,570 +的 App 而设计的 + +12 +00:00:36,570 --> 00:00:39,907 +用于管理、编辑照片或自定义相机 + +13 +00:00:39,907 --> 00:00:42,976 +或构建让人们以独特的方式 + +14 +00:00:42,976 --> 00:00:45,445 +浏览照片库的 App + +15 +00:00:45,445 --> 00:00:48,315 +这些类型的 App 可能需要监控 + +16 +00:00:48,315 --> 00:00:50,717 +照片库随时间变化情况 + +17 +00:00:50,717 --> 00:00:54,354 +以便于更加密切的反映相册的内容 + +18 +00:00:54,354 --> 00:00:57,524 +假设我创建了一个社交远足 App + +19 +00:00:57,524 --> 00:01:00,260 +允许人们分享和编辑 + +20 +00:01:00,260 --> 00:01:02,796 +和朋友一起远足旅行的照片 + +21 +00:01:02,796 --> 00:01:04,431 +当有人启动 App 时 + +22 +00:01:04,431 --> 00:01:07,868 +该 App 通过 +获取从旅行开始到结束的时间戳 + +23 +00:01:07,868 --> 00:01:11,004 +收集最近一次远足时的手机照片 + +24 +00:01:11,004 --> 00:01:13,340 +并把他们在山上远足经历 +的生成拼贴画 + +25 +00:01:13,340 --> 00:01:16,210 +拼贴画与图片库中所选照片 + +26 +00:01:16,210 --> 00:01:18,111 +保持同步 + +27 +00:01:18,111 --> 00:01:19,813 +如果有人收到远足照片 + +28 +00:01:19,813 --> 00:01:21,582 +例如来自朋友的 + +29 +00:01:21,582 --> 00:01:25,886 +该 App 将使用 +这些更新照片生成新的拼贴画 + +30 +00:01:25,886 --> 00:01:28,255 +到目前为止为了让 App 发现 + +31 +00:01:28,255 --> 00:01:30,858 +新插入的图片资产 + +32 +00:01:30,858 --> 00:01:33,360 +并对以前的远足拼贴画进行更改 + +33 +00:01:33,360 --> 00:01:37,097 +该 App 需要 +执行一系列参数提取 + +34 +00:01:37,097 --> 00:01:40,100 +要确定插入了哪些图片资产 + +35 +00:01:40,100 --> 00:01:41,635 +该 App 需要能够获取 +图片资产创建日期 + +36 +00:01:41,635 --> 00:01:46,573 +晚于 App +最后一次启动日期的资产 + +37 +00:01:46,573 --> 00:01:50,511 +确定资产更新和删除的日期比较棘手 + +38 +00:01:50,511 --> 00:01:54,281 +该 App 需要重新获取 +每个拼贴中的每个图片资产 + +39 +00:01:54,281 --> 00:01:56,350 +并检查图片修改日期 + +40 +00:01:56,350 --> 00:01:58,385 +从而确定图片资产的更新时间 + +41 +00:01:58,385 --> 00:02:00,320 +但这可能会带来误报 + +42 +00:02:00,320 --> 00:02:02,256 +作为图片资产 图片的修改时间 + +43 +00:02:02,256 --> 00:02:06,426 +可以由相册的内部处理活动设置 + +44 +00:02:06,426 --> 00:02:09,696 +照片库中的删除更难追踪 + +45 +00:02:09,696 --> 00:02:13,100 +因为需要提取所有跟踪的资产 + +46 +00:02:13,100 --> 00:02:16,170 +并对未随提取返回的资产进行区分 + +47 +00:02:16,170 --> 00:02:19,306 +总的来说这意味着每次启动 App + +48 +00:02:19,306 --> 00:02:22,576 +都需要做三个单独的检查 + +49 +00:02:22,576 --> 00:02:24,578 +如果 App 显示大量图片资产 + +50 +00:02:24,578 --> 00:02:28,515 +那么提取和计算开销会非常大 + +51 +00:02:28,515 --> 00:02:31,118 +而不是对不确定的结果 + +52 +00:02:31,118 --> 00:02:32,986 +进行不同的提取和检查 + +53 +00:02:32,986 --> 00:02:35,856 +如果有办法把确已发生的图片变化 + +54 +00:02:35,856 --> 00:02:38,525 +统一到一个 +API 调用里会怎么样呢? + +55 +00:02:38,525 --> 00:02:42,529 +好吧 +我很高兴地告诉您我们已经做到了! + +56 +00:02:42,529 --> 00:02:46,099 +新的变更历史 API +允许以更简单的方式 + +57 +00:02:46,099 --> 00:02:50,437 +跟踪照片库的离线更新 + +58 +00:02:50,437 --> 00:02:53,574 +变更历史由变更时间线组成 + +59 +00:02:53,574 --> 00:02:55,976 +例如插入、更新 + +60 +00:02:55,976 --> 00:02:58,679 +和删除照片库 + +61 +00:02:58,679 --> 00:03:00,380 +在这个时间线示例中 + +62 +00:03:00,380 --> 00:03:04,184 +过去三天 +有各种资产、相簿和文件夹的更改 + +63 +00:03:04,184 --> 00:03:07,921 +保存于变更历史记录中 + +64 +00:03:07,921 --> 00:03:10,657 +使用此时间线您如何确定 + +65 +00:03:10,657 --> 00:03:14,027 +最近两天发生了哪些变化 + +66 +00:03:14,027 --> 00:03:17,497 +或者上一次您启动 App 的时间? + +67 +00:03:17,497 --> 00:03:20,534 +您现在可以使用持久化更改令牌 + +68 +00:03:20,534 --> 00:03:23,103 +在给定的时间点 + +69 +00:03:23,103 --> 00:03:25,672 +表示照片库的状态 + +70 +00:03:25,672 --> 00:03:29,476 +此令牌可以 +在 App 启动时持久化 + +71 +00:03:29,476 --> 00:03:32,713 +并且它可用于获取该令牌生成后 + +72 +00:03:32,713 --> 00:03:34,815 +照片库的更改 + +73 +00:03:34,815 --> 00:03:37,551 +包括第三方 App 的修改 + +74 +00:03:37,551 --> 00:03:40,487 +请注意如果您的应用处于受限库模式 + +75 +00:03:40,487 --> 00:03:43,457 +则只有更改 +用户选择的 PhotoKit 对象 + +76 +00:03:43,457 --> 00:03:45,459 +会返回信息 + +77 +00:03:45,459 --> 00:03:48,695 +此更改令牌是设备本地的 + +78 +00:03:48,695 --> 00:03:51,164 +并且任何时候从 +持久化更改或图片库实例访问 + +79 +00:03:51,164 --> 00:03:55,435 +开销都会更小 + +80 +00:03:55,435 --> 00:03:58,238 +这个新的 API +在以下任何平台上都可用 + +81 +00:03:58,238 --> 00:04:06,313 +支持 PhotoKit 的平台有 +macOS、iOS、iPadOS 和 tvOS + +82 +00:04:06,313 --> 00:04:10,250 +当您的 App +正在运行并使用照片库时 + +83 +00:04:10,250 --> 00:04:14,855 +您可以在 App 中 +存储持久化更改令牌 + +84 +00:04:14,855 --> 00:04:19,193 +您可以使用该令牌来获取此后 + +85 +00:04:19,193 --> 00:04:21,328 +发生的照片库更改 + +86 +00:04:21,328 --> 00:04:23,263 +对于每一个持久化更改 + +87 +00:04:23,263 --> 00:04:25,299 +您可以对于三种类型的相册对象 + +88 +00:04:25,299 --> 00:04:28,368 +获取更改详细信息 + +89 +00:04:28,368 --> 00:04:33,273 +资产、资产集合和集合列表 + +90 +00:04:33,273 --> 00:04:36,543 +那么这在代码中是什么样的呢? + +91 +00:04:36,543 --> 00:04:39,446 +首先 您需要使用 +上次存储的更改令牌 + +92 +00:04:39,446 --> 00:04:42,249 +获取持久化更改 + +93 +00:04:42,249 --> 00:04:45,586 +接下来您需要枚举 + +94 +00:04:45,586 --> 00:04:50,157 +并获取更改对象更改详细信息—— +在本例中 + +95 +00:04:50,157 --> 00:04:53,160 +每个持久化更改对象 +都是“asset”型 + +96 +00:04:53,160 --> 00:04:55,529 +这些更改详细信息提供了 + +97 +00:04:55,529 --> 00:04:59,633 +自更改令牌以来 更新、删除 + +98 +00:04:59,633 --> 00:05:01,702 +和插入到照片库中的 + +99 +00:05:01,702 --> 00:05:04,404 +本地标识符的信息 + +100 +00:05:04,404 --> 00:05:06,473 +处理完这些改动后 + +101 +00:05:06,473 --> 00:05:10,777 +您可以存储最后一个更改令牌 +以供将来使用 + +102 +00:05:10,777 --> 00:05:14,681 +让我们对比一下 +新的持久化历史 API + +103 +00:05:14,681 --> 00:05:18,418 +和现有的改变观察者 API + +104 +00:05:18,418 --> 00:05:22,256 +PHChanges 处理活动的 +内存中的获取结果 + +105 +00:05:22,256 --> 00:05:25,692 +并在您的 App 运行时 + +106 +00:05:25,692 --> 00:05:28,328 +用于记录照片库的实时更改 + +107 +00:05:28,328 --> 00:05:30,430 +另一方面 持久化历史记录 + +108 +00:05:30,430 --> 00:05:33,567 +记录了对照片库的长期更改 + +109 +00:05:33,567 --> 00:05:35,469 +并可用于报告 + +110 +00:05:35,469 --> 00:05:38,572 +App 不活动时的更改 + +111 +00:05:38,572 --> 00:05:41,575 +您可以根据您的 App 的需求 + +112 +00:05:41,575 --> 00:05:45,212 +同时使用这两种 API +或者任选其一 + +113 +00:05:45,212 --> 00:05:47,381 +回到远足应用示例 + +114 +00:05:47,381 --> 00:05:50,384 +我现在想使用持久化历史 API + +115 +00:05:50,384 --> 00:05:53,120 +跟踪资产变化 + +116 +00:05:53,120 --> 00:05:55,722 +以便于创建和更新远足拼贴画 + +117 +00:05:55,722 --> 00:05:59,459 +首先我将使用最后存储的更改令牌 + +118 +00:05:59,459 --> 00:06:02,062 +并获取持久化更改 + +119 +00:06:02,062 --> 00:06:05,566 +接下来我将遍历持久化更改 + +120 +00:06:05,566 --> 00:06:08,368 +抓取相关资产的变更明细 + +121 +00:06:08,368 --> 00:06:11,138 +然后进行插入、更新操作 + +122 +00:06:11,138 --> 00:06:13,807 +并删除标识符 + +123 +00:06:13,807 --> 00:06:16,910 +现在我需要从变更历史中 + +124 +00:06:16,910 --> 00:06:19,713 +识别出影响 App 的图片库更改 + +125 +00:06:19,713 --> 00:06:22,182 +因为 App 不需要获取 + +126 +00:06:22,182 --> 00:06:25,519 +更改返回的所有信息 + +127 +00:06:25,519 --> 00:06:28,188 +对 App 来说 + +128 +00:06:28,188 --> 00:06:32,826 +了解哪一个远足图片资产 +已加入到图片库 + +129 +00:06:32,826 --> 00:06:34,995 +以及哪些被更新和删除的资产 + +130 +00:06:34,995 --> 00:06:38,599 +在以前的远足拼贴画中引用过很重要 + +131 +00:06:38,599 --> 00:06:40,734 +我已经通过持久化更改 +生成了三个枚举定义 + +132 +00:06:40,734 --> 00:06:44,872 +插入、更新和删除资产的 + +133 +00:06:44,872 --> 00:06:47,708 +本地标识符 + +134 +00:06:47,708 --> 00:06:51,345 +我现在如何更新 App +以反映这些状态? + +135 +00:06:51,345 --> 00:06:53,981 +使用插入标识符集 + +136 +00:06:53,981 --> 00:06:56,416 +我可以通过获取 +每次远足的开始和结束日期 + +137 +00:06:56,416 --> 00:07:00,621 +通过远足图片资产的插入时间戳 + +138 +00:07:00,621 --> 00:07:02,656 +和他们的创建时间 + +139 +00:07:02,656 --> 00:07:08,128 +来确定添加了哪些资产 + +140 +00:07:08,128 --> 00:07:11,632 +更新后的资产可能会进行调整 + +141 +00:07:11,632 --> 00:07:15,002 +所以我可以使用新的 +hasAdjustments API + +142 +00:07:15,002 --> 00:07:20,908 +检查我是否需要 +在 UI 中重绘资产 + +143 +00:07:20,908 --> 00:07:23,844 +我可以使用已删除资产的本地标识符 + +144 +00:07:23,844 --> 00:07:27,748 +以确定哪些拼贴画需要重新生成 + +145 +00:07:27,748 --> 00:07:31,785 +现在我已经处理了 +所有离线照片库的更改 + +146 +00:07:31,785 --> 00:07:36,056 +并且我的 App 的内容是最新的 + +147 +00:07:36,056 --> 00:07:38,525 +以下是当您使用 +新的变更历史 API 时 + +148 +00:07:38,525 --> 00:07:42,496 +应该记住的几件事 + +149 +00:07:42,496 --> 00:07:45,499 +首先确定哪些更改对您 + +150 +00:07:45,499 --> 00:07:49,269 +和您的 App 很重要 +并且只检查这些更改 + +151 +00:07:49,269 --> 00:07:51,905 +考虑执行一个 + +152 +00:07:51,905 --> 00:07:54,474 +更新和插入资产的大型获取请求 +以提高性能 + +153 +00:07:54,474 --> 00:07:59,580 +而不是用多个较小的请求 + +154 +00:07:59,580 --> 00:08:02,549 +照片库的内容可能会因处理 + +155 +00:08:02,549 --> 00:08:05,219 +和后台同步活动而发生很大变化 + +156 +00:08:05,219 --> 00:08:07,020 +所以您最终可能会在 + +157 +00:08:07,020 --> 00:08:08,789 +大量变化中进行枚举 + +158 +00:08:08,789 --> 00:08:12,159 +尤其是当您的 App 不经常启动 + +159 +00:08:12,159 --> 00:08:14,394 +正因为如此我们推荐您 + +160 +00:08:14,394 --> 00:08:17,731 +在后台线程上请求更改历史记录 + +161 +00:08:17,731 --> 00:08:20,734 +以避免阻塞 UI + +162 +00:08:20,734 --> 00:08:22,803 +在获取持久化历史记录时 + +163 +00:08:22,803 --> 00:08:25,572 +可能发生两种类型的错误 + +164 +00:08:25,572 --> 00:08:26,607 +如果更改令牌 + +165 +00:08:26,607 --> 00:08:29,543 +比更改的可用历史记录更早 + +166 +00:08:29,543 --> 00:08:33,514 +将返回更改令牌过期的报错 + +167 +00:08:33,514 --> 00:08:35,716 +在某些情况下持久化更改 + +168 +00:08:35,716 --> 00:08:38,685 +不能依赖于完全重建 + +169 +00:08:38,685 --> 00:08:40,420 +所发生的更改 + +170 +00:08:40,420 --> 00:08:44,958 +并将返回更改详细信息不可用的报错 + +171 +00:08:44,958 --> 00:08:47,761 +在这些情况下我们建议 + +172 +00:08:47,761 --> 00:08:51,031 +重新获取照片库中的跟踪对象 + +173 +00:08:51,031 --> 00:08:54,234 +以确保您的应用的内容是最新的 + +174 +00:08:54,234 --> 00:08:56,670 +在我们结束之前 +还有一些我想与您分享 + +175 +00:08:56,670 --> 00:09:01,041 +新的 PhotoKit API 的内容 + +176 +00:09:01,041 --> 00:09:04,411 +PhotoKit 现在 +支持按媒体子类型 + +177 +00:09:04,411 --> 00:09:08,182 +和智能相册访问电影视频 + +178 +00:09:08,182 --> 00:09:11,585 +还有两个新的错误代码 + +179 +00:09:11,585 --> 00:09:13,020 +如果照片库绑定 +在 macOS 系统的 + +180 +00:09:13,020 --> 00:09:17,124 +File Provider 同步根目录下 + +181 +00:09:17,124 --> 00:09:19,092 +图片库可能会损坏 + +182 +00:09:19,092 --> 00:09:23,564 +尝试执行更改时将返回错误 + +183 +00:09:23,564 --> 00:09:25,732 +如果由于网络问题 + +184 +00:09:25,732 --> 00:09:27,434 +找不到资产资源 + +185 +00:09:27,434 --> 00:09:31,171 +资源请求将返回网络错误的报错 + +186 +00:09:31,171 --> 00:09:33,106 +请在开发者文档查看 + +187 +00:09:33,106 --> 00:09:35,409 +所有最新的更新 + +188 +00:09:35,409 --> 00:09:38,545 +最后一定要在相册选取器中 + +189 +00:09:38,545 --> 00:09:39,813 +看看今年的会议 + +190 +00:09:39,813 --> 00:09:44,585 +因为它是使用和访问 +相册的最简单方法 + +191 +00:09:44,585 --> 00:09:48,322 +我们很高兴您能 +使用新的变更历史 API + +192 +00:09:48,322 --> 00:09:51,291 +以及 PhotoKit 中 +所有出色的新功能 + +193 +00:09:51,291 --> 00:09:52,993 +谢谢! + +194 +00:09:52,993 --> 00:09:57,397 +♪ + diff --git a/zho/2022 Session 10133 Build a productivity app for Apple Watch.srt b/zho/2022 Session 10133 Build a productivity app for Apple Watch.srt new file mode 100644 index 0000000..d0a3076 --- /dev/null +++ b/zho/2022 Session 10133 Build a productivity app for Apple Watch.srt @@ -0,0 +1,2002 @@ +1 +00:00:01,268 --> 00:00:07,274 +[音乐] + +2 +00:00:09,977 --> 00:00:12,079 +Anne: 大家好 欢迎你们 + +3 +00:00:12,112 --> 00:00:13,247 +我是 Anne Hitchcock + +4 +00:00:13,280 --> 00:00:15,616 +是 watchOS 软件工程师 + +5 +00:00:15,649 --> 00:00:17,017 +今天 我想向您展示 + +6 +00:00:17,050 --> 00:00:18,585 +如何在 watchOS 上创建 + +7 +00:00:18,619 --> 00:00:20,521 +效率 App + +8 +00:00:20,554 --> 00:00:22,422 +自从 watchOS 6 中 +引入了 SwiftUI + +9 +00:00:22,456 --> 00:00:25,292 +和独立的 Watch App 以来 + +10 +00:00:25,325 --> 00:00:27,961 +您已经能够在 Watch App 中 +做得比以往更多 + +11 +00:00:28,529 --> 00:00:33,166 +每年 watchOS 上的 SwiftUI +都会有更多功能 + +12 +00:00:33,200 --> 00:00:34,501 +同时 + +13 +00:00:34,535 --> 00:00:37,771 +watchOS 也有了一些新功能 +比如键盘 + +14 +00:00:37,804 --> 00:00:41,208 +让您为 Watch 开发全新的 App + +15 +00:00:41,875 --> 00:00:45,045 +我想向您展示 +如何将其中的一些功能组合起来 + +16 +00:00:45,078 --> 00:00:48,182 +构建一个 App +来跟踪代办清单 + +17 +00:00:49,016 --> 00:00:52,319 +我们将创建一个新的 Watch App + +18 +00:00:52,352 --> 00:00:55,889 +添加要显示的简单项目列表 + +19 +00:00:55,923 --> 00:00:58,225 +让用户将项目添加至列表 + +20 +00:00:58,258 --> 00:00:59,927 +然后进行编辑 + +21 +00:01:00,894 --> 00:01:02,596 +当添加这些功能时 + +22 +00:01:02,629 --> 00:01:06,700 +我们将讨论 Watch App 中 +常见的导航策略 + +23 +00:01:06,733 --> 00:01:08,735 +以及如何正确选择 + +24 +00:01:10,103 --> 00:01:13,106 +我们将与朋友分享条目 以分担负载 + +25 +00:01:14,241 --> 00:01:16,243 +然后会在我们的 App 中添加一个图表 + +26 +00:01:16,276 --> 00:01:20,080 +以帮助我们发现效率趋势 +并保持动力 + +27 +00:01:21,281 --> 00:01:23,150 +我们将使用数码表冠来制作 + +28 +00:01:23,183 --> 00:01:24,751 +可滚动图表 + +29 +00:01:24,785 --> 00:01:27,054 +以显示更大的数据范围 + +30 +00:01:28,188 --> 00:01:31,158 +我们从创建一个新的 App 开始 + +31 +00:01:32,492 --> 00:01:34,361 +在 Xcode 中创建一个新项目 + +32 +00:01:35,262 --> 00:01:39,032 +在 watchOS 选项卡中 +选择 App 并单击下一步 + +33 +00:01:40,400 --> 00:01:44,605 +选择 Product Name 后 您有几个选择 + +34 +00:01:44,638 --> 00:01:46,073 +最重要的是 + +35 +00:01:46,106 --> 00:01:48,775 +是创建 Watch 专用 App + +36 +00:01:48,809 --> 00:01:52,246 +还是带有配套 iOS App 的 Watch App + +37 +00:01:52,846 --> 00:01:55,849 +我们来谈谈一个优秀的 +Watch App 的要素 + +38 +00:01:55,883 --> 00:01:58,919 +以及何时需要配套的 iOS App + +39 +00:01:59,953 --> 00:02:03,156 +出色的 Watch App 可实现快速交互 + +40 +00:02:03,190 --> 00:02:04,992 +比如体能训练中的界面 + +41 +00:02:05,025 --> 00:02:08,595 +让您快速开始最喜欢的体能训练 + +42 +00:02:08,629 --> 00:02:11,532 +没人愿意定定站着 举起他们的手臂 + +43 +00:02:11,565 --> 00:02:13,267 +然后才能点进去 +尝试找到一些东西 + +44 +00:02:14,101 --> 00:02:18,038 +出色的 Watch App 应该很容易 +获得重要的信息 + +45 +00:02:18,071 --> 00:02:19,206 +和功能 + +46 +00:02:20,707 --> 00:02:24,011 +出色的 Watch App 专注于其核心的目的 + +47 +00:02:24,912 --> 00:02:29,283 +例如 天气 App 显示今天的天气预报 + +48 +00:02:29,316 --> 00:02:33,353 +相关的当前情况 +以及简单的 10 天天气预测 + +49 +00:02:34,488 --> 00:02:36,690 +专注于 App 中的关键内容 + +50 +00:02:36,723 --> 00:02:39,159 +这样人们就可以轻松找到他们需要的 + +51 +00:02:39,193 --> 00:02:40,694 +信息和行动 + +52 +00:02:42,229 --> 00:02:44,698 +一款优秀的 Watch App + +53 +00:02:44,731 --> 00:02:47,034 +会设计成可以独立于 +配套的 iPhone 使用 + +54 +00:02:47,901 --> 00:02:52,172 +例如 联系人 App +可以与手机同步 + +55 +00:02:52,206 --> 00:02:54,608 +但不需要您的 iPhone 在附近 + +56 +00:02:54,641 --> 00:02:56,376 +就可以访问您的 Apple Watch 上的 + +57 +00:02:56,410 --> 00:02:57,878 +联系人信息 + +58 +00:02:59,479 --> 00:03:02,049 +您可能还想为您的 Watch App + +59 +00:03:02,082 --> 00:03:05,118 +安装配套的 iOS App 的原因有很多 + +60 +00:03:05,152 --> 00:03:10,090 +包括提供 Apple Watch +捕获数据的历史记录 + +61 +00:03:10,123 --> 00:03:13,794 +或者像健身 App 那样 +提供详细的趋势分析 + +62 +00:03:15,729 --> 00:03:18,432 +由于我们的 App 具有集中的功能集 + +63 +00:03:18,465 --> 00:03:20,901 +快速的交互和有限的数据 + +64 +00:03:20,934 --> 00:03:23,003 +我们将创建一个 Watch 专用 App + +65 +00:03:24,705 --> 00:03:27,508 +在这一点上 我想花几分钟 + +66 +00:03:27,541 --> 00:03:29,810 +谈谈创建的目标 + +67 +00:03:31,612 --> 00:03:33,714 +如果您过去曾开发过 Watch App + +68 +00:03:33,747 --> 00:03:36,550 +那么您的 Watch 项目会有两个目标 + +69 +00:03:36,583 --> 00:03:39,086 +WatchKit App 目标带有情节提要 + +70 +00:03:39,119 --> 00:03:42,990 +材料 也许还有一些 +与本地化相关的文件 + +71 +00:03:43,023 --> 00:03:47,160 +以及包含所有 App 代码的 +WatchKit 扩展目标 + +72 +00:03:47,194 --> 00:03:49,897 +这些双重目标是 + +73 +00:03:49,930 --> 00:03:52,199 +早期 watchOS 遗留下来的 + +74 +00:03:52,232 --> 00:03:56,737 +并且确实没有充分的理由 +再使用多个 Watch 目标了 + +75 +00:03:57,671 --> 00:04:03,510 +从 Xcode 14 开始 新的 +Watch App 有单一的 Watch App 目标 + +76 +00:04:03,544 --> 00:04:06,547 +所有与 Watch App 相关的 + +77 +00:04:06,580 --> 00:04:08,916 +代码 材料 本地化 + +78 +00:04:08,949 --> 00:04:10,551 +Siri 意图以及 Widget 扩展 + +79 +00:04:10,584 --> 00:04:12,085 +都包含在这个目标内 + +80 +00:04:13,353 --> 00:04:16,623 +好消息是 单一目标的 Watch App + +81 +00:04:16,657 --> 00:04:19,526 +可支持的最旧版本是 watchOS 7 + +82 +00:04:19,560 --> 00:04:24,097 +您可以简化项目结构 +并减少混乱和重复 + +83 +00:04:24,131 --> 00:04:26,800 +同时也支持那些没有使用 + +84 +00:04:26,834 --> 00:04:28,168 +最新的 watchOS 的用户 + +85 +00:04:29,636 --> 00:04:31,338 +如果您有现有的 App + +86 +00:04:31,371 --> 00:04:33,307 +带有 WatchKit 扩展目标 + +87 +00:04:33,340 --> 00:04:34,942 +它将继续工作 + +88 +00:04:34,975 --> 00:04:38,245 +您可以继续使用 Xcode +更新您的 App + +89 +00:04:38,278 --> 00:04:40,848 +并通过 App Store 发布您的 App + +90 +00:04:42,282 --> 00:04:44,284 +如果您已经有一个 +使用 SwiftUI lifecycle 的 + +91 +00:04:44,318 --> 00:04:46,286 +Watch App + +92 +00:04:46,320 --> 00:04:52,626 +那么使用 Xcode 14 中的迁移工具 +就可以很容易地过渡到单个目标 + +93 +00:04:52,659 --> 00:04:55,562 +选择您的目标并从编辑器菜单中 + +94 +00:04:55,596 --> 00:04:57,598 +选择 Validate Setting + +95 +00:04:57,631 --> 00:04:59,967 +如果您的部署目标 +是 watchOS 7 或更高版本 + +96 +00:05:00,000 --> 00:05:02,936 +将提供目标折叠选项 + +97 +00:05:04,705 --> 00:05:06,673 +如果您尚未实现飞跃 + +98 +00:05:06,707 --> 00:05:08,876 +现在是时候开始 + +99 +00:05:08,909 --> 00:05:12,179 +将您的 App 转换为使用 + +100 +00:05:12,212 --> 00:05:15,749 +以享受单目标 Watch App 的简单性 + +101 +00:05:15,782 --> 00:05:18,585 +以及 SwiftUI 的所有功能 + +102 +00:05:20,087 --> 00:05:24,391 +目标不是我们在 Xcode 14 中 +进行的唯一简化功能 + +103 +00:05:24,424 --> 00:05:26,426 +我们同时也让您能更轻松地 + +104 +00:05:26,460 --> 00:05:28,295 +为 App 添加图标 + +105 +00:05:28,328 --> 00:05:33,000 +现在 您仅需要一张 +1024x1024 像素的图像就行了 + +106 +00:05:34,067 --> 00:05:35,903 +App 图标图像将按比例缩放 + +107 +00:05:35,936 --> 00:05:38,172 +以便在所有 Watch 设备上显示 + +108 +00:05:39,473 --> 00:05:41,074 +请务必在设备的主屏幕 + +109 +00:05:41,108 --> 00:05:43,310 +通知以及 iPhone 上 + +110 +00:05:43,343 --> 00:05:45,479 +Watch App 的 + +111 +00:05:45,512 --> 00:05:47,381 +设置中 + +112 +00:05:47,414 --> 00:05:49,216 +使用您的 App 图标进行测试 + +113 +00:05:50,584 --> 00:05:52,286 +如有必要 您可以为 + +114 +00:05:52,319 --> 00:05:55,756 +特定的较小尺寸添加自定义图像 + +115 +00:05:55,789 --> 00:05:56,823 +例如 + +116 +00:05:56,857 --> 00:05:59,359 +如果您的 App 图标在图像中 + +117 +00:05:59,393 --> 00:06:01,795 +有一些细节在较小的尺寸中丢失了 + +118 +00:06:01,828 --> 00:06:04,932 +您可以为这些尺寸 +添加特定的图标图像 + +119 +00:06:04,965 --> 00:06:07,234 +并删除图像细节 + +120 +00:06:07,267 --> 00:06:09,803 +现在让我们通过添加任务项列表 + +121 +00:06:09,837 --> 00:06:12,072 +来为 App 添加一些功能 + +122 +00:06:12,806 --> 00:06:14,775 +我们将首先为任务列表 + +123 +00:06:14,808 --> 00:06:16,944 +创建一个数据模型 + +124 +00:06:16,977 --> 00:06:20,647 +ListItem 结构 +将是可识别和可散列的 + +125 +00:06:20,681 --> 00:06:22,816 +我们将给它一个要显示的描述 + +126 +00:06:24,284 --> 00:06:27,387 +然后创建一个简单的模型来存储数据 + +127 +00:06:27,421 --> 00:06:29,489 +并发布列表项数组 + +128 +00:06:30,624 --> 00:06:33,927 +最后 添加模型作为环境对象 + +129 +00:06:33,961 --> 00:06:35,929 +所以我们的视图 +可以访问我们的模型 + +130 +00:06:37,397 --> 00:06:41,502 +现在使用数据模型 +在 SwiftUI 中创建一个 List + +131 +00:06:41,535 --> 00:06:44,037 +由于目前还没有任务 + +132 +00:06:44,071 --> 00:06:46,607 +当我们预览这个时 +得到的是一个空列表 + +133 +00:06:47,641 --> 00:06:50,010 +我们得做点什么了 + +134 +00:06:50,043 --> 00:06:53,447 +我们应该给人们一种将任务 +添加到他们列表中的方法 + +135 +00:06:54,448 --> 00:06:57,017 +我们想添加一个按钮 +用户可以点击该按钮 + +136 +00:06:57,050 --> 00:06:59,052 +将新项目添加到列表中 + +137 +00:06:59,887 --> 00:07:03,023 +文本字段链接是 +watchOS 9 中的新功能 + +138 +00:07:03,056 --> 00:07:06,159 +让您从按钮调用文本输入选项 + +139 +00:07:06,193 --> 00:07:08,028 +并提供多种样式选择 + +140 +00:07:08,061 --> 00:07:10,697 +使其在 App 中感觉自然且友好 + +141 +00:07:12,266 --> 00:07:16,436 +您可以用简单的字符串 +创建一个基本的文本字段链接 + +142 +00:07:16,470 --> 00:07:19,039 +或者使用 Label 来创建一个 +更自定义的按钮 + +143 +00:07:20,374 --> 00:07:23,477 +使用视图修改器修改按钮外观 + +144 +00:07:23,510 --> 00:07:25,746 +包括 foregroundColor + +145 +00:07:25,779 --> 00:07:27,814 +foregroundStyle + +146 +00:07:27,848 --> 00:07:29,249 +和 buttonStyle + +147 +00:07:30,784 --> 00:07:33,086 +我们将创建一个 AddItemLink 视图 + +148 +00:07:33,120 --> 00:07:35,689 +以封装我们在 App 中使用的 + +149 +00:07:35,722 --> 00:07:38,525 +文本字段链接的样式和行为 + +150 +00:07:39,593 --> 00:07:42,462 +我们将为按钮使用自定义标签 + +151 +00:07:42,496 --> 00:07:44,231 +当有人输入文字时 + +152 +00:07:44,264 --> 00:07:46,366 +我们会将新项目添加到列表中 + +153 +00:07:47,734 --> 00:07:49,870 +既然我们已经决定 +使用文本字段链接 + +154 +00:07:49,903 --> 00:07:52,806 +添加按钮来添加新的列表项 + +155 +00:07:52,840 --> 00:07:55,876 +我们需要考虑 +把文本字段链接放在哪里 + +156 +00:07:57,644 --> 00:08:00,280 +在 Watch App 中向列表添加操作时 + +157 +00:08:00,314 --> 00:08:02,783 +有几个选择 + +158 +00:08:02,816 --> 00:08:06,320 +对于短列表中的主要操作 + +159 +00:08:06,353 --> 00:08:11,859 +在列表末尾使用按钮 +导航链接或文本字段链接 + +160 +00:08:11,892 --> 00:08:15,262 +将动作添加为列表末尾的项目 + +161 +00:08:15,295 --> 00:08:17,531 +是短列表 + +162 +00:08:17,564 --> 00:08:18,966 +如世界时钟中的 + +163 +00:08:18,999 --> 00:08:21,068 +城市列表中的主要动作的不错选择 + +164 +00:08:21,802 --> 00:08:23,036 +然而 + +165 +00:08:23,070 --> 00:08:25,439 +如果您预计会有很长的项目清单 + +166 +00:08:25,472 --> 00:08:27,975 +用户每次想要执行操作时 + +167 +00:08:28,008 --> 00:08:31,578 +都必须继续滚动到列表的末尾 + +168 +00:08:31,612 --> 00:08:33,046 +对于具有较长列表的常用操作 + +169 +00:08:33,080 --> 00:08:36,083 +请使用工具栏项 + +170 +00:08:37,451 --> 00:08:41,755 +要添加工具栏项 +请将工具栏修改器添加到列表中 + +171 +00:08:41,788 --> 00:08:44,791 +并将操作视图用作内容 + +172 +00:08:44,825 --> 00:08:47,594 +这将向列表中添加一个工具栏项 + +173 +00:08:47,628 --> 00:08:50,097 +并自动放置工具栏项 + +174 +00:08:50,130 --> 00:08:52,466 +虽然我想一直保持很短的 + +175 +00:08:52,499 --> 00:08:53,800 +待办清单 + +176 +00:08:53,834 --> 00:08:55,836 +但我很确定并不会 + +177 +00:08:55,869 --> 00:08:58,705 +所以我要把文本字段链接 +放在工具栏项中 + +178 +00:08:58,739 --> 00:09:00,707 +使其易于访问 + +179 +00:09:02,242 --> 00:09:05,479 +让我们花点时间回顾一下 +我们已经完成了什么 + +180 +00:09:05,512 --> 00:09:08,315 +我们为列表项创建了一个模型 + +181 +00:09:08,348 --> 00:09:11,485 +将其存储为环境对象 + +182 +00:09:11,518 --> 00:09:13,554 +创建了一个显示项目的列表 + +183 +00:09:13,587 --> 00:09:16,723 +并添加了一个文本字段链接 +以添加新项目 + +184 +00:09:23,330 --> 00:09:25,432 +创建只有描述的项目 + +185 +00:09:25,465 --> 00:09:28,535 +很简单 但不是很有用 + +186 +00:09:28,569 --> 00:09:31,638 +我们需要将项目标记为完成 + +187 +00:09:31,672 --> 00:09:34,041 +我们可能想要一种为任务 + +188 +00:09:34,074 --> 00:09:36,143 +设置优先级的方法或添加 + +189 +00:09:36,176 --> 00:09:37,778 +对工作量的估计 + +190 +00:09:37,811 --> 00:09:40,781 +为此 我们将添加一个详细视图 + +191 +00:09:40,814 --> 00:09:42,783 +这样做之前 我想回顾一下 + +192 +00:09:42,816 --> 00:09:45,052 +Watch 上的 SwiftUI 中的 + +193 +00:09:45,085 --> 00:09:47,387 +App 导航结构的选项 + +194 +00:09:48,222 --> 00:09:50,657 +分层导航用于具有 + +195 +00:09:50,691 --> 00:09:53,594 +列表-详细关系的视图 + +196 +00:09:53,627 --> 00:09:57,397 +从 watchOS 9 开始 +使用 SwiftUI NavigationStack + +197 +00:09:57,431 --> 00:10:00,834 +来创建使用这种类型的 +导航结构的接口 + +198 +00:10:02,135 --> 00:10:04,571 +基于页面的导航用于 + +199 +00:10:04,605 --> 00:10:06,173 +平面结构的视图 + +200 +00:10:06,206 --> 00:10:08,242 +所有视图都是对等的 + +201 +00:10:09,510 --> 00:10:12,212 +基于页面的导航的一个很好的例子 + +202 +00:10:12,246 --> 00:10:15,015 +是健身 App 的锻炼中视图 + +203 +00:10:15,048 --> 00:10:16,650 +在锻炼过程中 + +204 +00:10:16,683 --> 00:10:20,587 +人们可以轻松地在锻炼控制 指标 + +205 +00:10:20,621 --> 00:10:21,788 +和回放控制之间滑动 + +206 +00:10:23,223 --> 00:10:25,459 +全屏 App 只有一个使用 + +207 +00:10:25,492 --> 00:10:27,861 +整个显示的单一视图 + +208 +00:10:27,895 --> 00:10:30,464 +这通常用于游戏等 App + +209 +00:10:30,497 --> 00:10:32,966 +和其他有一个主视图的 App + +210 +00:10:34,234 --> 00:10:38,205 +对于全屏视图 +请使用 ignoresSafeArea 修改器 + +211 +00:10:38,238 --> 00:10:41,642 +将您的内容扩展到显示器的边缘 + +212 +00:10:41,675 --> 00:10:45,245 +并且工具栏修改器的 +可见性值为 hidden + +213 +00:10:45,279 --> 00:10:46,914 +以隐藏导航栏 + +214 +00:10:48,415 --> 00:10:50,450 +模态表是在当前视图上 + +215 +00:10:50,484 --> 00:10:52,653 +滑动的全屏视图 + +216 +00:10:52,686 --> 00:10:54,755 +它应作为 + +217 +00:10:54,788 --> 00:10:57,491 +当前工作流的一部分完成的重要任务 + +218 +00:10:58,892 --> 00:11:00,727 +区分何时使用 + +219 +00:11:00,761 --> 00:11:03,197 +分层流与何时使用模态图 + +220 +00:11:03,230 --> 00:11:05,532 +非常重要 + +221 +00:11:07,000 --> 00:11:11,839 +邮件 App 使用分层样式显示消息列表 + +222 +00:11:11,872 --> 00:11:15,976 +并显示每条消息或线程 +作为详细视图 + +223 +00:11:16,009 --> 00:11:18,979 +您可以从消息的详细信息中 +执行一些操作 + +224 +00:11:19,012 --> 00:11:21,014 +但在返回列表之前 + +225 +00:11:21,048 --> 00:11:22,816 +不必做任何事 + +226 +00:11:23,917 --> 00:11:27,387 +如果您返回列表 +然后点击“新信息” + +227 +00:11:27,421 --> 00:11:31,225 +邮件使用模态表显示 +新信息视图 + +228 +00:11:32,125 --> 00:11:34,294 +模态表是正确的选择 + +229 +00:11:34,328 --> 00:11:37,598 +因为您需要填写新消息的详细信息 +或在继续之前 + +230 +00:11:37,631 --> 00:11:39,233 +选择取消 + +231 +00:11:40,267 --> 00:11:41,935 +要显示模态表 + +232 +00:11:41,969 --> 00:11:46,173 +创建一个属性来控制工作表呈现状态 + +233 +00:11:46,206 --> 00:11:50,344 +根据用户界面中的操作设置属性 + +234 +00:11:50,377 --> 00:11:52,145 +并在表示状态属性为 true 时 + +235 +00:11:52,179 --> 00:11:54,681 +使用工作表修改器 + +236 +00:11:54,715 --> 00:11:57,317 +显示自定义模式工作表内容 + +237 +00:11:58,986 --> 00:12:01,889 +添加自定义工具栏项目到模态表 + +238 +00:12:01,922 --> 00:12:04,558 +为您的项目添加一个工具栏 + +239 +00:12:04,591 --> 00:12:07,661 +请注意 您的工具栏项目应使用 +模态展示位置 + +240 +00:12:07,694 --> 00:12:09,530 +像 confirmationAction + +241 +00:12:09,563 --> 00:12:11,031 +cancellationAction + +242 +00:12:11,064 --> 00:12:12,432 +和 destructiveAction + +243 +00:12:14,201 --> 00:12:17,070 +我们将使用模式表 +作为详细信息视图 + +244 +00:12:17,104 --> 00:12:18,972 +因为我们正在编辑一个项目 + +245 +00:12:19,006 --> 00:12:21,241 +而且想专注于这个单一的任务 + +246 +00:12:21,275 --> 00:12:23,544 +直到我们完成并点击完成 + +247 +00:12:24,745 --> 00:12:27,514 +要了解有关 SwiftUI 中导航的更多信息 + +248 +00:12:27,548 --> 00:12:30,083 +包括关于 NavigationStack 的更多细节 + +249 +00:12:30,117 --> 00:12:31,885 +和程序化导航 + +250 +00:12:31,919 --> 00:12:35,189 +请观看“SwiftUI 导航开发指南”视频 + +251 +00:12:36,757 --> 00:12:40,060 +现在我们已经决定了 +如何导航到详细视图 + +252 +00:12:40,093 --> 00:12:42,396 +我们将更新列表项结构 + +253 +00:12:42,429 --> 00:12:45,132 +我们有新的属性来存储估计工作 + +254 +00:12:45,165 --> 00:12:47,568 +创建日期和完成日期 + +255 +00:12:49,102 --> 00:12:52,206 +让我们为用户提供一种 +查看和编辑这些细节的方法 + +256 +00:12:53,240 --> 00:12:57,444 +我们将创建一个详细视图 +其中包含用于编辑说明的文本字段 + +257 +00:12:57,477 --> 00:13:01,648 +和一个用于将任务标记为 +未完成或不完成的切换开关 + +258 +00:13:01,682 --> 00:13:05,285 +但是我们应该怎么做估计的工作呢 + +259 +00:13:05,319 --> 00:13:07,721 +我们知道值都将是数字 + +260 +00:13:07,754 --> 00:13:10,657 +可以指定一个有效值的范围 + +261 +00:13:11,758 --> 00:13:14,228 +从 watchOS 9 开始 + +262 +00:13:14,261 --> 00:13:16,697 +我们可以使用 Stepper + +263 +00:13:16,730 --> 00:13:18,699 +当您想要提供精细控制 + +264 +00:13:18,732 --> 00:13:22,469 +来编辑顺序值时 +Stepper 是个不错的选择 + +265 +00:13:23,470 --> 00:13:27,774 +您可以指定一个值的范围 +并可选地提供步骤 + +266 +00:13:29,543 --> 00:13:33,113 +您还可以使用 Stepper 来编辑 +逻辑顺序 + +267 +00:13:33,146 --> 00:13:35,749 +但不一定是数值 + +268 +00:13:36,683 --> 00:13:39,286 +例如 也许我们要注意 + +269 +00:13:39,319 --> 00:13:41,588 +项目的估计压力水平 + +270 +00:13:42,623 --> 00:13:44,791 +我们可以创建一个表情符号数组 + +271 +00:13:44,825 --> 00:13:47,294 +来表示压力水平 + +272 +00:13:47,327 --> 00:13:49,730 +然后创建一个 Stepper + +273 +00:13:49,763 --> 00:13:54,601 +将值绑定到选定 +在压力水平表情符号数组的索引中 + +274 +00:13:54,635 --> 00:13:58,672 +并将范围设置为表情符号索引的范围 + +275 +00:13:58,705 --> 00:14:00,073 +逐步执行这些值 + +276 +00:14:00,107 --> 00:14:01,675 +会增加或减少 + +277 +00:14:01,708 --> 00:14:04,178 +我们为项目估计的压力水平 + +278 +00:14:05,312 --> 00:14:08,582 +准备 WWDC 讲座很有趣 + +279 +00:14:08,615 --> 00:14:12,019 +但与大家分享精彩的 +Watch App 开发更是一个欢庆的派对 + +280 +00:14:12,853 --> 00:14:15,589 +当我的清单上有压力项目时 + +281 +00:14:15,622 --> 00:14:19,459 +或者只是我清单上的很多项目 +我感到压力 + +282 +00:14:19,493 --> 00:14:21,962 +我想与朋友分享我列表中的一个项目 + +283 +00:14:21,995 --> 00:14:23,230 +来寻求帮助 + +284 +00:14:24,498 --> 00:14:27,301 +我们将把一个按钮 +添加到我们的详细视图 + +285 +00:14:27,334 --> 00:14:29,036 +允许用户使用共享表 + +286 +00:14:29,069 --> 00:14:31,171 +来共享项目 + +287 +00:14:31,205 --> 00:14:33,674 +我希望能够在我的详细视图中 +点击一个按钮 + +288 +00:14:33,707 --> 00:14:35,375 +来分享项目 + +289 +00:14:35,409 --> 00:14:38,178 +从朋友列表中进行挑选 +以寻求帮助 + +290 +00:14:38,212 --> 00:14:40,080 +编辑我的消息 然后发送 + +291 +00:14:41,348 --> 00:14:43,817 +为此 我们将使用一个新工具 + +292 +00:14:43,851 --> 00:14:47,588 +watchOS 9 上的 SwiftUI 可供我们使用 + +293 +00:14:47,621 --> 00:14:49,723 +分享链接 + +294 +00:14:49,756 --> 00:14:53,827 +我们可以通过创建包含项目 +共享链接来共享列表项 + +295 +00:14:53,861 --> 00:14:55,495 +我们可以有选择地 + +296 +00:14:55,529 --> 00:14:57,130 +自定义带有主题和消息的 + +297 +00:14:57,164 --> 00:15:00,033 +消息初始文本 + +298 +00:15:00,067 --> 00:15:02,936 +当有人分享该项目时 + +299 +00:15:02,970 --> 00:15:05,539 +提供预览显示在共享表 + +300 +00:15:05,572 --> 00:15:08,876 +您可以使用 ShareLink +从 SwiftUI App 进行分享 + +301 +00:15:08,909 --> 00:15:12,513 +在 iOS macOS 和 watchOS 中 + +302 +00:15:13,847 --> 00:15:15,983 +请务必查看“Transferable 简介”视频 + +303 +00:15:16,016 --> 00:15:18,051 +了解更多 ShareLink 的详细信息 + +304 +00:15:18,085 --> 00:15:19,786 +和选项 + +305 +00:15:19,820 --> 00:15:22,890 +现在我可以跟踪完成的项目 + +306 +00:15:22,923 --> 00:15:25,492 +并寻求帮助以完成工作 + +307 +00:15:25,526 --> 00:15:27,294 +我还想添加图表 + +308 +00:15:27,327 --> 00:15:29,096 +看看我的效率 + +309 +00:15:29,863 --> 00:15:32,199 +我选择使用条形图 + +310 +00:15:32,232 --> 00:15:34,468 +因为我只有一个数据序列 + +311 +00:15:34,501 --> 00:15:36,136 +和不同的数据值 + +312 +00:15:37,037 --> 00:15:38,705 +只要我限制一次显示的数据量 + +313 +00:15:38,739 --> 00:15:40,774 +条形图将清楚地显示 + +314 +00:15:40,807 --> 00:15:45,779 +Watch 显示屏上的这些数据 + +315 +00:15:45,812 --> 00:15:48,015 +我们将首先添加 图表视图 + +316 +00:15:48,048 --> 00:15:50,717 +到我们 App 的导航结构 + +317 +00:15:50,751 --> 00:15:53,654 +我选择了基于页面的导航策略 + +318 +00:15:53,687 --> 00:15:55,989 +因为在项目列表和图表之间 + +319 +00:15:56,023 --> 00:15:57,991 +没有列表细节关系 + +320 +00:15:58,759 --> 00:16:00,427 +有人可以在列表 + +321 +00:16:00,460 --> 00:16:02,029 +和图表之间随时滑动 + +322 +00:16:03,664 --> 00:16:05,432 +为我们的列表和图表 + +323 +00:16:05,465 --> 00:16:07,234 +添加基于页面的导航 + +324 +00:16:07,267 --> 00:16:11,405 +让我们从创建一个 ItemList 结构开始 +封装列表视图 + +325 +00:16:12,940 --> 00:16:15,642 +我把内容视图里的整个内容 + +326 +00:16:15,676 --> 00:16:18,045 +移动到这个新项目列表 + +327 +00:16:18,078 --> 00:16:20,948 +在这里封装项目列表 会让我们 + +328 +00:16:20,981 --> 00:16:23,584 +在内容视图中拥有简单易读的 + +329 +00:16:23,617 --> 00:16:24,852 +标签视图代码 + +330 +00:16:26,553 --> 00:16:29,623 +我们还需要为我们的图表视图 +创建一个结构 + +331 +00:16:31,225 --> 00:16:33,527 +我会暂时放一个占位符 + +332 +00:16:33,560 --> 00:16:36,096 +所以在我们构建图表之前 + +333 +00:16:36,129 --> 00:16:37,898 +我们可以专注在导航结构上 + +334 +00:16:39,466 --> 00:16:42,069 +现在我们将用一个带有 +两个标签的页面样式标签视图 + +335 +00:16:42,102 --> 00:16:44,972 +来设置我们的内容视图 + +336 +00:16:45,005 --> 00:16:47,274 +项目列表和图表 + +337 +00:16:49,309 --> 00:16:51,845 +既然我们已经设置了导航结构 + +338 +00:16:51,879 --> 00:16:53,914 +让我们谈谈如何构建这个图表 + +339 +00:16:54,615 --> 00:16:57,117 +我知道可以使用 SwiftUI Canvas + +340 +00:16:57,150 --> 00:16:58,952 +并绘制图表 + +341 +00:16:58,986 --> 00:17:00,687 +但从 watchOS 9 开始 + +342 +00:17:00,721 --> 00:17:04,091 +我们有一个更简单的答案 + +343 +00:17:04,825 --> 00:17:09,563 +Swift Charts 也可以在 iOS 上使用 +macOS 和 tvOS + +344 +00:17:09,596 --> 00:17:13,267 +因此您可以在任何使用 +SwiftUI 的地方重复使用图表 + +345 +00:17:14,401 --> 00:17:16,803 +我们将汇总我们想要绘制图表的数据 + +346 +00:17:16,837 --> 00:17:19,406 +然后让 Swift Charts 为我们显示 + +347 +00:17:21,041 --> 00:17:25,712 +对于图表 +我们希望显示按日期完成的项目数 + +348 +00:17:25,746 --> 00:17:28,815 +我们将创建一个结构 +以存储图表的聚合数据 + +349 +00:17:30,050 --> 00:17:31,685 +然后我们会写一个小方法 + +350 +00:17:31,718 --> 00:17:33,453 +来将列表项数据 + +351 +00:17:33,487 --> 00:17:35,155 +聚合为图表数据元素 + +352 +00:17:36,690 --> 00:17:41,128 +通过指定要显示的数据 +来显示一个简单的图表 + +353 +00:17:41,161 --> 00:17:43,997 +并从数据中定义系列 + +354 +00:17:44,031 --> 00:17:46,633 +我们使用日期作为 x 值 + +355 +00:17:46,667 --> 00:17:49,603 +完成的项目数 作为 y 值 + +356 +00:17:51,338 --> 00:17:54,541 +在我的 Watch 显示屏上 +实现我想要的样子 + +357 +00:17:54,575 --> 00:17:56,844 +我正在使用图表的 chartXAxis 修改器 + +358 +00:17:56,877 --> 00:18:00,013 +自定义 x 轴 + +359 +00:18:00,614 --> 00:18:04,818 +我正在为轴值标签指定格式样式 + +360 +00:18:04,852 --> 00:18:07,254 +我也不想要垂直网格线 + +361 +00:18:07,287 --> 00:18:10,791 +所以我省略了一个 +AxisGridLine 标记 + +362 +00:18:10,824 --> 00:18:16,029 +我还使用chartYAxis 修改器 +来自定义 y 轴 + +363 +00:18:16,063 --> 00:18:20,767 +我指定了一个网格线样式看起来 +很适合我在 Watch 上的图表 + +364 +00:18:20,801 --> 00:18:23,937 +我正在格式化轴值标签 作为整数 + +365 +00:18:23,971 --> 00:18:25,873 +并省略顶部标签 + +366 +00:18:25,906 --> 00:18:29,142 +以防止它在图表的顶部被剪裁 + +367 +00:18:29,176 --> 00:18:33,747 +想要了解更多 Swift Chart +可以实现的神奇功能 + +368 +00:18:33,780 --> 00:18:36,283 +请观看“认识 Swift Charts” + +369 +00:18:36,316 --> 00:18:39,319 +和“Swift Charts:提高标准”视频 + +370 +00:18:40,854 --> 00:18:42,689 +我们的图表看起来不错 + +371 +00:18:42,723 --> 00:18:44,925 +但我想在展示更多数据的同时 + +372 +00:18:44,958 --> 00:18:47,828 +仍保持出色的观看体验 + +373 +00:18:47,861 --> 00:18:50,297 +所以我要让它可滚动 + +374 +00:18:50,330 --> 00:18:52,900 +为此 我们将使用 + +375 +00:18:52,933 --> 00:18:55,636 +新的 digitalCrownRotation 修改器 + +376 +00:18:55,669 --> 00:18:57,838 +它允许我们为数码表冠活动 + +377 +00:18:57,871 --> 00:18:59,773 +设置回调 + +378 +00:18:59,806 --> 00:19:01,041 +我们将实施 + +379 +00:19:01,074 --> 00:19:03,610 +图表的自定义滚动行为 + +380 +00:19:05,412 --> 00:19:08,549 +让我们通过添加一些属性 + +381 +00:19:08,582 --> 00:19:10,984 +来添加 +digitalCrownRotation 修改器 + +382 +00:19:11,018 --> 00:19:12,920 +以便当某人在图表上滚动时存储状态 + +383 +00:19:13,854 --> 00:19:17,824 +highlightedDateIndex是当前滚动位置 + +384 +00:19:17,858 --> 00:19:20,027 +数据点的日期索引 + +385 +00:19:21,061 --> 00:19:22,729 +我们将存储 crown offset + +386 +00:19:22,763 --> 00:19:25,232 +所以可以显示当前表冠位置 + +387 +00:19:25,265 --> 00:19:27,634 +当这个人在滚动图表时 + +388 +00:19:28,368 --> 00:19:32,239 +表冠随之移动 +这是一个数据点上 + +389 +00:19:32,272 --> 00:19:34,208 +或数据点之间的中间值 + +390 +00:19:35,409 --> 00:19:38,478 +要追踪是否有人正在进行滚动操作 + +391 +00:19:38,512 --> 00:19:40,848 +我们将存储空闲状态 + +392 +00:19:40,881 --> 00:19:42,316 +我们将使用这些信息 + +393 +00:19:42,349 --> 00:19:44,017 +添加一点动画 + +394 +00:19:44,051 --> 00:19:46,854 +随着表冠滚动停止和开始 + +395 +00:19:48,856 --> 00:19:52,059 +现在有了属性存储值 + +396 +00:19:52,092 --> 00:19:54,828 +我们可以添加 +数码表冠旋转修改器 + +397 +00:19:56,129 --> 00:20:00,033 +我们将把 detent 值 +绑定到 highlightedDateIndex 属性 + +398 +00:20:01,134 --> 00:20:04,771 +在机械术语中 止动器是一种 + +399 +00:20:04,805 --> 00:20:06,507 +保持某物在某个位置的系统 + +400 +00:20:06,540 --> 00:20:09,309 +直到施加足够的力来移动它 + +401 +00:20:09,343 --> 00:20:12,446 +例如 当我打开车门时 + +402 +00:20:12,479 --> 00:20:15,516 +有一个停顿点 +就是门将暂定的地方 + +403 +00:20:15,549 --> 00:20:17,017 +我可以用力一点 + +404 +00:20:17,050 --> 00:20:19,953 +把门打开到另一个停顿点 + +405 +00:20:19,987 --> 00:20:22,656 +要关闭它 需要用力拉 + +406 +00:20:22,689 --> 00:20:26,527 +克服阻力 把它拉离停顿点 + +407 +00:20:26,560 --> 00:20:30,631 +否则 车门将弹回停顿点的位置 + +408 +00:20:30,664 --> 00:20:32,599 +这就是止动器 + +409 +00:20:33,367 --> 00:20:34,735 +车门的停顿点 + +410 +00:20:34,768 --> 00:20:37,504 +帮助我们了解这个 API 中的 detent + +411 +00:20:38,338 --> 00:20:40,741 +Detent 是您的视图中 + +412 +00:20:40,774 --> 00:20:42,376 +表冠的静止槽口位置 + +413 +00:20:44,211 --> 00:20:46,980 +在 onChange 回调的处理程序中 + +414 +00:20:47,014 --> 00:20:49,983 +我们将 isCrownIdle 的值 +设置为错误 + +415 +00:20:50,017 --> 00:20:52,686 +因为我们知道表冠在滚动 + +416 +00:20:52,719 --> 00:20:55,789 +我们将表冠偏移值设置为当前值 + +417 +00:20:55,822 --> 00:20:59,560 +让我们在滚动期间 +显示图表上的当前位置 + +418 +00:21:00,827 --> 00:21:03,564 +在 onIdle 回调的处理程序中 + +419 +00:21:03,597 --> 00:21:06,466 +我们将 isCrownIdle 的值设置为真 + +420 +00:21:08,068 --> 00:21:10,270 +现在我们可以在图表滚动时 + +421 +00:21:10,304 --> 00:21:11,872 +显示表冠的位置 + +422 +00:21:12,773 --> 00:21:16,777 +为此 我们可以使用 +Swift Charts 中的 RuleMark 类型 + +423 +00:21:17,644 --> 00:21:20,881 +RuleMark 是图表上的一条直线 + +424 +00:21:20,914 --> 00:21:24,351 +您可以用它来显示水平线或垂直线 + +425 +00:21:24,384 --> 00:21:26,787 +以显示阈值 例如 + +426 +00:21:26,820 --> 00:21:28,555 +显示斜线 + +427 +00:21:29,656 --> 00:21:31,592 +我们将创建一个 RuleMark + +428 +00:21:31,625 --> 00:21:33,393 +具有表冠偏移日期值 + +429 +00:21:33,427 --> 00:21:36,363 +以显示表冠滚动的当前位置 + +430 +00:21:38,031 --> 00:21:40,033 +为了让它看起来更美观 + +431 +00:21:40,067 --> 00:21:42,703 +我想让表冠位置线褪色 + +432 +00:21:42,736 --> 00:21:44,238 +当表冠停止移动时 + +433 +00:21:45,072 --> 00:21:46,840 +对此进行动画处理非常简单 + +434 +00:21:46,874 --> 00:21:49,643 +使用我们添加的 isCrownIdle 属性 + +435 +00:21:50,777 --> 00:21:54,147 +我们将添加一个属性来存储 +我们在 foregroundStyle 中 + +436 +00:21:54,181 --> 00:21:56,650 +为 RuleMark 使用颜色的不透明度 + +437 +00:21:57,985 --> 00:22:01,054 +在图表中添加一个 onChange 修改器 + +438 +00:22:01,088 --> 00:22:04,391 +当 isCrownIdle 值发生变化时 + +439 +00:22:04,424 --> 00:22:07,160 +可以使 crownPositionOpacity +值发生变化 + +440 +00:22:08,262 --> 00:22:12,766 +然后更新 RuleMark 的前景样式 +以使用不透明度 + +441 +00:22:14,568 --> 00:22:18,705 +要在滚动时在图表条形图旁边显示值 + +442 +00:22:18,739 --> 00:22:21,208 +我们可以向 BarMark 添加注释 + +443 +00:22:21,975 --> 00:22:26,246 +我们将注释放置在栏的顶部前导侧 + +444 +00:22:26,280 --> 00:22:28,348 +当它是最后一栏时 + +445 +00:22:28,382 --> 00:22:29,917 +否则 我们将它定位在 + +446 +00:22:29,950 --> 00:22:31,785 +顶部尾随侧 + +447 +00:22:33,387 --> 00:22:35,722 +让我们一起来看看 +我们的成果 + +448 +00:22:35,756 --> 00:22:38,559 +只需使用 digitalCrownRotation 修改器 + +449 +00:22:38,592 --> 00:22:40,494 +Swift Charts 中的 RuleMark + +450 +00:22:40,527 --> 00:22:42,829 +和一个简单的 SwiftUI 动画 + +451 +00:22:44,731 --> 00:22:48,202 +创建自定义可滚动图表的最后一步 + +452 +00:22:48,235 --> 00:22:52,606 +在有人进行滚动操作时 +调整图表的数据范围 + +453 +00:22:52,639 --> 00:22:54,975 +创建一个属性来存储可见范围 + +454 +00:22:56,009 --> 00:23:00,414 +创建 chartData 变量 +以向图表提供区域内的数据 + +455 +00:23:01,281 --> 00:23:04,284 +当 highlightedDateIndex 更改时 + +456 +00:23:04,318 --> 00:23:07,020 +调用一个方法来检查图表数据范围 + +457 +00:23:07,054 --> 00:23:09,056 +并在必要时进行更新 + +458 +00:23:10,157 --> 00:23:14,161 +当有人使用数码表冠 +滚动图表时 + +459 +00:23:14,194 --> 00:23:16,897 +图表将滚动以显示可用数据 + +460 +00:23:17,865 --> 00:23:21,602 +现在 我们已经完成了 +我们计划的所有功能的实现 + +461 +00:23:23,303 --> 00:23:26,139 +想了解有关在 watchOS 9 中可用的 + +462 +00:23:26,173 --> 00:23:28,008 +新的 SwiftUI 功能的更多信息 + +463 +00:23:28,041 --> 00:23:30,911 +请查看“SwiftUI 的新功能” + +464 +00:23:31,712 --> 00:23:33,614 +在规划 Watch App + +465 +00:23:33,647 --> 00:23:35,716 +或您的新 Watch App 功能时 + +466 +00:23:35,749 --> 00:23:36,783 +请想想什么能帮助打造 + +467 +00:23:36,817 --> 00:23:38,785 +出色的 Watch App 体验 + +468 +00:23:39,686 --> 00:23:41,421 +在设计您的 App 时 + +469 +00:23:41,455 --> 00:23:43,891 +考虑一下您的 App 导航策略 + +470 +00:23:43,924 --> 00:23:46,960 +以确保您的 App 简单 直观 + +471 +00:23:47,828 --> 00:23:52,165 +使用 SwiftUI 获得更简单 +更丰富的开发选项 + +472 +00:23:52,199 --> 00:23:54,868 +继续构建出色的 Watch App + +473 +00:23:54,902 --> 00:23:56,203 +请记住 因为有您 + +474 +00:23:56,236 --> 00:23:58,438 +我们确定世上有 App +可以做到这一点 + +475 +00:23:59,006 --> 00:24:01,074 +[音乐] + diff --git a/zho/2022 Session 10135 Get timely alerts from Bluetooth devices on watchOS.srt b/zho/2022 Session 10135 Get timely alerts from Bluetooth devices on watchOS.srt new file mode 100644 index 0000000..b4107bc --- /dev/null +++ b/zho/2022 Session 10135 Get timely alerts from Bluetooth devices on watchOS.srt @@ -0,0 +1,994 @@ +1 +00:00:01,468 --> 00:00:07,474 +[古怪的音乐] + +2 +00:00:09,977 --> 00:00:11,578 +Yann Ly-Gagnon: 大家好 +我是 Yann + +3 +00:00:11,612 --> 00:00:13,146 +我是一名核心蓝牙工程师 + +4 +00:00:13,180 --> 00:00:15,349 +今天 我想和大家谈一谈 + +5 +00:00:15,382 --> 00:00:17,484 +Apple Watch 上的 +蓝牙设备的适时提醒 + +6 +00:00:18,752 --> 00:00:22,022 +首先 我们回顾一下 +当 watchOS App 在后台运行时 + +7 +00:00:22,055 --> 00:00:24,124 +如何更新复杂功能 + +8 +00:00:26,026 --> 00:00:30,664 +然后我们将深入研究如何收听 +您的 watchOS App 发出的适时提醒 + +9 +00:00:32,833 --> 00:00:36,203 +我们还会看一看有什么新的方法能 +帮助我们在 watchOS 9 上 + +10 +00:00:36,236 --> 00:00:37,504 +发现新的外围设备 + +11 +00:00:39,606 --> 00:00:43,076 +最后 我们会提供最佳实践和建议 + +12 +00:00:43,110 --> 00:00:45,312 +来帮助您设计您的蓝牙配件 + +13 +00:00:47,748 --> 00:00:49,950 +让我们进入我们的第一个主题 + +14 +00:00:49,983 --> 00:00:53,520 +如何在 watchOS App 的后台 +更新复杂功能 + +15 +00:00:54,288 --> 00:00:57,758 +去年 在 watchOS 8 中 +我们介绍了一种 + +16 +00:00:57,791 --> 00:01:00,060 +在后台 App 刷新期间 +使用您的蓝牙配件 + +17 +00:01:00,093 --> 00:01:01,595 +更新复杂功能的方法 + +18 +00:01:03,163 --> 00:01:06,266 +这对数据非常有用 可以定期更新 + +19 +00:01:06,300 --> 00:01:09,036 +就像在这个例子中向我展示 +当前气温 + +20 +00:01:12,506 --> 00:01:17,411 +我们快速回顾一下 去年的 watchOS +允许您更新您的复杂功能 + +21 +00:01:17,444 --> 00:01:21,548 +并在在后台定期运行期间 +使用后台 App 刷新 + +22 +00:01:21,582 --> 00:01:24,985 +每当后台 App 刷新时 +它都会允许您的 App + +23 +00:01:25,018 --> 00:01:26,320 +重新连接到您的蓝牙外围设备 + +24 +00:01:26,353 --> 00:01:29,156 +检索数据 +然后断开与外围设备的连接 + +25 +00:01:30,090 --> 00:01:32,993 +有关此内容的更多详细信息 +请查看视频 + +26 +00:01:33,026 --> 00:01:35,429 +“Connect Bluetooth devices +to Apple Watch” + +27 +00:01:37,564 --> 00:01:40,834 +但是如果用户想对 +恰巧发生在您的蓝牙外围设备上的 + +28 +00:01:40,868 --> 00:01:42,336 +限时事件有所了解该怎么办呢 + +29 +00:01:43,637 --> 00:01:47,407 +在 watchOS 9 中 我们将介绍一种 + +30 +00:01:47,441 --> 00:01:50,177 +从后台的蓝牙附件中收听警报的方法 + +31 +00:01:52,312 --> 00:01:54,147 +这是它的工作原理 + +32 +00:01:54,181 --> 00:01:56,884 +当您的 App 运行时 连接您的设备 + +33 +00:01:56,917 --> 00:01:58,652 +开始监控一个特性 + +34 +00:02:00,621 --> 00:02:03,624 +当您的 App 停止运行时 +核心蓝牙会 + +35 +00:02:03,657 --> 00:02:06,126 +继续保持与您的设备相连接 + +36 +00:02:06,159 --> 00:02:08,161 +收听您的特性的改变 + +37 +00:02:09,630 --> 00:02:12,666 +当您的设备改变了该特性的值时 + +38 +00:02:12,699 --> 00:02:15,769 +您的 App 会运行起来 +处理该事件 + +39 +00:02:15,802 --> 00:02:20,340 +例如 您可以发布本地通知 +或发送网络请求 + +40 +00:02:20,374 --> 00:02:23,544 +这旨在为用户提供他们所关心的 + +41 +00:02:23,577 --> 00:02:24,811 +限时事件的信息 + +42 +00:02:26,613 --> 00:02:29,216 +假设我有一个食物温度计 + +43 +00:02:29,249 --> 00:02:32,486 +我可以设置所需的烹饪温度 + +44 +00:02:32,519 --> 00:02:34,588 +当我从烤箱拿走我的食物的时候 +它就会发出警报 + +45 +00:02:35,656 --> 00:02:38,559 +随着温度接近所需的温度 + +46 +00:02:38,592 --> 00:02:41,361 +温度计会改变特性的值 + +47 +00:02:41,395 --> 00:02:44,698 +该 App 会发出 +食物快好了的本地通知 + +48 +00:02:46,200 --> 00:02:49,269 +食物完成烹饪后 +我就会收到所需的通知 + +49 +00:02:51,205 --> 00:02:55,275 +如果温度还在不断上升 +我会收到一个最后的通知 + +50 +00:02:58,445 --> 00:03:02,049 +首先 让我们回顾一下如何 +配置后台模式 + +51 +00:03:03,350 --> 00:03:08,689 +将 Bluetooth-central 添加到您的 +Watch App Info.plist 中的 UIBackgroundModes 中 + +52 +00:03:10,324 --> 00:03:14,528 +在 Xcode 中 +它被称为 Required background modes + +53 +00:03:14,561 --> 00:03:17,931 +您应该使用 CoreBluetooth +添加 App communicates using CoreBluetooth + +54 +00:03:19,099 --> 00:03:25,472 +如果您想以后台执行为中心 +请注意 那些 + +55 +00:03:25,506 --> 00:03:27,841 +Info.plist 条目与您的 iOS App 相同 + +56 +00:03:29,910 --> 00:03:33,480 +您需要手动编辑 +您的 watchApp info.plist + +57 +00:03:33,514 --> 00:03:37,150 +而不是依赖 iOS 的 Signing capabilities + +58 +00:03:38,619 --> 00:03:40,320 +让我们看一下代码 + +59 +00:03:40,354 --> 00:03:43,590 +假设您已经连接 +您找到了 GATT 服务 + +60 +00:03:43,624 --> 00:03:46,593 +并且刚刚发现了一个 GATT 特性 + +61 +00:03:46,627 --> 00:03:50,664 +您会得到 +didDiscoverCharacteristicFor 回调 + +62 +00:03:53,200 --> 00:03:54,535 +在回调内部 + +63 +00:03:54,568 --> 00:03:57,871 +您可以在每次值变化时 +决定接收通知 + +64 +00:03:58,972 --> 00:04:02,009 +这与 watchOS 8 中的 API 相同 + +65 +00:04:02,042 --> 00:04:05,979 +不同的是 当您的 App 在后台时 +它也可以工作 + +66 +00:04:08,282 --> 00:04:11,485 +然后用授权的方法 +处理 didUpdateValueFor + +67 +00:04:11,518 --> 00:04:15,322 +特性值的变化 + +68 +00:04:17,691 --> 00:04:22,563 +一旦特性发生变化 +您可以在此处发布本地通知 + +69 +00:04:22,596 --> 00:04:26,433 +发送网络请求 +或任何对您的 App 有意义的东西 + +70 +00:04:27,267 --> 00:04:31,438 +此方法将同时在前台和背景中调用 + +71 +00:04:31,471 --> 00:04:35,309 +所以要确保您在两种情况下 +执行正确的行动 + +72 +00:04:37,044 --> 00:04:40,848 +现在让我们谈一谈 +一些您需要考虑的情况 + +73 +00:04:42,216 --> 00:04:45,285 +首先是蓝牙重新连接 + +74 +00:04:45,319 --> 00:04:48,689 +如果您的设备超出范围 +蓝牙连接将在 + +75 +00:04:48,722 --> 00:04:50,557 +超时后断开 + +76 +00:04:51,725 --> 00:04:55,696 +如果发生这种情况 +您的 App 将短暂进入后台运行 + +77 +00:04:55,729 --> 00:05:00,367 +这种情况叫做 connectPeripheral +为的是尝试重新连接 + +78 +00:05:00,400 --> 00:05:03,871 +这与 iOS 上发生的情况相同 + +79 +00:05:03,904 --> 00:05:08,075 +一旦设备再次进入范围内 +核心蓝牙将重新连接 + +80 +00:05:09,710 --> 00:05:12,246 +现在 让我们谈谈一些限制 + +81 +00:05:12,279 --> 00:05:15,449 +这些限制对于 Apple Watch 用户 +保持最佳电池寿命来说 + +82 +00:05:15,482 --> 00:05:17,017 +十分重要 + +83 +00:05:19,987 --> 00:05:23,423 +如果您的设备位于蓝牙范围的边缘 + +84 +00:05:23,457 --> 00:05:27,461 +并在后台 BLE 连接中反复断开 + +85 +00:05:27,494 --> 00:05:30,097 +重新连接范围将被缩小 + +86 +00:05:30,130 --> 00:05:34,201 +这意味着只有在设备靠近 +Apple Watch 时才会重新连接 + +87 +00:05:35,869 --> 00:05:39,373 +这些限制在 +24 小时的滚动窗口中有效 + +88 +00:05:39,406 --> 00:05:42,476 +当用户与您的 App 互动时 +就会重置 + +89 +00:05:43,544 --> 00:05:47,381 +另一个限制是后台运行时 + +90 +00:05:47,414 --> 00:05:48,682 +发出警报的次数 + +91 +00:05:50,250 --> 00:05:53,053 +当某些对客户来说 +非常重要的事情发生时 + +92 +00:05:53,086 --> 00:05:56,123 +监控特性才会改变 + +93 +00:05:56,156 --> 00:05:59,526 +如果您需要定期从您的设备中 +获取数据 + +94 +00:05:59,560 --> 00:06:01,295 +就必须进行后台 App 刷新 + +95 +00:06:03,564 --> 00:06:07,501 +当您的 App 即将超过限制时 + +96 +00:06:07,534 --> 00:06:12,806 +通知 LeGattNearBackgroundNotificationLimit +就会被发布 + +97 +00:06:12,840 --> 00:06:16,109 +监视该错误并认识到用户 +未与 watchOS App 交互 + +98 +00:06:16,143 --> 00:06:18,912 +对您的 App 来说 +是一个很好的做法 + +99 +00:06:20,147 --> 00:06:23,650 +如果这个警报很重要 +那么现在就是 + +100 +00:06:23,684 --> 00:06:25,986 +寻找另一种与您的用户 +相互沟通的最佳时间 + +101 +00:06:26,019 --> 00:06:28,856 +比如通过网络请求 + +102 +00:06:28,889 --> 00:06:31,425 +或 UI 在您的蓝牙外围设备上 +作出更改 + +103 +00:06:34,728 --> 00:06:38,966 +超出限制后 通知 + +104 +00:06:38,999 --> 00:06:43,837 +LeGattExceededBackgroundNotificationLimit +将被发布 + +105 +00:06:45,005 --> 00:06:49,510 +此时 您的 App +将不再接收后台运行 + +106 +00:06:49,543 --> 00:06:52,546 +并将恢复到没有后台连接的 + +107 +00:06:52,579 --> 00:06:54,815 +watchOS 8 行为 + +108 +00:06:54,848 --> 00:06:56,617 +并且只有后台 App 刷新 + +109 +00:06:57,951 --> 00:07:00,053 +您可以在 GATT Notification Updat 的 + +110 +00:07:00,087 --> 00:07:03,757 +错误字段检索这两个通知 + +111 +00:07:03,790 --> 00:07:06,026 +对于后台 BLE 连接 + +112 +00:07:06,059 --> 00:07:07,761 +我们建议利用这个错误 + +113 +00:07:07,794 --> 00:07:09,229 +来代替用倒计时的方法 + +114 +00:07:09,263 --> 00:07:10,597 +了解何时到达限制 + +115 +00:07:11,632 --> 00:07:16,737 +对于 watchOS 9 +后台运行时限制设置为 5 + +116 +00:07:16,770 --> 00:07:21,175 +每当用户与您的 App 交互时 +这两个限制就会被重置 + +117 +00:07:21,208 --> 00:07:24,778 +它们也会在达到限制的 24 小时后重置 + +118 +00:07:24,811 --> 00:07:28,715 +以防没有用户与您的 App 交互 + +119 +00:07:28,749 --> 00:07:33,820 +注意 这些限制仅适用于 +蓝牙后台 LE 连接 + +120 +00:07:33,854 --> 00:07:37,090 +如果复杂功能位于活跃的表盘上 +后台的 App + +121 +00:07:37,124 --> 00:07:40,327 +将忽略这些限制 继续刷新 + +122 +00:07:41,595 --> 00:07:45,699 +您得到的处理每个事件的时间非常短 + +123 +00:07:45,732 --> 00:07:49,269 +时间可能不够做极其复杂的处理 + +124 +00:07:49,303 --> 00:07:51,939 +但足以提醒用户 +一些重要的事情正在发生 + +125 +00:07:52,873 --> 00:07:55,843 +最后 收听后台的适时提醒 + +126 +00:07:55,876 --> 00:07:59,079 +需要 Apple Watch Series 6 或更高版本 + +127 +00:07:59,112 --> 00:08:03,250 +收取提醒并不是您可以在后台做的 +唯一的事情 + +128 +00:08:03,283 --> 00:08:07,487 +在 watchOS 9 中 当您的 App +在后台运行时 您可以发现外围设备 + +129 +00:08:09,823 --> 00:08:13,660 +比方说 我有蓝牙医疗设备 + +130 +00:08:13,694 --> 00:08:16,930 +和一个可以检测任何适时提醒的 +watchOS App + +131 +00:08:17,698 --> 00:08:21,268 +为了省电 +外围设备在检测到严重情况之前 + +132 +00:08:21,301 --> 00:08:23,103 +不会显示 + +133 +00:08:24,705 --> 00:08:29,243 +因此 这个设备和 Apple Watch 之间 +没有任何联系 + +134 +00:08:30,077 --> 00:08:34,948 +在这里 watchOS App 将从医疗设备 + +135 +00:08:34,982 --> 00:08:36,183 +扫描唯一的 Service UUID + +136 +00:08:37,451 --> 00:08:41,388 +现在 当医疗设备检测到 +情况严重时 + +137 +00:08:41,421 --> 00:08:43,457 +它就开始公布 + +138 +00:08:43,490 --> 00:08:47,828 +Apple Watch 发现了这个外围设备 +并在后台启动 App + +139 +00:08:49,363 --> 00:08:52,065 +然后 App 就会提示用户检测的条件 + +140 +00:08:54,701 --> 00:08:56,003 +这就是它的工作原理 + +141 +00:08:56,937 --> 00:09:00,374 +Watch App 会启动对外围设备的扫描 + +142 +00:09:00,407 --> 00:09:03,043 +核心蓝牙将继续在后台扫描 + +143 +00:09:05,579 --> 00:09:08,515 +一旦外围设备被检测到 + +144 +00:09:08,549 --> 00:09:12,319 +App 就会在后台运行 并发起连接 + +145 +00:09:15,088 --> 00:09:18,692 +我们深入研究一下 +实现这一目标的代码 + +146 +00:09:18,725 --> 00:09:21,662 +API 没有从 watchOS 8 开始改变 + +147 +00:09:21,695 --> 00:09:25,299 +但是这种扫描方法将得到推崇 +甚至 App 在后台也是如此 + +148 +00:09:26,533 --> 00:09:28,969 +使用您想关注的 UUID 服务 + +149 +00:09:29,002 --> 00:09:32,306 +调用 scanForPeripherals + +150 +00:09:32,339 --> 00:09:36,009 +当您的 App 位于前台时 +您可以在您的 App 中执行此操作 + +151 +00:09:36,043 --> 00:09:38,779 +并且当 App 转到后台运行时 +还将继续 + +152 +00:09:38,812 --> 00:09:42,649 +请注意 如果您要求选择 +allowDuplicatesKey + +153 +00:09:42,683 --> 00:09:45,419 +它只适用于App 在前台的时候 + +154 +00:09:46,253 --> 00:09:47,621 +现在 我们来谈谈一些限制 + +155 +00:09:48,622 --> 00:09:51,358 +您的 App 在 App 启动之间 + +156 +00:09:51,391 --> 00:09:54,261 +获得的后台运行次数是有限制的 + +157 +00:09:54,294 --> 00:09:55,495 +这种限制在 + +158 +00:09:55,529 --> 00:09:57,598 +GATT 特性发生变化时 +与我们之前看到的后台运行 + +159 +00:09:57,631 --> 00:10:00,367 +结合在了一起 + +160 +00:10:00,400 --> 00:10:02,970 +此外 在后台扫描外围设备 + +161 +00:10:03,003 --> 00:10:05,372 +需要 Apple Watch Series 6 或更高版本 + +162 +00:10:06,974 --> 00:10:10,177 +总之 Watch 在后台扫描的时候 + +163 +00:10:10,210 --> 00:10:14,715 +我们只能扫描到有限数量的 +Bluetooth service UUID + +164 +00:10:15,716 --> 00:10:19,052 +现在我们谈谈如何 +充分利用这些新功能 + +165 +00:10:19,086 --> 00:10:20,821 +来设计您的配件 + +166 +00:10:23,557 --> 00:10:25,259 +在设置您的蓝牙遥控配件时 + +167 +00:10:25,292 --> 00:10:27,060 +您需要考虑电量平衡的问题 + +168 +00:10:30,230 --> 00:10:33,700 +如果电量损耗受到了影响 +您应该选择拓扑 + +169 +00:10:33,734 --> 00:10:35,969 +让您的设备进入深度睡眠 + +170 +00:10:36,003 --> 00:10:38,138 +并且只有在收到相关信息时 + +171 +00:10:38,172 --> 00:10:39,873 +才会发出提醒信号 + +172 +00:10:39,907 --> 00:10:44,611 +平衡就是在每次发出适时提醒时 + +173 +00:10:44,645 --> 00:10:48,215 +您的蓝牙发现时间会延长 +但您能节省更多的电量 + +174 +00:10:49,316 --> 00:10:53,020 +这个是在医疗设备中提供拓扑的案例 + +175 +00:10:54,855 --> 00:10:56,256 +另一方面 + +176 +00:10:56,290 --> 00:10:58,025 +如果您需要减少 + +177 +00:10:58,058 --> 00:10:59,259 +适时提醒的延迟时间 + +178 +00:10:59,293 --> 00:11:01,295 +而电量尚且充足的话 + +179 +00:11:01,328 --> 00:11:03,096 +您可以考虑使用 + +180 +00:11:03,130 --> 00:11:04,965 +后台 LE 连接 + +181 +00:11:04,998 --> 00:11:05,999 +根据 GATT 的指示 + +182 +00:11:06,033 --> 00:11:07,301 +发送您的提醒 + +183 +00:11:07,868 --> 00:11:11,305 +注意 每个 App 的两个蓝牙连接 +是有限制的 + +184 +00:11:12,806 --> 00:11:16,243 +这是我们在示例中看到的 +用于温度传感器的拓扑 + +185 +00:11:17,611 --> 00:11:22,816 +为了让您的用户拥有 +适时提醒的最佳体验 + +186 +00:11:22,850 --> 00:11:27,287 +考虑在您的外围设备上 +尽可能多的添加配置和智能 + +187 +00:11:27,321 --> 00:11:30,791 +通过对时间不是很敏感的通讯系统 +过滤掉对时间敏感的数据 + +188 +00:11:32,159 --> 00:11:36,930 +回到我们的温度示例 +您只可以发送相关的事件 + +189 +00:11:36,964 --> 00:11:40,667 +或什么时候温度会产生变化的消息 +而不是传送输每一个温度数据 + +190 +00:11:41,568 --> 00:11:44,204 +这种方法的好处是 如果您合理地 + +191 +00:11:44,238 --> 00:11:47,140 +将对时间敏感的数据 +从周期性数据分离出来 + +192 +00:11:47,174 --> 00:11:49,943 +您的外围设备和 Apple Watch 用户 + +193 +00:11:49,977 --> 00:11:53,847 +将节省电量 +从而获得整体更好的体验 + +194 +00:11:56,016 --> 00:11:59,152 +当您的设备断开连接时 +我们推荐发布 + +195 +00:11:59,186 --> 00:12:00,954 +重新建立连接的通知 + +196 +00:12:01,822 --> 00:12:04,057 +通知间隔取决于 + +197 +00:12:04,091 --> 00:12:06,693 +您的外围蓝牙设备的请求 + +198 +00:12:06,727 --> 00:12:12,332 +例如重新连接需要多快 +电池寿命等 + +199 +00:12:12,366 --> 00:12:16,837 +在附件指南中 我们提供了几个 +您可以使用的不同的值 + +200 +00:12:17,738 --> 00:12:20,974 +例如 如果您的设备电池受限 + +201 +00:12:21,008 --> 00:12:25,846 +您可以使用一个 1022.5 毫秒的值 + +202 +00:12:27,114 --> 00:12:30,717 +另一个例子 +如果您以 20 毫秒的速率发送通知 + +203 +00:12:30,751 --> 00:12:34,788 +它就允许在理想的条件下 +在 1 秒内完成检测 + +204 +00:12:36,156 --> 00:12:40,127 +您只有在关键事件发生时 + +205 +00:12:40,160 --> 00:12:42,996 +才能使用这么快的通知速率 + +206 +00:12:44,965 --> 00:12:48,235 +现在让我们谈谈连接间隔 + +207 +00:12:48,268 --> 00:12:52,973 +如果您选择 +您的设备在后台保持连接的拓 + +208 +00:12:53,006 --> 00:12:55,409 +我们强烈建议使用较长的连接间隔 + +209 +00:12:55,442 --> 00:12:58,645 +例如 至少 150 毫秒 + +210 +00:12:58,679 --> 00:13:00,981 +这会让您的外围设备节省电量 + +211 +00:13:01,014 --> 00:13:03,717 +在 Apple Watch 上 +提供最佳的用户体验 + +212 +00:13:04,751 --> 00:13:09,656 +蓝牙 5.3 即将根据连接等级 +登陆 Apple Watch + +213 +00:13:09,690 --> 00:13:12,259 +这在蓝牙外围设备空闲时 + +214 +00:13:12,292 --> 00:13:14,428 +允许增加连接间隔 + +215 +00:13:14,461 --> 00:13:17,064 +并在您需要较短的延迟时 + +216 +00:13:17,097 --> 00:13:18,532 +迅速转换到更小的连接间隔 + +217 +00:13:19,900 --> 00:13:24,071 +这是一个显示平台之间差异的表格 + +218 +00:13:24,104 --> 00:13:28,876 +这些是目前支持低功耗蓝牙的配置 + +219 +00:13:28,909 --> 00:13:32,946 +去年我们把watchOS 后台 App 刷新 +作为一种新的 + +220 +00:13:32,980 --> 00:13:35,449 +后台执行模式进行了介绍 + +221 +00:13:35,482 --> 00:13:38,685 +今年 如果您拥有 Series 6 +及更高版本 + +222 +00:13:38,719 --> 00:13:42,422 +我们就会如我们今天描述的那样 +利用即时警报改进后台的执行 + +223 +00:13:44,057 --> 00:13:45,359 +感谢收看 + +224 +00:13:46,693 --> 00:13:48,662 +[古怪的音乐] + diff --git a/zho/2022 Session 10139 Make a great SharePlay experience.srt b/zho/2022 Session 10139 Make a great SharePlay experience.srt new file mode 100644 index 0000000..78590c3 --- /dev/null +++ b/zho/2022 Session 10139 Make a great SharePlay experience.srt @@ -0,0 +1,1735 @@ +1 +00:00:00,133 --> 00:00:02,669 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:02,669 --> 00:00:09,676 +♪ + +3 +00:00:09,676 --> 00:00:12,980 +♪ 悬疑风古典乐 ♪ + +4 +00:00:12,980 --> 00:00:13,847 +[FaceTime 通话响铃] + +5 +00:00:13,847 --> 00:00:16,717 +Ryan Williams: +一个电话颠覆所有 + +6 +00:00:16,717 --> 00:00:18,519 +Priya Shah:您准备好 + +7 +00:00:18,519 --> 00:00:20,153 +这次演示需要的所有材料没? + +8 +00:00:20,153 --> 00:00:23,090 +因为我挂断电话之后 +您就只能靠自己了 + +9 +00:00:23,090 --> 00:00:26,426 +Ryan:没问题 +演示不会费我吹灰之力 + +10 +00:00:26,426 --> 00:00:28,362 +这本该是件轻而易举的事 + +11 +00:00:28,362 --> 00:00:31,498 +我只要选一类很棒的 SharePlay 体验 + +12 +00:00:31,498 --> 00:00:34,001 +来给我们的讲座开个头 + +13 +00:00:34,001 --> 00:00:36,170 +我的搭档就能好好睡个觉 + +14 +00:00:36,170 --> 00:00:39,806 +我缩小了“嫌疑人”范围 +但我选不出来 + +15 +00:00:39,806 --> 00:00:41,608 +我不得不轮流给我的队员打电话 + +16 +00:00:41,608 --> 00:00:45,045 +以帮助我走出困境 + +17 +00:00:45,045 --> 00:00:46,346 +首先 [SharePlay 通知提示声] + +18 +00:00:46,346 --> 00:00:48,682 +和 Adam 在健身房的测试训练 + +19 +00:00:48,682 --> 00:00:49,650 +[咔嗒声] Adam:我在大喘气 + +20 +00:00:49,650 --> 00:00:51,552 +我们总是低于平均值 + +21 +00:00:51,552 --> 00:00:53,120 +Siri:波比跳 + +22 +00:00:53,120 --> 00:00:55,489 +Adam:调用函数 [喘气] + +23 +00:00:55,489 --> 00:00:56,657 +重构代码 [咔嗒声] + +24 +00:00:56,657 --> 00:00:58,592 +Siri:踢臀跑 + +25 +00:00:58,592 --> 00:01:00,027 +Adam:点击“运行” +然后查看人们 + +26 +00:01:00,027 --> 00:01:01,628 +开发了什么的时刻总是很美好 + +27 +00:01:01,628 --> 00:01:03,197 +Siri:休息 [喘气] + +28 +00:01:03,197 --> 00:01:06,400 +Ryan:Adam 给我 +带来了灵感和汗水 + +29 +00:01:06,400 --> 00:01:08,936 +但我还要评估其它体验 + +30 +00:01:08,936 --> 00:01:11,371 +所以我打电话给 Agnes +和 Gav 一起货比三家 + +31 +00:01:11,371 --> 00:01:12,739 +[SharePlay 通知提示声] + +32 +00:01:12,739 --> 00:01:15,409 +虽然我很喜欢逛玩具市场 + +33 +00:01:15,409 --> 00:01:18,178 +但我还没准备好投标 + +34 +00:01:18,178 --> 00:01:19,813 +也许和 Justin 一起弹钢琴 + +35 +00:01:19,813 --> 00:01:22,716 +会是我想要的 + +36 +00:01:22,716 --> 00:01:23,951 +[SharePlay 通知提示声] + +37 +00:01:23,951 --> 00:01:29,556 +♪ 忧郁的钢琴曲 ♪ + +38 +00:01:29,556 --> 00:01:34,027 +我的思路逐渐清晰 + +39 +00:01:34,027 --> 00:01:37,965 +但我要再玩一局间谍游戏 + +40 +00:01:37,965 --> 00:01:39,666 +Gav:哇 他进来了 +Olivia:我们以为 + +41 +00:01:39,666 --> 00:01:40,801 +Adam:您以为 +Olivia:您可能是 + +42 +00:01:40,801 --> 00:01:42,002 +压力太大了 +[SharePlay 通知提示声] + +43 +00:01:42,002 --> 00:01:44,538 +Ryan:我妈没教过我 +做个半途而废的人 + +44 +00:01:44,538 --> 00:01:45,873 +开始游戏吧 + +45 +00:01:45,873 --> 00:01:51,879 +玩游戏时 脑海深处某个灵感迸发 + +46 +00:01:51,879 --> 00:01:54,481 +毕竟这是个很简单的案件 + +47 +00:01:54,481 --> 00:01:58,318 +我一直在寻找一款 +出色的 App 但实际上 + +48 +00:01:58,318 --> 00:02:00,954 +我从不同 App 里 +学到了一些东西 + +49 +00:02:00,954 --> 00:02:03,457 +我也知道 这不是平时的演示形式 + +50 +00:02:03,457 --> 00:02:06,927 +但请包涵一个时不时 +就做点虚拟化的人 + +51 +00:02:06,927 --> 00:02:10,497 +下面 如果您不介意的话 +我要去处理下一个案件了 + +52 +00:02:10,497 --> 00:02:13,934 +其他美好的体验仍有待解锁 + +53 +00:02:13,934 --> 00:02:16,170 +♪ 悬疑风古典乐 ♪ + +54 +00:02:18,205 --> 00:02:23,110 +您好 我是 SharePlay +团队的工程师 Ryan + +55 +00:02:23,110 --> 00:02:25,946 +探索所有您创造的奇妙 + +56 +00:02:25,946 --> 00:02:29,249 +SharePlay 体验 我们团队 +从中获得很多乐趣 + +57 +00:02:29,249 --> 00:02:33,954 +您的作品前所未有地 +把人们聚集了起来 + +58 +00:02:33,954 --> 00:02:37,024 +在过去的一年里 我们也学到了很多 + +59 +00:02:37,024 --> 00:02:38,592 +关于如何给人们 + +60 +00:02:38,592 --> 00:02:41,261 +提供良好的 SharePlay 体验 + +61 +00:02:41,261 --> 00:02:44,231 +所以今天 我们将带您 +了解如何在您的 App 中 + +62 +00:02:44,231 --> 00:02:48,602 +设计并构建出色的 SharePlay 体验 + +63 +00:02:48,602 --> 00:02:53,173 +我们将推荐把 SharePlay +作为连接人们的新方式 + +64 +00:02:53,173 --> 00:02:56,143 +然后我们将探讨如何营造现场感 + +65 +00:02:56,143 --> 00:02:59,213 +打破人与人之间的数字壁垒 + +66 +00:02:59,213 --> 00:03:01,048 +并让人们感觉到 + +67 +00:03:01,048 --> 00:03:03,283 +他们是处在同一个空间的 + +68 +00:03:03,283 --> 00:03:05,886 +我们将介绍您可以在 +您的 App 中设计的 + +69 +00:03:05,886 --> 00:03:07,821 +不同类型的 SharePlay 体验 + +70 +00:03:07,821 --> 00:03:10,324 +最后 我们会告诉您一些我们一路上 + +71 +00:03:10,324 --> 00:03:11,792 +学到的提示和技巧 + +72 +00:03:11,792 --> 00:03:13,894 +是关于如何让使用您 App 的人 + +73 +00:03:13,894 --> 00:03:16,230 +获得无缝连接的体验 + +74 +00:03:16,230 --> 00:03:19,566 +越来越多的人依赖 +FaceTime 通话 + +75 +00:03:19,566 --> 00:03:22,569 +和 iMessage 信息 +来保持联系 + +76 +00:03:22,569 --> 00:03:27,774 +我们用 iMessage 信息发 +文字或图片 来互相联络 + +77 +00:03:27,774 --> 00:03:31,011 +而用 FaceTime 时 +我们通过音频和视频来相互联络 + +78 +00:03:33,780 --> 00:03:35,883 +然而 人们共同拥有的 + +79 +00:03:35,883 --> 00:03:37,951 +意义非凡的时刻 + +80 +00:03:37,951 --> 00:03:40,387 +仅用对话是不够的 + +81 +00:03:40,387 --> 00:03:45,292 +我们聚在一起时 更多的是 +通过分享经历来共鸣 + +82 +00:03:45,292 --> 00:03:47,561 +所以为了营造那种亲密感 + +83 +00:03:47,561 --> 00:03:49,663 +我们开发了 SharePlay + +84 +00:03:49,663 --> 00:03:52,633 +只要采用 +Group Activities 框架 + +85 +00:03:52,633 --> 00:03:55,602 +您就可以在您的 App 中 + +86 +00:03:55,602 --> 00:03:58,505 +用这种全新的方式来让他们参与 + +87 +00:03:58,505 --> 00:04:00,874 +SharePlay 活动 互相联络 + +88 +00:04:00,874 --> 00:04:04,478 +而怎么定义活动的概念 +就变得尤为重要 + +89 +00:04:04,478 --> 00:04:07,414 +正在 FaceTime 通话中 +的某人开始一项活动时 + +90 +00:04:07,414 --> 00:04:10,484 +SharePlay 会直接把 +群组带入您的 App + +91 +00:04:10,484 --> 00:04:14,788 +您可以在 SharePlay 里创造 +几乎所有类型的体验 + +92 +00:04:14,788 --> 00:04:17,491 +一项活动真的可以是任何事情 + +93 +00:04:17,491 --> 00:04:20,827 +比如一起做饭 一起弹钢琴 + +94 +00:04:20,827 --> 00:04:23,564 +我们已经从您那看到了很多 + +95 +00:04:23,564 --> 00:04:25,232 +有创意的活动示例 + +96 +00:04:25,232 --> 00:04:27,801 +今年 我们专注于提升 + +97 +00:04:27,801 --> 00:04:31,738 +核心 SharePlay 体验 + +98 +00:04:31,738 --> 00:04:35,275 +使人们在您的 App 中 +共享经历变得更方便 + +99 +00:04:35,275 --> 00:04:39,346 +人们现在可以直接在您的 +App 里启动 SharePlay + +100 +00:04:39,346 --> 00:04:42,115 +如果有人在您的 App 中发现 + +101 +00:04:42,115 --> 00:04:44,284 +他想和朋友分享的绝佳内容 + +102 +00:04:44,284 --> 00:04:47,487 +他可以选择跟谁一起体验该内容 + +103 +00:04:47,487 --> 00:04:51,291 +并能够直接在您的 App 里 +邀请他们加入 SharePlay + +104 +00:04:51,291 --> 00:04:54,228 +这种方式下 人们无需提前计划 + +105 +00:04:54,228 --> 00:04:57,731 +不论什么时候他们有想法了 + +106 +00:04:57,731 --> 00:05:01,301 +就可以马上和朋友一起分享经历 + +107 +00:05:01,301 --> 00:05:05,038 +大家甚至可以在信息里启动 SharePlay + +108 +00:05:05,038 --> 00:05:07,374 +无需进行 FaceTime 通话 + +109 +00:05:07,374 --> 00:05:09,810 +就能和朋友分享经历 + +110 +00:05:09,810 --> 00:05:12,679 +我们相信人们会喜欢所有他们能 + +111 +00:05:12,679 --> 00:05:15,148 +在您的 App +启动 SharePlay 新的方式 + +112 +00:05:15,148 --> 00:05:17,518 +我们将在“SharePlay 中的新功能” + +113 +00:05:17,518 --> 00:05:20,487 +讲座中介绍如何应用那些新功能 + +114 +00:05:20,487 --> 00:05:22,122 +而那个讲座里也只提到了 + +115 +00:05:22,122 --> 00:05:24,091 +SharePlay 应用范围的冰山一角而已 + +116 +00:05:24,091 --> 00:05:27,060 +不过我们认为如果您发挥您的创造力 + +117 +00:05:27,060 --> 00:05:30,631 +来开发让人们关系更亲近的体验 + +118 +00:05:30,631 --> 00:05:33,534 +SharePlay 的真正潜力才能充分体现 + +119 +00:05:33,534 --> 00:05:37,371 +其中很重要的部分就是营造现场感 + +120 +00:05:37,371 --> 00:05:40,541 +所以在探讨如何打造这类体验之前 + +121 +00:05:40,541 --> 00:05:42,676 +我们要先了解与他人同在的意义 + +122 +00:05:42,676 --> 00:05:45,646 +何在 以及如何做出 + +123 +00:05:45,646 --> 00:05:47,514 +很棒的现场体验 + +124 +00:05:47,514 --> 00:05:50,284 +并把这类体验放进您的 App 里 + +125 +00:05:50,284 --> 00:05:53,887 +通常 数字通信工具是用于 + +126 +00:05:53,887 --> 00:05:57,157 +不在场的时候 +但 SharePlay 的情况不同 + +127 +00:05:57,157 --> 00:05:59,893 +为了制造人与人之间有意义的时刻 + +128 +00:05:59,893 --> 00:06:02,796 +我们需要找到让人们纷纷觉得 + +129 +00:06:02,796 --> 00:06:06,800 +就在实际现场的方法 +就像处在同一个物理空间一样 + +130 +00:06:06,800 --> 00:06:09,203 +现在知道了营造这种现场感的技巧 + +131 +00:06:09,203 --> 00:06:12,105 +可能在每种体验中都不同 + +132 +00:06:12,105 --> 00:06:14,508 +但是我们可以用一个技巧 +就是将您的 App + +133 +00:06:14,508 --> 00:06:17,144 +放进在现实世界中 +使用的情况下进行思考 + +134 +00:06:17,144 --> 00:06:20,180 +因此 下面是推荐您做的一个练习 + +135 +00:06:20,180 --> 00:06:23,584 +将 SharePlay 想象成一个传送门 + +136 +00:06:23,584 --> 00:06:26,520 +人们能通过手机来到同一个空间 + +137 +00:06:26,520 --> 00:06:27,821 +如果他们真的线下聚在一起 + +138 +00:06:27,821 --> 00:06:30,624 +他们会用您的 App 做什么? + +139 +00:06:30,624 --> 00:06:33,293 +如果这听着很异想天开 别担心 + +140 +00:06:33,293 --> 00:06:35,362 +我们等下会介绍几个方法 您能用来 + +141 +00:06:35,362 --> 00:06:38,298 +在您的 App 里营造这种现场感 + +142 +00:06:38,298 --> 00:06:40,534 +我们一起来做这个练习 + +143 +00:06:40,534 --> 00:06:42,703 +想象您给传送到一个房间里 + +144 +00:06:42,703 --> 00:06:44,972 +房间里有个唱片机 + +145 +00:06:44,972 --> 00:06:48,175 +每个人都能操作唱片机 + +146 +00:06:48,175 --> 00:06:52,145 +他们可以播放自己喜欢的歌曲 + +147 +00:06:52,145 --> 00:06:54,915 +开始播放后 房间里的其他人 + +148 +00:06:54,915 --> 00:06:58,352 +也可以走到唱机前进行操作 + +149 +00:06:58,352 --> 00:07:00,254 +他们可以把歌曲往向前调 + +150 +00:07:00,254 --> 00:07:03,590 +也可以直接跳过这首歌 + +151 +00:07:03,590 --> 00:07:05,359 +由此 可以得出我们需要 + +152 +00:07:05,359 --> 00:07:09,563 +在 App 中提供大家 +共同享有的播放控制权 + +153 +00:07:09,563 --> 00:07:13,133 +实际上 我们不设置任何 +限制是至关重要的 + +154 +00:07:13,133 --> 00:07:15,736 +不要限制个体能够控制的权限 + +155 +00:07:15,736 --> 00:07:17,704 +我们希望打造愉快的体验 + +156 +00:07:17,704 --> 00:07:20,007 +让每个人都觉得自己能够 + +157 +00:07:20,007 --> 00:07:22,943 +控制同一个音乐播放器 + +158 +00:07:22,943 --> 00:07:26,280 +现在某个人放了音乐 + +159 +00:07:26,280 --> 00:07:28,615 +下一件他可能会做的事就是 + +160 +00:07:28,615 --> 00:07:30,918 +看看周围谁在和他一起听 + +161 +00:07:30,918 --> 00:07:34,688 +虽然听着很理所当然 +但那个人可能在放 + +162 +00:07:34,688 --> 00:07:37,357 +他的最爱曲 很可能想要 + +163 +00:07:37,357 --> 00:07:40,994 +确定他的朋友就在跟他一起听着歌 + +164 +00:07:40,994 --> 00:07:42,729 +来到人们在通过手机 + +165 +00:07:42,729 --> 00:07:44,998 +经历上述情境的情况 +我们需要找到方法 + +166 +00:07:44,998 --> 00:07:47,301 +来提醒人们还有其他人在 + +167 +00:07:47,301 --> 00:07:49,036 +和他们一起做着同样的体验 + +168 +00:07:51,672 --> 00:07:54,141 +这个练习是个好方法 + +169 +00:07:54,141 --> 00:07:56,677 +能思考设计需要包含的因素 + +170 +00:07:56,677 --> 00:08:00,447 +以助力在几乎所有类型 +的体验中营造现场感 + +171 +00:08:00,447 --> 00:08:03,116 +接下来 我把舞台交给 Priya + +172 +00:08:03,116 --> 00:08:07,287 +探讨设计您的体验时需要注意的事项 + +173 +00:08:07,287 --> 00:08:09,389 +Priya:谢谢 Ryan + +174 +00:08:09,389 --> 00:08:11,892 +设计集体体验时 + +175 +00:08:11,892 --> 00:08:14,828 +首先要考虑的是您的 App + +176 +00:08:14,828 --> 00:08:16,597 +将支持什么共享活动 + +177 +00:08:16,597 --> 00:08:19,366 +起初这可能是个很有挑战性的问题 + +178 +00:08:19,366 --> 00:08:22,903 +因为许多 App +都是为个体而设计的 + +179 +00:08:22,903 --> 00:08:25,772 +App 擅长为个体进行个性化定制 + +180 +00:08:25,772 --> 00:08:27,407 +以提供愉快的体验 + +181 +00:08:27,407 --> 00:08:29,343 +但出色的个性化体验 + +182 +00:08:29,343 --> 00:08:33,447 +很可能不会转化成出色的集体体验 + +183 +00:08:33,447 --> 00:08:36,250 +这是您从不同的角度思考 + +184 +00:08:36,250 --> 00:08:39,086 +您的 App 的机会 去思考 + +185 +00:08:39,086 --> 00:08:41,455 +专为集体设计的体验 + +186 +00:08:41,455 --> 00:08:43,023 +设计活动时 + +187 +00:08:43,023 --> 00:08:45,959 +想想人们聚在一起的话喜欢做什么 + +188 +00:08:45,959 --> 00:08:47,928 +和朋友一起做饭 + +189 +00:08:47,928 --> 00:08:49,930 +一起调整呼吸做瑜伽 + +190 +00:08:49,930 --> 00:08:53,100 +一起看您最喜欢的球队赢得决赛 + +191 +00:08:53,100 --> 00:08:56,470 +又或者是观看《人生切割术》 +留下的悬念时一起屏息 + +192 +00:08:56,470 --> 00:08:58,939 +以上举例都是 SharePlay 的上佳之选 + +193 +00:08:58,939 --> 00:09:01,742 +因为这些都是人们喜欢亲身 + +194 +00:09:01,742 --> 00:09:03,210 +参加的活动 + +195 +00:09:03,210 --> 00:09:05,312 +SharePlay 提供了获得 + +196 +00:09:05,312 --> 00:09:08,849 +面向集体的丰富协调经验的机会 + +197 +00:09:08,849 --> 00:09:12,319 +集体里的每个人拥有控制权 +并同步享有同样的体验 + +198 +00:09:12,319 --> 00:09:14,221 +即便人们不在一起 + +199 +00:09:14,221 --> 00:09:15,923 +也能营造现场感 + +200 +00:09:15,923 --> 00:09:19,560 +举个例子 +用 SharePlay 看 Apple TV+ + +201 +00:09:19,560 --> 00:09:21,962 +对着视频按播放就能大家 + +202 +00:09:21,962 --> 00:09:23,363 +一起看 + +203 +00:09:23,363 --> 00:09:27,234 +每个人的播放头都是同步的 +暂停 播放 搜索命令 + +204 +00:09:27,234 --> 00:09:28,869 +都是一致的 + +205 +00:09:28,869 --> 00:09:31,872 +所以 Ryan 按了暂停或 +Adam 点了继续播放时 + +206 +00:09:31,872 --> 00:09:36,076 +每个人的视频暂停和播放都是同步的 + +207 +00:09:36,076 --> 00:09:38,512 +Apple TV+ 就是个很好的 + +208 +00:09:38,512 --> 00:09:41,215 +单视图协调体验示例 + +209 +00:09:41,215 --> 00:09:44,852 +每个人观看和收听的都是一样的内容 + +210 +00:09:44,852 --> 00:09:47,020 +如果想给您的 App +提供像这样的同步 + +211 +00:09:47,020 --> 00:09:50,757 +媒体体验 您可以添加 +共用的播放控件控制 + +212 +00:09:50,757 --> 00:09:53,427 +只要采用“AVPlaybackCoordinator” + +213 +00:09:53,427 --> 00:09:56,563 +并使用“coordinateWithSession”方法 + +214 +00:09:56,563 --> 00:09:59,099 +该系统将使每个人都保持完美同步 + +215 +00:09:59,099 --> 00:10:03,170 +就像他们都在同个房间里 +共用同个遥控器一样 + +216 +00:10:03,170 --> 00:10:05,138 +可有时 我们分享的活动 + +217 +00:10:05,138 --> 00:10:07,641 +不同参与者会有不同的体验 + +218 +00:10:07,641 --> 00:10:10,477 +个别参与者在同个同步体验中 + +219 +00:10:10,477 --> 00:10:13,213 +可能有不同的视图 + +220 +00:10:13,213 --> 00:10:15,983 +比如 在玩“Heads Up!” +游戏的情况下 + +221 +00:10:15,983 --> 00:10:18,819 +一个人要猜出屏幕上的单词 + +222 +00:10:18,819 --> 00:10:22,155 +他的队友则要解释或诠释出线索 + +223 +00:10:22,155 --> 00:10:23,824 +如果猜的人能看到答案 + +224 +00:10:23,824 --> 00:10:26,226 +这个游戏就没有难度了 + +225 +00:10:26,226 --> 00:10:28,529 +因此这个游戏有两种视图 + +226 +00:10:28,529 --> 00:10:31,932 +而不是所有参与者 +看到的都是同个视图 + +227 +00:10:31,932 --> 00:10:35,068 +如果您想提供像 +这样的多视图协调体验 + +228 +00:10:35,068 --> 00:10:37,971 +您可以用 +“GroupSessionMessenger”类 + +229 +00:10:37,971 --> 00:10:41,642 +里的“send”方法并指定 + +230 +00:10:41,642 --> 00:10:45,179 +应该接收消息的参与者子集 + +231 +00:10:45,179 --> 00:10:47,781 +所以当您选好了您要设计的活动 + +232 +00:10:47,781 --> 00:10:49,883 +以及支持活动所需的视图 + +233 +00:10:49,883 --> 00:10:53,153 +下一步就是在人们 +跟您的 App 互动时 + +234 +00:10:53,153 --> 00:10:55,155 +给予他们良好的体验感 + +235 +00:10:55,155 --> 00:10:56,790 +我们来探讨几个因素 + +236 +00:10:56,790 --> 00:10:58,792 +这些因素可以 + +237 +00:10:58,792 --> 00:11:02,129 +让您 App 的 SharePlay +体验好用易懂 + +238 +00:11:02,129 --> 00:11:04,898 +为了打造出色的 SharePlay 体验 + +239 +00:11:04,898 --> 00:11:07,534 +分阶段考虑共享活动是很重要的 + +240 +00:11:07,534 --> 00:11:12,005 +可分为开始 期间和结束三个阶段 + +241 +00:11:12,005 --> 00:11:14,875 +我们添加了不用 +FaceTime 通话 + +242 +00:11:14,875 --> 00:11:17,511 +就能开启 SharePlay 会话的功能 + +243 +00:11:17,511 --> 00:11:20,714 +因此在人们遇到想和朋友 +分享的内容或活动时 + +244 +00:11:20,714 --> 00:11:23,584 +他们可以直接在您的 App 里 + +245 +00:11:23,584 --> 00:11:25,919 +启动 SharePlay 会话 + +246 +00:11:25,919 --> 00:11:28,422 +您能够直接在您的 App 里 + +247 +00:11:28,422 --> 00:11:31,692 +让所有人进入您设计的体验类型中 + +248 +00:11:31,692 --> 00:11:33,961 +如果人们 +在浏览您的 App 时看到 + +249 +00:11:33,961 --> 00:11:35,696 +想和朋友分享的事物 + +250 +00:11:35,696 --> 00:11:38,799 +他们可能会点击分享 +按钮来呈现分享栏 + +251 +00:11:38,799 --> 00:11:41,702 +为了在分享栏里显示 SharePlay 的功能 + +252 +00:11:41,702 --> 00:11:44,972 +您可以用 +“registerGroupActivity(_:)”方法 + +253 +00:11:44,972 --> 00:11:47,441 +注册 App 的集体活动 + +254 +00:11:47,441 --> 00:11:49,743 +这样人们就能直接 + +255 +00:11:49,743 --> 00:11:53,680 +在您 App 的分享栏看到 +SharePlay 活动的选项 + +256 +00:11:53,680 --> 00:11:56,049 +为了在您的 App 中 + +257 +00:11:56,049 --> 00:11:58,919 +更容易找到集体活动 您可以支持 + +258 +00:11:58,919 --> 00:12:01,522 +直接在 App UI 里 + +259 +00:12:01,522 --> 00:12:03,290 +显示出 SharePlay 按钮 + +260 +00:12:03,290 --> 00:12:07,728 +为此 您可以采用 +“GroupActivitySharingController” + +261 +00:12:07,728 --> 00:12:10,731 +这让人们可以开始一个 SharePlay 会话 + +262 +00:12:10,731 --> 00:12:13,033 +选择想要 SharePlay 的朋友 + +263 +00:12:13,033 --> 00:12:15,102 +以及选择他们是否想通过 +信息或 FaceTime 通话 + +264 +00:12:15,102 --> 00:12:16,537 +共享播放 + +265 +00:12:16,537 --> 00:12:18,505 +我准备和 Adam 跟 Ryan + +266 +00:12:18,505 --> 00:12:21,008 +SharePlay 歌曲 + +267 +00:12:21,008 --> 00:12:22,709 +系统会向他俩显示 + +268 +00:12:22,709 --> 00:12:25,979 +关于集体活动的信息 包括标题 + +269 +00:12:25,979 --> 00:12:28,982 +可选填的副标题以及图像 + +270 +00:12:28,982 --> 00:12:31,451 +重点是这些信息是叙述性的 + +271 +00:12:31,451 --> 00:12:34,054 +以便 Ryan 和 Adam +加入 SharePlay 会话后 + +272 +00:12:34,054 --> 00:12:36,757 +知道他们要做什么 + +273 +00:12:36,757 --> 00:12:39,026 +因此要想为您的集体 +活动提供有用信息 + +274 +00:12:39,026 --> 00:12:41,828 +请务必实现元数据属性 + +275 +00:12:41,828 --> 00:12:45,799 +并返回一个 +“GroupActivityMetadata”实例 + +276 +00:12:45,799 --> 00:12:48,669 +您也可以考虑包含网页型的 URL + +277 +00:12:48,669 --> 00:12:51,271 +为可能没有在他们的设备上安装 + +278 +00:12:51,271 --> 00:12:53,207 +您的 App 的参与者着想 + +279 +00:12:53,207 --> 00:12:55,142 +这样他们能快速轻松地 + +280 +00:12:55,142 --> 00:12:59,813 +下载您的 App +然后参加朋友的活动 + +281 +00:12:59,813 --> 00:13:01,315 +要注意一点 + +282 +00:13:01,315 --> 00:13:03,350 +某人在 Messages 组里 + +283 +00:13:03,350 --> 00:13:04,551 +或 FaceTime 通话中 + +284 +00:13:04,551 --> 00:13:08,021 +并不意味着他们已经进入了集体活动 + +285 +00:13:08,021 --> 00:13:09,756 +想要找出谁在参与着 + +286 +00:13:09,756 --> 00:13:11,091 +SharePlay 会话 + +287 +00:13:11,091 --> 00:13:13,727 +人们可以在详情视图查看 + +288 +00:13:13,727 --> 00:13:15,395 +这里看到 +Ryan 在和我一起听歌 + +289 +00:13:15,395 --> 00:13:17,531 +但是在进行 +FaceTime 通话的 Adam + +290 +00:13:17,531 --> 00:13:20,734 +还没进入 SharePlay 活动 + +291 +00:13:20,734 --> 00:13:23,504 +有机会时 您也可以 +在您 App 的 UI 中 + +292 +00:13:23,504 --> 00:13:25,239 +显示上述的信息 + +293 +00:13:25,239 --> 00:13:26,640 +这是个好办法 + +294 +00:13:26,640 --> 00:13:29,142 +能知道每个人都和您在同一页面上 + +295 +00:13:29,142 --> 00:13:32,779 +这也有助于保持集体的现场感 + +296 +00:13:32,779 --> 00:13:34,281 +如果每个人都在同个房间 + +297 +00:13:34,281 --> 00:13:35,516 +只是看周围一眼 + +298 +00:13:35,516 --> 00:13:39,820 +您就会知道有多少个人 +和您一起享受着活动 + +299 +00:13:39,820 --> 00:13:42,456 +然后我们都有几个 +聚会总是迟到的朋友 + +300 +00:13:42,456 --> 00:13:45,359 +因此 根据您 App 的体验类型 + +301 +00:13:45,359 --> 00:13:47,494 +您可以考虑设立等待区 + +302 +00:13:47,494 --> 00:13:49,363 +在开始体验之前 人们可以 + +303 +00:13:49,363 --> 00:13:51,431 +等其他人加入的区域 + +304 +00:13:51,431 --> 00:13:54,234 +比如“Heads Up!”就有等待区 +每个人都加入 + +305 +00:13:54,234 --> 00:13:57,104 +SharePlay 会话后 您就可以 +点击“Let's Play!” + +306 +00:13:57,104 --> 00:13:59,273 +开始游戏 + +307 +00:13:59,273 --> 00:14:01,808 +我们已经介绍了如何无缝启动 + +308 +00:14:01,808 --> 00:14:04,611 +并加入 SharePlay 活动 + +309 +00:14:04,611 --> 00:14:07,748 +接着我们来思考如何制作 + +310 +00:14:07,748 --> 00:14:09,750 +活动期间直观的体验 + +311 +00:14:09,750 --> 00:14:12,986 +个体作为活动进行中的 +一份子 每个人都有可能 + +312 +00:14:12,986 --> 00:14:15,489 +同时操作使用您的 App + +313 +00:14:15,489 --> 00:14:18,091 +我们已经跟我们的设备建立了联系 + +314 +00:14:18,091 --> 00:14:19,493 +我们碰到了屏幕某个地方 + +315 +00:14:19,493 --> 00:14:21,728 +都会导致页面发生改变 + +316 +00:14:21,728 --> 00:14:23,664 +但是当您跨设备 + +317 +00:14:23,664 --> 00:14:25,699 +进行一次共享的体验 + +318 +00:14:25,699 --> 00:14:29,169 +某人的屏幕可能会因他人的操作 + +319 +00:14:29,169 --> 00:14:31,572 +而发生变化 + +320 +00:14:31,572 --> 00:14:34,575 +因此 在 SharePlay 会话期间 +发生的变化 + +321 +00:14:34,575 --> 00:14:37,144 +有必要让每个人都知道原因 + +322 +00:14:37,144 --> 00:14:39,613 +例如 Ryan 可能暂停了电影 + +323 +00:14:39,613 --> 00:14:42,015 +而几个人都在他的设备上观看 + +324 +00:14:42,015 --> 00:14:43,951 +在 Ryan 暂停视频时 + +325 +00:14:43,951 --> 00:14:45,986 +其他人的也会暂停 + +326 +00:14:45,986 --> 00:14:48,989 +即使其他人没有动他们的设备 + +327 +00:14:48,989 --> 00:14:51,892 +SharePlay 系统负责把类似的更改 + +328 +00:14:51,892 --> 00:14:55,462 +发消息通知给小组的其他成员 + +329 +00:14:55,462 --> 00:14:58,632 +但对某些活动来讲 人们 +可能会觉得这类信息很有用 + +330 +00:14:58,632 --> 00:15:01,301 +那就是活动期间相关事项的 + +331 +00:15:01,301 --> 00:15:04,571 +内置于 App 的上下文信息 + +332 +00:15:04,571 --> 00:15:05,739 +举个例子 + +333 +00:15:05,739 --> 00:15:08,976 +在 Moleskin 制作的 +Flow App 中使用 SharePlay 时 + +334 +00:15:08,976 --> 00:15:12,346 +许多人可能在同一页面上绘图 + +335 +00:15:12,346 --> 00:15:15,749 +当有人画了什么时 +App 会显示姓名首字母 + +336 +00:15:15,749 --> 00:15:17,618 +让大家都知道是谁画的 + +337 +00:15:17,618 --> 00:15:22,222 +而这为整个小组提供了更直观的体验 + +338 +00:15:22,222 --> 00:15:24,725 +这也有助于加强与小组其他成员 + +339 +00:15:24,725 --> 00:15:26,360 +之间的现场感 + +340 +00:15:26,360 --> 00:15:28,629 +这功能变得更加重要了 因为现在 + +341 +00:15:28,629 --> 00:15:31,431 +您可以通过消息 SharePlay +之前您可能 + +342 +00:15:31,431 --> 00:15:34,301 +没能通过音频或视频 +获得您朋友的持续反馈 + +343 +00:15:34,301 --> 00:15:36,637 +前面讲到我们和朋友一起开始 + +344 +00:15:36,637 --> 00:15:37,804 +SharePlay 活动 + +345 +00:15:37,804 --> 00:15:40,007 +也讲到了加入活动方面的功能 + +346 +00:15:40,007 --> 00:15:43,310 +现在 我们聚焦在活动本身 + +347 +00:15:43,310 --> 00:15:46,380 +您能够拥有完全沉浸式的体验 + +348 +00:15:46,380 --> 00:15:50,450 +体验支持全屏观看 +也可能会隐藏状态栏 + +349 +00:15:50,450 --> 00:15:54,188 +例如 Apple TV App +在人们观看视频时 + +350 +00:15:54,188 --> 00:15:55,756 +会隐藏状态栏 + +351 +00:15:55,756 --> 00:15:58,325 +和其他界面元素 + +352 +00:15:58,325 --> 00:16:02,529 +但重要的是要记住状态栏 + +353 +00:16:02,529 --> 00:16:06,600 +让人们能够访问主要的控制 + +354 +00:16:06,600 --> 00:16:08,769 +所以请让人们能够 +重新显示隐藏的状态栏 + +355 +00:16:08,769 --> 00:16:12,039 +通过设置简单 易发现的手势 + +356 +00:16:12,039 --> 00:16:15,709 +让人们能在活动期间 +访问这些类型的控制 + +357 +00:16:15,709 --> 00:16:19,847 +在 Apple TV App 中 +单次轻点便可再次显示状态栏 + +358 +00:16:19,847 --> 00:16:24,852 +并在 UI 中显示主要的体验控制 + +359 +00:16:24,852 --> 00:16:26,520 +也请记住 + +360 +00:16:26,520 --> 00:16:28,388 +App 界面中的活动 + +361 +00:16:28,388 --> 00:16:31,391 +只是整个体验的一部分 + +362 +00:16:31,391 --> 00:16:33,160 +在您设计 SharePlay 体验期间 + +363 +00:16:33,160 --> 00:16:34,928 +请思考人们如何通过 + +364 +00:16:34,928 --> 00:16:37,130 +您的 App 与小组其他成员互动 + +365 +00:16:37,130 --> 00:16:40,667 +无论人们是用 FaceTime 通话 +还是用 Messages 发短信 + +366 +00:16:40,667 --> 00:16:42,536 +他们都在进行多任务处理 + +367 +00:16:42,536 --> 00:16:45,339 +所以在某些情况下 有人可能会 + +368 +00:16:45,339 --> 00:16:48,675 +在小组活动期间 +从您的 App 离开 + +369 +00:16:48,675 --> 00:16:51,979 +这种情况下 +请记得提供画中画功能支持 + +370 +00:16:51,979 --> 00:16:54,348 +以提供良好的同步媒体体验 + +371 +00:16:54,348 --> 00:16:56,650 +这将允许每个人继续 + +372 +00:16:56,650 --> 00:16:57,885 +和朋友观看 + +373 +00:16:57,885 --> 00:17:01,955 +并维持与小组其他成员间的现场感 + +374 +00:17:01,955 --> 00:17:04,124 +这样不管是否有人在回复消息 + +375 +00:17:04,124 --> 00:17:06,393 +亦或是在通过 +FaceTime 通话与小组联系 + +376 +00:17:06,393 --> 00:17:09,429 +就不用每次都暂停视频 + +377 +00:17:09,429 --> 00:17:12,132 +在您的 App 里建立 +这样的小组活动时 + +378 +00:17:12,132 --> 00:17:13,534 +注意这些事项将有助于 + +379 +00:17:13,534 --> 00:17:16,403 +提供端到端 SharePlay 的无缝体验 + +380 +00:17:16,403 --> 00:17:18,105 +打破数字壁垒 + +381 +00:17:18,105 --> 00:17:20,941 +让人们能制造有意义的时刻 + +382 +00:17:20,941 --> 00:17:22,876 +并感受到互相的陪伴 + +383 +00:17:22,876 --> 00:17:26,079 +因此 请务必注册您的小组活动 + +384 +00:17:26,079 --> 00:17:29,783 +人们就可以直接在您的 +App 里开始 SharePlay + +385 +00:17:29,783 --> 00:17:33,453 +配置描述性元数据 +以便人们知道参加活动时 + +386 +00:17:33,453 --> 00:17:35,289 +会发生什么 + +387 +00:17:35,289 --> 00:17:37,624 +对晚来的加入者提供定制体验 + +388 +00:17:37,624 --> 00:17:39,560 +并提供关于 UI 可能 + +389 +00:17:39,560 --> 00:17:42,396 +发生变化的原因的上下文信息 + +390 +00:17:42,396 --> 00:17:45,065 +确保控制易于访问 + +391 +00:17:45,065 --> 00:17:48,602 +最后请记得支持媒体画中画 + +392 +00:17:48,602 --> 00:17:52,639 +我们今天谈了很多 +所以我们来快速回顾一下 + +393 +00:17:52,639 --> 00:17:55,676 +您现在可以直接在您的 +App 里启动 SharePlay 会话 + +394 +00:17:55,676 --> 00:17:58,312 +无需通过 FaceTime 通话 + +395 +00:17:58,312 --> 00:17:59,813 +这拓宽了构建 + +396 +00:17:59,813 --> 00:18:02,583 +各种小组活动的道路 + +397 +00:18:02,583 --> 00:18:04,685 +因此我们建议您做传送门练习 + +398 +00:18:04,685 --> 00:18:07,254 +来帮助思考如何为您的 App + +399 +00:18:07,254 --> 00:18:09,223 +设计一种 + +400 +00:18:09,223 --> 00:18:11,725 +能让人们身临其境的体验 + +401 +00:18:11,725 --> 00:18:14,361 +重新构想以一群人为中心的 App + +402 +00:18:14,361 --> 00:18:17,431 +相关内容和活动 创造出色的体验 + +403 +00:18:17,431 --> 00:18:20,200 +并在构建您的体验时用上最佳的操作 + +404 +00:18:20,200 --> 00:18:23,370 +以避免受碍于数字壁垒 + +405 +00:18:23,370 --> 00:18:25,606 +我们迫不及待地想看见您想到的 + +406 +00:18:25,606 --> 00:18:26,940 +关于 SharePlay 的创造性用途 + +407 +00:18:26,940 --> 00:18:28,642 +我们希望您能享受这次讲座 + +408 +00:18:28,642 --> 00:18:30,244 +Adam 和 Priya:感谢收看 + +409 +00:18:30,244 --> 00:18:34,515 +♪ + diff --git a/zho/2022 Session 10140 What's new in SharePlay.srt b/zho/2022 Session 10140 What's new in SharePlay.srt new file mode 100644 index 0000000..c91347b --- /dev/null +++ b/zho/2022 Session 10140 What's new in SharePlay.srt @@ -0,0 +1,1203 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,877 --> 00:00:13,747 +Adam: 大家好 我是 Adam +同播共享团队的工程师 + +3 +00:00:13,780 --> 00:00:16,316 +很高兴能有机会 +与大家分享同播共享的更新内容 + +4 +00:00:16,350 --> 00:00:18,485 +以及您如何将其 +应用到 App 中 + +5 +00:00:18,519 --> 00:00:24,091 +我们先来看下从您的 App +启动同播共享的几个新 API + +6 +00:00:24,124 --> 00:00:28,595 +接下来 我们来看一些激动人心的 +GroupSessionMessenger 更新 + +7 +00:00:28,629 --> 00:00:34,201 +最后是关于实现同播共享体验的 +一些最佳实践 + +8 +00:00:34,234 --> 00:00:36,303 +从您的 App 中 +启动同播共享 + +9 +00:00:36,336 --> 00:00:38,805 +我们有求必应 + +10 +00:00:38,839 --> 00:00:44,211 +从 iOS 15.4 开始 您可以用新 API +在 App 中启动同播共享 + +11 +00:00:44,244 --> 00:00:46,813 +而无需进行 FaceTime 通话 + +12 +00:00:46,847 --> 00:00:48,782 +我们来看下是怎样的 + +13 +00:00:48,815 --> 00:00:52,386 +现在只需要找到 +我们最爱的同播共享 App + +14 +00:00:52,419 --> 00:00:54,621 +比如说音乐 App + +15 +00:00:54,655 --> 00:00:56,723 +找到要同播共享的歌曲 + +16 +00:00:56,757 --> 00:01:00,227 +如 Viral Hits 长按 + +17 +00:01:00,260 --> 00:01:01,728 +在快捷菜单中 + +18 +00:01:01,762 --> 00:01:03,730 +您会看到现在有了一个 +新的同播共享按钮 + +19 +00:01:03,764 --> 00:01:05,899 +我点击选择 + +20 +00:01:05,933 --> 00:01:07,634 +然后跳转到了人物选择器 + +21 +00:01:07,668 --> 00:01:11,238 +我们可以选择 Sue +开启一个 FaceTime 通话 + +22 +00:01:13,507 --> 00:01:16,076 +如您所见 这里有一个小窗口 + +23 +00:01:16,109 --> 00:01:17,511 +显示分阶段活动 + +24 +00:01:17,544 --> 00:01:20,480 +如果 Sue 加入了 +我们就可以开始 + +25 +00:01:20,514 --> 00:01:22,216 +进行群组会话 + +26 +00:01:24,151 --> 00:01:26,520 +我认为这是一个很强大的功能 + +27 +00:01:26,553 --> 00:01:29,189 +但我们将其分解成更详细的细节 + +28 +00:01:30,257 --> 00:01:34,094 +这里 用户可以从分享面板 +开启同播共享 + +29 +00:01:34,127 --> 00:01:37,898 +您可能会想知道 +这个功能需要怎么启用 + +30 +00:01:37,931 --> 00:01:41,602 +答案就是 如果您的 App +授权了同播共享 + +31 +00:01:41,635 --> 00:01:44,972 +无需额外工作即可 +免费获得此按钮 + +32 +00:01:45,005 --> 00:01:47,774 +但这并不是最佳的用户体验 + +33 +00:01:47,808 --> 00:01:52,312 +因为用户无法通过系统 UI +开启 GroupActivity + +34 +00:01:52,346 --> 00:01:55,449 +相反 还需要重新回到 +您 App 的交互界面 + +35 +00:01:55,482 --> 00:01:58,352 +选择需要同播共享的功能 + +36 +00:01:58,385 --> 00:02:03,023 +那我们来看看您的 App +可以如何应用我们的新 API + +37 +00:02:03,056 --> 00:02:06,360 +答案就是 您只需要在 +NSItemProvider 上 + +38 +00:02:06,393 --> 00:02:08,061 +注册您的 GroupActivity + +39 +00:02:08,095 --> 00:02:11,698 +然后将 ItemProvider +提供到分享面板 + +40 +00:02:13,500 --> 00:02:15,202 +想要保留同播共享按钮 + +41 +00:02:15,235 --> 00:02:17,204 +但却不放在显眼位置吗 + +42 +00:02:17,237 --> 00:02:18,539 +没问题 + +43 +00:02:18,572 --> 00:02:21,441 +您可以用 +UIActivityViewController 上的 + +44 +00:02:21,475 --> 00:02:23,911 +allowsProminentActivity 来调整行为 + +45 +00:02:23,944 --> 00:02:26,747 +只要将 allowsProminentActivity +设置为 false + +46 +00:02:27,981 --> 00:02:31,785 +如果您 App 中有一部分内容 +不支持同播共享怎么办呢 + +47 +00:02:31,818 --> 00:02:35,022 +虽然我们很希望所有内容 +都支持同播共享 + +48 +00:02:35,055 --> 00:02:37,791 +您可以通过提示 UIActivityViewController +排除同播共享类型活动 + +49 +00:02:37,824 --> 00:02:42,229 +来在分享面板中 +隐藏同播共享选项 + +50 +00:02:44,164 --> 00:02:46,733 +如果您想直接在您的 App 内 +放置一个按钮 + +51 +00:02:46,767 --> 00:02:50,304 +那就可以使用我们 +新的 API - GroupActivitySharingController + +52 +00:02:50,337 --> 00:02:54,208 +来创建我们的 UIViewController +然后就可以显示了 + +53 +00:02:55,909 --> 00:02:58,011 +一旦有人在您的 +App 内开启了这种体验 + +54 +00:02:58,045 --> 00:03:00,314 +开始了 FaceTime 通话 +或者同播共享会话 + +55 +00:03:00,347 --> 00:03:05,252 +就会有提示可以激活 +分阶段 GroupActivity + +56 +00:03:05,285 --> 00:03:08,355 +激活后 您的 App 就可以 +收到 GroupSession 了 + +57 +00:03:08,388 --> 00:03:10,591 +如果您在想“等下 Adam +您刚刚说的是” + +58 +00:03:10,624 --> 00:03:12,726 +“分阶段 GroupActivity 吗” +不用担心 + +59 +00:03:12,759 --> 00:03:14,628 +为什么呢 是的 我确实这么说了 + +60 +00:03:14,661 --> 00:03:17,898 +这个想法先放一边 +我们稍后讲到最佳实践的时候 + +61 +00:03:17,931 --> 00:03:20,367 +再进一步深入讨论 + +62 +00:03:20,400 --> 00:03:24,605 +现在 我们先看下在 +DrawTogether App 中如何使用 + +63 +00:03:25,706 --> 00:03:27,274 +这是我们的 DrawTogether App + +64 +00:03:27,307 --> 00:03:31,211 +也是与之前在 WWDC 2021 +“Build custom experiences with Group Activities”讲座里 + +65 +00:03:31,245 --> 00:03:34,014 +介绍的 App 是一样的 + +66 +00:03:34,047 --> 00:03:39,219 +如果您还没有看过那个讲座 +我强烈建议您去看下 + +67 +00:03:39,253 --> 00:03:41,321 +如果您已经看过了 + +68 +00:03:41,355 --> 00:03:44,124 +就会记得我们的 App 中 +是没有任何共享按钮的 + +69 +00:03:44,157 --> 00:03:46,159 +但如果您可以发起群组会话 + +70 +00:03:46,193 --> 00:03:48,762 +就会有一个同播共享按钮 + +71 +00:03:48,795 --> 00:03:51,098 +我们来调整这一行为 + +72 +00:03:51,131 --> 00:03:54,268 +这样即使 isEligibleForGroupSession +为 false + +73 +00:03:54,301 --> 00:03:58,539 +现在 也会显示这一按钮来 +让用户开启同播共享会话 + +74 +00:04:00,040 --> 00:04:02,876 +现在我们可以看下 +它是如何运行的了 + +75 +00:04:02,910 --> 00:04:05,712 +我们跳转到 ControlBar 代码 + +76 +00:04:05,746 --> 00:04:07,848 +现在 如您所见 +我们有一个 if 语句 + +77 +00:04:07,881 --> 00:04:10,050 +确保没有群组会话 + +78 +00:04:10,083 --> 00:04:13,053 +以及我们可以发起群组会话 + +79 +00:04:13,086 --> 00:04:16,990 +我们把后面的语句移除 + +80 +00:04:17,024 --> 00:04:18,859 +放到下面 + +81 +00:04:24,865 --> 00:04:27,234 +现在我们要做的是 +注册一个新的变量 + +82 +00:04:27,267 --> 00:04:30,404 +这样就知道何时需要显示 +我们的 GroupActivitySharingController + +83 +00:04:30,437 --> 00:04:34,942 +所以我们在这里添加一个新的变量 + +84 +00:04:34,975 --> 00:04:39,513 +现在我们来处理该变量 +变为 true 时的情况 + +85 +00:04:43,150 --> 00:04:45,452 +并且我们还需要一个 wrapper + +86 +00:04:45,485 --> 00:04:49,389 +这样可以在 SwiftUI 中 +展示 GroupActivitySharingController + +87 +00:04:55,562 --> 00:04:59,700 +最后 我们只需要加入一个 +else 语句 + +88 +00:04:59,733 --> 00:05:02,603 +如果不能发起群组会话 + +89 +00:05:02,636 --> 00:05:05,005 +就将 isSharingControllerPresented +设置为 true + +90 +00:05:08,008 --> 00:05:10,177 +让我们来看看代码的 +实际运行效果 + +91 +00:05:10,210 --> 00:05:12,546 +我们到 DrawTogether App 中 + +92 +00:05:12,579 --> 00:05:14,681 +您可以看到 这里有 +同播共享按钮 + +93 +00:05:14,715 --> 00:05:17,751 +我们可以点击 出现人物选择器 + +94 +00:05:19,920 --> 00:05:24,157 +现在就可以在您的 App 中 +体验强大的同播共享功能了 + +95 +00:05:24,191 --> 00:05:26,660 +但这并不是我们唯一的更新 + +96 +00:05:26,693 --> 00:05:30,864 +现在我们再来看下 +GroupSessionMessenger 方面的更新 + +97 +00:05:30,898 --> 00:05:34,768 +在 GroupSessionMessenger 中 +我们有两个激动人心的更新内容 + +98 +00:05:34,801 --> 00:05:38,839 +第一个更新内容 +您可能遇到过这个神奇的数字 + +99 +00:05:38,872 --> 00:05:43,310 +这是您可通过 GroupSessionMessenger +发送的有效载荷 + +100 +00:05:43,343 --> 00:05:45,646 +而这已成往事 + +101 +00:05:45,679 --> 00:05:51,885 +我们现在将其提升了四倍 +高达 256KB + +102 +00:05:51,919 --> 00:05:53,887 +在这个改变下 +您的 App 无需担心 + +103 +00:05:53,921 --> 00:05:57,024 +需要把消息拆分成更小的消息 + +104 +00:05:57,057 --> 00:06:01,795 +您只用简单地发送消息 +专注于搭建完美的体验即可 + +105 +00:06:01,828 --> 00:06:03,497 +如果这还不足以让您兴奋 + +106 +00:06:03,530 --> 00:06:06,066 +那我们下一个更新内容肯定可以 + +107 +00:06:06,099 --> 00:06:08,202 +就是 Unreliable messaging + +108 +00:06:08,235 --> 00:06:10,003 +作为 GroupSessionMessenger +的一部分 + +109 +00:06:10,037 --> 00:06:13,006 +您现在可以选择消息的可靠性 + +110 +00:06:13,040 --> 00:06:16,810 +这让您可以根据所需的体验 +在 reliable 或 + +111 +00:06:16,844 --> 00:06:19,513 +unreliable messaging 中进行选择 + +112 +00:06:20,948 --> 00:06:23,617 +我们只需要利用 +GroupSessionMessenger 中 + +113 +00:06:23,650 --> 00:06:25,085 +新的初始化器 + +114 +00:06:25,118 --> 00:06:28,488 +允许我们 +指定 message reliability + +115 +00:06:30,524 --> 00:06:32,960 +现在我们知道了 +应如何使用 API + +116 +00:06:32,993 --> 00:06:35,429 +那体验方面呢 + +117 +00:06:35,462 --> 00:06:38,398 +我们什么时候要使用 +unreliable messaging 呢 + +118 +00:06:38,432 --> 00:06:40,634 +这是一个很好的问题 + +119 +00:06:41,802 --> 00:06:46,240 +人们通过 FaceTime 通话 +和同播共享来进行实时操作 + +120 +00:06:46,273 --> 00:06:48,909 +我们想象下有三个人 + +121 +00:06:48,942 --> 00:06:51,912 +Amy Brian 和 Chris + +122 +00:06:51,945 --> 00:06:54,348 +他们加入了一个会话并同步 + +123 +00:06:54,381 --> 00:06:58,485 +随着时间的流逝 电影也在进行 + +124 +00:06:58,519 --> 00:07:00,787 +但如果 Amy 想要做一些 +与他们当下的指定时间内 + +125 +00:07:00,821 --> 00:07:04,925 +相关的一些事情怎么办呢 + +126 +00:07:04,958 --> 00:07:07,094 +如果您使用 reliable messaging + +127 +00:07:07,127 --> 00:07:11,131 +我们可确保该消息 +可在所有设备上收到 + +128 +00:07:11,164 --> 00:07:13,333 +但这并不意味着会在他们 + +129 +00:07:13,367 --> 00:07:16,003 +预期的时间内收到 + +130 +00:07:16,036 --> 00:07:18,572 +例如 Chris 收到了消息 + +131 +00:07:18,605 --> 00:07:21,041 +但 Brian 第一次错过了消息 + +132 +00:07:21,074 --> 00:07:23,377 +随后也适时收到了 + +133 +00:07:23,410 --> 00:07:26,947 +但记住 电影仍在播放 + +134 +00:07:26,980 --> 00:07:30,484 +所以现在我们到了 Amy +预期消息能被收到 + +135 +00:07:30,517 --> 00:07:32,085 +而 Brian 并未收到的位置 + +136 +00:07:32,119 --> 00:07:35,756 +他是在后续的时间收到的 +但那时已经太晚了 + +137 +00:07:35,789 --> 00:07:39,493 +这是 unreliable 网络的 +一个完美例子 + +138 +00:07:39,526 --> 00:07:42,429 +它可以告知开发者 +什么消息需要在另一端 + +139 +00:07:42,462 --> 00:07:44,965 +以可靠的方式收到 + +140 +00:07:44,998 --> 00:07:46,733 +而什么消息不需要 + +141 +00:07:46,767 --> 00:07:50,204 +在延迟会极大影响用户体验的 +情况下 设计协议时 + +142 +00:07:50,237 --> 00:07:53,707 +理解这一概念是非常重要的 + +143 +00:07:53,740 --> 00:07:56,043 +Unreliable messages +使用的是 UDP + +144 +00:07:56,076 --> 00:07:59,713 +每条消息的延迟和成本更少 + +145 +00:07:59,746 --> 00:08:02,616 +这样的话 通过这一方式发送消息 + +146 +00:08:02,649 --> 00:08:05,185 +您能获得更即时的体验 + +147 +00:08:05,219 --> 00:08:08,889 +现在我们来看下如何在我们的 +DrawTogether App 中使用它 + +148 +00:08:08,922 --> 00:08:12,693 +您可能还记得 WWDC '21 的 +这个屏幕界面 + +149 +00:08:12,726 --> 00:08:15,963 +尤其是我画技精湛的笑脸 + +150 +00:08:15,996 --> 00:08:18,632 +我们看看您在屏幕上 +画这个笑脸的时候 + +151 +00:08:18,665 --> 00:08:20,534 +发生了什么事 + +152 +00:08:22,769 --> 00:08:26,673 +在我们的 App 中 我们有一些代码 +是听从 GestureRecognizer 的 + +153 +00:08:26,707 --> 00:08:30,777 +然后每次发送消息的时候 +都会有变化 + +154 +00:08:30,811 --> 00:08:33,647 +这意味着我们画笑脸的时候 + +155 +00:08:33,680 --> 00:08:35,682 +GestureRecognizer 给我们的每个点 + +156 +00:08:35,716 --> 00:08:38,719 +都会持续发送新消息 + +157 +00:08:38,752 --> 00:08:40,787 +这就太多消息了 + +158 +00:08:40,821 --> 00:08:44,491 +现在我们将协议改为 +使用 unreliable messaging + +159 +00:08:44,525 --> 00:08:47,027 +获得更无缝衔接的绘画体验 + +160 +00:08:48,562 --> 00:08:51,698 +我们在这里所做的是每次从 +GestureRecognizer 中 + +161 +00:08:51,732 --> 00:08:53,133 +收到一条更新时 + +162 +00:08:53,166 --> 00:08:57,504 +就会用 unreliable messaging +发送我们新增的点 + +163 +00:08:57,538 --> 00:09:00,674 +一旦手势完成 +我们使用 reliable messaging + +164 +00:09:00,707 --> 00:09:05,779 +提供所有点 这样用户可以看到 +他们错过的每个点 + +165 +00:09:05,812 --> 00:09:08,482 +这让我们可以利用较低的延迟 + +166 +00:09:08,515 --> 00:09:13,353 +通过 unreliable messaging +获得更即时的绘制体验 + +167 +00:09:13,387 --> 00:09:16,089 +我们看看如何用代码来实现 + +168 +00:09:16,123 --> 00:09:19,059 +首先跳转到 +我们的 messages 文件 + +169 +00:09:20,427 --> 00:09:24,331 +然后定义我们新的 +message 类型 + +170 +00:09:25,132 --> 00:09:28,302 +如您所见 这个新的 message 类型 +和旧的几乎一样 + +171 +00:09:28,335 --> 00:09:32,573 +但这次会包含我们笔画的所有点 + +172 +00:09:32,606 --> 00:09:35,609 +现在我们跳转到 canvas 文件 + +173 +00:09:40,514 --> 00:09:42,683 +我们要设置 +一个 handler 函数 + +174 +00:09:42,716 --> 00:09:45,385 +来处理即将收到的新消息 + +175 +00:09:50,791 --> 00:09:54,294 +然后创建 unreliable messenger + +176 +00:09:54,328 --> 00:09:56,897 +首先 创建一个变量 + +177 +00:09:59,833 --> 00:10:02,102 +现在将其初始化 + +178 +00:10:06,006 --> 00:10:08,742 +我们会听取结束笔画的消息 + +179 +00:10:12,846 --> 00:10:16,650 +将前一条消息 +也标记为 unreliable messenger + +180 +00:10:19,720 --> 00:10:21,522 +但我们需要一个发送消息的方式 + +181 +00:10:21,555 --> 00:10:24,291 +所以我们上去 finishedStroke + +182 +00:10:26,360 --> 00:10:29,296 +然后开始发送我们的 +新消息类型 + +183 +00:10:31,365 --> 00:10:34,635 +我们将旧的函数改为 +用 unreliable messenger + +184 +00:10:34,668 --> 00:10:37,104 +来发送所有点 + +185 +00:10:39,039 --> 00:10:41,575 +现在可以看下代码的运行情况了 + +186 +00:10:41,608 --> 00:10:43,744 +跳转到 DrawTogether App + +187 +00:10:43,777 --> 00:10:47,080 +可以看到它是如何无缝衔接的 + +188 +00:10:47,114 --> 00:10:48,415 +好了 + +189 +00:10:49,816 --> 00:10:53,320 +如我之前所说 我们来讨论下 +实现同播共享的 + +190 +00:10:53,353 --> 00:10:55,956 +一些最佳实践 + +191 +00:10:55,989 --> 00:10:58,425 +您可以记得刚刚我提到一个术语 + +192 +00:10:58,458 --> 00:11:00,460 +就是 Staged GroupActivity + +193 +00:11:00,494 --> 00:11:02,930 +这个术语对您的 App 来说 +意味着什么呢 + +194 +00:11:02,963 --> 00:11:05,132 +让我们来看一个示例场景 + +195 +00:11:07,100 --> 00:11:09,636 +假如左边的设备 Adam + +196 +00:11:09,670 --> 00:11:12,806 +和右边的设备 Brian +开启了同播共享 + +197 +00:11:12,840 --> 00:11:15,475 +但 Adam 想要继续他们 +之前看的节目 + +198 +00:11:15,509 --> 00:11:18,078 +所以当有人激活了 +staged GroupActivity 时 + +199 +00:11:18,111 --> 00:11:21,982 +我们想要跳转到之前节目的 +具体时间点 + +200 +00:11:22,015 --> 00:11:24,117 +而不是从头开始 + +201 +00:11:24,151 --> 00:11:27,855 +这就会带来一个问题 因为 +Adam 知道我们的节目 + +202 +00:11:27,888 --> 00:11:31,024 +还有 11 分钟未看 +但 Brian 的设备不知道 + +203 +00:11:31,058 --> 00:11:35,295 +这意味着如果 Brian 的设备 +激活 staged GroupActivity + +204 +00:11:35,329 --> 00:11:37,631 +这个节目可能会从头播放 + +205 +00:11:37,664 --> 00:11:39,366 +那我们可以怎么办呢 + +206 +00:11:39,399 --> 00:11:42,202 +这就要取决于 +您的 App 和体验了 + +207 +00:11:43,203 --> 00:11:45,305 +我们来看几个想法 + +208 +00:11:45,339 --> 00:11:46,640 +在播放的情况下 + +209 +00:11:46,673 --> 00:11:49,977 +我们想要每个设备继续其 +初始播放状态 + +210 +00:11:50,010 --> 00:11:52,613 +其它设备也同样赶上进度 + +211 +00:11:52,646 --> 00:11:57,317 +这意味着由于 Adam 的设备 +知道播放状态是在 23 秒处 + +212 +00:11:57,351 --> 00:12:00,087 +他加入会话时 +会告诉其它所有设备 + +213 +00:12:00,120 --> 00:12:02,222 +他的预期播放状态 + +214 +00:12:02,256 --> 00:12:05,359 +他们会将其作为事实来源 + +215 +00:12:05,392 --> 00:12:09,830 +您使用同播共享创建的 +所有体验都是同样的原则 + +216 +00:12:09,863 --> 00:12:12,499 +每个加入会话的人都应向 +其他人提供 + +217 +00:12:12,533 --> 00:12:15,602 +他们对会话的理解 + +218 +00:12:15,636 --> 00:12:18,805 +因为会话是对等的 无主的 + +219 +00:12:18,839 --> 00:12:21,375 +我们再深入看下这一点 + +220 +00:12:21,408 --> 00:12:24,711 +无主会话这个概念不好理解 + +221 +00:12:24,745 --> 00:12:29,583 +但在设计适宜的同播共享体验时 +是非常重要的 + +222 +00:12:29,616 --> 00:12:31,752 +在这个情况下 +Adam 左边的设备 + +223 +00:12:31,785 --> 00:12:34,721 +想要将会话切换到 +Apple TV 上 + +224 +00:12:34,755 --> 00:12:39,860 +这样他的手机会离开群组会话 +而 TV 加入会话 + +225 +00:12:39,893 --> 00:12:42,429 +但如果我们应用了所有权 +会发生什么呢 + +226 +00:12:42,462 --> 00:12:46,600 +所有人离线 所以 + +227 +00:12:46,633 --> 00:12:49,636 +记住 这不仅仅是对 TV 而言 + +228 +00:12:50,771 --> 00:12:53,874 +在 iOS 16 中 我们现在有了 +FaceTime 通话接力 + +229 +00:12:53,907 --> 00:12:56,810 +这样 Adam 可以 +用 iPad 来接力 + +230 +00:12:56,844 --> 00:12:59,046 +是一样的 + +231 +00:12:59,079 --> 00:13:00,180 +嘣 + +232 +00:13:00,214 --> 00:13:01,682 +这还不是全部 + +233 +00:13:01,715 --> 00:13:04,418 +我们只提到了用户流中 + +234 +00:13:04,451 --> 00:13:08,322 +将会话从一台设备切换到 +另一台设备的案例 + +235 +00:13:08,355 --> 00:13:10,891 +但是还有很多其它的案例 + +236 +00:13:10,924 --> 00:13:14,895 +好吧 别担心 我们长话短说 +只是再多分析一个案例 + +237 +00:13:14,928 --> 00:13:17,664 +大家应该很熟悉这个屏幕 + +238 +00:13:17,698 --> 00:13:19,366 +这是 FaceTime HUD + +239 +00:13:19,399 --> 00:13:22,202 +但如果我们点击同播共享按钮 +会发生什么呢 + +240 +00:13:23,437 --> 00:13:25,973 +我们现在能看到一个按钮 +End SharePlay + +241 +00:13:26,006 --> 00:13:30,410 +可以让您 … 对的 +结束同播共享 + +242 +00:13:30,444 --> 00:13:32,779 +这让您可以为所有人 +结束同播共享 + +243 +00:13:32,813 --> 00:13:35,549 +基本上系统会以 +您的 App 的名义 + +244 +00:13:35,582 --> 00:13:38,018 +在群组会话中调用 .end() + +245 +00:13:38,051 --> 00:13:41,288 +这意味着不管您多谨慎想着 +不要调用 .end() + +246 +00:13:41,321 --> 00:13:44,691 +除非设备是所有者 +系统还是会以您的名义 + +247 +00:13:44,725 --> 00:13:47,895 +在群组会话中调用 .end() + +248 +00:13:47,928 --> 00:13:50,931 +所以要记住 尽管这个概念 +不太好理解 + +249 +00:13:50,964 --> 00:13:54,301 +要确保您的 App +没有所有权的概念 + +250 +00:13:54,334 --> 00:13:58,672 +这意味着会有更好的使用体验 + +251 +00:13:58,705 --> 00:14:00,507 +以上就是讲座的所有内容 + +252 +00:14:00,541 --> 00:14:04,444 +您可以在 App 中用新的 API +开启同播共享功能 + +253 +00:14:04,478 --> 00:14:06,847 +为您的 App 探索全新的 + +254 +00:14:06,880 --> 00:14:10,717 +低延迟的 使用 unreliable messaging 的 +通讯方式了 + +255 +00:14:11,952 --> 00:14:14,955 +我们很希望能听到大家的声音 +所以记得用 Feedback assistant + +256 +00:14:14,988 --> 00:14:16,690 +向我们提出反馈 + +257 +00:14:16,723 --> 00:14:19,426 +希望您喜欢我们所做的这些更新 + +258 +00:14:19,459 --> 00:14:22,829 +非常期待看到大家搭建的 +不可思议的体验 + +259 +00:14:22,863 --> 00:14:25,999 +如果您还没有看 记得要查看 +我们另一个 WWDC 讲座 + +260 +00:14:26,033 --> 00:14:28,635 +“Make a great SharePlay experience” + +261 +00:14:28,669 --> 00:14:31,471 +如果您想看下 +我们在媒体播放方面 + +262 +00:14:31,505 --> 00:14:32,873 +所做的增强功能 + +263 +00:14:32,906 --> 00:14:36,777 +也可以查看 +“Display ads and other interstitials in SharePlay” + +264 +00:14:36,810 --> 00:14:39,980 +有任何问题 您可在 GroupActivities labs + +265 +00:14:40,013 --> 00:14:41,315 +and challenges 中联系我们 + +266 +00:14:41,348 --> 00:14:44,985 +感谢大家的观看 +祝大家有一个美好的 WWDC 旅程 + +267 +00:14:45,018 --> 00:14:46,987 +我们迫不及待看大家的成果了 + diff --git a/zho/2022 Session 10141 Explore USD tools and rendering.srt b/zho/2022 Session 10141 Explore USD tools and rendering.srt new file mode 100644 index 0000000..9bb08f0 --- /dev/null +++ b/zho/2022 Session 10141 Explore USD tools and rendering.srt @@ -0,0 +1,1436 @@ +1 +00:00:01,335 --> 00:00:07,341 +[古怪的音乐] + +2 +00:00:09,910 --> 00:00:13,714 +Stella: 大家好 +欢迎参加今年的 WWDC + +3 +00:00:13,747 --> 00:00:15,916 +我是 Stella + +4 +00:00:15,949 --> 00:00:16,984 +Alex: 我是 Alex + +5 +00:00:17,017 --> 00:00:20,420 +Stella 和我一起在 Apple +进行了很多和 USD 有关的工作 + +6 +00:00:20,454 --> 00:00:23,891 +今天 我们将和您一起探索 +USD 工具的新升级和渲染 + +7 +00:00:23,924 --> 00:00:24,992 +开始吧 Stella + +8 +00:00:27,160 --> 00:00:29,530 +Stella: USD是一种基础技术 + +9 +00:00:29,563 --> 00:00:34,835 +它随着与内容创造工具的 +不断发展和深入融合 + +10 +00:00:34,868 --> 00:00:40,641 +使创造 asset 和内容的方式越来越多 + +11 +00:00:40,674 --> 00:00:45,045 +为游戏 AR 电影和网页进行渲染 + +12 +00:00:45,078 --> 00:00:47,147 +所有这些技术都以 USD 为中心 + +13 +00:00:48,015 --> 00:00:53,787 +今天 我们将专注于生态的 +两个部分 工具和渲染 + +14 +00:00:54,688 --> 00:00:58,325 +让我们从 USD 工具的更新开始吧 + +15 +00:00:59,693 --> 00:01:02,930 +然后 我们将向您展示 +AR 快速查看里新的照明 如何使您的 asset + +16 +00:01:02,963 --> 00:01:07,134 +看起来更棒 + +17 +00:01:07,167 --> 00:01:12,072 +深入探索 USD 渲染 + +18 +00:01:12,105 --> 00:01:16,476 +最后 我们会向您展示 +如何集成 Hydra + +19 +00:01:19,580 --> 00:01:23,450 +让我们先从 Apple 生态的 +USD 工具开始吧 + +20 +00:01:24,818 --> 00:01:28,922 +我们将谈及 USDZTools +Reality Converter + +21 +00:01:28,956 --> 00:01:33,427 +然后跟进可以帮助您 +创建 USDZ 内容的 + +22 +00:01:33,460 --> 00:01:35,095 +额外的工具和框架 + +23 +00:01:37,965 --> 00:01:40,167 +USDZ Tools 是一个 + +24 +00:01:40,200 --> 00:01:43,971 +包含必要的命令行 +USD Python 工具 + +25 +00:01:44,004 --> 00:01:50,477 +以帮助您生成 验证 +和检查 USDZ 文件的包 + +26 +00:01:50,511 --> 00:01:55,182 +该包还包括一个 +名为 uszconvert 的转换器 + +27 +00:01:55,215 --> 00:02:00,053 +它可以把其他主要的 3D 文件格式 +创建为 USDZ 文件 + +28 +00:02:01,121 --> 00:02:07,227 +Python 脚本为自动化和 +成批处理提供了强大的工具 + +29 +00:02:07,261 --> 00:02:11,698 +此外 它们是您探索 USD +及学习如何使用 API 的 + +30 +00:02:11,732 --> 00:02:13,333 +很好的方式 + +31 +00:02:14,268 --> 00:02:19,673 +今年 我们将为您带来支持 +Python 3 和 Apple 芯片的产品 + +32 +00:02:19,706 --> 00:02:23,977 +我们还升级了 USD 版本 +便于您使用 + +33 +00:02:24,011 --> 00:02:27,681 +新的 USD 功能和性能改进 + +34 +00:02:30,117 --> 00:02:35,055 +除此之外 我们还为 usdzconvert +添加了很棒的新功能 + +35 +00:02:35,088 --> 00:02:39,826 +您现在可以使用 useObjMtl 标记 +将有纹理的 OBJ 文件 + +36 +00:02:39,860 --> 00:02:44,298 +转换为 USDZ 了 + +37 +00:02:44,331 --> 00:02:50,304 +我们还为 GLTF 文件 +添加了对点和线的支持 + +38 +00:02:50,337 --> 00:02:55,776 +为 FBX 文件添加了 +对动画的场景时间的支持 + +39 +00:02:55,809 --> 00:03:01,882 +要想展示全部 usdzconvert 选项 +及自定义您的转换方式 + +40 +00:03:01,915 --> 00:03:06,320 +只要在终端键入 +“usdzconvert --help” 即可 + +41 +00:03:08,388 --> 00:03:13,193 +这会为您显示所有可用的 +usdzconvert 选项 + +42 +00:03:13,227 --> 00:03:14,394 +如添加版权信息 + +43 +00:03:16,897 --> 00:03:23,103 +或为您的 3D 模型提供 +diffuseColor 或 normalMap + +44 +00:03:23,136 --> 00:03:25,272 +以及更多 + +45 +00:03:25,305 --> 00:03:28,475 +此外 如果您更倾向于在您的 +工作流中使用 UI 编辑器 + +46 +00:03:29,910 --> 00:03:32,145 +而非使用命令行 + +47 +00:03:32,179 --> 00:03:38,652 +我们也有用 USDZ 工具搭建的 +Reality Converter + +48 +00:03:38,685 --> 00:03:43,390 +并能提供和 usdzconvert 一样的功能 + +49 +00:03:43,423 --> 00:03:46,293 +不过是在编辑窗口中展现 + +50 +00:03:46,326 --> 00:03:52,633 +使在 MacOS 上转换 +查看及自定义 USD 内容更加方便 + +51 +00:03:53,634 --> 00:03:56,637 +只需导入常见的 3D 文件格式 + +52 +00:03:56,670 --> 00:04:00,841 +如 OBJ 或 GLTF 或 FBX + +53 +00:04:00,874 --> 00:04:05,245 +即可查看转换后的 USDZ 结果 + +54 +00:04:05,279 --> 00:04:09,983 +近几年 我们还优化了 UI +以简化您的工作流 + +55 +00:04:10,817 --> 00:04:14,221 +您可以选择材质来查看更多信息 + +56 +00:04:19,760 --> 00:04:23,564 +用您自己的纹理自定义材料性质 + +57 +00:04:31,939 --> 00:04:35,509 +添加版权或编辑文件元数据 + +58 +00:04:41,915 --> 00:04:47,454 +以及选择经典或新光照 +这一点我们之后会在讲座中 + +59 +00:04:47,487 --> 00:04:48,856 +详细讲到 + +60 +00:04:50,791 --> 00:04:54,127 +您甚至可以通过内置选项 +预览您的 USDZ 对象 + +61 +00:04:54,161 --> 00:04:59,166 +在各种照明条件下的情况 + +62 +00:04:59,199 --> 00:05:00,501 +并相应地调整曝光 + +63 +00:05:02,870 --> 00:05:06,206 +在 asset 方面 我们添加了一个新功能 + +64 +00:05:06,240 --> 00:05:12,045 +让您选择纹理质量 +同时导出一个 USDZ 文件 + +65 +00:05:12,079 --> 00:05:17,818 +默认情况下 纹理会被导出为 +原始 未压缩的大小 + +66 +00:05:17,851 --> 00:05:22,956 +但是 如果您倾向于 +减小您的 USDZ 文件大小 + +67 +00:05:22,990 --> 00:05:26,927 +您现在可以选择压缩纹理到 +JPEG 格式 + +68 +00:05:29,096 --> 00:05:31,832 +在本例中 我们使用对象捕获 +以高分辨率扫描了 + +69 +00:05:33,667 --> 00:05:35,702 +这个棋子 + +70 +00:05:35,736 --> 00:05:40,073 +为了减少文件大小 +而不丢失网格细节 + +71 +00:05:40,107 --> 00:05:46,180 +我们使用了 RealityConverter +导出带有压缩纹理的模型 + +72 +00:05:46,213 --> 00:05:49,416 +视觉上的差异很难被注意到 + +73 +00:05:49,449 --> 00:05:54,354 +而我们得到了缩小了 80% 的文件 + +74 +00:05:56,290 --> 00:05:58,458 +下面是更令人兴奋的消息 + +75 +00:05:58,492 --> 00:06:04,164 +RealityConverter 现在可以自动修复 +您的 USD asset 的问题了 + +76 +00:06:04,198 --> 00:06:09,870 +它将纠正不匹配的属性和连接类型 + +77 +00:06:09,903 --> 00:06:15,976 +修复具有多个顶级 prim +和一个缺失的默认 prim 的 stage + +78 +00:06:16,009 --> 00:06:22,683 +更新已弃用的属性 +并添加缺失的 stage 元数据 + +79 +00:06:22,716 --> 00:06:29,189 +我们还添加了通用二进制支持 +所以现在它在 Apple 芯片上原生运行 + +80 +00:06:30,924 --> 00:06:34,561 +现在 如果您想从头 +开始创建 3D 模型呢 + +81 +00:06:35,963 --> 00:06:41,969 +去年 我们推出了 Object Capture +作为 macOS 上的 RealityKit API + +82 +00:06:42,002 --> 00:06:47,307 +它提供了一种创新的方式 +来创建 USDZ asset + +83 +00:06:47,341 --> 00:06:52,713 +然后 您就可以使用 Reality Composer +构成一个具有多个 asset 的场景 + +84 +00:06:52,746 --> 00:06:56,884 +今年 我们为您带来了 RoomPlan API + +85 +00:06:56,917 --> 00:07:00,921 +它可以让您创建 +您房间的参数化 3D 扫描 + +86 +00:07:01,889 --> 00:07:05,826 +我强烈推荐您去看看这三个讲座 + +87 +00:07:05,859 --> 00:07:10,097 +这些技术一起运作 +使所有人都比以往任何时候 + +88 +00:07:10,130 --> 00:07:13,867 +更容易创造沉浸式的 AR 体验 + +89 +00:07:14,601 --> 00:07:16,537 +我们今天介绍的 + +90 +00:07:16,570 --> 00:07:19,706 +所有这些工具都可以在 +Apple 开发者网站上的 + +91 +00:07:19,740 --> 00:07:24,511 +AR Creation Tools 页面上下载 + +92 +00:07:24,545 --> 00:07:26,346 +快去看看吧 + +93 +00:07:26,914 --> 00:07:31,718 +接下来 让我们看看 +AR 快速查看的新照明吧 + +94 +00:07:32,586 --> 00:07:38,158 +AR 快速查看是 iOS 上内置的 +系统范围的 AR 查看器 + +95 +00:07:38,192 --> 00:07:43,697 +它允许您在物理空间中 +如桌子 墙壁或地板上 + +96 +00:07:43,730 --> 00:07:47,134 +放置 3D USDZ 对象 + +97 +00:07:47,167 --> 00:07:51,972 +并通过简单的触摸手势与它们交互 + +98 +00:07:52,005 --> 00:07:56,109 +您甚至可以用 Reality Composer +制作交互式场景 + +99 +00:07:56,143 --> 00:07:58,812 +并将它们保存到 USDZ 文件中 + +100 +00:07:58,846 --> 00:08:05,052 +这样您就可以用 iMessage +邮件 备忘录 和其它方式与他人分享 + +101 +00:08:05,085 --> 00:08:09,489 +我们不断努力使 AR 快速查看 + +102 +00:08:09,523 --> 00:08:13,393 +渲染更逼真 今年 + +103 +00:08:13,427 --> 00:08:18,065 +我们在 AR 快速查看中引入了 +改进照明 + +104 +00:08:18,098 --> 00:08:23,770 +它更明亮 有增强的对比度 +和改善过的形状定义 + +105 +00:08:23,804 --> 00:08:26,206 +会使您的 asset 看起来更好 + +106 +00:08:27,407 --> 00:08:31,044 +下面是一个 AirPods Pro +在物体模式下的 + +107 +00:08:31,078 --> 00:08:33,580 +经典和新照明的例子 + +108 +00:08:33,614 --> 00:08:37,518 +AirPods Pro 在两种照明条件下 +看起来都很棒 + +109 +00:08:37,551 --> 00:08:40,320 +您会注意到新的照明选项 + +110 +00:08:40,354 --> 00:08:42,422 +提供了更明亮的颜色 + +111 +00:08:42,456 --> 00:08:45,425 +更高的对比度和更多的亮点 + +112 +00:08:47,895 --> 00:08:52,599 +现在让我们把 AirPods Max +放在桌子上 用新的灯光在 AR 模式下 + +113 +00:08:52,633 --> 00:08:53,700 +查看它 + +114 +00:08:54,668 --> 00:08:56,937 +很惊人 不是吗 + +115 +00:08:57,938 --> 00:09:02,476 +所以您该如何在 asset 中 +应用新的照明呢 + +116 +00:09:02,509 --> 00:09:04,278 +这很简单 + +117 +00:09:04,311 --> 00:09:08,949 +您只需要通过在您的 USDZ 文件中 +设置新的 preferredIblVersion 元数据 + +118 +00:09:08,982 --> 00:09:14,521 +来选择最适合您的内容的照明 + +119 +00:09:15,956 --> 00:09:19,960 +在这里 我们已经将 +preferredIblVersion 的值设置为 2 + +120 +00:09:19,993 --> 00:09:23,797 +这将指示 AR 快速查看 +使用新的照明系统 + +121 +00:09:24,998 --> 00:09:28,936 +让我们从更细节处理解它 + +122 +00:09:28,969 --> 00:09:31,405 +preferredIBLVersion 元数据 + +123 +00:09:31,438 --> 00:09:34,274 +可以包含 0 1 和 2 的值 + +124 +00:09:36,143 --> 00:09:38,645 +当 asset 的 preferredIblVersion + +125 +00:09:38,679 --> 00:09:42,049 +设置为 0 时 将使用系统默认照明 + +126 +00:09:43,016 --> 00:09:46,787 +如果设置为 1 +它将继续使用经典照明 + +127 +00:09:48,255 --> 00:09:51,058 +如果值为 2 将会使用新照明 + +128 +00:09:52,059 --> 00:09:56,797 +这意味着您也可以轻松地 +将您的当前 asset 更新到 + +129 +00:09:56,830 --> 00:09:57,664 +新的照明 + +130 +00:09:58,198 --> 00:10:02,970 +我们建议您做出明确的选择 +并在所有 asset 中 + +131 +00:10:03,003 --> 00:10:05,339 +设置此元数据 + +132 +00:10:05,372 --> 00:10:07,608 +为此 您可以使用带有 + +133 +00:10:07,641 --> 00:10:12,546 +preferrediblversion 标志的 usdzconvert + +134 +00:10:12,579 --> 00:10:15,849 +例如 下面是如何使用标志 + +135 +00:10:15,883 --> 00:10:20,087 +将消防栓 OBJ 文件转换为 +用新照明的 USDZ + +136 +00:10:20,921 --> 00:10:24,625 +或者您可以使用 Reality Converter + +137 +00:10:24,658 --> 00:10:27,194 +它现在默认使用新照明 + +138 +00:10:28,161 --> 00:10:31,465 +但是如果您想使用经典照明 + +139 +00:10:31,498 --> 00:10:34,201 +在属性面板中有一个新的选项 + +140 +00:10:35,836 --> 00:10:40,774 +在这里 我们能预览经典和 +新照明下的 AirPods Max asset + +141 +00:10:42,242 --> 00:10:45,546 +这提供了一种比较差异的简单方法 + +142 +00:10:47,247 --> 00:10:50,250 +通过点击照明图标 应用的照明也会 + +143 +00:10:50,284 --> 00:10:52,986 +被突出显示 供您参考 + +144 +00:10:54,821 --> 00:10:59,159 +最后 对于没有此元数据的 asset + +145 +00:10:59,193 --> 00:11:02,729 +AR 快速查看将根据文件的 + +146 +00:11:02,763 --> 00:11:05,566 +日期-时间戳自动确定照明版本 + +147 +00:11:06,900 --> 00:11:13,507 +如果该 asset 是在 2022 年 7 月 1 日 +之后创建的 它将使用新照明 + +148 +00:11:14,808 --> 00:11:18,345 +更早的 asset 将继续使用经典照明 + +149 +00:11:18,378 --> 00:11:20,113 +这样它们的外观就不会改变 + +150 +00:11:21,148 --> 00:11:24,718 +现在 我会把话题交给 Alex +聊一聊 USD 渲染 + +151 +00:11:24,751 --> 00:11:26,053 +谢谢您 Stella + +152 +00:11:26,086 --> 00:11:29,022 +我们今天已经看到了很多 +渲染过的 USD + +153 +00:11:29,056 --> 00:11:33,460 +现在 我们将探索是什么 +使 USD 渲染和 Hydra 成为了 + +154 +00:11:33,493 --> 00:11:35,495 +您 3D 内容创建途径的 +一个绝佳选择 + +155 +00:11:35,529 --> 00:11:38,298 +以及您该如何将它 +集成到您自己的 App 中 + +156 +00:11:39,399 --> 00:11:43,303 +首先 让我们后退一步 +总体讨论一下渲染 + +157 +00:11:44,371 --> 00:11:51,011 +渲染器会将 3D 模型 +相机和灯光的集合作为输入 + +158 +00:11:51,044 --> 00:11:53,847 +并使用它们生成图像 + +159 +00:11:53,881 --> 00:11:56,416 +渲染器有许多 它们中的每一个 + +160 +00:11:56,450 --> 00:12:00,254 +都是为特定目的而构建的 +并针对不同的用例进行了优化 + +161 +00:12:01,321 --> 00:12:04,324 +有些渲染器是为 +实时 App 设计的 + +162 +00:12:04,358 --> 00:12:07,794 +比如渲染游戏中的角色 +或 AR 场景 + +163 +00:12:08,662 --> 00:12:12,966 +另一些则需要更长的时间 +但能产生更逼真的图像 + +164 +00:12:13,000 --> 00:12:16,537 +例如 为好莱坞电影制作视觉效果 + +165 +00:12:17,804 --> 00:12:21,208 +所有渲染器都会对其功能做出选择 +并且都是独一无二的 + +166 +00:12:22,276 --> 00:12:24,678 +Apple 平台上 +也存在针对不同用例的 + +167 +00:12:24,711 --> 00:12:26,713 +不同 USD 渲染器 + +168 +00:12:27,414 --> 00:12:30,117 +我们在 developer.apple.com 上 +添加了关于这些 + +169 +00:12:30,150 --> 00:12:31,985 +不同渲染器的文档 + +170 +00:12:32,953 --> 00:12:36,223 +它将帮助您理解它们之间的差异 + +171 +00:12:36,256 --> 00:12:39,126 +解释它们支持哪些 USD 功能 + +172 +00:12:39,159 --> 00:12:43,230 +并为您提供如何编写最适合您的 +USD 的指导 + +173 +00:12:44,364 --> 00:12:48,168 +Apple 平台上的渲染器之一 +是 RealityKit + +174 +00:12:48,202 --> 00:12:51,171 +它具有逼真的渲染系统 + +175 +00:12:51,205 --> 00:12:55,008 +为交互式增强现实体验进行了优化 + +176 +00:12:55,042 --> 00:12:57,110 +并被用于 AR 快速查看 + +177 +00:12:57,144 --> 00:12:59,880 +它是 USDZ 文件的主要渲染器 + +178 +00:13:00,814 --> 00:13:07,588 +在 macOS 上使用 USD 渲染的 +另一个选择是皮克斯的开源渲染器 Storm + +179 +00:13:07,621 --> 00:13:10,190 +它针对生产级 asset 进行优化设计 + +180 +00:13:10,224 --> 00:13:13,627 +被用于大型场景的实时预览 + +181 +00:13:14,661 --> 00:13:18,699 +这是一种很好的技术 +可以让您在内容创建途径中 + +182 +00:13:18,732 --> 00:13:21,435 +可视化和迭代 asset + +183 +00:13:22,402 --> 00:13:25,005 +Storm 使用了一种叫做 Hydra 的技术 + +184 +00:13:25,939 --> 00:13:30,978 +Hydra 是 USD 开源项目的核心方面 + +185 +00:13:31,011 --> 00:13:34,815 +接下来 让我们来了解一下 +Hydra 和 Storm 之间的联系 + +186 +00:13:35,649 --> 00:13:38,519 +我们从之前的这个图表开始 + +187 +00:13:38,552 --> 00:13:40,988 +这里 我们使用 Storm 作为渲染器 + +188 +00:13:42,189 --> 00:13:46,527 +输入通常被称为 “场景图” + +189 +00:13:46,560 --> 00:13:49,162 +Storm 会生成它的渲染预览 + +190 +00:13:50,364 --> 00:13:55,068 +但是 如果您想使用不同的渲染器 + +191 +00:13:55,102 --> 00:13:56,537 +生成相同场景的逼真图像呢 + +192 +00:13:57,538 --> 00:14:00,307 +这正是 Hydra 存在的意义 + +193 +00:14:00,340 --> 00:14:03,944 +Hydra 并没有将场景与渲染器 +紧密耦合 + +194 +00:14:03,977 --> 00:14:07,714 +而是充当了 +场景与渲染器之间的抽象层 + +195 +00:14:07,748 --> 00:14:10,551 +将数据从场景传输到渲染器 + +196 +00:14:11,752 --> 00:14:14,488 +这允许您在任何时候 +根据您的需要 + +197 +00:14:14,521 --> 00:14:19,393 +轻松切换渲染器 +而不需要改变您的场景图 + +198 +00:14:19,426 --> 00:14:23,297 +例如 您可以使用 Storm +和皮克斯的 RenderMan + +199 +00:14:24,431 --> 00:14:28,235 +在您的内容创建途径中 +您可以使用 Storm 快速渲染 + +200 +00:14:28,268 --> 00:14:29,736 +快速迭代 + +201 +00:14:29,770 --> 00:14:32,039 +然后在准备好后 + +202 +00:14:32,072 --> 00:14:34,208 +切换到 RenderMan +来生成最终的图像 + +203 +00:14:35,142 --> 00:14:38,212 +对场景图也是如此 + +204 +00:14:38,245 --> 00:14:42,916 +您对 Hydra 的输入可以是 +USD 场景图 也可以是不同的 + +205 +00:14:43,951 --> 00:14:48,288 +这允许您在多个 App 中 +使用相同的渲染器 + +206 +00:14:48,322 --> 00:14:53,627 +即使每个 App +都有自己完全不同的场景图 + +207 +00:14:53,660 --> 00:14:57,731 +连接 Hydra 与场景图 +和渲染器的接口 + +208 +00:14:57,764 --> 00:14:59,900 +被称为委托 + +209 +00:14:59,933 --> 00:15:04,137 +场景图通过场景委托 +连接到 Hydra + +210 +00:15:04,171 --> 00:15:07,875 +渲染器通过渲染委托 +连接到 Hydra + +211 +00:15:08,542 --> 00:15:10,477 +这就是您的 Hydra + +212 +00:15:11,245 --> 00:15:15,816 +Foundry's Nuke 13 +已经在用 Hydra 渲染视口了 + +213 +00:15:15,849 --> 00:15:19,486 +这使 macOS 上的 Nuke 设计师 +有更高质的体验 + +214 +00:15:19,520 --> 00:15:22,589 +并与用 Nuke 的 3D 系统的设计师 +有互动体验 + +215 +00:15:23,657 --> 00:15:27,060 +这是通过使用 Hydra +与自定义场景委托 + +216 +00:15:27,094 --> 00:15:28,862 +和 Metal-accelerated Storm 实现的 + +217 +00:15:30,063 --> 00:15:33,767 +我们要很高兴地告诉大家 +我们已经与皮克斯动画工作室合作 + +218 +00:15:33,800 --> 00:15:38,972 +公开发行 +Metal accelerated Storm 的开源版本 + +219 +00:15:39,006 --> 00:15:42,442 +您可以在 USD 22.05 中使用它 + +220 +00:15:43,243 --> 00:15:45,579 +现在我们已经看到了 Hydra 的力量 + +221 +00:15:45,612 --> 00:15:47,781 +让我们看一个有着 +USD 场景图 用 Storm 作为渲染器的 + +222 +00:15:47,814 --> 00:15:51,051 +典型用例的 + +223 +00:15:51,084 --> 00:15:53,487 +Hydra 示例 App + +224 +00:15:53,520 --> 00:15:57,291 +它将让您能开始使用 Hydra +构建内容创建工具 + +225 +00:15:57,324 --> 00:15:59,560 +和 3D 工作流 App + +226 +00:16:00,427 --> 00:16:05,899 +我们的示例 App HydraPlayer +非常简单但功能强大 + +227 +00:16:05,933 --> 00:16:10,771 +它用 Storm 渲染了一个 USD 文件 +让我们能在它周围移动相机 + +228 +00:16:12,172 --> 00:16:14,241 +我们很高兴能让 HydraPlayer + +229 +00:16:14,274 --> 00:16:18,378 +成为一个公共样本项目 +让您马上开始使用 + +230 +00:16:18,412 --> 00:16:21,315 +它可以在会话资源中找到 + +231 +00:16:21,348 --> 00:16:23,183 +并在自述文件中提供了完整的说明 + +232 +00:16:24,384 --> 00:16:27,221 +我鼓励开发者现在暂停这个视频 + +233 +00:16:27,254 --> 00:16:31,058 +下载这个项目 然后跟着我们一起看 + +234 +00:16:32,326 --> 00:16:35,896 +在您的 Xcode 项目中 +您会发现 4 个类 + +235 +00:16:35,929 --> 00:16:41,068 +AppDelegate 相机 渲染器 +和 View Controller + +236 +00:16:41,101 --> 00:16:44,071 +AppDelegate 基本上 +就是您的根对象 + +237 +00:16:44,104 --> 00:16:46,273 +会管理与系统的交互 + +238 +00:16:47,040 --> 00:16:49,776 +相机类是 USD 场景摄像机的 + +239 +00:16:49,810 --> 00:16:51,545 +一个简单表示 + +240 +00:16:51,578 --> 00:16:53,947 +以便于转换用户输入 + +241 +00:16:54,882 --> 00:16:58,886 +渲染器类将处理我们 +与 USD 和 Hydra 的所有交互 + +242 +00:16:59,920 --> 00:17:04,124 +最后 ViewController +会处理我们的用户输入 + +243 +00:17:05,092 --> 00:17:08,795 +在我们构建 启动 HydraPlayer 之前 +有三件事要做 + +244 +00:17:09,897 --> 00:17:14,434 +准备环境 在搭载 Apple 芯片的 +Mac 上使用 Rosetta + +245 +00:17:14,468 --> 00:17:16,870 +以及下载并构建 USD & Hydra + +246 +00:17:16,904 --> 00:17:18,372 +那么就让我们开始吧 + +247 +00:17:20,007 --> 00:17:23,010 +首先 我们要准备开发环境 + +248 +00:17:23,043 --> 00:17:27,247 +确保您已经安装了 Xcode +Python 和 CMake + +249 +00:17:29,716 --> 00:17:32,553 +现在 让我们打开一个终端 +来进行其他两个步骤 + +250 +00:17:34,087 --> 00:17:38,292 +如果您使用的是搭载 Apple 芯片的 Mac +那么您需要在 Rosetta 下运行 + +251 +00:17:38,325 --> 00:17:42,496 +而 USD 正在过渡到完全支持 arm64 + +252 +00:17:42,529 --> 00:17:45,065 +为此 使用 arch 命令 + +253 +00:17:46,600 --> 00:17:49,937 +一旦您的环境准备好了 +我们就必须下载 USD + +254 +00:17:49,970 --> 00:17:52,005 +和 Hydra 源代码 + +255 +00:17:52,039 --> 00:17:57,110 +两者都在同一个 GitHub 存储库 +PixarAnimationStudios/USD 中 + +256 +00:17:57,978 --> 00:18:01,148 +现在我们有了代码 +就可以构建它了 + +257 +00:18:01,181 --> 00:18:04,818 +USD 自带一个方便的 +Python 构建脚本 + +258 +00:18:04,852 --> 00:18:09,323 +我们添加标志 “generator Xcode” +和 “no-python” + +259 +00:18:09,356 --> 00:18:12,226 +并指定我们想要安装 USD 的位置 + +260 +00:18:13,160 --> 00:18:16,997 +让我们把它放在源代码 +“USDInstall” 旁边 + +261 +00:18:17,030 --> 00:18:21,201 +一旦 USD 完成建设 +我们就准备好建立 HydraPlayer 了 + +262 +00:18:22,169 --> 00:18:26,507 +让我们再次回到这个图表 +并使用它来确定 HydraPlayer 的 + +263 +00:18:26,540 --> 00:18:29,443 +关键部分 以详细检查 + +264 +00:18:30,344 --> 00:18:36,183 +我们要看看如何加载 3D 模型 +如何设置相机 + +265 +00:18:36,216 --> 00:18:38,552 +以及设置场景灯光 + +266 +00:18:38,585 --> 00:18:42,389 +然后我们将学习 +如何得到我们的场景图传到 Storm + +267 +00:18:42,422 --> 00:18:46,126 +最后 如何制作一个应用窗口的图像 + +268 +00:18:47,160 --> 00:18:50,964 +所以让我们从由 USD +加载我们的 3D 模型开始 + +269 +00:18:50,998 --> 00:18:56,170 +在 ViewController 的 viewDidAppear 中 +当视图第一次出现时 + +270 +00:18:56,203 --> 00:18:59,806 +我们要用一个 NSOpenPanel +创建一个文件选择器 + +271 +00:19:01,875 --> 00:19:04,645 +一旦选择了一个文件 + +272 +00:19:04,678 --> 00:19:07,981 +渲染器就可以开始 +设置我们的场景并加载 USD 文件 + +273 +00:19:09,049 --> 00:19:12,786 +使用 USD API 加载文件非常简单 + +274 +00:19:12,819 --> 00:19:15,956 +我们只需在文件路径上打开 USD 阶段 + +275 +00:19:17,824 --> 00:19:19,793 +就是这样 我们的文件加载完成了 + +276 +00:19:20,961 --> 00:19:26,466 +接下来 我们要设置相机 +在我们的代码中 这很直接 + +277 +00:19:26,500 --> 00:19:30,237 +我们首先要在 setupCamera 中 +创建一个新的场景摄像机 + +278 +00:19:31,738 --> 00:19:36,543 +然后 我们要根据场景 +计算世界的大小和中心 + +279 +00:19:37,377 --> 00:19:43,550 +接下来 移动我们的相机 +至一个良好的距离 然后聚焦在中心 + +280 +00:19:43,584 --> 00:19:46,787 +这样 我们的相机 +就能捕捉到整个场景 + +281 +00:19:47,988 --> 00:19:50,324 +太好了 现在我们的相机就设置好了 + +282 +00:19:50,357 --> 00:19:54,061 +接下来 灯光 + +283 +00:19:54,094 --> 00:19:59,266 +我们让它保持简单 +创建一个简单的环境光 + +284 +00:19:59,299 --> 00:20:03,971 +并将它的位置设置成与相机匹配 +就这样 + +285 +00:20:04,004 --> 00:20:09,910 +这样 我们就有了 有着3D 模型 +相机和灯光的完整场景 + +286 +00:20:09,943 --> 00:20:13,947 +现在我们可以把场景交给 Storm 了 + +287 +00:20:13,981 --> 00:20:17,951 +首先 我们需要初始化渲染引擎 + +288 +00:20:17,985 --> 00:20:24,892 +在这里 我们创建了一个新的 +UsdImagingGLEngine 它是 Storm 的类名 + +289 +00:20:24,925 --> 00:20:28,762 +这里最重要的参数是 rootPath + +290 +00:20:28,795 --> 00:20:33,100 +它将引擎指向我们 +包含 3D 模型的 USD stage + +291 +00:20:33,133 --> 00:20:37,171 +要深入了解其他参数和 +UsdImagingGLEngine + +292 +00:20:37,204 --> 00:20:40,440 +请查看皮克斯的 USD API 文档 + +293 +00:20:41,575 --> 00:20:45,779 +接下来 要在引擎中设置 +我们的摄像机 + +294 +00:20:45,812 --> 00:20:48,849 +并设置光线设置 + +295 +00:20:48,882 --> 00:20:53,053 +最后 我们要通过设置渲染参数 + +296 +00:20:53,086 --> 00:20:55,155 +来定义我们想要 Storm 渲染的方式 + +297 +00:20:55,856 --> 00:20:59,126 +例如 当我们想要 +渲染一个透明的背景 + +298 +00:20:59,159 --> 00:21:03,030 +以便渲染后的图像 +与我们应用的配色方案好好配合时 + +299 +00:21:03,730 --> 00:21:05,966 +这对于带有动画的场景很重要 + +300 +00:21:05,999 --> 00:21:08,535 +因为这也是我们指定时间代码的地方 + +301 +00:21:10,337 --> 00:21:12,472 +现在我们准备好渲染图像了 + +302 +00:21:13,740 --> 00:21:16,510 +我们已经完成了所有必要的设置 + +303 +00:21:16,543 --> 00:21:19,813 +因此渲染命令只有一行代码 + +304 +00:21:20,614 --> 00:21:26,086 +我们获得结果并将其显示在窗口中 +然后就完成了 + +305 +00:21:26,119 --> 00:21:28,689 +我们正在渲染 USD 玩具飞机 + +306 +00:21:28,722 --> 00:21:31,825 +实际上 我们在渲染的 +不仅仅是一个飞机 + +307 +00:21:31,859 --> 00:21:35,929 +HydraPlayer 可以轻松地 +用数千万个三角形 + +308 +00:21:35,963 --> 00:21:37,998 +渲染数千个动画 asset + +309 +00:21:39,166 --> 00:21:42,636 +如果您还没有这么做 +请查看本讲座的资源 + +310 +00:21:42,669 --> 00:21:45,806 +下载示例项目 +并享受进一步探索它的乐趣 + +311 +00:21:47,074 --> 00:21:50,511 +我们一起探索了 Apple 的 +USD 工具的更新 + +312 +00:21:50,544 --> 00:21:54,581 +它们使这些工具更强大 +也使您的 asset 看起来更棒 + +313 +00:21:54,615 --> 00:21:56,717 +Stella: 我们了解了 Hydra 的功能 + +314 +00:21:56,750 --> 00:21:59,820 +并浏览了 HydraPlayer 示例项目 + +315 +00:21:59,853 --> 00:22:03,223 +看到了如何将其集成到 +自己的 App 中 + +316 +00:22:04,525 --> 00:22:08,128 +要了解更多关于 USD 的重要概念 + +317 +00:22:08,161 --> 00:22:11,698 +请查看讲座 +“Understand USD fundamentals” + +318 +00:22:12,866 --> 00:22:14,468 +谢谢 + +319 +00:22:14,501 --> 00:22:16,436 +[古怪的音乐] + diff --git a/zho/2022 Session 10142 Efficiency awaits - Background tasks in SwiftUI.srt b/zho/2022 Session 10142 Efficiency awaits - Background tasks in SwiftUI.srt new file mode 100644 index 0000000..605c308 --- /dev/null +++ b/zho/2022 Session 10142 Efficiency awaits - Background tasks in SwiftUI.srt @@ -0,0 +1,1068 @@ +1 +00:00:00,234 --> 00:00:03,470 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,470 --> 00:00:09,409 +♪ + +3 +00:00:09,409 --> 00:00:13,280 +欢迎收看 +“静候高效:SwiftUI 的后台任务” + +4 +00:00:13,280 --> 00:00:17,050 +我是 watchOS 框架团队 +的工程师 John Gallagher + +5 +00:00:17,050 --> 00:00:20,420 +本期视频将介绍 +一个全新 SwiftUI API + +6 +00:00:20,420 --> 00:00:22,990 +该 API 可运用 Swift 并发性 +来处理后台任务 + +7 +00:00:22,990 --> 00:00:26,493 +且在 Apple 的所有平台上 +都能够平稳运行 + +8 +00:00:26,493 --> 00:00:29,930 +首先 我们将以一款名为 +Stormy 的 App 作为示例 + +9 +00:00:29,930 --> 00:00:32,599 +该 App 专用于 +在暴风雨天气拍摄天空 + +10 +00:00:32,599 --> 00:00:36,236 +其中就用到了后台任务 + +11 +00:00:36,236 --> 00:00:39,940 +接着 我们将深入了解 +App 是如何使用后台任务的 + +12 +00:00:39,940 --> 00:00:44,811 +后台任务又是如何在幕后工作的 + +13 +00:00:44,811 --> 00:00:48,081 +接下去 我们将介绍 +如何使用新的 SwiftUI API + +14 +00:00:48,081 --> 00:00:52,319 +来处理后台任务 + +15 +00:00:52,319 --> 00:00:57,124 +最后是回顾该 API +如何通过运用 Swift 并发性 + +16 +00:00:57,124 --> 00:01:03,096 +将后台任务简化到了前所未有的程度 + +17 +00:01:03,096 --> 00:01:07,568 +新的 API 在多种平台通用 +如 watchOS iOS tvOS + +18 +00:01:07,568 --> 00:01:09,503 +Mac Catalyst 和小组件 + +19 +00:01:09,503 --> 00:01:11,972 +包括运行于 Mac 的 iOS App + +20 +00:01:11,972 --> 00:01:13,874 +也就是说 您学会在一个平台 + +21 +00:01:13,874 --> 00:01:15,976 +处理后台任务后 + +22 +00:01:15,976 --> 00:01:19,046 +其概念和模式也适用于其他平台 + +23 +00:01:19,046 --> 00:01:22,683 +新 API 通过 Swift 并发性 + +24 +00:01:22,683 --> 00:01:25,319 +减少了深度嵌套的 +完成处理程序及回调的需要 + +25 +00:01:25,319 --> 00:01:26,987 +因此也自然而然地 + +26 +00:01:26,987 --> 00:01:29,923 +减少了大部分可变状态 + +27 +00:01:29,923 --> 00:01:32,492 +有了 Swift 并发性原生的 +任务取消功能 + +28 +00:01:32,492 --> 00:01:35,863 +App 能够以合适方式 +及时完成任务 + +29 +00:01:35,863 --> 00:01:40,100 +不必被系统关闭后台进程 + +30 +00:01:40,100 --> 00:01:42,402 +我们所开发的这款 +名为 Stormy 的 App + +31 +00:01:42,402 --> 00:01:44,338 +适合爱好拍摄云层的用户 + +32 +00:01:44,338 --> 00:01:46,507 +该 App 能够在 +风雨即将到来的时候 + +33 +00:01:46,507 --> 00:01:49,076 +提醒用户拍摄时机 + +34 +00:01:49,076 --> 00:01:51,945 +如果当天有暴风雨 +该 App 将在中午显示通知 + +35 +00:01:51,945 --> 00:01:56,884 +提醒用户拍摄天空 + +36 +00:01:56,884 --> 00:01:58,719 +用户只需要点击通知 + +37 +00:01:58,719 --> 00:02:01,121 +就能够拍摄天空 +并将照片上传到个人资料 + +38 +00:02:01,121 --> 00:02:03,090 +以供日后欣赏 + +39 +00:02:03,090 --> 00:02:07,561 +这张照片将在后台上传 + +40 +00:02:07,561 --> 00:02:09,196 +上传完成后 + +41 +00:02:09,196 --> 00:02:11,965 +该 App 会再次通知 + +42 +00:02:11,965 --> 00:02:15,602 +让我们深入了解下 +后台任务是如何做到的 + +43 +00:02:15,602 --> 00:02:18,372 +我们将运用这张图表 +站在更高层次观察 + +44 +00:02:18,372 --> 00:02:20,274 +看看如何运用后台任务 + +45 +00:02:20,274 --> 00:02:23,677 +做到只在暴风雨天气发送通知 + +46 +00:02:23,677 --> 00:02:26,280 +我们将用左边的进度条 + +47 +00:02:26,280 --> 00:02:28,282 +表示 App 的前台运行时间 + +48 +00:02:28,282 --> 00:02:32,219 +中间的进度条表示 +App 后台运行时间 + +49 +00:02:32,219 --> 00:02:36,857 +右侧的则是系统运行时间 + +50 +00:02:36,857 --> 00:02:40,027 +当该 App 第一次被前台启动时 + +51 +00:02:40,027 --> 00:02:41,728 +这是我们的第一个时机 + +52 +00:02:41,728 --> 00:02:46,834 +可以安排一个中午时 +后台刷新 App 的任务 + +53 +00:02:46,834 --> 00:02:50,971 +由此 当 App +因用户退出被暂停时 + +54 +00:02:50,971 --> 00:02:53,540 +系统将按照预定的时间 + +55 +00:02:53,540 --> 00:02:57,544 +在后台再次唤醒我们的 App + +56 +00:02:57,544 --> 00:02:59,913 +我们把任务安排在中午 + +57 +00:02:59,913 --> 00:03:02,416 +这样系统就会 +按时在后台唤醒 App + +58 +00:03:02,416 --> 00:03:07,421 +并发送后台 App 刷新任务 + +59 +00:03:07,421 --> 00:03:08,922 +安排好了后台运行时间 + +60 +00:03:08,922 --> 00:03:11,325 +接下来 我们需要弄清楚 +外面是否是暴风雨天气 + +61 +00:03:11,325 --> 00:03:16,029 +确认后再向用户发送通知 + +62 +00:03:16,029 --> 00:03:19,366 +一开始 我们将向天气服务 +发出网络请求 + +63 +00:03:19,366 --> 00:03:22,703 +来检查当前天气 + +64 +00:03:22,703 --> 00:03:25,272 +URL 会话已经安排在后台 + +65 +00:03:25,272 --> 00:03:26,974 +App 可以暂停 + +66 +00:03:26,974 --> 00:03:30,711 +以等待网络请求完成 + +67 +00:03:30,711 --> 00:03:32,179 +当获取天气数据的请求 + +68 +00:03:32,179 --> 00:03:33,780 +在后台完成后 + +69 +00:03:33,780 --> 00:03:36,850 +我们的 App 将 +使用新的 URL 会话任务 + +70 +00:03:36,850 --> 00:03:41,855 +在后台继续运行 + +71 +00:03:41,855 --> 00:03:44,892 +有了天气数据请求的结果 + +72 +00:03:44,892 --> 00:03:47,961 +我们的 App 就知道了 +是否有暴风雨天气 + +73 +00:03:47,961 --> 00:03:50,097 +并且可以选择是否发送通知 + +74 +00:03:50,097 --> 00:03:55,602 +来提醒用户拍摄天空照片 + +75 +00:03:55,602 --> 00:03:58,672 +现在 那个 URL 任务的工作 +已经完成 + +76 +00:03:58,672 --> 00:04:02,943 +系统可以再次暂停 App + +77 +00:04:02,943 --> 00:04:06,013 +让我们继续深入 +看看单个后台任务的详情 + +78 +00:04:06,013 --> 00:04:07,814 +看看它是如何工作的 + +79 +00:04:07,814 --> 00:04:11,351 +为此 需要仔细观察 +单个 App 刷新 + +80 +00:04:11,351 --> 00:04:14,321 +后台任务的生命周期 + +81 +00:04:14,321 --> 00:04:19,026 +来把这里放大一点 + +82 +00:04:19,026 --> 00:04:21,962 +首先 系统会唤醒我们的 App + +83 +00:04:21,962 --> 00:04:25,732 +并向其发送 App 刷新后台任务 + +84 +00:04:25,732 --> 00:04:29,236 +然后 我们在后台继续发出网络请求 + +85 +00:04:29,236 --> 00:04:32,840 +查看外面是否为暴风雨天气 + +86 +00:04:32,840 --> 00:04:35,776 +理想情况下 +在分配给该 App 刷新 + +87 +00:04:35,776 --> 00:04:38,745 +的后台运行时时间内 + +88 +00:04:38,745 --> 00:04:41,949 +网络请求就能完成 + +89 +00:04:41,949 --> 00:04:43,650 +得到网络响应后 + +90 +00:04:43,650 --> 00:04:47,154 +就可以立即发布通知 + +91 +00:04:47,154 --> 00:04:48,856 +通知发出后 + +92 +00:04:48,856 --> 00:04:52,192 +刷新期间需要做的事情都已完成 + +93 +00:04:52,192 --> 00:04:56,296 +系统可以再次暂停 App + +94 +00:04:56,296 --> 00:04:59,233 +但是 如果获取天气数据的请求 + +95 +00:04:59,233 --> 00:05:02,069 +没有及时完成呢? + +96 +00:05:02,069 --> 00:05:04,838 +如果 App 在处理当前任务时 + +97 +00:05:04,838 --> 00:05:06,240 +后台运行时间不足 + +98 +00:05:06,240 --> 00:05:08,942 +系统会向 App 发出 +时间不足的信号 + +99 +00:05:08,942 --> 00:05:13,113 +提醒我们好好处理这种情况 + +100 +00:05:13,113 --> 00:05:15,516 +如果在后台运作时间结束之前 + +101 +00:05:15,516 --> 00:05:18,118 +App 尚未发出任务完成信号 + +102 +00:05:18,118 --> 00:05:20,721 +App 可能会被系统退出 + +103 +00:05:20,721 --> 00:05:24,525 +也无法发送未来的后台任务请求 + +104 +00:05:24,525 --> 00:05:27,427 +在这种情况下 应该要 +确保我们的网络请求 + +105 +00:05:27,427 --> 00:05:29,830 +是后台网络请求 + +106 +00:05:29,830 --> 00:05:33,233 +才能够立即完成 App 刷新任务 + +107 +00:05:33,233 --> 00:05:34,468 +然后再次唤醒 + +108 +00:05:34,468 --> 00:05:36,103 +来争取额外的后台运行时间 + +109 +00:05:36,103 --> 00:05:39,840 +直到网络请求完成 + +110 +00:05:39,840 --> 00:05:42,075 +后台 URL 会话安排下去后 + +111 +00:05:42,075 --> 00:05:45,646 +系统可以再次暂停 App + +112 +00:05:45,646 --> 00:05:49,783 +接下来 让我们深入了解 +SwiftUI 的后台任务 API + +113 +00:05:49,783 --> 00:05:52,686 +是如何帮助我们 +构建 Stormy 的 + +114 +00:05:52,686 --> 00:05:56,356 +首先 我们需要一个基础 App + +115 +00:05:56,356 --> 00:06:00,294 +然后 我们将编写一个函数 +来让后台 App + +116 +00:06:00,294 --> 00:06:02,796 +在明天中午刷新 + +117 +00:06:02,796 --> 00:06:07,601 +先创建一个代表明天中午的日期 + +118 +00:06:07,601 --> 00:06:10,904 +接着创建一个 +后台 App 刷新请求 + +119 +00:06:10,904 --> 00:06:13,407 +最早开始日期为明天中午 + +120 +00:06:13,407 --> 00:06:15,742 +将其提交给调度程序 + +121 +00:06:15,742 --> 00:06:18,078 +这样 就能够让系统在明天中午 + +122 +00:06:18,078 --> 00:06:21,014 +唤醒 App + +123 +00:06:21,014 --> 00:06:22,916 +我们想要在用户 +第一次打开 App 时 + +124 +00:06:22,916 --> 00:06:25,118 +以及每天中午请求天气数据的时候 + +125 +00:06:25,118 --> 00:06:29,122 +调用这个函数 + +126 +00:06:29,122 --> 00:06:31,225 +我们可以使用 +新的后台任务场景修饰符 + +127 +00:06:31,225 --> 00:06:32,860 +来注册一个和已安排后台任务 + +128 +00:06:32,860 --> 00:06:38,098 +相对应的处理程序 + +129 +00:06:38,098 --> 00:06:40,367 +当 App 收到后台任务时 + +130 +00:06:40,367 --> 00:06:42,636 +使用此修饰符注册的块会开始运行 + +131 +00:06:42,636 --> 00:06:46,440 +而该修饰符必须 +与收到的后台任务匹配 + +132 +00:06:46,440 --> 00:06:50,177 +在本例中 我们使用的 +任务类型是 appRefresh + +133 +00:06:50,177 --> 00:06:51,745 +该类型可以提前安排 + +134 +00:06:51,745 --> 00:06:54,448 +来为 App 在指定日期 + +135 +00:06:54,448 --> 00:06:57,584 +提供一定的后台运行时间 + +136 +00:06:57,584 --> 00:06:59,953 +请求和后台任务修饰符中的处理程序 + +137 +00:06:59,953 --> 00:07:02,823 +使用相同的标识符 + +138 +00:07:02,823 --> 00:07:05,592 +这样能够在您的 +App 收到相应任务时 + +139 +00:07:05,592 --> 00:07:10,731 +让系统识别出要调用的处理程序 + +140 +00:07:10,731 --> 00:07:12,266 +为了能够保证 + +141 +00:07:12,266 --> 00:07:14,134 +下一天继续安排任务 + +142 +00:07:14,134 --> 00:07:16,370 +我们将通过调用刚刚编写的 +scheduleAppRefresh 函数 + +143 +00:07:16,370 --> 00:07:19,339 +来启动我们的后台任务 + +144 +00:07:19,339 --> 00:07:24,912 +好在明天中午 +再次安排后台运行时间 + +145 +00:07:24,912 --> 00:07:28,282 +现在 安排在中午的 +后台任务再次启动了 + +146 +00:07:28,282 --> 00:07:29,783 +提出网络请求 + +147 +00:07:29,783 --> 00:07:31,718 +检查外面是否有暴风雨 + +148 +00:07:31,718 --> 00:07:36,323 +并使用 Swift 关键字 +await 来等待结果 + +149 +00:07:36,323 --> 00:07:38,859 +那么 如果网络请求返回后显示 + +150 +00:07:38,859 --> 00:07:40,928 +确实是暴风雨天气 + +151 +00:07:40,928 --> 00:07:43,697 +就可以等着向用户发送通知 + +152 +00:07:43,697 --> 00:07:46,834 +提醒他们上传天空照片 + +153 +00:07:46,834 --> 00:07:48,902 +当我们的闭包体返回时 + +154 +00:07:48,902 --> 00:07:50,404 +系统分配给我们 App 的 + +155 +00:07:50,404 --> 00:07:52,306 +底层后台任务 + +156 +00:07:52,306 --> 00:07:54,708 +将被隐式标记为完成 + +157 +00:07:54,708 --> 00:07:58,512 +系统可以再次暂停我们的 App + +158 +00:07:58,512 --> 00:08:01,748 +使用 Swift 并发性 +可以在有需要时 + +159 +00:08:01,748 --> 00:08:04,251 +进行需要长时间操作的后台任务 + +160 +00:08:04,251 --> 00:08:06,420 +且无需在工作完成时 + +161 +00:08:06,420 --> 00:08:08,589 +进行显式回调 + +162 +00:08:08,589 --> 00:08:11,024 +Apple 平台上的许多 API + +163 +00:08:11,024 --> 00:08:12,726 +例如添加通知 + +164 +00:08:12,726 --> 00:08:14,661 +已经支持将 Swift 并发 + +165 +00:08:14,661 --> 00:08:16,830 +用于异步操作 + +166 +00:08:16,830 --> 00:08:20,000 +这是照片 notifyForPhoto + +167 +00:08:20,000 --> 00:08:22,135 +直接就可以使用 + +168 +00:08:22,135 --> 00:08:24,805 +使用的异步添加通知方法 + +169 +00:08:24,805 --> 00:08:29,076 +可以在 UserNotificationCenter 找到 + +170 +00:08:29,076 --> 00:08:32,513 +让我们深入说说 该如何在一些 +繁重工作中应用 + +171 +00:08:32,513 --> 00:08:34,314 +Swift 并发性和异步/等待 + +172 +00:08:34,314 --> 00:08:38,452 +让处理后台任务变得比以往更容易 + +173 +00:08:38,452 --> 00:08:41,121 +还是使用本期的示例 + +174 +00:08:41,121 --> 00:08:43,490 +让我们编写异步 isStormy 函数 + +175 +00:08:43,490 --> 00:08:46,293 +异步功能需要发出网络请求 + +176 +00:08:46,293 --> 00:08:49,563 +来检查外面的天气 + +177 +00:08:49,563 --> 00:08:52,199 +首先 我们将获得 +共享的 URL 会话 + +178 +00:08:52,199 --> 00:08:56,336 +并实例化对天气数据的请求 + +179 +00:08:56,336 --> 00:08:59,006 +URL 会话 +采用了 Swift 并发 + +180 +00:08:59,006 --> 00:09:01,275 +并且可以从异步上下文中等待的网络 + +181 +00:09:01,275 --> 00:09:06,480 +下载数据 + +182 +00:09:06,480 --> 00:09:08,582 +有了网络响应 + +183 +00:09:08,582 --> 00:09:12,786 +我们可以读取天气数据并返回结果 + +184 +00:09:12,786 --> 00:09:14,788 +但是当我们的 App + +185 +00:09:14,788 --> 00:09:16,657 +无法运行时间到期之前 + +186 +00:09:16,657 --> 00:09:19,927 +完成网络请求的话该怎么办呢 + +187 +00:09:19,927 --> 00:09:23,297 +回想一下 在这种情况下需要保证 + +188 +00:09:23,297 --> 00:09:27,167 +已经将 URL 会话 +设置为后台会话 + +189 +00:09:27,167 --> 00:09:30,103 +并确保其将使用 +URL 会话后台任务 + +190 +00:09:30,103 --> 00:09:34,441 +把启动事件发送到 App + +191 +00:09:34,441 --> 00:09:37,010 +回到代码 + +192 +00:09:37,010 --> 00:09:41,448 +我们使用了共享的 URL 会话 + +193 +00:09:41,448 --> 00:09:44,451 +相反 我们这次应该从后台配置 + +194 +00:09:44,451 --> 00:09:46,954 +创建一个 URL 会话 + +195 +00:09:46,954 --> 00:09:51,191 +且将 sessionSendsLaunchEvents +属性设置为 true + +196 +00:09:51,191 --> 00:09:54,661 +以此 即使 App 暂停 +也能让系统 + +197 +00:09:54,661 --> 00:09:58,398 +运行部分网络请求 +然后唤醒 App + +198 +00:09:58,398 --> 00:10:02,903 +继续完成 URL 会话后台任务 + +199 +00:10:02,903 --> 00:10:06,373 +请注意 这在 +watchOS 上尤为重要 + +200 +00:10:06,373 --> 00:10:09,409 +因为在 watchOS 上 +后台 App 的所有网络请求 + +201 +00:10:09,409 --> 00:10:16,049 +都必须通过 +后台 URL 会话进行请求 + +202 +00:10:16,049 --> 00:10:18,318 +不过 目前为止还没有完成 + +203 +00:10:18,318 --> 00:10:22,322 +回想一下 当后台任务运行时到期时 + +204 +00:10:22,322 --> 00:10:24,391 +系统将取消异步任务 + +205 +00:10:24,391 --> 00:10:26,026 +而该任务正在运行 + +206 +00:10:26,026 --> 00:10:28,929 +提供给后台任务修饰符的闭包 + +207 +00:10:28,929 --> 00:10:32,466 +这意味着 后台运行时到期时 + +208 +00:10:32,466 --> 00:10:38,772 +从这里发出的网络请求也将被取消 + +209 +00:10:38,772 --> 00:10:41,041 +为了对任务取消进行响应和处理 + +210 +00:10:41,041 --> 00:10:43,810 +我们可以使用 +Swift 并发内置的 + +211 +00:10:43,810 --> 00:10:47,114 +withTaskCancellationHandler +即 任务取消处理程序函数 + +212 +00:10:47,114 --> 00:10:49,483 +而不是单单等待结果 + +213 +00:10:49,483 --> 00:10:54,721 +我们将下载放入 +withTaskCancellationHandler 的调用中 + +214 +00:10:54,721 --> 00:10:57,057 +和其他的一起等待 + +215 +00:10:57,057 --> 00:11:00,327 +传递给 withTaskCancellationHandler +的第一个块 + +216 +00:11:00,327 --> 00:11:03,897 +是我们想要运行和等待的异步过程 + +217 +00:11:03,897 --> 00:11:07,768 +第二个尾随闭包的 +onCancel 是将运行的代码 + +218 +00:11:07,768 --> 00:11:10,237 +当任务被取消时 + +219 +00:11:10,237 --> 00:11:13,507 +看这里 当即时网络请求 + +220 +00:11:13,507 --> 00:11:15,442 +由于运行时间到期被取消时 + +221 +00:11:15,442 --> 00:11:19,112 +将网络请求提升为后台下载任务 + +222 +00:11:19,112 --> 00:11:20,647 +可以用于调用恢复 + +223 +00:11:20,647 --> 00:11:23,150 +触发即使 App 暂停 + +224 +00:11:23,150 --> 00:11:26,286 +也会继续运行的后台下载 + +225 +00:11:26,286 --> 00:11:30,023 +此代码没有发出两次底层网络请求 + +226 +00:11:30,023 --> 00:11:33,227 +因为背后使用的是 +相同的 URL 会话 + +227 +00:11:33,227 --> 00:11:36,930 +而 URL 会话将在后台删除 + +228 +00:11:36,930 --> 00:11:41,301 +重复的进程中请求 + +229 +00:11:41,301 --> 00:11:44,605 +最后 需要确保 +App 已完成设置 + +230 +00:11:44,605 --> 00:11:48,275 +以处理后台 URL 会话的启动 + +231 +00:11:48,275 --> 00:11:51,078 +我们可以再次使用后台任务修饰符 + +232 +00:11:51,078 --> 00:11:54,781 +但这次是 URL 会话任务类型 + +233 +00:11:54,781 --> 00:11:56,483 +通过使用和之前的 + +234 +00:11:56,483 --> 00:11:59,887 +后台 URL 会话 +配置相同的标识符 + +235 +00:11:59,887 --> 00:12:02,756 +我们可以确保这个块只在 + +236 +00:12:02,756 --> 00:12:08,662 +特定的 URL 会话产生 +后台任务时被调用 + +237 +00:12:08,662 --> 00:12:12,132 +我们已经深入了解了 +用于处理后台任务的 + +238 +00:12:12,132 --> 00:12:13,767 +全新统一 SwiftUI API + +239 +00:12:13,767 --> 00:12:16,303 +也知道了 Swift 并发性 +如何简化了 + +240 +00:12:16,303 --> 00:12:20,607 +管理任务完成和到期的过程 + +241 +00:12:20,607 --> 00:12:23,377 +有关 Swift 并发的更多信息 + +242 +00:12:23,377 --> 00:12:25,946 +请查看 WWDC 2021 讲话 + +243 +00:12:25,946 --> 00:12:29,049 +“Swift 中的异步/等待” + +244 +00:12:29,049 --> 00:12:31,385 +要了解更多 SwiftUI +并发性相关信息 + +245 +00:12:31,385 --> 00:12:34,054 +推荐收看同样是 +WWDC 2021 讲话的 + +246 +00:12:34,054 --> 00:12:37,090 +“在 SwiftUI 中发现并发” + +247 +00:12:37,090 --> 00:12:38,091 +感谢收看 + +248 +00:12:38,091 --> 00:12:41,795 +“静候高效:SwiftUI 的后台任务” + +249 +00:12:41,795 --> 00:12:46,133 +♪ + diff --git a/zho/2022 Session 10143 Discover Managed Device Attestation.srt b/zho/2022 Session 10143 Discover Managed Device Attestation.srt new file mode 100644 index 0000000..2d13bab --- /dev/null +++ b/zho/2022 Session 10143 Discover Managed Device Attestation.srt @@ -0,0 +1,1581 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,178 +Bob: 大家好 我是 Bob Whiteman + +3 +00:00:11,211 --> 00:00:13,747 +iOS 设备管理高级工程师 + +4 +00:00:13,780 --> 00:00:17,651 +我很高兴与大家分享企业和教育环境中 + +5 +00:00:17,684 --> 00:00:22,623 +设备管理的一个重要的安全新功能 + +6 +00:00:22,656 --> 00:00:26,593 +我们首先回顾一下设备安全现状 + +7 +00:00:26,627 --> 00:00:29,596 +用户需要访问组织资源 + +8 +00:00:29,630 --> 00:00:34,067 +如网站 应用服务器和数据库 + +9 +00:00:34,101 --> 00:00:39,006 +还有一些攻击者也想访问这些资源 + +10 +00:00:39,039 --> 00:00:43,277 +保护资源的经典模型是 +边界安全模型 + +11 +00:00:43,310 --> 00:00:46,413 +您在内网周围划出安全边界 + +12 +00:00:46,446 --> 00:00:49,216 +设置防火墙或 VPN + +13 +00:00:49,249 --> 00:00:53,020 +以允许合法客户端访问并拒绝威胁 + +14 +00:00:53,053 --> 00:00:59,259 +但这种模式并没有跟上 +人们与现代组织的互动方式 + +15 +00:00:59,293 --> 00:01:04,331 +云服务提供商将资源置于边界之外 + +16 +00:01:04,364 --> 00:01:07,501 +威胁可以从外围开始 + +17 +00:01:08,902 --> 00:01:13,707 +威胁可以通过冒用合法客户端 +来渗透防线 + +18 +00:01:15,442 --> 00:01:20,080 +更现代的安全模型不信任网络边界 + +19 +00:01:20,113 --> 00:01:24,451 +相反 每个资源执行自己的信任评估 + +20 +00:01:24,484 --> 00:01:28,188 +这是零信任架构的核心原则 + +21 +00:01:29,623 --> 00:01:33,193 +您可以将信任评估视为一个函数 + +22 +00:01:33,227 --> 00:01:36,864 +输入是关于客户端的状态信息 + +23 +00:01:36,897 --> 00:01:41,502 +输出是授予或拒绝访问的决定 + +24 +00:01:41,535 --> 00:01:45,873 +正确的信任评估至关重要 + +25 +00:01:45,906 --> 00:01:49,643 +误报会妨碍用户活动 + +26 +00:01:49,676 --> 00:01:55,682 +或者更糟糕的是 +误报允许攻击者访问您的资源 + +27 +00:01:55,716 --> 00:02:00,521 +这意味着 +掌握准确的状态信息也很重要 + +28 +00:02:00,554 --> 00:02:03,824 +我们来研究一下状态的常见组成部分 + +29 +00:02:03,857 --> 00:02:08,161 +您使用有关客户端及其请求的 +所有可用信息 + +30 +00:02:08,195 --> 00:02:09,897 +提出请求的人 + +31 +00:02:09,930 --> 00:02:13,667 +他们使用的设备 他们的位置等等 + +32 +00:02:13,700 --> 00:02:16,103 +信任评估可能在访问 + +33 +00:02:16,136 --> 00:02:20,240 +不同资源的状态中使用不同的细节 + +34 +00:02:20,274 --> 00:02:25,245 +访问低安全性的资源 +可能只需要用户的身份 + +35 +00:02:25,279 --> 00:02:30,684 +但访问关键的基础设施 +可能需要评估所有状态项 + +36 +00:02:30,717 --> 00:02:34,555 +由组织决定哪些细节是相关的 + +37 +00:02:36,190 --> 00:02:40,093 +状态的一个核心元素是用户的身份 + +38 +00:02:40,127 --> 00:02:42,896 +这表明谁在提出请求 + +39 +00:02:44,364 --> 00:02:48,435 +Apple 设备提供了几种 +支持验证用户身份的技术 + +40 +00:02:48,468 --> 00:02:51,605 +比如 Extensible Single Sign On 功能 + +41 +00:02:51,638 --> 00:02:54,208 +包括内置的 Kerberos 扩展 + +42 +00:02:54,241 --> 00:02:59,146 +以方便对 App 网站和 +帐户进行用户身份验证 + +43 +00:02:59,179 --> 00:03:02,015 +新的 +Enrollment Single Sign On feature + +44 +00:03:02,049 --> 00:03:05,853 +能让 App 在用户注册过程中 + +45 +00:03:05,886 --> 00:03:09,323 +及之后便于认证 + +46 +00:03:09,356 --> 00:03:12,359 +但本期讲座不是关于用户身份 + +47 +00:03:12,392 --> 00:03:15,262 +而是关于设备身份的 + +48 +00:03:15,295 --> 00:03:20,434 +此状态元素指示哪个设备 +正在发出请求 + +49 +00:03:22,102 --> 00:03:26,406 +设备在每次 MDM 通信中 +报告的 UDID + +50 +00:03:26,440 --> 00:03:31,945 +是您的 MDM 服务器知道它 +正在管理哪个设备的主要方式 + +51 +00:03:31,979 --> 00:03:35,582 +DeviceInformation 查询 +还提供设备的 + +52 +00:03:35,616 --> 00:03:39,887 +MDM 服务器属性 包括序列号 + +53 +00:03:39,920 --> 00:03:44,625 +除 MDM 服务器外 +受管理设备经常与组织内的 + +54 +00:03:44,658 --> 00:03:47,528 +其他系统通信 + +55 +00:03:47,561 --> 00:03:52,766 +因此 MDM 服务器经常使用 +客户端证书配置设备 + +56 +00:03:52,799 --> 00:03:57,504 +此证书向其他系统声明设备的身份 + +57 +00:03:57,538 --> 00:04:01,041 +这些识别设备的方法对我们很有帮助 + +58 +00:04:01,074 --> 00:04:06,980 +但它们等于相信 +这款设备就是它自称的那个样子 + +59 +00:04:07,014 --> 00:04:08,982 +随着形势的变化 + +60 +00:04:09,016 --> 00:04:11,818 +设备比以往任何时候都更加分散 + +61 +00:04:11,852 --> 00:04:14,488 +我们的安全需求也在不断变化 + +62 +00:04:14,521 --> 00:04:18,225 +为了解决该问题 我很高兴分享一个 +用于认证设备身份的 + +63 +00:04:18,258 --> 00:04:21,094 +强大新方法 + +64 +00:04:21,128 --> 00:04:24,598 +Managed Device Attestation + +65 +00:04:24,631 --> 00:04:30,237 +有了 Managed Device Attestation +设备将在发出请求时 + +66 +00:04:30,270 --> 00:04:32,039 +提供关于自身的有力证据 + +67 +00:04:32,072 --> 00:04:34,908 +它改进了状态信息 + +68 +00:04:34,942 --> 00:04:39,012 +因此 建立在这个基础上的 +信任评估更准确 + +69 +00:04:39,046 --> 00:04:43,283 +简言之 Managed Device Attestation +是指合法设备 + +70 +00:04:43,317 --> 00:04:48,889 +能够可靠地访问资源并阻止攻击者 + +71 +00:04:48,922 --> 00:04:53,360 +这个发布为 iOS 16 iPadOS 16 +和 tvOS 16 带来了 + +72 +00:04:53,393 --> 00:04:58,031 +Managed Device Attestation + +73 +00:04:58,065 --> 00:05:02,803 +本期讲座中 +我们将首先概述新的认证功能 + +74 +00:05:02,836 --> 00:05:06,673 +解释使用认证的好处 + +75 +00:05:06,707 --> 00:05:10,644 +然后深入到实现细节 + +76 +00:05:10,677 --> 00:05:14,648 +首先 什么是认证 + +77 +00:05:14,681 --> 00:05:18,185 +认证是对事实的声明 + +78 +00:05:18,218 --> 00:05:21,788 +如果您信任提出请求的实体 + +79 +00:05:21,822 --> 00:05:25,092 +您就接受了这是真实的事实 + +80 +00:05:25,125 --> 00:05:30,297 +在软件中 +认证是经过加密签名的事实 + +81 +00:05:30,330 --> 00:05:33,400 +通常是 X.509 证书 + +82 +00:05:33,433 --> 00:05:38,105 +如果您信任签名者 +那么您就会接受事实是真实的 + +83 +00:05:38,138 --> 00:05:40,674 +对于 Managed Device Attestation + +84 +00:05:40,707 --> 00:05:45,012 +事实是设备的身份和其他属性 + +85 +00:05:45,045 --> 00:05:47,648 +签名者是 Apple + +86 +00:05:47,681 --> 00:05:51,885 +接受这些设备事实的准确性 +需要信任 Apple + +87 +00:05:51,919 --> 00:05:57,658 +但是 不需要信任 +Apple 编写的每一行代码 + +88 +00:05:58,525 --> 00:06:01,795 +只需信任 Secure Enclave + +89 +00:06:01,828 --> 00:06:03,997 +和 Apple 的认证服务器 + +90 +00:06:04,031 --> 00:06:08,635 +这些服务器可以访问 Apple 的 +生产记录和操作系统目录 + +91 +00:06:08,669 --> 00:06:11,939 +如果您将数据保存在 Apple 设备上 + +92 +00:06:11,972 --> 00:06:15,309 +就是在毫无保留地信任这些设备 + +93 +00:06:15,342 --> 00:06:20,747 +以下是我们如何将认证的力量 +带到被管理的设备上 + +94 +00:06:20,781 --> 00:06:26,119 +Managed Device Attestation +提供了两种使用认证证书的方法 + +95 +00:06:26,153 --> 00:06:29,623 +我们增强了 +DeviceInformation MDM 命令 + +96 +00:06:29,656 --> 00:06:34,661 +使 MDM 服务器可以 +使用认证的好处 + +97 +00:06:34,695 --> 00:06:39,366 +我们还增加了对 AutomaticCertificate +Management Environment 协议的支持 + +98 +00:06:39,399 --> 00:06:44,004 +这是通过添加 ACME 配置文件 +有效载荷实现的 + +99 +00:06:44,037 --> 00:06:46,306 +它使认证的好处在整个组织的 + +100 +00:06:46,340 --> 00:06:49,543 +基础设施中都可用 + +101 +00:06:50,711 --> 00:06:53,046 +对于 DeviceInformation 认证 + +102 +00:06:53,080 --> 00:06:58,919 +MDM 服务器发出 +DeviceInformationquery 并指定一些新密钥 + +103 +00:06:58,952 --> 00:07:02,489 +Apple 服务器将获取认证 + +104 +00:07:02,523 --> 00:07:05,225 +并将它返回给 MDM 服务器 + +105 +00:07:05,259 --> 00:07:08,462 +然后 MDM 服务器评估认证 + +106 +00:07:10,297 --> 00:07:11,965 +但注意 + +107 +00:07:11,999 --> 00:07:16,036 +DeviceInformation 认证 +向 MDM 服务器声明 + +108 +00:07:16,069 --> 00:07:18,972 +“A device exists with these properties” + +109 +00:07:19,006 --> 00:07:23,510 +但不能认证 MDMserver +当前正在与之通信的设备 + +110 +00:07:23,544 --> 00:07:25,712 +是同一个设备 + +111 +00:07:25,746 --> 00:07:28,815 +为此 您需要 ACME 有效载荷认证 + +112 +00:07:31,151 --> 00:07:34,721 +ACME 有效载荷认证 +为设备的身份提供了 + +113 +00:07:34,755 --> 00:07:37,090 +最强有力的认证 + +114 +00:07:37,124 --> 00:07:40,427 +当您安装包含 ACME +有效载荷的配置文件时 + +115 +00:07:40,460 --> 00:07:45,299 +设备会从组织 ACME 服务器 +请求证书 + +116 +00:07:45,332 --> 00:07:49,503 +这与安装 SCEP 有效载荷非常相似 + +117 +00:07:49,536 --> 00:07:53,440 +设备向 ACME 服务器提供认证 + +118 +00:07:53,473 --> 00:07:57,244 +基于对设备身份的有力认证 + +119 +00:07:57,277 --> 00:08:00,447 +ACME 服务器颁发组织的 + +120 +00:08:00,480 --> 00:08:04,017 +其他服务器信任的新客户端证书 + +121 +00:08:04,051 --> 00:08:06,820 +这两个新功能使用认证证书 + +122 +00:08:06,854 --> 00:08:08,689 +来证明几件事 + +123 +00:08:08,722 --> 00:08:11,792 +该设备是正品 Apple 硬件 + +124 +00:08:11,825 --> 00:08:15,495 +该设备是特定装置 + +125 +00:08:15,529 --> 00:08:18,832 +该设备具有某种属性 + +126 +00:08:18,866 --> 00:08:22,836 +并且私钥已绑定到设备 + +127 +00:08:22,870 --> 00:08:26,573 +它向不同的服务器证明 它们正在 + +128 +00:08:26,607 --> 00:08:28,642 +与同一设备通信 + +129 +00:08:28,675 --> 00:08:32,079 +这些证书对您有什么好处 + +130 +00:08:32,112 --> 00:08:34,982 +认证主要是一种安全功能 + +131 +00:08:35,015 --> 00:08:39,419 +所以我将描述一些威胁 +以及认证如何降低威胁 + +132 +00:08:40,420 --> 00:08:45,125 +首先 一款被泄露的设备 +会谎报其属性 + +133 +00:08:45,158 --> 00:08:47,895 +所以 Apple 会认证其属性 + +134 +00:08:47,928 --> 00:08:49,596 +即使操作系统受到威胁 + +135 +00:08:49,630 --> 00:08:52,766 +这也不会影响认证的可靠性 + +136 +00:08:52,799 --> 00:08:56,703 +只需要 Secure Enclave 完好无损 + +137 +00:08:56,737 --> 00:09:01,441 +或者受损设备提供了过时的属性认证 + +138 +00:09:01,475 --> 00:09:03,744 +而这些属性已经发生了变化 + +139 +00:09:03,777 --> 00:09:09,116 +证明文件中的临时文件可确保 +事实是最新的 + +140 +00:09:09,149 --> 00:09:12,953 +ACME 有效载荷认证 +可以减轻其他威胁 + +141 +00:09:12,986 --> 00:09:16,990 +受损设备 +在与 MDM 服务器通信时 + +142 +00:09:17,024 --> 00:09:20,127 +发送不同的设备标识符 + +143 +00:09:20,160 --> 00:09:25,799 +因此 Apple 验证设备标识符的方式 +与设备用于验证 + +144 +00:09:25,832 --> 00:09:29,837 +TLS 连接的客户端身份相关联 + +145 +00:09:29,870 --> 00:09:31,905 +这可以向 MDM 服务器和 + +146 +00:09:31,939 --> 00:09:36,210 +其他组织服务器 +证明它们与哪个设备通信 + +147 +00:09:37,678 --> 00:09:42,149 +或者攻击者从合法设备中提取私钥 + +148 +00:09:42,182 --> 00:09:47,120 +并使用它来发出请求 +欺骗合法设备 + +149 +00:09:47,154 --> 00:09:51,491 +Apple 证实 +私钥受 Secure Enclave 保护 + +150 +00:09:51,525 --> 00:09:53,794 +该软件对私钥的 + +151 +00:09:53,827 --> 00:09:57,297 +导出或导入具有特别强的保护 + +152 +00:09:57,331 --> 00:10:01,335 +最后 攻击者劫持证书请求 + +153 +00:10:01,368 --> 00:10:06,940 +以获取证书颁发机构 +为不同的设备颁发证书 + +154 +00:10:06,974 --> 00:10:10,177 +Apple 通过将请求设备与 +证书请求绑定的方式 + +155 +00:10:10,210 --> 00:10:13,146 +来验证该设备的身份 + +156 +00:10:13,180 --> 00:10:15,949 +因此 证书颁发机构只向合法设备 + +157 +00:10:15,983 --> 00:10:19,052 +颁发证书 + +158 +00:10:19,086 --> 00:10:23,423 +证书为您提供安全方面的好处 +从而减轻多种威胁 + +159 +00:10:23,457 --> 00:10:26,727 +那么您如何在您的环境中使用呢 + +160 +00:10:26,760 --> 00:10:31,965 +让我们详细了解 +如何实现 Managed Device Attestation + +161 +00:10:31,999 --> 00:10:36,270 +首先 对 DeviceInformation 命令 +进行了增强 + +162 +00:10:36,303 --> 00:10:40,741 +MDM 服务器可以向 +受管设备发出此命令 + +163 +00:10:40,774 --> 00:10:45,546 +该请求包括服务器想知道的属性列表 + +164 +00:10:45,579 --> 00:10:49,883 +我们添加了一个新属性 +DevicePropertiesCertification + +165 +00:10:49,917 --> 00:10:53,120 +将其添加到 Queries 数组 +意味着 MDM 服务器 + +166 +00:10:53,153 --> 00:10:56,323 +正在请求认证 + +167 +00:10:56,356 --> 00:10:59,059 +为确保认证是新鲜的 + +168 +00:10:59,092 --> 00:11:04,097 +MDM 服务器可以使用 +DeviceAttestationNonce 密钥 + +169 +00:11:04,131 --> 00:11:08,702 +与 Queries 密钥出现在 +请求中的同一级别 + +170 +00:11:08,735 --> 00:11:10,537 +该密钥是可选的 + +171 +00:11:10,571 --> 00:11:15,809 +它的值是一个数据对象 +最大大小为 32 字节 + +172 +00:11:15,843 --> 00:11:19,213 +这是一个请求认证的示例 + +173 +00:11:19,246 --> 00:11:23,383 +查询数组包含 +DevicePropertiesCertification 密钥 + +174 +00:11:23,417 --> 00:11:26,887 +并且有一个32 字节的临时文件 + +175 +00:11:26,920 --> 00:11:29,623 +取证成功时 + +176 +00:11:29,656 --> 00:11:34,127 +响应包含一个 +DevicePropertiesCertificate 密钥 + +177 +00:11:34,161 --> 00:11:37,331 +它的值是一个数据对象数组 + +178 +00:11:37,364 --> 00:11:42,336 +数组中的每个元素 +是证书链中的一个证书 + +179 +00:11:42,369 --> 00:11:44,938 +这是一个示例响应 + +180 +00:11:44,972 --> 00:11:48,775 +叶证书首先出现在数组中 + +181 +00:11:48,809 --> 00:11:53,780 +它包含自定义 OID 中的设备属性 + +182 +00:11:53,814 --> 00:11:59,720 +前两个 OID 是设备标识属性 +序列号和 UDID + +183 +00:11:59,753 --> 00:12:05,392 +如果 MDM 注册是 User Enrollment +则它们会从证书中省略 + +184 +00:12:05,425 --> 00:12:10,797 +其余 OID 是匿名的 +可用于所有注册类型 + +185 +00:12:10,831 --> 00:12:14,468 +sepOS 版本是指在 +Secure Enclave 上运行的 + +186 +00:12:14,501 --> 00:12:17,437 +操作系统的版本 + +187 +00:12:17,471 --> 00:12:20,841 +临时文件 OID 中存在正确的值 + +188 +00:12:20,874 --> 00:12:24,811 +证明证书生成了 + +189 +00:12:24,845 --> 00:12:27,314 +当 MDM 服务器收到认证时 + +190 +00:12:27,347 --> 00:12:30,851 +必须按照以下顺序仔细地验证 + +191 +00:12:30,884 --> 00:12:34,087 +它验证证书链是否植根于预期的 + +192 +00:12:34,121 --> 00:12:36,757 +Apple 证书颁发机构 + +193 +00:12:36,790 --> 00:12:38,959 +Apple 证书颁发机构 + +194 +00:12:38,992 --> 00:12:42,963 +可以从 +Apple Private PKI Repository 中获得 + +195 +00:12:42,996 --> 00:12:46,834 +它验证叶证书中的临时文件 +是否与 DeviceInformation + +196 +00:12:46,867 --> 00:12:50,270 +请求中的临时文件匹配 +如果已指定的话 + +197 +00:12:50,304 --> 00:12:55,342 +然后它解析出剩余的 OID +并评估它们的值 + +198 +00:12:55,375 --> 00:12:59,546 +生成新的认证需要使用设备 +和 Apple 服务器上的 + +199 +00:12:59,580 --> 00:13:01,415 +大量资源 + +200 +00:13:01,448 --> 00:13:06,286 +所以对于请求新认证证书的频率 +存在速率限制 + +201 +00:13:06,320 --> 00:13:10,824 +目前每七天请求一个新认证 + +202 +00:13:10,858 --> 00:13:16,063 +通过指定新的临时文件 +来请求新的认证 + +203 +00:13:16,096 --> 00:13:19,933 +省略一个临时文件表明 +新鲜度不是问题 + +204 +00:13:19,967 --> 00:13:24,771 +因此 设备可以返回其最新的认证 + +205 +00:13:24,805 --> 00:13:29,076 +如果指定了随机数 +并匹配缓存的认证 + +206 +00:13:29,109 --> 00:13:32,613 +则返回缓存的认证 + +207 +00:13:32,646 --> 00:13:36,316 +当 MDM 服务器在认证中 +验证临时文件时 + +208 +00:13:36,350 --> 00:13:38,952 +它应该检测到不匹配的临时文件 + +209 +00:13:38,986 --> 00:13:44,057 +并确定这是否是由于缓存而导致的 + +210 +00:13:44,091 --> 00:13:48,028 +但不要仅仅因为这是利率上限 + +211 +00:13:48,061 --> 00:13:50,297 +就要求每七天更新一次认证 + +212 +00:13:50,330 --> 00:13:54,201 +这样做只会延迟您的 +MDM 服务器发现更改的速度 + +213 +00:13:54,234 --> 00:13:58,605 +在设备属性上 更不用说浪费资源了 + +214 +00:13:58,639 --> 00:14:03,677 +相反 监视其他 DeviceInformation +属性中的相关更改 + +215 +00:14:03,710 --> 00:14:05,646 +比如操作系统版本 + +216 +00:14:05,679 --> 00:14:10,050 +当其中一项发生更改时 +就请求新的认证 + +217 +00:14:10,083 --> 00:14:14,788 +这可确保在更改后尽快更新认证 + +218 +00:14:14,821 --> 00:14:18,392 +而不是等待速率限制到期 + +219 +00:14:18,425 --> 00:14:23,830 +为了防止设备被泄露 +并谎报这些其他属性 + +220 +00:14:23,864 --> 00:14:27,701 +您可以偶尔随机要求提供新的认证 + +221 +00:14:27,734 --> 00:14:29,803 +以保持设备诚实 + +222 +00:14:29,837 --> 00:14:33,106 +请求认证可能会失败 + +223 +00:14:33,140 --> 00:14:36,243 +这种情况时 设备仍会响应 + +224 +00:14:36,276 --> 00:14:38,779 +但省略了一些信息 + +225 +00:14:38,812 --> 00:14:43,450 +可能响应中省略了 +DevicePropertiesCertification 字段 + +226 +00:14:43,483 --> 00:14:47,254 +或是一个预期的 OID +抑或是它的值被省略了 + +227 +00:14:47,287 --> 00:14:49,990 +失败的原因有很多 + +228 +00:14:50,023 --> 00:14:55,429 +设备在到达 Apple 认证服务器时 +遇到网络问题 + +229 +00:14:55,462 --> 00:14:58,098 +没有服务器 100% 的时间都在运行 + +230 +00:14:58,131 --> 00:15:02,202 +因此 Apple 的认证服务器 +可能存在问题 + +231 +00:15:02,236 --> 00:15:05,906 +或者设备硬件或软件可能受到损害 + +232 +00:15:05,939 --> 00:15:08,542 +或者甚至不是真正的 Apple 硬件 + +233 +00:15:08,575 --> 00:15:12,212 +在最后三种情况下 +Apple 的认证服务器 + +234 +00:15:12,246 --> 00:15:17,584 +拒绝为它们无法验证的属性 +发布认证 + +235 +00:15:17,618 --> 00:15:20,187 +认证失败的原因有很多 + +236 +00:15:20,220 --> 00:15:24,625 +从无害的网络故障到主动攻击 + +237 +00:15:24,658 --> 00:15:27,361 +不幸的是 +MDM 服务器没有可靠的方法 + +238 +00:15:27,394 --> 00:15:30,931 +知道确切的原因 + +239 +00:15:30,964 --> 00:15:34,101 +这是因为关于故障的唯一信息来源 + +240 +00:15:34,134 --> 00:15:39,439 +是设备本身 +它可能是一个在撒谎的受损设备 + +241 +00:15:39,473 --> 00:15:43,277 +那么 MDM 服务器应该 +如何解释故障呢 + +242 +00:15:43,310 --> 00:15:48,148 +认证失败时 +不要总是假设最坏的情况 + +243 +00:15:48,182 --> 00:15:50,484 +如果您有一个零信任架构 + +244 +00:15:50,517 --> 00:15:52,753 +那么您可能会采用以下方式处理它 + +245 +00:15:52,786 --> 00:15:56,790 +该组织计算设备的信任分数 + +246 +00:15:56,823 --> 00:16:02,896 +失败或意外失效的认证 +会降低该分数 + +247 +00:16:02,930 --> 00:16:05,966 +信任评分降低会触发不同的操作 + +248 +00:16:05,999 --> 00:16:08,969 +比如拒绝服务访问 + +249 +00:16:09,002 --> 00:16:11,705 +将设备标记为人工调查 + +250 +00:16:11,738 --> 00:16:15,642 +或通过清除设备 +吊销其证书来进行补救 + +251 +00:16:15,676 --> 00:16:20,414 +这可以确保 +对失败的认证做出适当的响应 + +252 +00:16:20,447 --> 00:16:24,952 +让我们继续实施 ACME +有效载荷认证 + +253 +00:16:24,985 --> 00:16:28,522 +安装 ACME 有效载荷 +涉及几个步骤 + +254 +00:16:28,555 --> 00:16:33,460 +我将描述该过程中的不同参与者 +然后是每个步骤 + +255 +00:16:33,493 --> 00:16:37,764 +我们从 iPhone iPad 或 +Apple TV 开始 + +256 +00:16:38,999 --> 00:16:43,737 +在大多数情况下 +这是由 MDM 服务器管理 + +257 +00:16:43,770 --> 00:16:45,606 +有一个 ACME 服务器 + +258 +00:16:45,639 --> 00:16:50,777 +这执行了 ACME协议 RFC 8555 + +259 +00:16:50,811 --> 00:16:56,783 +因此它可以从组织证书颁发机构 +颁发客户端证书 + +260 +00:16:56,817 --> 00:17:01,555 +并且有 Apple 的认证服务器 +发布认证 + +261 +00:17:03,390 --> 00:17:07,294 +第一步是 +让 MDM 服务器安装配置文件 + +262 +00:17:07,327 --> 00:17:10,397 +包含 ACME 有效载荷 + +263 +00:17:10,430 --> 00:17:16,036 +有效载荷指定设备 +将生成的密钥属性 + +264 +00:17:16,069 --> 00:17:22,276 +设备将请求的证书属性 + +265 +00:17:22,309 --> 00:17:27,548 +以及如何从 ACME 服务器请求证书 + +266 +00:17:27,581 --> 00:17:29,483 +要开始安装配置文件 + +267 +00:17:29,516 --> 00:17:33,587 +设备生成请求的密钥类型 + +268 +00:17:33,620 --> 00:17:37,991 +为了使用证书 +密钥必须是硬件绑定的 + +269 +00:17:38,025 --> 00:17:42,296 +虽然 ACME 有效载荷支持 RSA +和各种大小的密钥 + +270 +00:17:42,329 --> 00:17:47,801 +但为了获得硬件绑定密钥 +必须使用 ECSECPrimeRandom + +271 +00:17:47,835 --> 00:17:53,707 +您的最佳选择是 +ECSECPrimeRandom 384 位密钥 + +272 +00:17:53,740 --> 00:17:58,345 +因为这是最高安全性的硬件绑定密钥 + +273 +00:17:58,378 --> 00:18:03,217 +创建密钥后 设备将与 +ACME 服务器进行初始联系 + +274 +00:18:05,052 --> 00:18:08,155 +设备请求 DirectoryURL + +275 +00:18:08,188 --> 00:18:11,792 +它指定用于其余过程的 URL + +276 +00:18:11,825 --> 00:18:14,595 +与 ACME 服务器的通信 + +277 +00:18:14,628 --> 00:18:18,699 +然后两个系统创建一个帐户 +和一个订单 + +278 +00:18:18,732 --> 00:18:24,404 +服务器提供 +device-attest-01 验证类型 + +279 +00:18:24,438 --> 00:18:27,508 +然后 ACME 服务器生成一个临时文件 + +280 +00:18:27,541 --> 00:18:32,012 +并将其发送到令牌字段中的设备 + +281 +00:18:32,045 --> 00:18:36,483 +ACME 协议最初用于 +颁发服务器证书 + +282 +00:18:36,517 --> 00:18:39,319 +但是在这里 +我们使用的验证类型 + +283 +00:18:39,353 --> 00:18:42,356 +是在 IETF 草案中引入的 + +284 +00:18:42,389 --> 00:18:45,692 +该草案指定了 ACME 协议的扩展 + +285 +00:18:45,726 --> 00:18:49,730 +认证和颁发客户端证书 + +286 +00:18:50,931 --> 00:18:53,000 +认证是可选的 + +287 +00:18:53,033 --> 00:18:55,502 +当有效载荷指定认证时 + +288 +00:18:55,536 --> 00:18:59,106 +设备请求 Apple 提供认证 + +289 +00:18:59,139 --> 00:19:03,443 +这几乎与 +DeviceInformation 认证相同 + +290 +00:19:03,477 --> 00:19:05,679 +它使用相同的 OID + +291 +00:19:05,712 --> 00:19:10,751 +并且为 User Enrollment +省略了设备标识的 OID + +292 +00:19:10,784 --> 00:19:13,153 +但有一些不同之处 + +293 +00:19:13,187 --> 00:19:20,394 +临时文件在嵌入认证之前 +使用 SHA-256 进行哈希处理 + +294 +00:19:20,427 --> 00:19:25,165 +临时文件来自 ACME 服务器 +而不是 MDM 服务器 + +295 +00:19:25,199 --> 00:19:29,436 +认证叶证书匹配的私钥 + +296 +00:19:29,469 --> 00:19:33,540 +是设备刚刚生成的那个 + +297 +00:19:33,574 --> 00:19:36,310 +认证证书与私钥匹配 + +298 +00:19:36,343 --> 00:19:42,816 +但是 该证书不能用于 +除认证之外的任何目的 + +299 +00:19:42,850 --> 00:19:46,687 +所以设备从 ACME 服务器 +请求另一个证书 + +300 +00:19:46,720 --> 00:19:50,824 +匹配私钥 这个证书对 TLS 有好处 + +301 +00:19:53,060 --> 00:19:56,029 +设备提供证书签名请求 + +302 +00:19:56,063 --> 00:20:00,367 +包含来自有效载荷的证书请求属性 + +303 +00:20:00,400 --> 00:20:03,670 +它提供了认证链 + +304 +00:20:03,704 --> 00:20:08,041 +它还提供来自 ACME +有效载荷的 ClientIdentifier + +305 +00:20:08,075 --> 00:20:10,344 +通常这就像一张票一样使用 + +306 +00:20:10,377 --> 00:20:13,413 +这有利于签发单一证书 + +307 +00:20:13,447 --> 00:20:15,883 +以防止重复请求 + +308 +00:20:15,916 --> 00:20:19,353 +ACME 服务器在发出证书之前 + +309 +00:20:19,386 --> 00:20:23,056 +必须按照此顺序仔细验证请求 + +310 +00:20:23,090 --> 00:20:28,629 +它必须验证 ClientIdentifier +是否有效且未使用 + +311 +00:20:28,662 --> 00:20:34,401 +认证证书必须链接到 +正确的 Apple CA + +312 +00:20:34,434 --> 00:20:40,541 +认证叶证书中的 +公钥必须与 CSR 匹配 + +313 +00:20:40,574 --> 00:20:47,681 +临时文件必须匹配 ACME 服务器 +之前发送的 SHA-256 哈希值 + +314 +00:20:47,714 --> 00:20:52,386 +然后 ACME 服务器 +可以评估剩余的 OID + +315 +00:20:52,419 --> 00:20:55,389 +请记住 认证可能会失败 + +316 +00:20:55,422 --> 00:21:00,093 +在颁发证书时 ACME 服务器 +应该仔细考虑失败 + +317 +00:21:00,127 --> 00:21:05,532 +就像我们在 DeviceInformation +案例中审查认证失败一样 + +318 +00:21:05,566 --> 00:21:08,402 +从这里开始 事情很快就结束了 + +319 +00:21:08,435 --> 00:21:11,538 +ACME 服务器从组织 CA 颁发 + +320 +00:21:11,572 --> 00:21:14,842 +客户端证书 并将其返回给设备 + +321 +00:21:17,077 --> 00:21:22,015 +ACME 服务器是客户端证书 +颁发的最终机构 + +322 +00:21:22,049 --> 00:21:25,919 +它可以选择尊重或覆盖 CSR 中的属性 + +323 +00:21:25,953 --> 00:21:28,789 +例如 SubjectAltName + +324 +00:21:28,822 --> 00:21:31,859 +设备将证书存储在密钥链中 + +325 +00:21:31,892 --> 00:21:35,095 +这样就完成了 ACME 有效载荷的安装 + +326 +00:21:36,930 --> 00:21:38,999 +让我们把这一切联系起来 + +327 +00:21:39,032 --> 00:21:42,469 +服务器如何知道与它们通信的设备 + +328 +00:21:42,503 --> 00:21:45,339 +就是声称的那个 + +329 +00:21:45,372 --> 00:21:49,376 +设备使用同一个私钥的方式有多种 + +330 +00:21:49,409 --> 00:21:51,879 +在获得 Apple 认证时 + +331 +00:21:51,912 --> 00:21:55,048 +从 ACME 服务器获取客户端证书时 + +332 +00:21:55,082 --> 00:21:58,785 +以及使用 TLS 与其他服务器通信时 + +333 +00:21:58,819 --> 00:22:01,421 +因为密钥是硬件绑定的 + +334 +00:22:01,455 --> 00:22:05,659 +我们知道所有这些操作 +都是由同一个设备执行的 + +335 +00:22:05,692 --> 00:22:11,465 +而且我们有一个 +描述该设备的认证证书 + +336 +00:22:11,498 --> 00:22:15,802 +结合这些 组织服务器现在 + +337 +00:22:15,836 --> 00:22:19,173 +在授予访问权限时 +对设备的身份有信心 + +338 +00:22:21,742 --> 00:22:24,745 +就像证书和 SCEP 有效载荷一样 + +339 +00:22:24,778 --> 00:22:28,081 +配置文件中的其他有效载荷 +可以引用 ACME 有效载荷 + +340 +00:22:28,115 --> 00:22:30,350 +以使用证书 + +341 +00:22:30,384 --> 00:22:33,820 +将它用于 MDM Wi-Fi VPN + +342 +00:22:33,854 --> 00:22:35,989 +Kerberos 和 Safari 浏览器 + +343 +00:22:36,023 --> 00:22:39,626 +所有这些系统都得益于认证 + +344 +00:22:42,196 --> 00:22:44,865 +一个设备可以有多达 10 个 +ACME 有效载荷 + +345 +00:22:44,898 --> 00:22:48,635 +同时使用安装的认证 + +346 +00:22:48,669 --> 00:22:52,105 +请注意 硬件绑定的密钥不会被保留 + +347 +00:22:52,139 --> 00:22:54,808 +当受管设备的备份恢复时 + +348 +00:22:54,842 --> 00:22:58,011 +即使恢复到同一设备 + +349 +00:22:58,045 --> 00:23:02,149 +如果您对 Managed Device Attestation +不做任何其他操作 + +350 +00:23:02,182 --> 00:23:05,819 +那么可以对 MDM 客户端身份 +使用 ACME 有效载荷 + +351 +00:23:05,853 --> 00:23:10,290 +因此 MDM 服务器可以 +确定它正在管理哪个设备 + +352 +00:23:10,324 --> 00:23:12,059 +我们来总结一下 + +353 +00:23:12,092 --> 00:23:17,898 +您可以使用 Managed Device Attestation +认证来修复多类威胁 + +354 +00:23:17,931 --> 00:23:23,403 +利用 DeviceInformation 认证 +来改进设备标识组件的状态 + +355 +00:23:23,437 --> 00:23:27,107 +以获得更好的信任评估 + +356 +00:23:27,140 --> 00:23:33,113 +而且 您现在可以在设备访问 +组织资源时使用 ACME 认证 + +357 +00:23:33,146 --> 00:23:35,349 +来认证其身份 + +358 +00:23:35,382 --> 00:23:40,053 +我们期待开发者实施 +Managed Device Attestation + +359 +00:23:40,087 --> 00:23:44,725 +我们将共同提高 +开发者设备部署的安全性 + +360 +00:23:44,758 --> 00:23:48,395 +谢谢 祝您的 WWDC 之旅一切顺利 + diff --git a/zho/2022 Session 10144 Deliver reliable streams with HLS Content Steering.srt b/zho/2022 Session 10144 Deliver reliable streams with HLS Content Steering.srt new file mode 100644 index 0000000..e92728c --- /dev/null +++ b/zho/2022 Session 10144 Deliver reliable streams with HLS Content Steering.srt @@ -0,0 +1,1564 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,977 --> 00:00:12,846 +Zheng Naiwei: 大家好 +欢迎来到 WWDC + +3 +00:00:12,880 --> 00:00:16,750 +我叫 Zheng Naiwei +来自 Apple 的 AVFoundation 团队 + +4 +00:00:16,783 --> 00:00:20,120 +在本次演讲中 +我们将讨论如何通过添加到 + +5 +00:00:20,153 --> 00:00:25,492 +HLS Content Steering 中的新功能 +来提高流媒体传输的可靠性 + +6 +00:00:26,660 --> 00:00:29,029 +我们今天将介绍三个主题 + +7 +00:00:29,062 --> 00:00:31,798 +如果开发者还没有听说过 +Content Steering 请不要担心 + +8 +00:00:31,832 --> 00:00:33,967 +这是一项 HLS 技术 + +9 +00:00:34,001 --> 00:00:37,104 +可以动态引导流媒体流量 + +10 +00:00:37,137 --> 00:00:39,907 +以提高流媒体服务质量 + +11 +00:00:39,940 --> 00:00:42,976 +我会进行一个简短的回顾 +以帮助开发者上手 + +12 +00:00:44,878 --> 00:00:48,182 +然后 我将介绍 +新的 Pathway 克隆功能 + +13 +00:00:48,215 --> 00:00:52,219 +它可以带来 +超越极限的动态控制能力 + +14 +00:00:52,252 --> 00:00:55,689 +以进一步提高流媒体服务的可靠性 + +15 +00:00:56,990 --> 00:01:04,031 +最后 我将使用具体的例子 +来指导开发者 + +16 +00:01:04,064 --> 00:01:06,533 +话不多说 开始吧 + +17 +00:01:07,768 --> 00:01:10,571 +在我们没有推出 +Content Steering 的时候 + +18 +00:01:10,604 --> 00:01:14,074 +HLS 规范中 +没有对错误回退的变体选择 + +19 +00:01:14,107 --> 00:01:16,310 +进行标准化定义 + +20 +00:01:16,343 --> 00:01:19,580 +在选择下一个回退变体时 +不同的客户端会有 + +21 +00:01:19,613 --> 00:01:22,349 +不同的实现方式 + +22 +00:01:22,382 --> 00:01:25,586 +但是一种典型的方法是 +在多变量播放列表中 + +23 +00:01:25,619 --> 00:01:27,354 +遵循变量顺序 + +24 +00:01:28,255 --> 00:01:32,826 +如果流媒体提供商想要 +指定一组回退 CDN + +25 +00:01:32,860 --> 00:01:35,863 +那么他们就需要列出 +每个CDN中的每一个变体 + +26 +00:01:35,896 --> 00:01:38,866 +并在多变体播放列表中正确地排列 + +27 +00:01:38,899 --> 00:01:42,302 +这样 如果客户端播放器 +第一个变体遇到故障 + +28 +00:01:42,336 --> 00:01:46,106 +它可以在播放列表中 +移动到下一个变体 + +29 +00:01:46,139 --> 00:01:50,511 +故障变体将在做选择时受到惩罚 + +30 +00:01:50,544 --> 00:01:55,249 +在这种情况下 我们看到客户端 +播放器在 CDN1 的 + +31 +00:01:55,282 --> 00:02:01,088 +6 Mbps 变体上有问题 +因此按照多变体播放列表中的顺序 + +32 +00:02:01,121 --> 00:02:04,758 +移动到下一个 +CDN1 的 3 Mbps 变体 + +33 +00:02:04,791 --> 00:02:10,097 +如果很不幸 +CDN1 的 3 Mbps 变体也坏了 + +34 +00:02:10,130 --> 00:02:14,201 +客户端播放器将不再保留 +CDN1 的变体 + +35 +00:02:14,234 --> 00:02:18,672 +而是转向 CDN2 的 6 Mbps 变体 + +36 +00:02:18,705 --> 00:02:22,776 +它可以断断续续地执行此操作 +直到没有要回退的变体为止 + +37 +00:02:22,809 --> 00:02:26,780 +但是 即使播放列表的 +创作服务器可以控制 + +38 +00:02:26,813 --> 00:02:28,248 +回退变体的顺序 + +39 +00:02:28,282 --> 00:02:30,117 +这种控制只发生在 + +40 +00:02:30,150 --> 00:02:34,354 +客户端请求多变体播放列表时 + +41 +00:02:34,388 --> 00:02:36,390 +一旦播放列表发出 + +42 +00:02:36,423 --> 00:02:39,459 +就无法更改回退顺序 + +43 +00:02:39,493 --> 00:02:42,863 +这就是 Content Steering +进入画面的地方 + +44 +00:02:42,896 --> 00:02:45,165 +借助 Content Steering 流媒体提供商 + +45 +00:02:45,199 --> 00:02:49,203 +现在可以将变体分组到 +具有不同 CDN host 的路径中 + +46 +00:02:50,904 --> 00:02:55,542 +错误回退行为现已针对 +Content Steering 进行了标准化 + +47 +00:02:55,576 --> 00:02:57,377 +通路按偏好排序 + +48 +00:02:57,411 --> 00:03:00,514 +在此示例中 顶部的 CDN1 通路 + +49 +00:03:00,547 --> 00:03:05,452 +是首选 其次是 CDN2 和 CDN3 + +50 +00:03:05,485 --> 00:03:08,922 +流媒体提供商还托管 Steering Server + +51 +00:03:08,956 --> 00:03:13,160 +为每个客户端播放器 +生成 Steering Manifest + +52 +00:03:13,193 --> 00:03:16,964 +Steering Manifest 定义了 +路径优先级的规则 + +53 +00:03:16,997 --> 00:03:18,565 +所以 播放器可以遵守规则 + +54 +00:03:18,599 --> 00:03:22,169 +在变体流之间进行选择和回退 + +55 +00:03:23,036 --> 00:03:27,241 +例如 流媒体提供商正尝试 + +56 +00:03:27,274 --> 00:03:31,378 +将一些流量从 CDN1 转移到 CND2 + +57 +00:03:31,411 --> 00:03:33,547 +它将生成带有新路径 + +58 +00:03:33,580 --> 00:03:36,283 +优先级规则的 Steering Manifest + +59 +00:03:36,316 --> 00:03:39,086 +当 CDN1 的客户端播放器 + +60 +00:03:39,119 --> 00:03:42,122 +请求更新 Steering Manifest 时 + +61 +00:03:42,155 --> 00:03:45,526 +Steering Server 可以将准备好的带有 + +62 +00:03:45,559 --> 00:03:48,395 +规则更改的 Steering Manifest +发送给客户端 + +63 +00:03:48,428 --> 00:03:52,065 +客户端将解析并查看 +新的路径优先级规则 + +64 +00:03:52,099 --> 00:03:55,936 +并将其应用于其播放会话 + +65 +00:03:55,969 --> 00:03:59,106 +在这种情况下 规则更改 +切换了 CDN1 和 CDN2 + +66 +00:03:59,139 --> 00:04:02,209 +通路之间的首选项顺序 + +67 +00:04:02,242 --> 00:04:07,514 +因此客户端播放器 +将立即从 CDN2 切换播放 + +68 +00:04:07,548 --> 00:04:09,850 +然后 如果发生故障 + +69 +00:04:09,883 --> 00:04:14,988 +客户端将首先在当前路径中 +耗尽回退变体 + +70 +00:04:15,022 --> 00:04:17,424 +并根据其当前路径优先级 + +71 +00:04:17,457 --> 00:04:20,627 +回退到最优先的路径 + +72 +00:04:20,661 --> 00:04:24,498 +在这种情况下 +如果 CDN2 中的所有变体都出错了 + +73 +00:04:24,531 --> 00:04:28,168 +客户端播放器可以开始 +从 CDN1 的变体中进行选择 + +74 +00:04:28,202 --> 00:04:30,737 +这是下一个首选途径 + +75 +00:04:30,771 --> 00:04:34,041 +当我们将 Content Steering +应用到全球范围时 + +76 +00:04:34,074 --> 00:04:37,644 +它可以解决更大的区域 负载均衡问题 + +77 +00:04:37,678 --> 00:04:41,782 +假设我们的流媒体服务提供商 +在世界各地运营 + +78 +00:04:41,815 --> 00:04:44,284 +具有两个主要的 CDN 提供商 + +79 +00:04:44,318 --> 00:04:47,788 +要将这些 CDN 分配给 +全球客户端播放器 + +80 +00:04:47,821 --> 00:04:51,158 +Steering Server 准备了 +两个不同的 Steering Manifest + +81 +00:04:51,191 --> 00:04:56,230 +一个倾向于 CDN1 +另一个倾向于 CDN2 + +82 +00:04:56,263 --> 00:04:58,699 +然后它根据客户端播放器的区域 + +83 +00:04:58,732 --> 00:05:02,002 +分发这些 Steering Manifest + +84 +00:05:02,035 --> 00:05:06,306 +以便北美和南美使用 CDN1 + +85 +00:05:06,340 --> 00:05:10,143 +世界其他地区使用 CDN2 + +86 +00:05:10,177 --> 00:05:13,981 +在世界地图的顶部 +我们显示了一个水平堆叠的条形图 + +87 +00:05:14,014 --> 00:05:18,719 +表示 CDN1 和 CDN2 之间的流量分布 + +88 +00:05:18,752 --> 00:05:23,123 +截至目前 这两个 CDN +都为全球一半的流量提供服务 + +89 +00:05:24,024 --> 00:05:27,995 +但是 随着时间的推移 +流媒体服务提供商观察到 + +90 +00:05:28,028 --> 00:05:31,798 +由于全球日光偏移 + +91 +00:05:31,832 --> 00:05:34,635 +CDN2 的流量显著增加 + +92 +00:05:34,668 --> 00:05:38,372 +与此同时 +流向 CDN1 的流量也在减少 + +93 +00:05:39,640 --> 00:05:44,711 +因此 流媒体提供商决定 +引导欧洲地区使用 CDN1 + +94 +00:05:44,745 --> 00:05:48,749 +它通过准备一个更倾向于 CDN1 的 +Steering Manifest 来实现这一点 + +95 +00:05:48,782 --> 00:05:52,653 +并将其发送给欧洲地区的客户 + +96 +00:05:52,686 --> 00:05:56,757 +现在 该区域中的这些客户端播放器 +将流量引导到 CDN1 + +97 +00:05:56,790 --> 00:05:58,792 +把 CDN2 卸载 + +98 +00:05:58,825 --> 00:06:01,461 +全球流量变得更加平衡 + +99 +00:06:01,495 --> 00:06:05,632 +现在让我们看一下 +具有内容控制支持的 + +100 +00:06:05,666 --> 00:06:07,801 +HLS 多变量播放列表 + +101 +00:06:07,835 --> 00:06:11,805 +首先 我们看到 +EXT-X-CONTENT-STEERING 标签 + +102 +00:06:11,839 --> 00:06:16,610 +这表示此多变量播放列表 +使用 Content Steering + +103 +00:06:16,643 --> 00:06:19,713 +然后我们有 SERVER-URI 属性 + +104 +00:06:19,746 --> 00:06:24,017 +指定客户端应从何处请求 +Steering Manifest 更新 + +105 +00:06:25,252 --> 00:06:29,957 +然后 下一个 PATHWAY-ID 属性 +指定启动时播放 + +106 +00:06:29,990 --> 00:06:32,993 +要选择的初始路径 + +107 +00:06:33,026 --> 00:06:38,198 +然后我们可以看到每个变体流 +都被赋予了一个 PATHWAY-ID 属性 + +108 +00:06:38,232 --> 00:06:40,267 +将它们分组到通路中 + +109 +00:06:40,300 --> 00:06:43,470 +每个通路应具有相同的变体流集 + +110 +00:06:43,504 --> 00:06:47,975 +唯一的区别是它们的 URI +和媒体组名称 + +111 +00:06:48,008 --> 00:06:51,011 +这个例子中有两个通路 + +112 +00:06:51,044 --> 00:06:53,847 +即 CDN1 和 CDN2 + +113 +00:06:53,881 --> 00:06:58,585 +两者都包含两个变体流 +一个 6 Mbps 高分辨率视频 + +114 +00:06:58,619 --> 00:07:02,956 +和一个 3 Mbps 低分辨率视频 + +115 +00:07:02,990 --> 00:07:06,260 +唯一的区别是它们的 URI 主机名 + +116 +00:07:06,293 --> 00:07:09,663 +每个路径还有两个不同的音频组 + +117 +00:07:09,696 --> 00:07:13,100 +它们具有不同的 URI 主机名 + +118 +00:07:13,133 --> 00:07:17,404 +下面是一个示例 Steering Manifest +它是一个 JSON 文档 + +119 +00:07:17,437 --> 00:07:22,176 +PATHWAY-PRIORITY 字段是按 +首选项顺序排列的通路 ID 列表 + +120 +00:07:22,209 --> 00:07:27,347 +因此 在这种情况下 接收客户端 +播放器将首选 CDN1 而不是 CDN2 + +121 +00:07:27,381 --> 00:07:30,784 +这是 Steering Server +提供给欧洲客户的 + +122 +00:07:30,817 --> 00:07:34,922 +Steering Manifest 让他们选择 CDN1 + +123 +00:07:34,955 --> 00:07:38,258 +通过更改 Steering Manifest 的 +PATHWAY-PRIORITY 字段 + +124 +00:07:38,292 --> 00:07:42,095 +一个 Steering Server 可以控制 +每个客户端的转向策略 + +125 +00:07:42,129 --> 00:07:45,699 +这就是 Content Steering 的快速概述 + +126 +00:07:45,732 --> 00:07:48,402 +如果您想要更深入的了解 + +127 +00:07:48,435 --> 00:07:51,772 +随时查看我的 WWDC21 演讲 + +128 +00:07:51,805 --> 00:07:56,710 +通过 HLS Content Steering +提高全球流媒体可用性 + +129 +00:07:56,743 --> 00:07:59,713 +但是 我们提供支持 +更具可扩展性和更可靠的 + +130 +00:07:59,746 --> 00:08:03,417 +流媒体服务的旅程并不止于此 + +131 +00:08:03,450 --> 00:08:08,188 +如今 公司可以访问 +更多通用的云基础架构 + +132 +00:08:08,222 --> 00:08:12,659 +和工具来完成过去无法想象的事情 + +133 +00:08:12,693 --> 00:08:16,463 +我们必须赶上技术的飞跃 + +134 +00:08:16,496 --> 00:08:20,267 +假设我们的流媒体服务提供商 +今年已经变得更大 + +135 +00:08:20,300 --> 00:08:24,872 +他们正在尝试一种 +新方法来满足不断增长的用户群的 + +136 +00:08:24,905 --> 00:08:27,040 +动态流量需求 + +137 +00:08:27,074 --> 00:08:31,845 +他们通过实时动态 +生成 CDN 服务器队列 + +138 +00:08:31,879 --> 00:08:35,215 +来减轻时间流量压力 + +139 +00:08:35,249 --> 00:08:38,819 +例如 它可以生成新的 CDN3 舰队 + +140 +00:08:38,852 --> 00:08:41,788 +并希望将其宣传给现有的客户 + +141 +00:08:41,822 --> 00:08:45,926 +但是 挑战是当现有客户要求时 + +142 +00:08:45,959 --> 00:08:48,428 +动态生成的 CDN 信息 + +143 +00:08:48,462 --> 00:08:50,964 +并不包含在多变量播放列表中 + +144 +00:08:50,998 --> 00:08:53,133 +因为它根本不存在 + +145 +00:08:53,166 --> 00:08:58,438 +那么 我们可以做些什么来告诉客户 +新的 CDN 的出现呢 + +146 +00:08:59,273 --> 00:09:03,043 +这就是我们新的 +Pathway Cloning 功能的用武之地 + +147 +00:09:03,076 --> 00:09:06,113 +这是一项具有向后兼容性的新功能 + +148 +00:09:06,146 --> 00:09:11,118 +在 WWDC21 中引入 +Content Steering 1.2 + +149 +00:09:11,151 --> 00:09:15,022 +有了 Pathway Cloning +Steering Server 可以使用一个 + +150 +00:09:15,055 --> 00:09:16,790 +紧凑的清单定义 + +151 +00:09:16,823 --> 00:09:20,160 +向现有的客户端宣布新的 CDN + +152 +00:09:20,194 --> 00:09:22,896 +通过假设通路的结构上相同 + +153 +00:09:22,930 --> 00:09:27,901 +可以通过复制和修改现有通路 +来创建新的路径 + +154 +00:09:27,935 --> 00:09:31,672 +我们来看看通路的结构 + +155 +00:09:31,705 --> 00:09:35,108 +通路由一个或多个变体流组成 + +156 +00:09:35,142 --> 00:09:39,046 +每个变体流只能在一个 +且只有一个通路中 + +157 +00:09:39,079 --> 00:09:41,748 +如果未指定 PATHWAY-ID 属性 + +158 +00:09:41,782 --> 00:09:45,619 +它隐含的属于默认的“ . ”通路 + +159 +00:09:45,652 --> 00:09:50,858 +每个变体流可以引用 +每种媒体类型的零个或一个媒体组 + +160 +00:09:50,891 --> 00:09:54,027 +音频 字幕和隐藏式字幕 + +161 +00:09:54,061 --> 00:09:57,497 +每个媒体组可以由多个变体流引用 + +162 +00:09:57,531 --> 00:09:59,600 +甚至来自不同的通路 + +163 +00:09:59,633 --> 00:10:02,636 +当我们现有通路中克隆出新的通路时 + +164 +00:10:02,669 --> 00:10:05,005 +我们不仅应该克隆其变体流 + +165 +00:10:05,038 --> 00:10:08,108 +而且还有引用的媒体组 +如果有的话 + +166 +00:10:10,844 --> 00:10:13,180 +然后 为了使其成为新的通路 + +167 +00:10:13,213 --> 00:10:16,783 +我们需要修改新克隆通路的变体 + +168 +00:10:16,817 --> 00:10:19,720 +和呈现流的 URI + +169 +00:10:19,753 --> 00:10:24,491 +让我们以克隆的通路中的 +6 Mbps 变体流为例 + +170 +00:10:25,993 --> 00:10:30,330 +假设此特定变体流 +具有如下所示的 URI + +171 +00:10:30,364 --> 00:10:33,867 +要将其修改为新通路的 URI +请执行以下操作 + +172 +00:10:33,901 --> 00:10:38,839 +最灵活的方法是 +完整替换完整的 URI 行 + +173 +00:10:38,872 --> 00:10:42,709 +这意味着我们需要 +在 Steering Manifest 中为每个 + +174 +00:10:42,743 --> 00:10:44,478 +克隆的通路存储一整套 URI + +175 +00:10:44,511 --> 00:10:48,415 +但是 在实践中 +我们通常可以做得更好 + +176 +00:10:48,448 --> 00:10:51,285 +在业界 +跨多个 CDN 部署流媒体资产 + +177 +00:10:51,318 --> 00:10:56,056 +并保留相同的 URI 路径结构 +是很常见的 + +178 +00:10:56,089 --> 00:11:00,661 +从同一 URI 提供的资产 +共享相同的 URI 主机名 + +179 +00:11:00,694 --> 00:11:02,829 +和查询参数 + +180 +00:11:03,664 --> 00:11:06,767 +如果是这种情况 +我们只需要在清单中 + +181 +00:11:06,800 --> 00:11:09,970 +存储主机和查询参数的替换 + +182 +00:11:10,003 --> 00:11:14,308 +并替换所有克隆 URI 的组件 +这样我们就得到了新的通路 + +183 +00:11:15,976 --> 00:11:21,381 +让我们看一下如何 +在 Manifest 对象中定义路径克隆 + +184 +00:11:21,415 --> 00:11:25,953 +我们添加了带有路径克隆对象数组的 +PATHWAY-CLONES 字段 + +185 +00:11:25,986 --> 00:11:31,558 +每个路径克隆对象定义 +从现有路径来的新通路 + +186 +00:11:31,592 --> 00:11:35,062 +在此示例中 +我们有一个路径克隆对象 + +187 +00:11:35,095 --> 00:11:41,335 +BASE-ID 字段指定 +CDN1 是要从中克隆的原始路径 + +188 +00:11:41,368 --> 00:11:46,673 +ID 字段 将新的路径 ID +指定为 CDN3 + +189 +00:11:46,707 --> 00:11:52,479 +接下来 有个 URI-REPLACEMENT 字段 +其中包含 URI 替换规则对象 + +190 +00:11:54,081 --> 00:11:58,785 +在此示例中 +我们使用 HOST 和查询参数替换规则 + +191 +00:11:58,819 --> 00:12:00,587 +这应该取代主机部分 + +192 +00:12:00,621 --> 00:12:06,527 +并分别插入或替换流 URI 的查询参数 + +193 +00:12:06,560 --> 00:12:09,029 +在这种情况下 我们将把主机部分 + +194 +00:12:09,062 --> 00:12:11,465 +替换为 cdn3.example.com + +195 +00:12:11,498 --> 00:12:15,936 +并添加或设置值为 xyz 的查询参数 foo + +196 +00:12:15,969 --> 00:12:19,973 +和值为 123 的查询参数栏 + +197 +00:12:21,241 --> 00:12:24,645 +让我们尝试在前面的示例 URI 上 + +198 +00:12:24,678 --> 00:12:27,714 +应用主机和参数 URI 替换 + +199 +00:12:27,748 --> 00:12:30,317 +首先 我们有基于 +多变量播放列表的 URI + +200 +00:12:30,350 --> 00:12:33,220 +解析的变体流 URI + +201 +00:12:34,288 --> 00:12:38,225 +在 Steering Manifest 中 +我们使用了主机 URI 替换规则 + +202 +00:12:38,258 --> 00:12:40,727 +因此 对于 URI 的主机部分 + +203 +00:12:40,761 --> 00:12:44,498 +我们用 cdn3.example.com 替换它 + +204 +00:12:44,531 --> 00:12:48,035 +并获取了新 URI 的新主机部件 + +205 +00:12:51,505 --> 00:12:55,943 +然后 我们从克隆的 URI 中 +保留 URI 路径组件 + +206 +00:12:59,179 --> 00:13:03,784 +最后 我们应用 +URI 查询参数替换规则 + +207 +00:13:03,817 --> 00:13:08,956 +在这里 我们替换 foo 参数 +因为它存在于原始 URI 上 + +208 +00:13:08,989 --> 00:13:13,927 +然后 我们追加 bar 参数 +因为它是一个新参数 + +209 +00:13:13,961 --> 00:13:19,132 +这样 我们有了新 URI 的 +替换查询参数部分 + +210 +00:13:19,166 --> 00:13:23,737 +最终结果 URI +来自新通路 CDN3 的 + +211 +00:13:23,770 --> 00:13:26,440 +6 Mbps 变体流的 URI + +212 +00:13:27,608 --> 00:13:31,512 +我们将相同的 URI 替换规则 +应用于其余变体 + +213 +00:13:31,545 --> 00:13:34,381 +和克隆通路中的再现 + +214 +00:13:34,414 --> 00:13:39,253 +对于 3 Mbps 变体流 +我们有原始 URI + +215 +00:13:39,286 --> 00:13:44,758 +并应用主机和参数 +替换规则以获取新的 URI + +216 +00:13:44,791 --> 00:13:48,362 +我们对音频和字幕再现 +执行相同的操作 + +217 +00:13:48,395 --> 00:13:53,400 +将 URI 替换规则 +应用于所有克隆的变体和格式副本后 + +218 +00:13:53,433 --> 00:13:57,538 +我们就有了一个 +从新的 CDN 主机服务的新通路 + +219 +00:13:58,505 --> 00:14:02,376 +让我们再举一个例子 +假设流媒体提供商 + +220 +00:14:02,409 --> 00:14:06,413 +希望通过对最快的 CDN 主机 +进行特殊调整 + +221 +00:14:06,446 --> 00:14:09,917 +来提供最高带宽的视频和音频流 + +222 +00:14:09,950 --> 00:14:13,287 +这与其他较低比特率的流不同 + +223 +00:14:13,320 --> 00:14:18,625 +这就是 per-stable-ID +URI 替换规则派上用场的地方 + +224 +00:14:18,659 --> 00:14:23,497 +在 HLS 中 STABLE-VARIANT-ID +和 STABLE-RENDITION-ID 属性 + +225 +00:14:23,530 --> 00:14:27,501 +被引入 以识别变体和再现流 + +226 +00:14:27,534 --> 00:14:30,237 +通过在多变量播放列表中设置 + +227 +00:14:30,270 --> 00:14:33,674 +我们稍后通过通路克隆对象中的 +稳定 ID + +228 +00:14:33,707 --> 00:14:36,310 +在Steering Manifest 中 + +229 +00:14:36,343 --> 00:14:38,045 +引用每个变体或呈现流 + +230 +00:14:38,078 --> 00:14:41,081 +并为每个流分配 URI 替换规则 + +231 +00:14:41,915 --> 00:14:45,519 +要定义这些特定的 +特殊 URI 替换规则 请执行以下操作 + +232 +00:14:45,552 --> 00:14:49,156 +我们需要为多变量播放列表中的 +所有变体和呈现流 + +233 +00:14:49,189 --> 00:14:51,358 +分配稳定的 ID + +234 +00:14:51,391 --> 00:14:56,430 +例如 我们将 +STABLE-RENDITION-ID “audio-en-ac3” + +235 +00:14:56,463 --> 00:14:58,599 +分配到 AC3 English 音频 + +236 +00:14:58,632 --> 00:15:01,902 +并将 STABLE-VARIANT-ID “video-4k-dv” + +237 +00:15:01,935 --> 00:15:05,572 +分配到 25 Mbps 4K 变体流 + +238 +00:15:05,606 --> 00:15:07,508 +然后 在 Steering Manifest 中 + +239 +00:15:07,541 --> 00:15:10,444 +我们可以通过引用其稳定 ID + +240 +00:15:10,477 --> 00:15:13,213 +添加两个灵活的替换规则 + +241 +00:15:13,247 --> 00:15:17,217 +对于变体流 我们将 +PER-VARIANT-URIS 字段 + +242 +00:15:17,251 --> 00:15:19,453 +添加到 URI-REPLACEMENT 对象 + +243 +00:15:19,486 --> 00:15:24,324 +使用 STABLE-VARIANT-ID +到 URI 记录的字典 + +244 +00:15:24,358 --> 00:15:27,895 +在这里 我们指定用 STABLE-VARIANT-ID +“video-4k-dv” + +245 +00:15:27,928 --> 00:15:33,934 +和下面的 URI 来替换变量流的 URI + +246 +00:15:33,967 --> 00:15:37,905 +对于格式副本流 +我们用 STABLE-RENDITION-ID + +247 +00:15:37,938 --> 00:15:40,007 +到 URI 记录的字典 +将 PER-RENDITION-URIS 字段 + +248 +00:15:40,040 --> 00:15:44,912 +添加到 URI-REPLACEMENT 对象 + +249 +00:15:44,945 --> 00:15:48,148 +这里我们指定用 STABLE-RENDITION-ID +“audio-en-ac3” + +250 +00:15:48,182 --> 00:15:53,887 +用以下 URI 替换呈现流的 URI + +251 +00:15:55,622 --> 00:15:58,725 +在这里 我们看到 +在应用 URI 替换后 + +252 +00:15:58,759 --> 00:16:03,897 +所有流都从新的 +cdn3.exmaple.com 主机提供服务 + +253 +00:16:03,931 --> 00:16:08,869 +除了 4K 视频变体 +和 AC3 英语音频再现 + +254 +00:16:08,902 --> 00:16:11,605 +其中它们具有特殊的 URI 替换规则 + +255 +00:16:11,638 --> 00:16:15,175 +将其指向 +faster.example.com 主机 + +256 +00:16:15,209 --> 00:16:18,745 +并具有不同的 URI 路径 +和查询组件 + +257 +00:16:20,414 --> 00:16:24,284 +有了通路克隆 +当流式处理提供程序动态生成时 + +258 +00:16:24,318 --> 00:16:28,021 +在本例中 就是新的 CDNfleet CDN3 + +259 +00:16:28,055 --> 00:16:30,424 +转向服务器可以添加 CDN3 + +260 +00:16:30,457 --> 00:16:35,762 +作为其 Steering Manifest 中 +现有客户端的通路克隆 + +261 +00:16:35,796 --> 00:16:39,800 +它还可以选择一个区域 例如欧洲 + +262 +00:16:39,833 --> 00:16:44,271 +来优先考虑将 CDN3 作为主要通路 + +263 +00:16:44,304 --> 00:16:47,975 +当欧洲客户获得 +Steering Manifest 更新时 + +264 +00:16:48,008 --> 00:16:51,745 +它们将引导流量转向 CDN3 + +265 +00:16:51,778 --> 00:16:54,114 +在本期演讲的最后一部分 + +266 +00:16:54,147 --> 00:16:57,818 +让我们将重点转移到 +Steering Server 的细节上 + +267 +00:16:57,851 --> 00:17:00,754 +解释如何实现服务器逻辑 + +268 +00:17:00,787 --> 00:17:05,959 +通过具体示例 +引导客户端流量 以实现负载平衡 + +269 +00:17:06,660 --> 00:17:09,796 +管理和编排大量客户端的一种方法 + +270 +00:17:09,830 --> 00:17:14,268 +以及应用分区规则 +是将每个客户端放入存储器中 + +271 +00:17:14,301 --> 00:17:16,904 +并在存储器级别应用规则 + +272 +00:17:16,937 --> 00:17:20,240 +在 Steering Server 上 +实施存储器非常简单 + +273 +00:17:20,274 --> 00:17:23,343 +不需要维护任何客户端会话状态 + +274 +00:17:23,377 --> 00:17:27,014 +当客户端请求 +初始 Steering Manifest 时 + +275 +00:17:27,047 --> 00:17:31,585 +它在 Steering Server URI 上 +发出 HTTP GET 请求 + +276 +00:17:31,618 --> 00:17:37,791 +然后 服务器从 12 个可能的存储中 +生成统一的随机数 + +277 +00:17:37,824 --> 00:17:41,528 +返回 Steering Manifest 时 +服务器会添加存储器编号 + +278 +00:17:41,562 --> 00:17:45,199 +在这种情况下 +7 为 RELOAD-URI 属性 + +279 +00:17:45,232 --> 00:17:47,568 +这将是来自客户端播放器 +下一个请求的 + +280 +00:17:47,601 --> 00:17:50,270 +Steering Manifest URI + +281 +00:17:50,304 --> 00:17:54,007 +以便下次客户端播放器 +请求 Steering Manifest 时 + +282 +00:17:54,041 --> 00:17:57,578 +它将在其请求参数中携带存储器编号 + +283 +00:17:57,611 --> 00:18:02,382 +并且服务器可以提取它并根据 +存储器编号应用转向规则 + +284 +00:18:03,183 --> 00:18:06,753 +现在 让我们看一个简单的 +双分区转向规则 + +285 +00:18:06,787 --> 00:18:09,923 +在这种情况下 +我们希望引导 50% 的流量 + +286 +00:18:09,957 --> 00:18:15,462 +倾向于 CDN1 +其他 50% 的流量倾向于 CDN2 + +287 +00:18:15,495 --> 00:18:18,599 +我们可以根据存储器编号 +编写此类规则 + +288 +00:18:18,632 --> 00:18:22,603 +如果客户端播放器的数 +落在前 6 个存储器中 + +289 +00:18:22,636 --> 00:18:27,641 +我们返回倾向于 CDN1的 +带有 PATHWAY-PRIORITY 的 Steering Manifest + +290 +00:18:27,674 --> 00:18:32,946 +否则返回倾向于 CDN2的 + +291 +00:18:32,980 --> 00:18:36,650 +由于客户端是统一分配到存储器的 + +292 +00:18:36,683 --> 00:18:42,256 +将 12 个存储器分成 6 个存储器 +可以对流量进行平均分区 + +293 +00:18:43,590 --> 00:18:49,596 +现在 假设一个名为 CDN3 的 +新通路是动态生成的 + +294 +00:18:49,630 --> 00:18:53,300 +Steering Server 可以使用 +通路克隆向客户端宣传它 + +295 +00:18:53,333 --> 00:18:57,204 +而客户端并不从它们的 +多变量播放列表中知道它 + +296 +00:18:57,237 --> 00:19:00,541 +用 Pathway Cloning +构建 Steering Manifest 时的 + +297 +00:19:00,574 --> 00:19:04,311 +一个常见问题是确定通路的集合 + +298 +00:19:04,344 --> 00:19:07,981 +需要包含在 +PATHWAY-CLONES 阵列中 + +299 +00:19:08,015 --> 00:19:12,986 +规则是克隆不在客户端的 +多变量播放列表中的通路 + +300 +00:19:13,020 --> 00:19:15,622 +但是 如果没有 +维护任何服务器端状态的 + +301 +00:19:15,656 --> 00:19:18,926 +客户端会话 +Steering Server 又如何 + +302 +00:19:18,959 --> 00:19:22,863 +知道客户端多变量 +播放列表中的路径集呢 + +303 +00:19:24,164 --> 00:19:27,534 +一种方法是在 +多变量播放列表的生成过程中 + +304 +00:19:27,568 --> 00:19:32,172 +在初始转向服务器 URI 中 + +305 +00:19:32,206 --> 00:19:35,509 +包含一组通路来作为查询参数 + +306 +00:19:35,542 --> 00:19:39,546 +在这种情况下 +多变量播放列表包含两个通路 + +307 +00:19:39,580 --> 00:19:42,115 +CDN1 和 CDN2 + +308 +00:19:42,149 --> 00:19:45,853 +因此 将它们作为查询参数 + +309 +00:19:45,886 --> 00:19:48,121 +包含在 SERVER-URI 属性中 + +310 +00:19:48,155 --> 00:19:52,492 +然后 客户端播放器 +将向 URI 发送请求 + +311 +00:19:52,526 --> 00:19:56,063 +将参数传送到 steering server + +312 +00:19:56,096 --> 00:19:58,832 +然后 Steering Server 可以提取参数 + +313 +00:19:58,866 --> 00:20:03,270 +作为客户端 +多变量播放列表中的通路集 + +314 +00:20:03,303 --> 00:20:06,573 +然后它可以通过 +用客户端多变量播放列表中的 + +315 +00:20:06,607 --> 00:20:09,476 +通路集减去可用通路集 + +316 +00:20:09,510 --> 00:20:13,313 +来计算要克隆的通路集 + +317 +00:20:13,347 --> 00:20:17,851 +在这种情况下 +可用的通路是 CDN1 2 和 3 + +318 +00:20:17,885 --> 00:20:22,856 +客户端多变量播放列表中的通路是 +CDN1 和 CDN2 + +319 +00:20:22,890 --> 00:20:25,526 +因此 需要包含的通路 + +320 +00:20:25,559 --> 00:20:29,096 +在 PATHWAY-CLONES 阵列中 +是 CDN3 + +321 +00:20:31,231 --> 00:20:33,700 +让我们也来看看 +当有三个可用的通路时 + +322 +00:20:33,734 --> 00:20:38,472 +Steering Server 如何更改其转向规则 + +323 +00:20:38,505 --> 00:20:41,241 +在这种情况下 服务器想要分区 + +324 +00:20:41,275 --> 00:20:45,379 +客户端流量在 CDN1 2 +和 3 之间均匀分布 + +325 +00:20:45,412 --> 00:20:50,817 +我们通过返回首选 CDN1 的 +PATHWAY-PRIORITY 来编写此规则 + +326 +00:20:50,851 --> 00:20:57,157 +如果客户端的存储器数量 +位于 12 个存储桶的前三分之一 + +327 +00:20:57,191 --> 00:21:00,794 +返回首选 CDN2 的 +PATHWAY-PRIORITY + +328 +00:21:00,827 --> 00:21:05,365 +如果客户端的存储器数 +在第二到第三个范围内 + +329 +00:21:05,399 --> 00:21:10,237 +否则返回首选 CDN3 的 +PATHWAY-PRIORITY + +330 +00:21:10,270 --> 00:21:15,142 +这样 每个通路将为 +三分之一的客户端流量提供服务 + +331 +00:21:15,175 --> 00:21:18,745 +凭借我们涵盖的一切 +开发者现在装备齐全 + +332 +00:21:18,779 --> 00:21:23,350 +使用自己的动态转向规则 +构建开发者的 Steering Server + +333 +00:21:23,383 --> 00:21:27,020 +这样做可以进一步 +提高流服务的可靠性 + +334 +00:21:28,555 --> 00:21:32,259 +这些是我们 +今年在内容指导方面的更新 + +335 +00:21:32,292 --> 00:21:33,627 +如果您还没有做过 + +336 +00:21:33,660 --> 00:21:38,432 +尝试采用 Content Steering +作为开发者的 HLS CDN 后备机制 + +337 +00:21:38,465 --> 00:21:43,303 +因为它用途更广 +并提供动态流量转向 + +338 +00:21:43,337 --> 00:21:47,541 +请同时利用新的通路克隆功能 + +339 +00:21:47,574 --> 00:21:50,410 +来提高服务的可靠性 + +340 +00:21:50,444 --> 00:21:57,417 +像往常一样 查看最新的 +IETF HLS 规范以了解更多技术细节 + +341 +00:21:57,451 --> 00:22:01,421 +请记得使用 +我们的 HTTP 实时流媒体工具 + +342 +00:22:01,455 --> 00:22:04,858 +在进行更改时验证播放列表 + +343 +00:22:04,892 --> 00:22:07,928 +最后 如果开发者有其他问题或建议 + +344 +00:22:07,961 --> 00:22:13,033 +请随时通过 hls-interest@ietf.org +与我们联系 + +345 +00:22:13,066 --> 00:22:16,436 +感谢您的加入 祝您今天愉快 + diff --git "a/zho/2022 Session 10145 What\342\200\231s new in HLS Interstitials.srt" "b/zho/2022 Session 10145 What\342\200\231s new in HLS Interstitials.srt" new file mode 100644 index 0000000..262b1ec --- /dev/null +++ "b/zho/2022 Session 10145 What\342\200\231s new in HLS Interstitials.srt" @@ -0,0 +1,780 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:14,147 +大家好 我是 Prashant +欢迎来到 WWDC + +3 +00:00:14,181 --> 00:00:18,085 +2021 年 +我们推出了 HLS Interstitials + +4 +00:00:18,118 --> 00:00:21,188 +可在您的 HLS 流中 +简单地加入广告 + +5 +00:00:21,221 --> 00:00:23,423 +和其它插屏 + +6 +00:00:23,457 --> 00:00:24,992 +今年 我们新增了 + +7 +00:00:25,025 --> 00:00:27,494 +让您更好地优化广告位 + +8 +00:00:27,528 --> 00:00:29,997 +同时调整展示方式的功能 + +9 +00:00:30,030 --> 00:00:33,467 +来 我们一起看看 +HLS Interstitials 有什么新内容吧 + +10 +00:00:33,500 --> 00:00:39,306 +在这次讲座中 我们先快速回顾下 +HLS Interstitials 是如何运作的 + +11 +00:00:39,339 --> 00:00:44,144 +接着 我们来讨论下新增的 +广告提示选项 + +12 +00:00:44,178 --> 00:00:47,147 +随后 我们来看下您可以如何 +调整广告体验 + +13 +00:00:47,181 --> 00:00:51,552 +尤其在使用 SNAP 属性的 +直播场景中 + +14 +00:00:51,585 --> 00:00:53,820 +然后 我们看下 +HLS specification 中新增的 + +15 +00:00:53,854 --> 00:00:57,291 +一些查询参数 + +16 +00:00:57,324 --> 00:01:00,761 +最后 我们来探讨在这些新功能下 + +17 +00:01:00,794 --> 00:01:03,564 +AVFoundation APIs 中的 +具体改变 + +18 +00:01:03,597 --> 00:01:05,933 +但在我们了解新功能前 + +19 +00:01:05,966 --> 00:01:09,369 +先快速回顾下 HLS interstitials + +20 +00:01:09,403 --> 00:01:12,573 +有了 HLS Interstitials +广告可以被当作一种独立的资产来处理 + +21 +00:01:12,606 --> 00:01:15,542 +它可以被加入到一条编程时间线 + +22 +00:01:15,576 --> 00:01:18,545 +不再需要链接非连续的标签 + +23 +00:01:18,579 --> 00:01:22,716 +相反 它们可以直接通过 +多元播放列表直接引用 + +24 +00:01:22,749 --> 00:01:26,353 +这让广告的安排更简单 因为您只需 + +25 +00:01:26,386 --> 00:01:29,323 +从您的主要内容指向 +多元播放列表即可 + +26 +00:01:30,324 --> 00:01:35,028 +这是典型的媒体播放列表 +显示主要内容时间线 + +27 +00:01:35,062 --> 00:01:38,031 +假设您要在回放期间 +安排两个广告 + +28 +00:01:38,065 --> 00:01:42,202 +您想要第一个广告 +在回放大约 5 秒后出现 + +29 +00:01:42,236 --> 00:01:46,773 +那您只要用 DATE-RANGE 标签 +指定广告的开始时间 + +30 +00:01:48,275 --> 00:01:51,445 +而第二个广告在 15 秒时出现 + +31 +00:01:51,478 --> 00:01:54,748 +那就在播放列表加入 +另一个标签 + +32 +00:01:54,781 --> 00:01:56,316 +就这么简单 + +33 +00:01:57,451 --> 00:02:02,222 +也可能您的主要内容里 +已经有一些嵌入广告了 + +34 +00:02:02,256 --> 00:02:05,325 +您甚至可以通过指定一个 +等同于这些内嵌广告时长的 + +35 +00:02:05,359 --> 00:02:07,861 +resume offset 来替换这些广告 + +36 +00:02:08,996 --> 00:02:12,432 +此外 HLS interstitials 还可让您 + +37 +00:02:12,466 --> 00:02:14,668 +为广告指定导航限制 + +38 +00:02:14,701 --> 00:02:17,371 +您甚至可以在直播场景中 +安排复位 + +39 +00:02:17,404 --> 00:02:18,639 +和其它方面 + +40 +00:02:18,672 --> 00:02:21,141 +您可查看 WWDC 2021 的 +“Dynamically insert midrolls + +41 +00:02:21,175 --> 00:02:26,513 +and prerolls in HLS” +以获得更多信息 + +42 +00:02:26,547 --> 00:02:29,650 +虽然您可以顺着内容时间线 +安排广告 + +43 +00:02:29,683 --> 00:02:33,086 +但今年 我们还新增了 +强制将广告放置在 + +44 +00:02:33,120 --> 00:02:35,589 +回放开始或结束的属性 + +45 +00:02:35,622 --> 00:02:39,760 +因此 我们增加了以下新提示选项 + +46 +00:02:39,793 --> 00:02:41,895 +您可指定 CUE 属性 + +47 +00:02:41,929 --> 00:02:46,400 +这一属性以下值的其中之一 +或组合 + +48 +00:02:46,433 --> 00:02:48,602 +PRE 值可以让广告 + +49 +00:02:48,635 --> 00:02:51,872 +在主要内容开始前出现 + +50 +00:02:51,905 --> 00:02:53,774 +在直播场景中 如果您想在 +节目开始前 + +51 +00:02:53,807 --> 00:02:56,243 +安排一个优质广告位 + +52 +00:02:56,276 --> 00:02:58,712 +这就尤为有用 + +53 +00:02:58,745 --> 00:03:00,948 +POST 值指示广告在 + +54 +00:03:00,981 --> 00:03:03,917 +主要内容后出现 + +55 +00:03:03,951 --> 00:03:06,954 +这在您安排片尾字幕的事件流中 +会比较有用 + +56 +00:03:06,987 --> 00:03:08,989 +比如实时事件的结尾 + +57 +00:03:09,890 --> 00:03:13,193 +ONCE 值可让广告 +只出现一次 + +58 +00:03:13,227 --> 00:03:15,696 +如果用户再退回到广告之前 + +59 +00:03:15,729 --> 00:03:18,332 +则不会再看到该广告 + +60 +00:03:18,365 --> 00:03:20,834 +分级屏幕是一个很好的应用 + +61 +00:03:20,868 --> 00:03:24,338 +典型的在回放开始时 +只播放一次的例子 + +62 +00:03:25,939 --> 00:03:29,042 +这里是一个播放列表的例子 +您的广告可以安排为 + +63 +00:03:29,076 --> 00:03:31,311 +前贴片广告和后贴片广告 + +64 +00:03:31,345 --> 00:03:34,615 +注意前贴片广告仅播放一次 + +65 +00:03:34,648 --> 00:03:37,351 +在回放开始大约 10 秒后 + +66 +00:03:37,384 --> 00:03:39,520 +我们也安排了一则单次广告 + +67 +00:03:40,654 --> 00:03:45,926 +现在 在直播场景中安排广告 +也面临着一系列的挑战 + +68 +00:03:45,959 --> 00:03:48,562 +比如 您的对象包装程序 +可能只用了一个 clock 函数 + +69 +00:03:48,595 --> 00:03:51,465 +来设置播放列表中的 +程序日期时间标签 + +70 +00:03:51,498 --> 00:03:53,700 +而生成媒体的解码器 + +71 +00:03:53,734 --> 00:03:56,136 +是由另一个 clock 函数生成的 + +72 +00:03:56,170 --> 00:03:59,873 +现在 这两个 clock 函数 +不一定要同步 + +73 +00:03:59,907 --> 00:04:03,377 +比如 在这个示例中 +片段 0 和片段 100 之间 + +74 +00:04:03,410 --> 00:04:07,581 +日期时间标签区别大约是 +800 秒 + +75 +00:04:09,449 --> 00:04:13,420 +然而 聚合媒体持续时间与之相比 +会略少 + +76 +00:04:13,453 --> 00:04:16,190 +因为个别片段持续时间 +在 8 秒以下 + +77 +00:04:17,558 --> 00:04:19,493 +在这样的场景中 +您的对象包装程序 clock 函数 + +78 +00:04:19,526 --> 00:04:21,929 +比解码器的 clock 函数略快 + +79 +00:04:21,962 --> 00:04:27,134 +实际广告开始的媒体时间 +可能在 slate 中的某处 + +80 +00:04:27,167 --> 00:04:29,436 +如果您想从偏移位置 +即和这里展示的广告持续时长一样处 + +81 +00:04:29,469 --> 00:04:32,506 +开始加入主内容 + +82 +00:04:32,539 --> 00:04:36,276 +实际上 结果您是丢失了 +跟随 slate 的一些主要内容 + +83 +00:04:37,544 --> 00:04:40,314 +您现在可使用 SNAP 属性 +和 OUT 值 + +84 +00:04:40,347 --> 00:04:43,317 +在最接近预期广告时间的 +段边界上 + +85 +00:04:43,350 --> 00:04:46,653 +摆脱主要内容 + +86 +00:04:46,687 --> 00:04:49,523 +同样地 用 SNAP 属性和 IN 值 + +87 +00:04:49,556 --> 00:04:54,294 +来迅速跳回最接近 +广告返回时间的主要内容处 + +88 +00:04:54,328 --> 00:04:56,964 +注意 我们希望您仅在 +直播场景 + +89 +00:04:56,997 --> 00:05:00,934 +使用 SNAP 属性 +因为在处理预打包需求内容时 + +90 +00:05:00,968 --> 00:05:03,637 +clock 函数偏移是不存在的 + +91 +00:05:04,638 --> 00:05:09,676 +这里是一个直播的播放列表 +广告安排有流出和流入 + +92 +00:05:10,410 --> 00:05:13,480 +今年 我们也增加了一些咨询参数 + +93 +00:05:13,514 --> 00:05:15,782 +可帮助优化广告库存 + +94 +00:05:15,816 --> 00:05:18,218 +以及优化会话管理 + +95 +00:05:18,252 --> 00:05:21,989 +现在 您在 Ad pod 中 +转变成了直播流转 + +96 +00:05:22,022 --> 00:05:25,025 +您会很有兴趣知道 +ad pod 现在进展到第几步了 + +97 +00:05:25,058 --> 00:05:28,262 +因此在剩余的时间里 +可以展示您最优价值的存货 + +98 +00:05:29,396 --> 00:05:33,367 +我们添加了 +HLS_start_offset 参数 + +99 +00:05:33,400 --> 00:05:35,235 +_HLS_start_offset 咨询参数 + +100 +00:05:35,269 --> 00:05:39,773 +只提供插页式广告 +Asset-list URL 的请求 + +101 +00:05:39,806 --> 00:05:42,709 +在直播内容方面 +这可向 asset-list 指定偏移 + +102 +00:05:42,743 --> 00:05:45,946 +回放在加入直播流时再次响起 + +103 +00:05:45,979 --> 00:05:47,481 +对于有需求内容的视频来说 + +104 +00:05:47,514 --> 00:05:49,583 +它将会是寻找用插屏广告的 +替代位置时 + +105 +00:05:49,616 --> 00:05:52,653 +Asset-list列表的偏移地址 + +106 +00:05:54,121 --> 00:05:57,257 +在这一样本中 我们有一个 +实时播放列表 有 15 秒广告 + +107 +00:05:57,291 --> 00:06:01,161 +在播放列表顶部 +安排在 5 秒后开始 + +108 +00:06:01,195 --> 00:06:05,399 +这里突出的片段 +将会被插页式广告取代 + +109 +00:06:05,432 --> 00:06:07,768 +现在在实时加入中 +典型的客户是直播边缘背后 + +110 +00:06:07,801 --> 00:06:10,737 +大约 3 个目标的时长 + +111 +00:06:10,771 --> 00:06:13,640 +此时已经安排好的 15 秒 ad pod + +112 +00:06:13,674 --> 00:06:15,709 +可能播放了 10 秒 + +113 +00:06:15,742 --> 00:06:20,080 +这就是 HLS_Start_offset +咨询参数的一部分 + +114 +00:06:20,113 --> 00:06:22,950 +现在客户只有 5 秒的 +剩余广告时间了 + +115 +00:06:22,983 --> 00:06:26,954 +服务器可以构建 asset-list +因此清单上最后 5 秒 + +116 +00:06:26,987 --> 00:06:29,089 +就播放了最有价值的广告 + +117 +00:06:30,190 --> 00:06:32,559 +在您的服务器中 +您可以能需要一个方法 + +118 +00:06:32,593 --> 00:06:35,896 +来在多重请求下 +跟踪一些回放的会话 + +119 +00:06:35,929 --> 00:06:39,967 +这样您不会一个广告 +重复看很多遍 + +120 +00:06:40,868 --> 00:06:44,037 +因此 要将广告请求 +与主要回放会话连接 + +121 +00:06:44,071 --> 00:06:47,741 +我们添加了 +HLS_primary_id 查询参数 + +122 +00:06:47,774 --> 00:06:51,411 +如果为了特定的回放会话的 +所有 http 请求 + +123 +00:06:51,445 --> 00:06:53,914 +客户设置回放会话 id 请求 header + +124 +00:06:53,947 --> 00:06:55,716 +然后他们可以将该部分 ID + +125 +00:06:55,749 --> 00:06:58,418 +作为 _HLS_primary_id +查询参数的一部分 + +126 +00:06:58,452 --> 00:07:02,890 +到 X-Asset-URI 和 +X-Asset-List 请求 + +127 +00:07:02,923 --> 00:07:05,459 +不用设置会话 id +请求 header 的顾客 + +128 +00:07:05,492 --> 00:07:08,428 +应为每个主要回放会话 +创建一个独立的值 + +129 +00:07:08,462 --> 00:07:11,865 +将其作为 _HLS_primary_id 查询参数 +来使用 + +130 +00:07:11,899 --> 00:07:15,469 +不管是主要还是插页式广告资产 + +131 +00:07:15,502 --> 00:07:18,038 +您可能调用了 AVFoundation + +132 +00:07:18,071 --> 00:07:22,943 +提供 AVPlayerInterstitialController +和 AVPlayerInterstitialEvent 对象 + +133 +00:07:22,976 --> 00:07:26,079 +让您从客户的角度计划广告 + +134 +00:07:26,113 --> 00:07:28,782 +现在我们也增加了对提示 +和 SNAP 选项的支持 + +135 +00:07:28,815 --> 00:07:32,219 +以及 AVPlayerInterstitialEvent 对象 + +136 +00:07:32,252 --> 00:07:35,589 +您可以通过 Cue 属性指定 +提示选项 不管广告是要 + +137 +00:07:35,622 --> 00:07:38,659 +前贴片广告还是后贴片 + +138 +00:07:38,692 --> 00:07:43,063 +通过日期范围标签中的 +Cue 属性发出播放一次的信号选项 + +139 +00:07:43,096 --> 00:07:46,366 +通过 willPlayOnce property +设置为布尔值 + +140 +00:07:46,400 --> 00:07:48,836 +选项到 Snap-Out 是通过 + +141 +00:07:48,869 --> 00:07:51,839 +alignsStartWithPrimarySegmentBoundary +属性发出信号的 + +142 +00:07:51,872 --> 00:07:53,807 +要 Snap-in 您要设置 + +143 +00:07:53,841 --> 00:07:56,877 +alignsResumptionWithPrimarySegmentBoundary +属性 + +144 +00:07:58,645 --> 00:08:01,148 +随着 AVPlayerInterstitialEvent 持续增长 + +145 +00:08:01,181 --> 00:08:03,917 +我们认为将其从对象创建中 + +146 +00:08:03,951 --> 00:08:05,986 +将其属性设置独立开来最好 + +147 +00:08:06,019 --> 00:08:10,090 +因此 我们现在 +做了 AVPlayerInterstitialEvent 可变对象 + +148 +00:08:10,123 --> 00:08:12,726 +您现在可以创建只有 +主要项目的对象 + +149 +00:08:12,759 --> 00:08:14,728 +以及事件的开始时间 + +150 +00:08:14,761 --> 00:08:17,030 +然后 您可以通过 +设置相关的属性 + +151 +00:08:17,064 --> 00:08:19,132 +指定不同的配置选项 + +152 +00:08:19,967 --> 00:08:22,236 +注意一旦事件在控制面板中 +设置好 + +153 +00:08:22,269 --> 00:08:24,471 +事件对象任何后续变动 + +154 +00:08:24,505 --> 00:08:26,273 +都不会反映在控制面板上 + +155 +00:08:26,306 --> 00:08:29,343 +由于控制面板已经做了 +这些对象的副本 + +156 +00:08:29,376 --> 00:08:30,911 +要让改变生效 + +157 +00:08:30,944 --> 00:08:34,515 +您要再次在控制面板上 +设置事件 + +158 +00:08:34,548 --> 00:08:38,886 +总而言之 您现在可以 +使用 X-CUE 属性 + +159 +00:08:38,919 --> 00:08:40,654 +将广告计划为前贴片 +或后贴片广告 + +160 +00:08:40,687 --> 00:08:45,692 +您也可以通过设置 X-CUE 为 1 次 +强制让广告只播放一次 + +161 +00:08:45,726 --> 00:08:50,464 +要管理直播场景中的偏移 +您可以使用 X-SNAP 属性 + +162 +00:08:50,497 --> 00:08:53,233 +在实时加入期间 +要构建您的 asset lists + +163 +00:08:53,267 --> 00:08:56,270 +您可以使用 +_HLS_start_offset 查询参数 + +164 +00:08:56,303 --> 00:08:58,872 +您可以使用 HLS_primary_id +查询参数 + +165 +00:08:58,906 --> 00:09:02,543 +来联系主要回放会话中的 +插页式广告请求 + +166 +00:09:02,576 --> 00:09:06,780 +您知道如果用 +HLS interstitials 来安排广告 + +167 +00:09:06,813 --> 00:09:11,018 +AVFoundation 是否会 +在 Shareplay 中管理它们 + +168 +00:09:11,051 --> 00:09:12,619 +您可查看“Display ads +and other interstitials in SharePlay” + +169 +00:09:12,653 --> 00:09:16,023 +以获得更多 +关于 SharePlay”的信息 + +170 +00:09:16,056 --> 00:09:18,926 +以上是我的全部内容 +感谢大家的观看 + diff --git a/zho/2022 Session 10147 Create a great video playback experience.srt b/zho/2022 Session 10147 Create a great video playback experience.srt new file mode 100644 index 0000000..16361a4 --- /dev/null +++ b/zho/2022 Session 10147 Create a great video playback experience.srt @@ -0,0 +1,1856 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,710 --> 00:00:11,678 +Jake: 大家好 我是 Jake + +3 +00:00:11,712 --> 00:00:13,313 +是 AVKit 团队的一名工程师 + +4 +00:00:13,347 --> 00:00:16,583 +欢迎观看 +打造出色的视频播放体验 + +5 +00:00:16,617 --> 00:00:21,021 +在 iOS 和 iPadOS 16 中 +我们从头开始搭建了全新的 + +6 +00:00:21,054 --> 00:00:22,389 +媒体播放器 + +7 +00:00:22,422 --> 00:00:24,658 +带来全新的外观和感觉 + +8 +00:00:24,691 --> 00:00:27,594 +旨在保持对内容的关注 + +9 +00:00:27,628 --> 00:00:30,364 +并适合更广泛的 App + +10 +00:00:30,397 --> 00:00:33,166 +我们还构建了许多新颖的交互模型 + +11 +00:00:33,200 --> 00:00:37,905 +让使用这款新媒体播放器 +有更加直观和无缝的体验 + +12 +00:00:37,938 --> 00:00:40,741 +我们认为开发者会爱上它 + +13 +00:00:40,774 --> 00:00:45,379 +在本期讲座中 我们将深入探讨 +新的系统媒体播放器 + +14 +00:00:45,412 --> 00:00:49,449 +我们将学习如何 +设计令人惊艳的播放体验 + +15 +00:00:49,483 --> 00:00:51,952 +我们将在 macOS 和 iOS 中 +看到一些 + +16 +00:00:51,985 --> 00:00:54,655 +令人兴奋的新的视觉智能功能 + +17 +00:00:54,688 --> 00:00:56,990 +我将介绍全新的 +新媒体播放器附带 + +18 +00:00:57,024 --> 00:00:59,092 +插页式广告体验 + +19 +00:00:59,126 --> 00:01:02,930 +并介绍我们从 tvOS +带来的一些新 API + +20 +00:01:02,963 --> 00:01:06,133 +最后 我们将介绍 +AVKit 中的一个新功能 + +21 +00:01:06,166 --> 00:01:08,869 +可选播放速度 + +22 +00:01:08,902 --> 00:01:12,940 +我们重新设计了 +tvOS 15.0 的系统播放器 + +23 +00:01:12,973 --> 00:01:14,608 +带来了全新的外观和感觉 + +24 +00:01:14,641 --> 00:01:17,611 +以及系统播放器的许多新功能 + +25 +00:01:17,644 --> 00:01:19,513 +和可用性改进 + +26 +00:01:19,546 --> 00:01:21,648 +好吧 我们听到了大家的需求 + +27 +00:01:21,682 --> 00:01:25,919 +很高兴地告诉大家我们也改进了 +iOS 系统播放器 + +28 +00:01:25,953 --> 00:01:28,555 +我们已经完全重新设计了 +原生媒体播放器 + +29 +00:01:28,589 --> 00:01:31,191 +采用了 tvOS 播放器的观感 + +30 +00:01:31,225 --> 00:01:35,095 +但重新设计了触控优先设备 + +31 +00:01:35,128 --> 00:01:37,631 +我们已经删除了面板上的颜色 + +32 +00:01:37,664 --> 00:01:41,268 +让界面在更广泛的 +App 中具有原生感 + +33 +00:01:41,301 --> 00:01:44,304 +并为用户带来更现代的感觉 + +34 +00:01:44,338 --> 00:01:47,307 +我们来更深入地了解一下 +所做的一些改进 + +35 +00:01:47,341 --> 00:01:51,712 +首先 我们将播放 暂停和 +跳跃控制放在前面和中间 + +36 +00:01:51,745 --> 00:01:54,681 +使它们更容易与之交互 + +37 +00:01:54,715 --> 00:01:58,952 +我们还将跳跃间隔从 15 秒 +下调至 10 秒 + +38 +00:01:58,986 --> 00:02:03,323 +可以更轻松地跟踪 +连续跳跃的距离 + +39 +00:02:03,357 --> 00:02:06,193 +接下来 我们还对时间轴的可用性 + +40 +00:02:06,226 --> 00:02:08,128 +进行了一些重大改进 + +41 +00:02:08,161 --> 00:02:12,566 +我们将移除用于标记 +时间轴当前位置的滑块旋钮 + +42 +00:02:12,599 --> 00:02:15,269 +相反 现在可以从滑块的任意位置 + +43 +00:02:15,302 --> 00:02:17,471 +与时间线进行交互 + +44 +00:02:17,504 --> 00:02:20,140 +拖动不再需要从当前时间标记开始 + +45 +00:02:20,174 --> 00:02:24,344 +这使得大家更容易 +准确地找到您想去的位置 + +46 +00:02:24,378 --> 00:02:26,446 +我们还用更直观的缩放手势 + +47 +00:02:26,480 --> 00:02:29,016 +取代了视频方面的控制 + +48 +00:02:29,049 --> 00:02:30,717 +我稍后会展示 + +49 +00:02:30,751 --> 00:02:35,155 +当然 新的 UI 对于竖屏内容 +看起来也很棒 + +50 +00:02:37,257 --> 00:02:40,861 +在 iPadOS 上 +播放器无缝集成到系统中 + +51 +00:02:40,894 --> 00:02:43,797 +全面支持键盘 触控板 + +52 +00:02:43,830 --> 00:02:47,367 +鼠标 游戏控制器等等 + +53 +00:02:47,401 --> 00:02:50,470 +我们还添加了一些 +与控件交互的新方法 + +54 +00:02:50,504 --> 00:02:53,807 +使导航内容和一些常见的交互 + +55 +00:02:53,841 --> 00:02:56,109 +更容易和直观 + +56 +00:02:56,143 --> 00:02:58,145 +让我们来看看这些 + +57 +00:02:58,178 --> 00:03:01,882 +首先 我们添加了一种更改 +视频缩放填充的新方法 + +58 +00:03:01,915 --> 00:03:05,886 +您现在可以使用捏合手势 +在可用缩放级别之间转换 + +59 +00:03:05,919 --> 00:03:09,990 +捏合将使视频 +位于显示屏的安全区域内 + +60 +00:03:10,023 --> 00:03:13,627 +扩展将放大视频以完全填满显示屏 + +61 +00:03:13,660 --> 00:03:17,631 +接下来 我们让 +最常见的交互之一更流畅 + +62 +00:03:17,664 --> 00:03:19,266 +播放或暂停 + +63 +00:03:19,299 --> 00:03:21,468 +您现在可以点击显示屏的中心 + +64 +00:03:21,502 --> 00:03:25,138 +哪怕播放和暂停视频的控制键 +被隐藏了 + +65 +00:03:25,172 --> 00:03:29,376 +最后 我们添加了一种通过 +媒体时间轴导航的新方法 + +66 +00:03:29,409 --> 00:03:32,880 +现在 您可以使用大家都了解 +和喜爱的滚动视图中相同的交互 + +67 +00:03:32,913 --> 00:03:37,050 +从视频的任何位置滚动时间轴 + +68 +00:03:37,084 --> 00:03:39,253 +当您滚动视频帧时 + +69 +00:03:39,286 --> 00:03:43,924 +界面消失 只留下最相关的 UI + +70 +00:03:43,957 --> 00:03:47,160 +允许将焦点保留在内容上 + +71 +00:03:47,194 --> 00:03:50,931 +我们还带来了 tvOS +播放器的一些新功能 + +72 +00:03:50,964 --> 00:03:54,134 +AVPlayerViewController +现在支持在全屏 UI 中 + +73 +00:03:54,168 --> 00:03:58,605 +显示内容标题 副标题和描述 + +74 +00:03:59,406 --> 00:04:02,976 +您可以通过传递 AVMetadataItems +为每个现有的 AVKit API + +75 +00:04:03,010 --> 00:04:04,611 +提供这些内容的字符串 + +76 +00:04:04,645 --> 00:04:07,314 +让我们看看这是如何完成的 + +77 +00:04:07,347 --> 00:04:11,218 +默认情况下 标题 副标题和 +内容描述将从 + +78 +00:04:11,251 --> 00:04:13,287 +媒体的元数据中提取 + +79 +00:04:13,320 --> 00:04:16,757 +但是 如果需要 +媒体中的值可以通过 + +80 +00:04:16,790 --> 00:04:19,426 +AVPlayerItem 上的 +externalMetadata API 被重写 + +81 +00:04:20,961 --> 00:04:24,131 +可以通过使用标识符 +commonIdentifierTitle + +82 +00:04:24,164 --> 00:04:26,900 +创建一个 AVMetadataItem + +83 +00:04:26,934 --> 00:04:30,838 +并将其添加到 playerItems 的 +externalMetadata 属性中 + +84 +00:04:30,871 --> 00:04:35,342 +标题应简短且具有描述性 +以避免使 UI 混乱 + +85 +00:04:35,375 --> 00:04:39,780 +同样 这里我们通过创建 +带有标识符 .iTunesMetadataTrackSubtitle + +86 +00:04:39,813 --> 00:04:44,484 +的 AVMetadataItem 来添加字幕 + +87 +00:04:44,518 --> 00:04:47,087 +字幕将显示在内容标题上方 + +88 +00:04:47,120 --> 00:04:49,790 +并且应该用几个词来描述内容 + +89 +00:04:51,358 --> 00:04:53,126 +最后 可以使用标识符 + +90 +00:04:53,160 --> 00:04:56,964 +.commonIdentifierDescription +来添加描述 + +91 +00:04:56,997 --> 00:05:00,901 +这将在标题和副标题的 +右侧显示一个 V 形 + +92 +00:05:00,934 --> 00:05:05,973 +选择标题将显示 +包含内容描述的信息面板 + +93 +00:05:06,006 --> 00:05:11,011 +描述应该是几句话 +包含有关内容的更多信息 + +94 +00:05:11,044 --> 00:05:13,714 +点击任意位置都会关闭信息面板 + +95 +00:05:15,816 --> 00:05:19,219 +总结一下 我们对 iOS 系统播放器 + +96 +00:05:19,253 --> 00:05:23,924 +进行全新的外观和感觉的提升 +使用全新的流线型触控优先交互模型 + +97 +00:05:23,957 --> 00:05:26,827 +附带许多其他改进 + +98 +00:05:26,860 --> 00:05:29,429 +在您的 App 中使用 +AVPlayerViewController + +99 +00:05:29,463 --> 00:05:32,132 +将得到系统播放器的全面支持 + +100 +00:05:32,165 --> 00:05:36,403 +支持画中画 SharePlay +视觉分析 + +101 +00:05:36,436 --> 00:05:40,240 +原生 Catalyst 支持 +新硬件和功能支持 + +102 +00:05:40,274 --> 00:05:42,276 +还有很多很多 + +103 +00:05:42,309 --> 00:05:46,780 +当然 开发者只需几行代码即可获得 +所有的这一切 + +104 +00:05:46,813 --> 00:05:52,653 +现在 让我们谈谈如何在开发者的 +App 中设计令人惊艳的播放体验 + +105 +00:05:52,686 --> 00:05:55,255 +当我们着手重新 +设计系统媒体播放器时 + +106 +00:05:55,289 --> 00:05:57,958 +我们从过去构建的内容 + +107 +00:05:57,991 --> 00:05:59,826 +以及为其他平台构建的内容中 +后退一步 + +108 +00:05:59,860 --> 00:06:04,431 +问自己 +怎样才能创造出优秀的用户体验 + +109 +00:06:04,464 --> 00:06:06,767 +我们想与开发者分享这个过程 + +110 +00:06:06,800 --> 00:06:09,503 +我们是如何设计新播放器的 + +111 +00:06:09,536 --> 00:06:11,839 +为什么要按照我们的方式设计 + +112 +00:06:11,872 --> 00:06:15,909 +我们认为定义了 +令人惊艳的媒体体验 + +113 +00:06:15,943 --> 00:06:20,314 +我们认为有三件事可以让 +媒体体验变得很棒 + +114 +00:06:20,347 --> 00:06:23,016 +体验应该是直观的 + +115 +00:06:23,050 --> 00:06:26,854 +它应该让人感觉轻松 熟悉 自然 + +116 +00:06:26,887 --> 00:06:29,656 +即使您从未使用过 + +117 +00:06:29,690 --> 00:06:31,725 +它应该与您的 App + +118 +00:06:31,758 --> 00:06:35,262 +和系统紧密结合 + +119 +00:06:35,295 --> 00:06:38,699 +最后 它应该以内容优先 + +120 +00:06:38,732 --> 00:06:42,302 +说到底 用户是来体验媒体的 + +121 +00:06:42,336 --> 00:06:46,473 +您的 App 和设计应该反映这一点 + +122 +00:06:46,507 --> 00:06:48,876 +现在让我们深入探究这三个方法 + +123 +00:06:48,909 --> 00:06:52,779 +首先让体验更直观 + +124 +00:06:52,813 --> 00:06:55,916 +通常情况下 +当一款 App 让人感觉很直观时 + +125 +00:06:55,949 --> 00:06:59,453 +很难说出原因 + +126 +00:06:59,486 --> 00:07:02,289 +当您看到它时就知道了 + +127 +00:07:02,322 --> 00:07:04,157 +那么究竟是什么让用户界面 + +128 +00:07:04,191 --> 00:07:06,927 +或体验更直观呢 + +129 +00:07:06,960 --> 00:07:10,063 +您怎么设计呢 + +130 +00:07:10,097 --> 00:07:12,866 +我们认为是熟悉 + +131 +00:07:12,900 --> 00:07:17,704 +当您可以利用过去的经验 +来帮助理解新事物时 + +132 +00:07:17,738 --> 00:07:19,540 +这就是直观 + +133 +00:07:19,573 --> 00:07:22,242 +当您不需要解释它的工作原理 + +134 +00:07:22,276 --> 00:07:24,278 +甚至不需要思考它是如何工作的 + +135 +00:07:24,311 --> 00:07:28,115 +它完全按照您的预期运行 + +136 +00:07:29,483 --> 00:07:35,255 +我们每个人都在构建 +日常交互技术和现实世界的体验 + +137 +00:07:35,289 --> 00:07:38,759 +这两者都是经验熟悉的重要来源 + +138 +00:07:38,792 --> 00:07:43,297 +也是我们在设计 +新系统媒体播放器时的起点 + +139 +00:07:43,330 --> 00:07:46,266 +我们可以从许多类型的经验中 +获得直觉 + +140 +00:07:46,300 --> 00:07:48,635 +但我想重点谈谈两个方面 + +141 +00:07:48,669 --> 00:07:53,507 +这两个是我们在设计 +系统媒体播放器时最常依赖的 + +142 +00:07:53,540 --> 00:07:55,542 +平台范例 + +143 +00:07:55,576 --> 00:07:57,444 +和现实世界 + +144 +00:07:57,477 --> 00:08:02,583 +第一个来自我们每天使用技术的经验 + +145 +00:08:02,616 --> 00:08:05,853 +多年使用电视遥控器告诉您 + +146 +00:08:05,886 --> 00:08:08,488 +方向键左右移动焦点 + +147 +00:08:08,522 --> 00:08:13,694 +同样 轻按触控设备上的 +音量按钮可以使音频静音 + +148 +00:08:13,727 --> 00:08:17,464 +这些交互感觉很直观 +因为它们很熟悉 + +149 +00:08:17,497 --> 00:08:20,968 +您可以在您的媒体体验中 +使用这一类的熟悉的交互 + +150 +00:08:21,001 --> 00:08:23,136 +有助于使您的 App 感觉更直观 + +151 +00:08:23,170 --> 00:08:26,273 +引人入胜 甚至自然使用 + +152 +00:08:26,306 --> 00:08:30,010 +相反 发现不熟悉或意料之外的交互 + +153 +00:08:30,043 --> 00:08:34,648 +可能会令人困惑 有时甚至令人沮丧 + +154 +00:08:34,681 --> 00:08:38,752 +让我们看一些在系统播放器中 + +155 +00:08:38,785 --> 00:08:41,255 +利用这种平台熟悉度的例子 + +156 +00:08:41,288 --> 00:08:44,658 +一个很好的例子是 +iOS 系统播放器的 + +157 +00:08:44,691 --> 00:08:46,793 +展示和关闭模型 + +158 +00:08:46,827 --> 00:08:50,297 +播放器从底部动画展现 + +159 +00:08:50,330 --> 00:08:55,335 +轻轻一击 +播放器可以通过将其推回而消失 + +160 +00:08:55,369 --> 00:08:59,273 +我们看到这个模型在 +触控优先设备中广泛使用 + +161 +00:08:59,306 --> 00:09:02,142 +例如 Music 中正在播放的 UI + +162 +00:09:02,176 --> 00:09:03,777 +从底部的迷你栏中呈现 + +163 +00:09:03,810 --> 00:09:08,048 +并且可以通过 +向下交互式滑动来关闭 + +164 +00:09:08,081 --> 00:09:11,084 +在某些情况下 +我们的经验并非来自 + +165 +00:09:11,118 --> 00:09:14,922 +对技术的理解 而是来自日常生活 + +166 +00:09:16,323 --> 00:09:20,027 +这些类型的体验来自现实世界 + +167 +00:09:20,060 --> 00:09:22,763 +数百万年的进化帮助我们 + +168 +00:09:22,796 --> 00:09:26,600 +对自然过程形成了一种 +深刻的本能理解 + +169 +00:09:26,633 --> 00:09:28,235 +您可以利用这种理解 + +170 +00:09:28,268 --> 00:09:32,172 +帮助在软件中构建熟悉和直观的体验 + +171 +00:09:32,206 --> 00:09:36,777 +一个很好的例子是我们 +在 iOS 播放器中的新滚动手势 + +172 +00:09:36,810 --> 00:09:39,413 +类似于在桌子上滚动玩具车 + +173 +00:09:39,446 --> 00:09:42,216 +视频上的每一次滑动都有动量 + +174 +00:09:42,249 --> 00:09:46,186 +在直接交互后继续移动时间轴 + +175 +00:09:46,220 --> 00:09:49,990 +直到时间轴慢慢停止 + +176 +00:09:50,023 --> 00:09:52,459 +这里的动量本身 +就与现实世界中的移动对象 + +177 +00:09:52,492 --> 00:09:54,995 +建立了联系 + +178 +00:09:55,028 --> 00:09:59,499 +这种联系有助于您 +发现互动的微妙深度 + +179 +00:09:59,533 --> 00:10:02,402 +就像玩具车一样 +我可以通过更加大力地推动 + +180 +00:10:02,436 --> 00:10:04,471 +或连续推几次 + +181 +00:10:04,505 --> 00:10:06,773 +让它跑得更快 + +182 +00:10:06,807 --> 00:10:10,210 +如果我抓住它 就会停止 + +183 +00:10:10,244 --> 00:10:15,148 +感觉很自然 因为它很自然 + +184 +00:10:15,182 --> 00:10:16,817 +最好的部分是 + +185 +00:10:16,850 --> 00:10:21,121 +如果您使用系统播放器 +您的 App 会感觉很直观 + +186 +00:10:21,154 --> 00:10:24,892 +我们建立并继承对系统播放器的 + +187 +00:10:24,925 --> 00:10:27,995 +直观和熟悉的所有自然交互 + +188 +00:10:28,028 --> 00:10:30,597 +所有的设计范式都以 + +189 +00:10:30,631 --> 00:10:35,669 +tvOS iOS 和 macOS +用户能够自然理解的方式优化 + +190 +00:10:35,702 --> 00:10:39,540 +所有这些只需要几行代码就能得到 + +191 +00:10:40,641 --> 00:10:46,313 +构建直观的设计 +是让您的媒体体验很棒的一个方面 + +192 +00:10:46,346 --> 00:10:50,217 +但如果没有人们所期待的 +所有功能和整合点 + +193 +00:10:50,250 --> 00:10:55,088 +您的 App 可能会 +无意中将注意力从内容中移开 + +194 +00:10:55,122 --> 00:11:00,027 +这将我们引向了令人惊艳的 +媒体体验的第二个关键方面 + +195 +00:11:00,527 --> 00:11:02,329 +紧密集成 + +196 +00:11:02,362 --> 00:11:06,600 +当体验紧密集成时 人们期望运行的 + +197 +00:11:06,633 --> 00:11:11,271 +所有功能 特性和设备都能正常工作 + +198 +00:11:11,305 --> 00:11:16,510 +重要的是 +他们的工作方式与其期望一致 + +199 +00:11:16,543 --> 00:11:19,213 +随着人们使用设备 就习惯于依赖 + +200 +00:11:19,246 --> 00:11:21,782 +平台的功能 + +201 +00:11:21,815 --> 00:11:24,918 +例如 下拉控制中心 + +202 +00:11:24,952 --> 00:11:30,390 +在 Now Playing 媒体控件中 +看到您的内容 + +203 +00:11:30,424 --> 00:11:33,894 +或者在看电视节目时响应通知 + +204 +00:11:33,927 --> 00:11:38,432 +并让视频顺利进入画中画 + +205 +00:11:38,465 --> 00:11:41,268 +将这种紧密的系统集成 +构建到您的 App 中 + +206 +00:11:41,301 --> 00:11:46,173 +是实现无缝体验的关键 + +207 +00:11:46,206 --> 00:11:48,709 +您的 App 应该感觉 +像是系统的原生部分 + +208 +00:11:48,742 --> 00:11:52,679 +我们努力为开发者提供 +实现这一目标所需的工具 + +209 +00:11:52,713 --> 00:11:56,350 +包括诸如 +CoreSpotlight 集成之类的东西 + +210 +00:11:56,383 --> 00:11:58,652 +使您的内容可搜索 + +211 +00:11:58,685 --> 00:12:03,257 +现在播放信息 以便您的内容 +可以出现在系统媒体 UI 中 + +212 +00:12:03,290 --> 00:12:07,160 +MediaRemote 命令允许 +您的 App 响应诸如 + +213 +00:12:07,194 --> 00:12:10,864 +键盘或电视遥控器上按下播放按钮 + +214 +00:12:10,898 --> 00:12:15,636 +我们甚至可以将您的媒体 +直接集成到电视 App 中 + +215 +00:12:15,669 --> 00:12:19,072 +将您的内容提供给更广泛的受众 + +216 +00:12:19,106 --> 00:12:21,975 +除了让您的 App 感觉原生化之外 + +217 +00:12:22,009 --> 00:12:26,079 +提供用户喜欢的所有功能很重要 + +218 +00:12:26,113 --> 00:12:31,018 +AirPlay SharePlay 和画中画等功能 + +219 +00:12:31,051 --> 00:12:33,353 +我们认为大家会期待这些功能 + +220 +00:12:33,387 --> 00:12:38,292 +并提供它们来增强 App 的使用体验 + +221 +00:12:38,325 --> 00:12:41,161 +用户将在许多设备上使用您的 App + +222 +00:12:41,195 --> 00:12:43,630 +甚至更多的输入格式 + +223 +00:12:43,664 --> 00:12:46,266 +为所有这些提供支持对于 + +224 +00:12:46,300 --> 00:12:50,237 +确保每个人都能获得 +您的体验至关重要 + +225 +00:12:50,270 --> 00:12:52,840 +这在 tvOS 上尤其重要 + +226 +00:12:52,873 --> 00:12:55,809 +因为支持所有可用的远程设备 + +227 +00:12:55,843 --> 00:12:59,012 +对确保每个人都能使用 +您的 App 至关重要 + +228 +00:12:59,046 --> 00:13:03,917 +这是我们始终建议在 tvOS 上 +使用系统媒体播放器的原因之一 + +229 +00:13:03,951 --> 00:13:08,555 +您的 App 应确保所有电视遥控器 键盘 + +230 +00:13:08,589 --> 00:13:12,659 +触控板 游戏控制器和耳机控制 + +231 +00:13:12,693 --> 00:13:15,329 +此外 您应该确保您的 App 的 UI 元素 + +232 +00:13:15,362 --> 00:13:17,297 +是在屏幕的安全区域内绘制的 + +233 +00:13:17,331 --> 00:13:22,269 +以避免与显示屏中的圆角 +或凹槽发生冲突 + +234 +00:13:22,302 --> 00:13:25,839 +我们认识到为所有 +这些集成点建立支持 + +235 +00:13:25,873 --> 00:13:30,577 +功能和硬件配置可能令人生畏 + +236 +00:13:30,611 --> 00:13:33,280 +这就是我们构建 +AVPlayerViewController 的原因 + +237 +00:13:33,313 --> 00:13:35,415 +所以只需几行代码 + +238 +00:13:35,449 --> 00:13:39,052 +任何使用您 App 的人都可以获得 +惊艳的媒体体验 + +239 +00:13:40,621 --> 00:13:42,689 +所有这些都将我们引向 + +240 +00:13:42,723 --> 00:13:46,660 +设计媒体体验最重要的方面 + +241 +00:13:46,693 --> 00:13:49,329 +使内容前置 + +242 +00:13:49,363 --> 00:13:52,132 +这应该是您设计的主要目标 + +243 +00:13:52,165 --> 00:13:56,603 +这也是我们认为优秀媒体体验的 +决定性因素 + +244 +00:13:56,637 --> 00:13:58,605 +当您的 App 感觉直观时 + +245 +00:13:58,639 --> 00:14:00,574 +当所有的集成点 + +246 +00:14:00,607 --> 00:14:04,845 +和人们期望的所有功能 +都能正常运行时 + +247 +00:14:04,878 --> 00:14:07,814 +您就可以聚焦到内容 + +248 +00:14:07,848 --> 00:14:10,817 +而其他所有部分都会淡出背景 + +249 +00:14:12,152 --> 00:14:14,454 +有几件事您应该记住 + +250 +00:14:14,488 --> 00:14:17,057 +尤其对于设计您的内容 + +251 +00:14:17,090 --> 00:14:20,360 +确保在您的界面和系统中 + +252 +00:14:20,394 --> 00:14:23,697 +提供所有适当的元数据 + +253 +00:14:23,730 --> 00:14:26,667 +提供此信息有助于为您的媒体 +提供背景信息 + +254 +00:14:26,700 --> 00:14:29,169 +并允许系统在控制中心 + +255 +00:14:29,203 --> 00:14:31,872 +和锁屏提供更好的体验 + +256 +00:14:31,905 --> 00:14:35,075 +这包括诸如标题和副标题之类的内容 + +257 +00:14:35,108 --> 00:14:39,146 +描述 缩略图 季和集信息 + +258 +00:14:39,179 --> 00:14:41,582 +或直播的开始和结束日期 + +259 +00:14:41,615 --> 00:14:45,719 +始终保持媒体的原始纵横比 + +260 +00:14:45,752 --> 00:14:48,722 +这允许系统将您的视频 +定位在屏幕上的 + +261 +00:14:48,755 --> 00:14:50,891 +正确位置 + +262 +00:14:50,924 --> 00:14:55,762 +对您的内容添加黑边 +会带来这样的体验 + +263 +00:14:55,796 --> 00:14:57,831 +或者这样的体验 + +264 +00:14:57,865 --> 00:15:02,269 +确保尽可能支持最新的媒体标准 + +265 +00:15:02,302 --> 00:15:06,240 +例如 HDR 和杜比全景声 + +266 +00:15:06,273 --> 00:15:09,910 +最后 确保包含音频和字幕轨道 + +267 +00:15:09,943 --> 00:15:11,879 +的多语言版本 + +268 +00:15:11,912 --> 00:15:15,315 +让尽可能多的人 +可以访问您的媒体 + +269 +00:15:17,384 --> 00:15:20,654 +如果说这部分演讲 +有什么值得注意的话 + +270 +00:15:20,687 --> 00:15:24,291 +您应该把注意力集中在内容上 + +271 +00:15:24,324 --> 00:15:28,362 +我们已经构建了通过 +AVPlayerViewController 来提供 + +272 +00:15:28,395 --> 00:15:32,699 +系统媒体播放器 以使开发者 +尽可能轻松地实现这一目标 + +273 +00:15:32,733 --> 00:15:36,937 +现在 让我们谈一谈添加到 +AVPlayerViewController 的一些新功能 + +274 +00:15:36,970 --> 00:15:40,040 +从新视觉智能功能开始 + +275 +00:15:40,073 --> 00:15:45,812 +在本例中 我们让一个视频 +暂停在一个带有代码片段的帧上 + +276 +00:15:45,846 --> 00:15:48,615 +长按代码片段可以选中它 + +277 +00:15:48,649 --> 00:15:53,687 +然后 您可以将其复制并 +直接粘贴到 Playground 中进行试用 + +278 +00:15:53,720 --> 00:15:55,956 +这也适用于 macOS + +279 +00:15:55,989 --> 00:15:59,293 +将光标悬停在相同的代码上 +将显示光标 + +280 +00:15:59,326 --> 00:16:01,595 +表示文本是可选的 + +281 +00:16:01,628 --> 00:16:03,997 +然后您可以用光标来使它高亮显示 + +282 +00:16:04,031 --> 00:16:06,767 +或使用 CMD+A 全选 + +283 +00:16:06,800 --> 00:16:10,938 +我们正在引入一个新的 API +来配合这个功能 + +284 +00:16:10,971 --> 00:16:16,009 +iOS 上的 AVPlayerViewController +和 macOS 上的 AVPlayerView 中可用 + +285 +00:16:16,043 --> 00:16:19,913 +allowsVideoFrameAnalysis +切换此功能 + +286 +00:16:19,947 --> 00:16:24,151 +这将为链接到新 SDK 的 +所有 App 启用 + +287 +00:16:24,184 --> 00:16:26,987 +当 allowedVideoFrameAnalysis +设置为 true + +288 +00:16:27,020 --> 00:16:28,755 +一旦媒体暂停 + +289 +00:16:28,789 --> 00:16:33,927 +AVKit 将在设定的时间段后 +开始分析当前视频帧 + +290 +00:16:33,961 --> 00:16:36,597 +请注意 出于性能原因 + +291 +00:16:36,630 --> 00:16:38,131 +我们不会分析在滚动时的帧 + +292 +00:16:38,165 --> 00:16:40,767 +或 FairPlay 受保护的内容 + +293 +00:16:40,801 --> 00:16:46,039 +总的来说 我们认为人们 +在大多数情况下都会期待这个功能 + +294 +00:16:46,073 --> 00:16:48,242 +但是 也有一些情况是 + +295 +00:16:48,275 --> 00:16:50,878 +在您的 App 中 + +296 +00:16:50,911 --> 00:16:54,414 +可能需要禁用可视分析 + +297 +00:16:54,448 --> 00:16:57,518 +例如 在性能关键的 App 中 + +298 +00:16:57,551 --> 00:17:00,120 +例如视频的集合视图 + +299 +00:17:00,153 --> 00:17:03,257 +或在不期望与视频交互的情况下 + +300 +00:17:03,290 --> 00:17:05,459 +如启动屏幕 + +301 +00:17:05,492 --> 00:17:08,495 +有关更多如何集成 +视觉智能功能集 + +302 +00:17:08,529 --> 00:17:12,866 +到您的 App 的信息 +请参看我们关于 VisionKit 的相关演讲 + +303 +00:17:12,900 --> 00:17:17,971 +接下来 让我们看看我们对 +插页式广告所做的一些改进 + +304 +00:17:18,005 --> 00:17:20,807 +到目前为止 仅有 tvOS 上的 +AVPlayerViewController 中 + +305 +00:17:20,841 --> 00:17:23,677 +支持插页式广告 + +306 +00:17:23,710 --> 00:17:28,482 +好吧 我很高兴地宣布 +我们也将为 iOS 带来相同级别的支持 + +307 +00:17:28,515 --> 00:17:32,186 +无论是在流中还是通过 +AVPlayerInterstitialEvents + +308 +00:17:32,219 --> 00:17:33,987 +在本地定义的插页式广告 + +309 +00:17:34,021 --> 00:17:36,757 +现在将沿时间线标记 + +310 +00:17:36,790 --> 00:17:40,527 +当时间轴抵达标记 +就会播放插页广告 + +311 +00:17:40,561 --> 00:17:44,698 +如果您的插页式广告 +已在您的 HLS 播放列表中完全定义 + +312 +00:17:44,731 --> 00:17:46,934 +您会自动得到这种行为 + +313 +00:17:46,967 --> 00:17:49,436 +无需采用 + +314 +00:17:49,469 --> 00:17:53,373 +如果没有 或者您的 App +需要更多自定义行为 + +315 +00:17:53,407 --> 00:17:56,310 +我们还引入了一些新的 API + +316 +00:17:56,343 --> 00:18:01,481 +AVInterstitialTimeRange +正在从 tvOS 移植到 iOS + +317 +00:18:01,515 --> 00:18:05,085 +这些将自动填充到 +AVPlayerItem 属性 + +318 +00:18:05,118 --> 00:18:07,221 +interstitialTimeRanges 中 + +319 +00:18:07,254 --> 00:18:10,657 +这也是从 tvOS 带来的 + +320 +00:18:10,691 --> 00:18:13,560 +使用 HLS 流时 +将为流中的每个插页式广告合成 + +321 +00:18:13,594 --> 00:18:17,097 +AVInterstitialTimeRange + +322 +00:18:17,130 --> 00:18:20,934 +AVFoundation API +在本地创建插页式事件时 + +323 +00:18:20,968 --> 00:18:23,103 +将为每个 AVInterstitialTimeRange + +324 +00:18:23,136 --> 00:18:26,740 +合成 AVPlayerInterstitialEvent + +325 +00:18:26,773 --> 00:18:28,842 +然而 与 tvOS 不同 + +326 +00:18:28,876 --> 00:18:32,446 +interstitialTimeRanges +是一个只读属性 + +327 +00:18:32,479 --> 00:18:35,816 +插页式广告需要在 HLS 流中或通过 + +328 +00:18:35,849 --> 00:18:38,385 +AVPlayerInterstitialEvents 来定义 + +329 +00:18:38,418 --> 00:18:41,488 +对于那些从他们的 +tvOS App 迁移支持的人 + +330 +00:18:41,522 --> 00:18:46,827 +这就相当于将 +translatesPlayerInterstitialEvents 设置为 Yes + +331 +00:18:47,761 --> 00:18:52,533 +我们还从 tvOS 引入了两个委托方法 + +332 +00:18:52,566 --> 00:18:55,068 +这些可用于了解插页式广告何时开始 + +333 +00:18:55,102 --> 00:18:57,538 +或结束播放 + +334 +00:18:57,571 --> 00:19:00,440 +让我们看看如何使用 +这些 API 来添加跳过按钮 + +335 +00:19:00,474 --> 00:19:03,043 +用于 iOS 上的贴片广告 + +336 +00:19:03,076 --> 00:19:05,979 +首先 我们将为主要媒体的播放器 +创建一个 + +337 +00:19:06,013 --> 00:19:08,549 +AVPlayerInterstitialEventController + +338 +00:19:08,582 --> 00:19:12,052 +接下来 我们将创建一个插页式事件 + +339 +00:19:12,085 --> 00:19:14,288 +并且为它定义一些限制 + +340 +00:19:14,321 --> 00:19:17,357 +这些限制可防止在插页式广告中搜索 + +341 +00:19:17,391 --> 00:19:20,761 +并防止跳过插页式广告 + +342 +00:19:20,794 --> 00:19:24,765 +然后我们将插页式广告 +添加到事件控制器 + +343 +00:19:24,798 --> 00:19:29,670 +最后 我们可以实现 +willPresentInterstitial 委托回调 + +344 +00:19:29,703 --> 00:19:33,307 +设定的时间间隔后 +调出广告跳过按钮 + +345 +00:19:33,340 --> 00:19:36,944 +跳过按钮后 我们将取消插页式广告 + +346 +00:19:36,977 --> 00:19:38,979 +就这么容易 + +347 +00:19:39,012 --> 00:19:42,950 +请注意 将任何 custom UI 元素 +添加到 AVPlayerViewController 时 + +348 +00:19:42,983 --> 00:19:45,185 +比如这个广告跳过按钮 + +349 +00:19:45,219 --> 00:19:47,421 +总是确保将它们添加为 + +350 +00:19:47,454 --> 00:19:49,423 +contentOverlayView 的子视图 + +351 +00:19:49,456 --> 00:19:51,892 +要详细了解如何整合插页式广告 + +352 +00:19:51,925 --> 00:19:54,061 +直接进入您的 HLS 播放列表 + +353 +00:19:54,094 --> 00:19:57,231 +或如何使用 +AVFoundation interstitials API + +354 +00:19:57,264 --> 00:20:02,436 +查看我们关于探索 HLS +动态片前和片中广告的相关演讲 + +355 +00:20:02,469 --> 00:20:06,940 +现在我们看一下 +今年在所有平台上添加的一个新功能 + +356 +00:20:06,974 --> 00:20:09,676 +原生支持播放速度控制 + +357 +00:20:09,710 --> 00:20:12,079 +AVPlayerView 和 +AVPlayerViewController + +358 +00:20:12,112 --> 00:20:16,717 +使用我们添加的一些新 API +显示播放速度菜单 + +359 +00:20:18,185 --> 00:20:22,523 +我们在 macOS iOS 和 tvOS 上 +提供此功能 + +360 +00:20:22,556 --> 00:20:25,058 +让我们来看看这是什么样子的 + +361 +00:20:25,092 --> 00:20:29,563 +在 tvOS上 您会在传输栏中 +看到一个新控件 + +362 +00:20:29,596 --> 00:20:32,599 +选择控件将显示可供选择的 + +363 +00:20:32,633 --> 00:20:34,968 +可用播放速度列表 + +364 +00:20:35,002 --> 00:20:39,873 +在 iOS 上 此菜单将出现 +在传输控制悬浮菜单中 + +365 +00:20:39,907 --> 00:20:45,212 +同样 在 macOS 上 +控件将出现在悬浮菜单中 + +366 +00:20:45,245 --> 00:20:49,816 +链接到新的 iOS macOS 和 +tvOS SDK 的所有 App + +367 +00:20:49,850 --> 00:20:52,119 +将自动获得此功能 + +368 +00:20:52,152 --> 00:20:55,355 +无需额外更改 + +369 +00:20:55,389 --> 00:20:57,891 +但是 根据您的场景 + +370 +00:20:57,925 --> 00:21:01,495 +某些 App 可能想要修改速度列表 + +371 +00:21:01,528 --> 00:21:05,632 +以编程方式选择速度 或完全禁用菜单 + +372 +00:21:05,666 --> 00:21:08,869 +为了适应这些场景 +我们添加了一些新的 API + +373 +00:21:08,902 --> 00:21:11,939 +到 AVPlayerView 和 +AVPlayerViewController + +374 +00:21:11,972 --> 00:21:13,273 +让我们来看看这些 + +375 +00:21:14,875 --> 00:21:20,514 +首先 我们在 AVKit 中新增了 +一个类 AVPlaybackSpeed + +376 +00:21:20,547 --> 00:21:23,817 +AVPlaybackSpeeds 代表 +用户可选择的速度选项 + +377 +00:21:23,851 --> 00:21:27,120 +在播放 UI 中 它们具有三个属性 + +378 +00:21:27,154 --> 00:21:30,157 +一个速率值 在初始化时定义 + +379 +00:21:30,190 --> 00:21:34,127 +选择播放速度时将在播放器上设置 + +380 +00:21:34,161 --> 00:21:37,164 +本地化名称 用于表示播放速度 + +381 +00:21:37,197 --> 00:21:39,533 +在无障碍系统内 + +382 +00:21:39,566 --> 00:21:42,669 +例如 2.5 的速度可能会使用本地化名称 + +383 +00:21:42,703 --> 00:21:45,172 +两倍半的速度 + +384 +00:21:45,205 --> 00:21:47,207 +和一个本地化的数字名称 + +385 +00:21:47,241 --> 00:21:50,010 +这个值是从 rate 属性合成的 + +386 +00:21:50,043 --> 00:21:53,680 +并且将是播放速度菜单中 +显示的字符串 + +387 +00:21:53,714 --> 00:21:56,016 +如果您的 App 需要 +自定义播放速度菜单 + +388 +00:21:56,049 --> 00:21:59,653 +在播放器外部 +使用此字符串表示速度 + +389 +00:22:01,021 --> 00:22:05,025 +最后 AVPlaybackSpeed +定义了列表应尽可能使用的 + +390 +00:22:05,058 --> 00:22:08,362 +系统默认速度 + +391 +00:22:08,395 --> 00:22:12,799 +您可以将 AVPlaybackSpeed +与 AVPlayerView 和 + +392 +00:22:12,833 --> 00:22:17,938 +AVPlayerViewController 上的 +一些新 API 结合使用 适应您的 App + +393 +00:22:17,971 --> 00:22:23,076 +速度属性允许定义 +播放速度的自定义列表 + +394 +00:22:23,110 --> 00:22:26,680 +默认情况下 +此属性将设置为 AVPlaybackSpeed + +395 +00:22:26,713 --> 00:22:29,082 +systemDefaultSpeeds 列表 + +396 +00:22:29,116 --> 00:22:32,953 +将其设置为空列表将会隐藏菜单 + +397 +00:22:32,986 --> 00:22:37,858 +selectedSpeed 属性将返回 +当前活动的速度 + +398 +00:22:37,891 --> 00:22:41,762 +最后是 selectSpeed 函数 +允许程序化选择 + +399 +00:22:41,795 --> 00:22:44,231 +当前速度 + +400 +00:22:44,264 --> 00:22:46,133 +请注意 您应该只使用此功能 + +401 +00:22:46,166 --> 00:22:50,871 +响应在播放器 UI 之外显式选择速度 + +402 +00:22:50,904 --> 00:22:54,808 +永远不要隐式覆盖选择的播放速度 + +403 +00:22:54,842 --> 00:22:58,145 +让我们看一个例子 + +404 +00:22:58,178 --> 00:23:00,647 +我们在这里创建一个 +AVPlayerViewController + +405 +00:23:00,681 --> 00:23:02,583 +并展示 + +406 +00:23:02,616 --> 00:23:07,287 +默认情况下 +将使用系统提供的播放速度列表 + +407 +00:23:07,321 --> 00:23:11,625 +您可以通过创建 AVPlaybackSpeed +向菜单添加新速度 + +408 +00:23:11,658 --> 00:23:15,829 +并将其添加到 +AVPlayerViewController 的速度列表中 + +409 +00:23:15,863 --> 00:23:20,601 +我们还可以通过设置 +一个空的速度列表来禁用菜单 + +410 +00:23:20,634 --> 00:23:23,270 +就这么简单 + +411 +00:23:23,303 --> 00:23:27,708 +但请注意 您应该始终 +调用 AVPlayer play() 开始回放 + +412 +00:23:27,741 --> 00:23:30,744 +永远不要通过调用 +setRate:1.0 开始播放 + +413 +00:23:30,777 --> 00:23:34,348 +因为所选速率可能不是 1.0 + +414 +00:23:34,381 --> 00:23:37,985 +至此 我想结束本次演讲 + +415 +00:23:38,018 --> 00:23:41,688 +我们看到了新设计的 iOS 系统播放器 + +416 +00:23:41,722 --> 00:23:46,026 +我们了解了 +如何设计自己的惊艳播放体验 + +417 +00:23:46,059 --> 00:23:49,062 +我们看到了一些 +很酷的新视觉智能功能 + +418 +00:23:49,096 --> 00:23:53,200 +并查看了新的 +插页式广告和播放速度 API + +419 +00:23:53,233 --> 00:23:54,868 +我希望您喜欢这个讲座 + +420 +00:23:54,902 --> 00:23:58,338 +并期待在开发者的 App 中 +看到这些功能 + +421 +00:23:58,372 --> 00:24:00,374 +请享受研讨会余下的部分吧 + diff --git a/zho/2022 Session 10148 Meet Apple Music API and MusicKit.srt b/zho/2022 Session 10148 Meet Apple Music API and MusicKit.srt new file mode 100644 index 0000000..60a6560 --- /dev/null +++ b/zho/2022 Session 10148 Meet Apple Music API and MusicKit.srt @@ -0,0 +1,1559 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,810 --> 00:00:12,346 +Justin Rennell: 大家好 欢迎来到 WWDC + +3 +00:00:12,379 --> 00:00:16,350 +我是 Justin +是 Apple Music 开发团队的工程师 + +4 +00:00:16,383 --> 00:00:19,553 +今天我将介绍 MusicKit + +5 +00:00:19,586 --> 00:00:22,322 +重点介绍使用 +Apple Music API 的基础知识 + +6 +00:00:22,356 --> 00:00:25,759 +在本期讲座中 +我将概述 MusicKit 客户端框架 + +7 +00:00:25,792 --> 00:00:29,096 +以及它们如何与 +Apple Music API web 服务集成 + +8 +00:00:29,129 --> 00:00:32,566 +我将解释如何作为开发人员 +获得访问权限 + +9 +00:00:32,599 --> 00:00:34,768 +以及使用 Apple Music API 的 +具体细节 包括 + +10 +00:00:34,801 --> 00:00:36,904 +请求内容和资源 + +11 +00:00:36,937 --> 00:00:40,174 +使用限制和分页来处理大型资源集合 + +12 +00:00:40,207 --> 00:00:43,777 +以及如何使用搜索端点 +在目录中查找内容 + +13 +00:00:43,810 --> 00:00:46,847 +最后 我将介绍一些可供 Apple Music +订阅者使用的个性化功能 + +14 +00:00:46,880 --> 00:00:50,851 +以及如何在您的 App 中 +提供对它们的访问权限 + +15 +00:00:51,885 --> 00:00:55,689 +我先简单介绍一下 MusicKit +和 Apple Music API + +16 +00:00:55,722 --> 00:01:00,160 +MusicKit 于 2017 年 +在 WWDC 首次发布 + +17 +00:01:00,194 --> 00:01:02,796 +从那以后 我们进行了改进 + +18 +00:01:02,829 --> 00:01:04,865 +使得与 Apple Music 的集成 +更加容易 + +19 +00:01:04,898 --> 00:01:07,868 +并继续添加对附加功能的支持 + +20 +00:01:07,901 --> 00:01:10,437 +MusicKit 是客户端框架 + +21 +00:01:10,470 --> 00:01:12,439 +和 Apple Music API 的组合 + +22 +00:01:12,472 --> 00:01:14,541 +两者一起使用 +可以将 Apple Music 功能 + +23 +00:01:14,575 --> 00:01:17,444 +添加到您的 App 中 + +24 +00:01:17,477 --> 00:01:20,147 +您可以从 Apple Music 中 +发现和获取内容 + +25 +00:01:20,180 --> 00:01:23,917 +包括艺术家 专辑 播放列表等 + +26 +00:01:23,951 --> 00:01:28,021 +并具有搜索目录 +和浏览流行排行榜的功能 + +27 +00:01:28,055 --> 00:01:31,692 +在用户同意的情况下 +MusicKit 和 Apple Music API + +28 +00:01:31,725 --> 00:01:34,328 +允许您验证订阅者播放可用内容 + +29 +00:01:34,361 --> 00:01:36,263 +并提供对个性化功能的访问 + +30 +00:01:36,296 --> 00:01:38,799 +包括他们的音乐库 推荐 + +31 +00:01:38,832 --> 00:01:41,435 +和最近播放的历史记录 + +32 +00:01:41,468 --> 00:01:44,238 +MusicKit 客户端框架提供了 + +33 +00:01:44,271 --> 00:01:45,772 +对订阅者进行身份验证 + +34 +00:01:45,806 --> 00:01:48,775 +以及在设备上 +开始和控制播放所需的 API + +35 +00:01:48,809 --> 00:01:52,145 +客户端框架可用于 +Apple 平台上的 App + +36 +00:01:52,179 --> 00:01:54,748 +使用 Javascript 的 网页 App + +37 +00:01:54,781 --> 00:01:57,918 +和使用可用 SDK 的 Android App + +38 +00:01:59,253 --> 00:02:01,889 +Apple 平台上的 MusicKit +拥有将 Apple Music + +39 +00:02:01,922 --> 00:02:04,291 +集成到 App 中所需的一切 + +40 +00:02:04,324 --> 00:02:07,227 +订阅者可以在您的 App 中 +进行身份验证或注册 + +41 +00:02:07,261 --> 00:02:11,265 +以开始和控制播放 +并访问其他个性化功能 + +42 +00:02:11,298 --> 00:02:15,235 +可用的 API 通过 +对资源和分页的原生支持 + +43 +00:02:15,269 --> 00:02:19,806 +加速了从 Apple Music 中 +发现和访问内容的调用 + +44 +00:02:19,840 --> 00:02:23,277 +后面涉及的许多关于 +直接访问 Apple Music API + +45 +00:02:23,310 --> 00:02:26,213 +和向 Apple Music API +发出请求的主题 + +46 +00:02:26,246 --> 00:02:28,949 +都由 Apple 平台上的 +MusicKit 自动处理 + +47 +00:02:28,982 --> 00:02:31,919 +我们鼓励为 Apple 平台 +编写 App 的开发人员 + +48 +00:02:31,952 --> 00:02:34,721 +观看讲座 +“Meet MusicKit for Swift” + +49 +00:02:34,755 --> 00:02:36,790 +以了解这些 API + +50 +00:02:36,823 --> 00:02:39,459 +并观看讲座 +“Explore more content with MusicKit” + +51 +00:02:39,493 --> 00:02:41,495 +以了解更多功能 + +52 +00:02:42,629 --> 00:02:45,232 +Web 上的 MusicKit 使您可以 + +53 +00:02:45,265 --> 00:02:47,568 +使用 Javascript 轻松地 +将 Apple Music 引入您的App + +54 +00:02:47,601 --> 00:02:49,670 +您可以发现 Apple Music 内容 + +55 +00:02:49,703 --> 00:02:52,973 +让订阅者登录以访问个性化功能 + +56 +00:02:53,006 --> 00:02:55,742 +并直接在您的网站上播放内容 + +57 +00:02:55,776 --> 00:02:58,378 +完全访问 Apple Music API +让您能够 + +58 +00:02:58,412 --> 00:03:01,215 +创造独特的音乐体验 + +59 +00:03:01,248 --> 00:03:03,851 +MusicKit 提供了一组 +内置的 web 组件 + +60 +00:03:03,884 --> 00:03:06,186 +包括一个全功能的媒体播放器 + +61 +00:03:06,220 --> 00:03:08,455 +这些组件使入门变得容易 + +62 +00:03:08,488 --> 00:03:11,291 +并且可以根据您的体验 +进行灵活定制 + +63 +00:03:12,960 --> 00:03:15,262 +Android 版的 MusicKit 可以让您 + +64 +00:03:15,295 --> 00:03:17,130 +将 Apple Music 集成到 +您的 Android App中 + +65 +00:03:17,164 --> 00:03:19,833 +支持对 Apple Music 订阅者 +进行身份验证 + +66 +00:03:19,867 --> 00:03:21,401 +控制内容播放 + +67 +00:03:21,435 --> 00:03:25,572 +对 Apple Music API 的完全访问 +让您能够构建丰富的音乐体验 + +68 +00:03:27,541 --> 00:03:31,345 +Apple Music API 是常见的 +JSON web 服务 + +69 +00:03:31,378 --> 00:03:34,715 +提供对发现功能 +和 Apple Music 目录内容的访问 + +70 +00:03:34,748 --> 00:03:37,518 +经过认证的用户 +可以访问个性化功能 + +71 +00:03:37,551 --> 00:03:40,020 +包括他们的音乐库 推荐 + +72 +00:03:40,053 --> 00:03:41,922 +和最近播放的历史记录 + +73 +00:03:42,656 --> 00:03:46,126 +接下来 我将解释如何获得访问权限 + +74 +00:03:46,159 --> 00:03:50,264 +要向 Apple Music API 发出请求 +您需要一个开发者令牌 + +75 +00:03:50,297 --> 00:03:52,332 +对于 Apple 平台上的 App + +76 +00:03:52,366 --> 00:03:54,801 +您可以通过为您的 App + +77 +00:03:54,835 --> 00:03:58,038 +启用 MusicKit 服务 +来利用自动令牌管理的优势 + +78 +00:03:58,071 --> 00:04:00,474 +这项服务可以 +在 Apple Developer Portal 的 + +79 +00:04:00,507 --> 00:04:03,377 +App ID 部分找到 + +80 +00:04:04,711 --> 00:04:06,713 +对于其他平台上的 App + +81 +00:04:06,747 --> 00:04:10,150 +您可以通过在 +Apple Developer Portal 上注册 + +82 +00:04:10,184 --> 00:04:12,119 +成为 MusicKit 开发者 +来获取开发者令牌 + +83 +00:04:12,152 --> 00:04:15,556 +从那里 您可以请求和下载私钥 + +84 +00:04:15,589 --> 00:04:18,425 +您将需要生成一个 JSON Web 令牌 + +85 +00:04:18,458 --> 00:04:20,727 +并使用您下载的私钥对其进行签名 + +86 +00:04:20,761 --> 00:04:23,864 +JSON Web 令牌分为两部分 + +87 +00:04:23,897 --> 00:04:25,432 +第一部分是必需的标头 + +88 +00:04:25,465 --> 00:04:30,137 +包括签名算法 alg 它必须是 ES256 + +89 +00:04:30,170 --> 00:04:32,272 +以及密钥标识符 kid + +90 +00:04:32,306 --> 00:04:35,509 +它包含在您的私钥下载中 + +91 +00:04:35,542 --> 00:04:38,078 +令牌的第二部分是声明 + +92 +00:04:38,111 --> 00:04:40,981 +Apple Music API +有三个必需的声明 + +93 +00:04:41,014 --> 00:04:43,116 +发布者 ID “iss” + +94 +00:04:43,150 --> 00:04:45,986 +这是您的团队 ID +可以在 Apple Developer portal 的 + +95 +00:04:46,019 --> 00:04:47,955 +会员部分找到 + +96 +00:04:47,988 --> 00:04:50,090 +发布时间为 iat + +97 +00:04:50,123 --> 00:04:53,160 +由自 Epoch 以来的秒数表示 + +98 +00:04:53,193 --> 00:04:55,529 +以及到期时间 exp + +99 +00:04:55,562 --> 00:04:58,599 +这与发布时间的时间格式相同 + +100 +00:04:58,632 --> 00:05:01,702 +生成的令牌最长 + +101 +00:05:01,735 --> 00:05:04,037 +可在发行后六个月内到期 + +102 +00:05:04,071 --> 00:05:07,107 +对于 网页 App +我们鼓励提供来源声明 + +103 +00:05:07,140 --> 00:05:10,010 +这将颁发一个 +仅对您的网站有效的令牌 + +104 +00:05:11,879 --> 00:05:14,314 +必须在授权标头中 + +105 +00:05:14,348 --> 00:05:18,352 +为 Apple Music API 的所有请求 +提供有效的签名令牌 + +106 +00:05:18,385 --> 00:05:21,955 +在 Apple 平台上为您的App +启用 MusicKit 服务后 + +107 +00:05:21,989 --> 00:05:23,924 +这将自动完成 + +108 +00:05:23,957 --> 00:05:26,860 +必须使用您生成的令牌 +配置 Web 上的 MusicKit + +109 +00:05:26,894 --> 00:05:29,563 +来向 Apple Music API 发出请求 + +110 +00:05:29,596 --> 00:05:32,833 +有关生成 JSON Web 令牌的 +更多信息 + +111 +00:05:32,866 --> 00:05:36,036 +请参阅 Apple Music API 文档 + +112 +00:05:36,069 --> 00:05:40,974 +现在我将向您展示如何 +使用 Apple Music API 请求资源 + +113 +00:05:41,008 --> 00:05:43,010 +资源对 Apple Music 内容进行建模 + +114 +00:05:43,043 --> 00:05:46,747 +例如艺术家 专辑 歌曲 播放列表等 + +115 +00:05:46,780 --> 00:05:49,416 +每个都有自己对应的类型 + +116 +00:05:49,449 --> 00:05:52,219 +可以通过搜索等发现功能 +或使用它们的标识符 + +117 +00:05:52,252 --> 00:05:56,657 +从 Apple Music API 端点获取资源 + +118 +00:05:56,690 --> 00:05:59,960 +下面是一个使用其标识符 + +119 +00:05:59,993 --> 00:06:02,763 +从 API 获取播放列表资源的 +示例请求 URL + +120 +00:06:02,796 --> 00:06:07,701 +Apple Music API +在 api.music.apple.com 上托管 + +121 +00:06:07,734 --> 00:06:10,404 +URL 的路径使用 RESTful 模式 + +122 +00:06:10,437 --> 00:06:13,874 +代表资源或功能的位置 + +123 +00:06:13,907 --> 00:06:16,977 +位置中的第一个元素是 API 的版本 + +124 +00:06:17,010 --> 00:06:18,779 +当前是版本 1 + +125 +00:06:18,812 --> 00:06:22,816 +当引入重大更改时 +可能会出现新版本 + +126 +00:06:22,850 --> 00:06:25,953 +版本与现有调用保持向后兼容性 + +127 +00:06:25,986 --> 00:06:30,490 +即使对资源和新功能进行了增强 + +128 +00:06:30,524 --> 00:06:33,026 +对于 Apple Music 目录中的请求 + +129 +00:06:33,060 --> 00:06:34,661 +该位置的下一部分表示 + +130 +00:06:34,695 --> 00:06:37,798 +要从中获取的特定目录 + +131 +00:06:37,831 --> 00:06:40,200 +Apple Music 是一项全球流媒体服务 + +132 +00:06:40,234 --> 00:06:44,438 +内容可能因地区而异 +我们将其称为店面 + +133 +00:06:45,772 --> 00:06:48,709 +有关店面和内容可用性的信息 + +134 +00:06:48,742 --> 00:06:53,614 +请观看题为“Cross reference content +with the Apple Music API”的讲座 + +135 +00:06:53,647 --> 00:06:56,550 +在这个例子中 +我将从美国店面的目录中 + +136 +00:06:56,583 --> 00:06:58,318 +获取一个播放列表 + +137 +00:06:58,352 --> 00:07:01,855 +用两个字母的国家代码 us 表示 + +138 +00:07:01,889 --> 00:07:05,125 +该位置的最后一部分是资源的标识 + +139 +00:07:05,158 --> 00:07:08,996 +由后面跟有标识符的 +类型播放列表表示 + +140 +00:07:10,163 --> 00:07:12,466 +由于 Apple Music +在许多地区都可用 + +141 +00:07:12,499 --> 00:07:14,434 +因此可以使用可选的 + +142 +00:07:14,468 --> 00:07:18,005 +语言标签查询参数 L 来支持本地化 + +143 +00:07:18,038 --> 00:07:22,409 +在这里 我为英语指定了 +语言标签 en-US + +144 +00:07:22,442 --> 00:07:28,081 +要获取以西班牙语本地化的内容 +我可以指定标签 es-MX + +145 +00:07:28,115 --> 00:07:29,249 +为了简单起见 + +146 +00:07:29,283 --> 00:07:31,718 +我不会在这些示例中指定语言标签 + +147 +00:07:31,752 --> 00:07:34,821 +这会导致店面的默认本地化 + +148 +00:07:34,855 --> 00:07:36,957 +可以通过访问店面引用端点 + +149 +00:07:36,990 --> 00:07:38,592 +找到 Apple Music + +150 +00:07:38,625 --> 00:07:41,862 +所在的店面及其支持的本地化 + +151 +00:07:41,895 --> 00:07:45,399 +更多细节可以在 +Apple Music API 文档中找到 + +152 +00:07:46,500 --> 00:07:49,269 +下面看一下 +对播放列表发出 GET 请求 + +153 +00:07:49,303 --> 00:07:51,271 +这将返回一个包含播放列表资源的 + +154 +00:07:51,305 --> 00:07:54,441 +“数据”数组的资源收集响应 + +155 +00:07:54,474 --> 00:07:59,146 +资源对象用 ID 值和类型 +指示内容的身份 + +156 +00:07:59,179 --> 00:08:03,851 +ID 和类型的组合代表了 +资源的唯一身份 + +157 +00:08:03,884 --> 00:08:08,388 +href 值指示 API 中 +可以获取资源的位置 + +158 +00:08:08,422 --> 00:08:12,960 +在这种情况下 请注意该位置 +与我们请求的路径相同 + +159 +00:08:12,993 --> 00:08:17,331 +内容的元数据值 +可在资源的属性映射中找到 + +160 +00:08:17,364 --> 00:08:21,702 +在关系图中可以找到 +与其他资源的直接连接 + +161 +00:08:21,735 --> 00:08:23,804 +例如此播放列表 curator 和曲目 + +162 +00:08:24,905 --> 00:08:26,940 +下面是属性映射的详细介绍 + +163 +00:08:26,974 --> 00:08:29,676 +其中包含播放列表的元数据值 + +164 +00:08:29,710 --> 00:08:32,312 +我将介绍一个在右侧小部件中 + +165 +00:08:32,346 --> 00:08:34,314 +使用其中一些属性的示例 + +166 +00:08:34,348 --> 00:08:39,887 +该小部件使用播放列表的名称 +curator 名称和描述属性 + +167 +00:08:39,920 --> 00:08:42,823 +playParams 是许多资源类型的 +通用属性 + +168 +00:08:42,856 --> 00:08:46,426 +它指示内容何时可以 +流式传输给订阅者 + +169 +00:08:46,460 --> 00:08:49,296 +这可用于确定是否应启用播放控制 + +170 +00:08:49,329 --> 00:08:53,634 +因为没有 playParams 的内容 +不可用于播放 + +171 +00:08:53,667 --> 00:08:56,537 +Artwork 是许多资源类型的 +另一个常见属性 + +172 +00:08:56,570 --> 00:08:59,806 +它包含图像的最大宽度和高度值 + +173 +00:08:59,840 --> 00:09:02,776 +以及可以从中加载图像的 url + +174 +00:09:05,078 --> 00:09:07,581 +在 Apple 开发者的反馈非常重要 + +175 +00:09:07,614 --> 00:09:10,651 +它可以帮助我们为每个人 +改进我们的 API 和服务 + +176 +00:09:10,684 --> 00:09:12,786 +今年 我们很高兴地宣布 + +177 +00:09:12,819 --> 00:09:15,389 +添加了我们最受欢迎的一个功能 + +178 +00:09:15,422 --> 00:09:18,258 +艺术家作品现在可在 +Apple Music API 中使用 + +179 +00:09:18,292 --> 00:09:20,994 +让简单的剪影成为过去 + +180 +00:09:21,028 --> 00:09:23,864 +所有新的和现有的 App 都可以 + +181 +00:09:23,897 --> 00:09:27,634 +通过查找添加到艺术家资源的 + +182 +00:09:27,668 --> 00:09:31,905 +艺术品属性来添加对这些图像的支持 + +183 +00:09:31,939 --> 00:09:35,209 +这是我们之前查看的播放列表的 + +184 +00:09:35,242 --> 00:09:37,010 +艺术作品 url 的缩写示例 + +185 +00:09:37,044 --> 00:09:42,482 +艺术品 url 包含以蓝色突出显示的 +宽度 w 和 高度 h 来标记 + +186 +00:09:42,516 --> 00:09:45,586 +要使用此 URL 加载插图 + +187 +00:09:45,619 --> 00:09:48,388 +请将这些标记替换为 +您的显示器所需的分辨率 + +188 +00:09:48,422 --> 00:09:51,825 +由于播放列表图片是方形的 + +189 +00:09:51,859 --> 00:09:53,994 +我将使用相同的宽度和高度分辨率 + +190 +00:09:54,027 --> 00:09:57,998 +下面是请求分辨率为 400x400 + +191 +00:09:58,031 --> 00:10:02,469 +300x300 和 200x200 的示例 + +192 +00:10:02,503 --> 00:10:05,072 +图像会以每种分辨率缩放显示 + +193 +00:10:05,105 --> 00:10:07,941 +对于较小的图像 文件大小会减小 + +194 +00:10:09,109 --> 00:10:11,745 +所有资源类型都有一组默认属性 + +195 +00:10:11,778 --> 00:10:15,415 +代表该资源的通用或基本元数据 + +196 +00:10:15,449 --> 00:10:18,118 +某些资源具有可以获取的附加属性 + +197 +00:10:18,151 --> 00:10:20,454 +称为扩展属性 + +198 +00:10:20,487 --> 00:10:24,658 +可以使用扩展查询参数 +来请求这些扩展属性 + +199 +00:10:24,691 --> 00:10:27,227 +例如 Apple Music 播放列表中的曲目 + +200 +00:10:27,261 --> 00:10:29,329 +要么是歌曲 要么是音乐视频 + +201 +00:10:29,363 --> 00:10:32,232 +如果您想知道播放列表 +包含的曲目类型 + +202 +00:10:32,266 --> 00:10:35,702 +可以请求 trackTypes 扩展属性 + +203 +00:10:35,736 --> 00:10:38,438 +扩展属性与它们的默认属性 + +204 +00:10:38,472 --> 00:10:41,175 +一起出现在资源的属性图中 + +205 +00:10:41,208 --> 00:10:44,611 +如果播放列表的曲目 +是音乐视频而不是歌曲 + +206 +00:10:44,645 --> 00:10:48,215 +也许您可以自定义播放按钮 +以通知查看者 + +207 +00:10:49,683 --> 00:10:52,319 +现在看一下关系图 +可以看到从这个播放列表 + +208 +00:10:52,352 --> 00:10:55,489 +到其他资源的几个直接连接 + +209 +00:10:55,522 --> 00:10:57,658 +许多资源具有自动关系 + +210 +00:10:57,691 --> 00:11:00,761 +在直接请求某些内容时 +会返回这些关系 + +211 +00:11:00,794 --> 00:11:06,033 +播放列表的自动关系 +是其 curator 和曲目 + +212 +00:11:06,066 --> 00:11:09,102 +命名关系是为了表明连接是什么 + +213 +00:11:09,136 --> 00:11:11,538 +例如此播放列表的 curator + +214 +00:11:11,572 --> 00:11:15,209 +它们有一个可以 +直接获取关系的 href 位置 + +215 +00:11:15,242 --> 00:11:18,579 +和一个用于相关资源集合的数据数组 + +216 +00:11:18,612 --> 00:11:22,216 +对于播放列表 +策展人关系是自动关联的 + +217 +00:11:22,249 --> 00:11:25,953 +这意味着只会出现相关资源的身份 + +218 +00:11:25,986 --> 00:11:30,824 +这允许使用其标识或 href +轻松链接到此资源 + +219 +00:11:30,858 --> 00:11:34,094 +由于播放列表已经包含 +curator 的姓名作为属性 + +220 +00:11:34,127 --> 00:11:36,263 +因此可能不需要包含 + +221 +00:11:36,296 --> 00:11:38,198 +相关 curator 资源的其他元数据 + +222 +00:11:38,232 --> 00:11:41,768 +资源的身份可以用来 +将 curator 命名为一个链接 + +223 +00:11:41,802 --> 00:11:45,772 +让人们可以根据自己的意愿 +导航到 curator 以发现其他内容 + +224 +00:11:45,806 --> 00:11:49,009 +如果您想通过播放列表 +显示 curator 的其他信息 + +225 +00:11:49,042 --> 00:11:52,713 +例如其艺术作品 +您将需要获取 curator 的元数据 + +226 +00:11:52,746 --> 00:11:55,415 +使用 include 参数指定 + +227 +00:11:55,449 --> 00:11:58,218 +您想要相关资源元数据的关系 + +228 +00:11:58,252 --> 00:12:00,888 +某些资源类型具有默认情况下 +未包含的其他关系 + +229 +00:12:00,921 --> 00:12:04,057 +也可以使用此参数请求这些关系 + +230 +00:12:04,091 --> 00:12:07,294 +请注意 包含关系会增加响应的大小 + +231 +00:12:07,327 --> 00:12:09,830 +并对 App 的速度产生负面影响 + +232 +00:12:09,863 --> 00:12:12,900 +许多可能需要从相关资源中 +获得的有用值 + +233 +00:12:12,933 --> 00:12:16,403 +可以直接作为原始资源的属性找到 + +234 +00:12:16,436 --> 00:12:18,739 +为了获得最佳性能 我们建议 + +235 +00:12:18,772 --> 00:12:22,910 +仅包含响应中所需的关系和元数据 + +236 +00:12:22,943 --> 00:12:26,079 +资源类型及其可用属性和关系的 + +237 +00:12:26,113 --> 00:12:30,150 +详细信息可以在 +Apple Music API 文档中找到 + +238 +00:12:30,184 --> 00:12:32,819 +有关扩展属性 关系 + +239 +00:12:32,853 --> 00:12:35,189 +和称为视图的特殊关系的更多信息 + +240 +00:12:35,222 --> 00:12:39,626 +请观看讲座 “Explore the catalog +with the Apple Music API” + +241 +00:12:39,660 --> 00:12:42,529 +重新访问示例播放列表的关系 + +242 +00:12:42,563 --> 00:12:45,566 +播放列表的曲目被自动包含在内 + +243 +00:12:45,599 --> 00:12:48,602 +这意味着相关曲目资源的属性元数据 + +244 +00:12:48,635 --> 00:12:50,904 +出现在响应中 + +245 +00:12:50,938 --> 00:12:54,274 +相关曲目的属性可用于 +显示播放列表的曲目列表 + +246 +00:12:54,308 --> 00:12:57,010 +使用它们的插图和右侧小部件中 + +247 +00:12:57,044 --> 00:12:58,946 +显示的其他元数据 + +248 +00:12:58,979 --> 00:13:01,215 +在之前的部分 我展示了 + +249 +00:13:01,248 --> 00:13:04,518 +一个从包含曲目的目录中 +获取播放列表资源的示例 + +250 +00:13:04,551 --> 00:13:07,621 +在这个部分 我将解释如何处理 + +251 +00:13:07,654 --> 00:13:09,590 +与大量资源的关系 + +252 +00:13:09,623 --> 00:13:13,594 +关系的相关资源出现在其数据数组中 + +253 +00:13:13,627 --> 00:13:16,129 +当相关资源数量较少时 + +254 +00:13:16,163 --> 00:13:19,233 +所有资源将出现在单个响应中 + +255 +00:13:19,266 --> 00:13:22,436 +必须在称为页面的多个部分中 + +256 +00:13:22,469 --> 00:13:25,305 +获取具有比单个响应中更多的 +相关资源的关系 + +257 +00:13:26,907 --> 00:13:30,511 +我将以大型播放列表的轨道关系为例 + +258 +00:13:30,544 --> 00:13:34,915 +默认情况下 +仅包含播放列表的前 100 首曲目 + +259 +00:13:34,948 --> 00:13:37,117 +如果播放列表的曲目超过 100 个 + +260 +00:13:37,150 --> 00:13:41,355 +则必须在后续页面中获取额外的曲目 + +261 +00:13:41,388 --> 00:13:45,192 +以下是包含 100 多首曲目的 +播放列表的示例响应 + +262 +00:13:45,225 --> 00:13:48,262 +如前所述 跟踪关系的 href + +263 +00:13:48,295 --> 00:13:51,532 +和资源收集数据出现在响应中 + +264 +00:13:51,565 --> 00:13:54,735 +由于此播放列表的曲目 +多于响应中包含的曲目 + +265 +00:13:54,768 --> 00:13:57,871 +因此下一个位置显示为数据的同级 + +266 +00:13:57,905 --> 00:14:00,307 +下一个位置表示可以获取集合中 + +267 +00:14:00,340 --> 00:14:03,043 +剩余资源的位置 + +268 +00:14:03,076 --> 00:14:05,879 +获取下一个位置会直接获取关系 + +269 +00:14:05,913 --> 00:14:08,448 +并从提供的偏移量 + +270 +00:14:08,482 --> 00:14:10,551 +开始返回关系的资源集合数据 + +271 +00:14:10,584 --> 00:14:14,121 +关系的默认限制将应用于每个页面 + +272 +00:14:14,154 --> 00:14:17,891 +您可以通过提供限制参数 +来选择自己的页面大小 + +273 +00:14:17,925 --> 00:14:19,893 +页面大小限制可以介于 1 + +274 +00:14:19,927 --> 00:14:22,329 +和特定关系的最大页面大小之间 + +275 +00:14:22,362 --> 00:14:25,132 +这可以在文档中找到 + +276 +00:14:25,165 --> 00:14:27,067 +如果关系的资源集合 + +277 +00:14:27,100 --> 00:14:30,137 +包含页面中 +返回的资源之外的其他资源 + +278 +00:14:30,170 --> 00:14:33,974 +则下一个位置 +将继续显示为数据的同级 + +279 +00:14:34,007 --> 00:14:38,512 +当资源集合用尽时 +下一个位置将不会显示 + +280 +00:14:38,545 --> 00:14:42,683 +请注意 下一个位置不反映 +请求选定的页面大小 + +281 +00:14:42,716 --> 00:14:45,853 +如果您希望使用 +与默认不同的页面大小 + +282 +00:14:45,886 --> 00:14:48,655 +则需要为每个请求 +提供一个限制参数 + +283 +00:14:48,689 --> 00:14:50,824 +始终使用响应中的下一个位置 + +284 +00:14:50,858 --> 00:14:52,659 +来给资源集合分页 + +285 +00:14:52,693 --> 00:14:55,262 +尝试计算您自己的偏移量 +可能会导致 + +286 +00:14:55,295 --> 00:14:58,098 +位置无效或结果重复的问题 + +287 +00:14:58,131 --> 00:15:00,701 +在下一个部分 我将展示 +如何使用 Apple Music API + +288 +00:15:00,734 --> 00:15:03,937 +在 Apple Music 目录中 +搜索 fof 内容 + +289 +00:15:03,971 --> 00:15:07,674 +Apple Music API 提供了 +使用搜索词 + +290 +00:15:07,708 --> 00:15:09,243 +在目录中查找内容的功能 + +291 +00:15:09,276 --> 00:15:11,845 +搜索请求类似于目录资源请求 + +292 +00:15:11,879 --> 00:15:15,916 +以 /search 作为位置 +以搜索词作为参数 + +293 +00:15:15,949 --> 00:15:19,920 +您可以使用 type 参数 +指定您感兴趣的内容类型 + +294 +00:15:19,953 --> 00:15:23,991 +并使用限制指定每种类型 +要包含的最大结果数 + +295 +00:15:24,024 --> 00:15:26,493 +当找到了更多的结果 +超过请求的限制时 + +296 +00:15:26,527 --> 00:15:29,463 +可以使用分页来继续搜索 + +297 +00:15:29,496 --> 00:15:33,667 +这是搜索带有“流行音乐”一词的 +专辑和歌曲的响应 + +298 +00:15:33,700 --> 00:15:37,538 +搜索端点返回带有结果对象的响应 + +299 +00:15:37,571 --> 00:15:40,240 +其中包含每个请求类型的组 +和匹配的内容 + +300 +00:15:40,274 --> 00:15:43,911 +对于此请求 +找到了匹配的专辑和歌曲 + +301 +00:15:45,345 --> 00:15:48,849 +该响应还包括一个元对象 +其中包含基于相关性 + +302 +00:15:48,882 --> 00:15:51,285 +为结果组推荐的顺序 + +303 +00:15:51,318 --> 00:15:53,487 +如果您正在构建 +一次处理多种内容类型的 + +304 +00:15:53,520 --> 00:15:56,957 +搜索体验 这可能会有所帮助 + +305 +00:15:56,990 --> 00:16:00,294 +每个结果组都有一个 href + +306 +00:16:00,327 --> 00:16:03,263 +和一个资源集合数据数组 + +307 +00:16:03,297 --> 00:16:05,866 +其中包含与搜索项 +相关类型的匹配资源 + +308 +00:16:05,899 --> 00:16:08,435 +如果结果组有更多匹配可用 + +309 +00:16:08,468 --> 00:16:12,873 +则该组将包含下一个位置 +可以在该位置获取更多匹配 + +310 +00:16:12,906 --> 00:16:16,276 +请求下一个位置会返回 +从偏移量开始的 + +311 +00:16:16,310 --> 00:16:18,378 +所选类型的更多结果 + +312 +00:16:18,412 --> 00:16:20,614 +在最后一个部分 我将讨论 + +313 +00:16:20,647 --> 00:16:23,150 +访问 Apple Music API 中的 +个性化功能 + +314 +00:16:24,351 --> 00:16:26,954 +Apple Music API 和 MusicKit 提供 + +315 +00:16:26,987 --> 00:16:29,523 +对特定用户的个性化功能的访问 + +316 +00:16:29,556 --> 00:16:32,192 +这些功能让您可以支持订阅者 + +317 +00:16:32,226 --> 00:16:34,862 +查看和搜索 +其 Apple Music 资料库中的内容 + +318 +00:16:34,895 --> 00:16:39,499 +包括添加他们喜欢的内容 +和创建新播放列表的功能 + +319 +00:16:39,533 --> 00:16:41,602 +个性化推荐可以基于 + +320 +00:16:41,635 --> 00:16:43,937 +个人的音乐品味来呈现 + +321 +00:16:43,971 --> 00:16:47,107 +您还可以让人们重新发现 +他们最近一直在听的音乐 + +322 +00:16:47,140 --> 00:16:50,511 +以便从上次中断的地方 +重新开始或提供全新的体验 + +323 +00:16:52,212 --> 00:16:54,114 +个性化功能可供 + +324 +00:16:54,147 --> 00:16:56,650 +积极订阅 Apple Music 的人使用 + +325 +00:16:56,683 --> 00:16:59,586 +要支持这些功能 您必须首先 + +326 +00:16:59,620 --> 00:17:02,155 +使用 MusicKit +对您的 App 用户进行身份验证 + +327 +00:17:02,189 --> 00:17:04,658 +并请求访问他们音乐数据的权限 + +328 +00:17:04,691 --> 00:17:09,162 +授予权限后 +Music User Token 将是可用的 + +329 +00:17:09,196 --> 00:17:13,867 +这个令牌被添加到 +Apple Music API 请求的 + +330 +00:17:13,901 --> 00:17:17,271 +music-user-token 标头中 +并用于验证对个性化数据的访问 + +331 +00:17:18,338 --> 00:17:23,110 +Music User Token 是特定于 +您的 App 和用户进行身份验证的 + +332 +00:17:23,143 --> 00:17:25,245 +此令牌不得跨设备共享 + +333 +00:17:25,279 --> 00:17:28,782 +因为一次只能为一台设备授予权限 + +334 +00:17:28,815 --> 00:17:31,985 +令牌可能会因 +个人订阅或密码的更改而失效 + +335 +00:17:32,019 --> 00:17:34,888 +或者如果他们撤销了 +对您的 App 的访问权限 + +336 +00:17:34,922 --> 00:17:37,191 +它也可能会随着时间的推移而过期 + +337 +00:17:37,224 --> 00:17:40,427 +可以通过提示他们重新登录 + +338 +00:17:40,460 --> 00:17:42,796 +并为您的 App 授予权限 +来刷新身份验证 + +339 +00:17:42,829 --> 00:17:45,299 +请注意 此令牌 +由 Apple 平台上的 MusicKit + +340 +00:17:45,332 --> 00:17:47,968 +和 Web 上的 MusicKit 自动管理 + +341 +00:17:48,001 --> 00:17:50,304 +更多相关的详细信息 +请参阅您正在使用的 + +342 +00:17:50,337 --> 00:17:51,872 +框架的文档 + +343 +00:17:51,905 --> 00:17:55,008 +在今天的讲座中 我展示了如何使用 + +344 +00:17:55,042 --> 00:17:58,078 +MusicKit 和 Apple Music API +将 Apple Music 集成到您的 App 中 + +345 +00:17:58,111 --> 00:18:01,315 +快速了解支持 +MusicKit 客户端框架的平台 + +346 +00:18:01,348 --> 00:18:05,152 +以及如何使用 Apple Music API +访问和查找目录中的内容 + +347 +00:18:05,185 --> 00:18:08,555 +以及一些可供订阅者使用的 +个性化功能 + +348 +00:18:08,589 --> 00:18:11,558 +有关今年 Apple 平台上 +MusicKit 更新的更多信息 + +349 +00:18:11,592 --> 00:18:14,761 +请查看讲座 +使用 MusicKit 探索更多内容 + +350 +00:18:14,795 --> 00:18:15,829 +感谢收看 + +351 +00:18:15,863 --> 00:18:18,398 +我们希望您享受 +今年余下的 WWDC 之旅 + +352 +00:18:18,432 --> 00:18:23,103 +[欢快的音乐] + diff --git "a/zho/2022 Session 10149 What\342\200\231s new in AVQT.srt" "b/zho/2022 Session 10149 What\342\200\231s new in AVQT.srt" new file mode 100644 index 0000000..10a9dd3 --- /dev/null +++ "b/zho/2022 Session 10149 What\342\200\231s new in AVQT.srt" @@ -0,0 +1,714 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,943 --> 00:00:11,111 +Ahmed Badr: 大家好 欢迎 + +3 +00:00:11,144 --> 00:00:14,348 +我是 Ahmed 来自 Apple 的 + +4 +00:00:14,381 --> 00:00:15,415 +显示和色彩技术团队 + +5 +00:00:15,449 --> 00:00:19,620 +今天 我与大家分享下 +我们在 Advanced Video Quality Tool + +6 +00:00:19,653 --> 00:00:23,824 +或简称 AVQT 中 +推出的新功能和增强功能 + +7 +00:00:23,857 --> 00:00:26,693 +首先快速回顾下 + +8 +00:00:26,727 --> 00:00:28,762 +什么是 AVQT + +9 +00:00:28,795 --> 00:00:34,268 +AVQT 是一个可执行的指令行 +于 WWDC 2021 首次推出 + +10 +00:00:34,301 --> 00:00:38,105 +它是基于全参考帧的视频质量测量 +可评估潜在压缩 + +11 +00:00:38,138 --> 00:00:41,208 +和缩放构建的视频质量 + +12 +00:00:41,241 --> 00:00:45,212 +它试图模仿人们是如何 +评估视频质量的 + +13 +00:00:45,245 --> 00:00:51,218 +AVQT 支持所有基于 AVFoundation 的 +视频格式 包括 SDR 和 HDR + +14 +00:00:51,251 --> 00:00:56,023 +包括 HDR10 HLG +和杜比视界 + +15 +00:00:56,056 --> 00:00:59,860 +AVQT 有三个独有的 +关键属性 + +16 +00:00:59,893 --> 00:01:04,531 +首先 AVQT 与人们如何评估视频 +达成了高度相关 + +17 +00:01:04,565 --> 00:01:06,266 +这可以应用到所有内容类型 + +18 +00:01:06,300 --> 00:01:09,603 +如动画 自然风景和运动 + +19 +00:01:09,636 --> 00:01:13,340 +第二 AVQT 有 +令人惊叹的处理速度 + +20 +00:01:13,373 --> 00:01:16,743 +这得益于 AVFoundation 和 Metal +AVQT 依赖它们 + +21 +00:01:16,777 --> 00:01:19,146 +完成视频解码和处理 + +22 +00:01:19,179 --> 00:01:23,650 +第三 AVQT 是为适应 +不同查看设置而设计的 + +23 +00:01:23,684 --> 00:01:26,286 +基于实际查看设置 +同一个视频可以导致 + +24 +00:01:26,320 --> 00:01:28,121 +不同的观看体验 + +25 +00:01:28,155 --> 00:01:30,657 +这可在 AVQT 中通过 + +26 +00:01:30,691 --> 00:01:34,461 +如显示分辨率 显示大小 视距等 +因素进行配置 + +27 +00:01:35,329 --> 00:01:39,566 +您可查看我们 2021 年的 “Evaluate videos with +Advanced Video Quality Tool” 视频 + +28 +00:01:39,600 --> 00:01:43,637 +以了解更多关于 AVQT 的信息 + +29 +00:01:43,670 --> 00:01:47,574 +在 WWDC 2021 宣布推出 +AVQT 的视频中 + +30 +00:01:47,608 --> 00:01:51,311 +我们展示了它在 M1 Macs 上 +可达到令人惊叹的处理速度 + +31 +00:01:51,345 --> 00:01:56,984 +从那之后 Apple 处理器 +就有了更强的能力 AVQT 也更快了 + +32 +00:01:57,017 --> 00:02:01,054 +这是 M1 处理器新成员的 +处理速度 + +33 +00:02:01,088 --> 00:02:04,691 +在 M1 Ultra 中 +AVQT 仅用了 20 分钟 + +34 +00:02:04,725 --> 00:02:08,862 +就评估了一个 2 小时时长 +HEVC 压缩 4K 电影 + +35 +00:02:08,896 --> 00:02:11,598 +这比实时要快 6 倍 + +36 +00:02:11,632 --> 00:02:14,268 +对于有类似时长的全高清电影 + +37 +00:02:14,301 --> 00:02:17,938 +AVQT 不到 11 分钟 +就处理完了视频 + +38 +00:02:17,971 --> 00:02:21,675 +这比实时快了 10 倍以上 + +39 +00:02:21,708 --> 00:02:25,279 +您现在可在同样的时间内 +评估更多视频 + +40 +00:02:26,513 --> 00:02:29,650 +接下来 我来为大家介绍下 +今年为 AVQT 增加的 + +41 +00:02:29,683 --> 00:02:32,986 +新功能和增强功能 + +42 +00:02:33,020 --> 00:02:36,590 +您现在可以用 AVQT +将您的视频品质视觉化 + +43 +00:02:36,623 --> 00:02:38,825 +无需额外步骤 + +44 +00:02:38,859 --> 00:02:42,329 +AVQT 的最新版本 +可以生成基于 HTML 的报告 + +45 +00:02:42,362 --> 00:02:44,765 +有交互图和表格 + +46 +00:02:44,798 --> 00:02:47,968 +展示您视频品质的分析结果 + +47 +00:02:48,001 --> 00:02:52,072 +这些报告通过添加新的 +visualize 标记即可生成 + +48 +00:02:53,006 --> 00:02:55,576 +您可识别您视频中 + +49 +00:02:55,609 --> 00:02:58,545 +质量未达预期的部分 + +50 +00:02:58,579 --> 00:03:01,882 +您也可以与其他同事 +共享 AVQT 报告 + +51 +00:03:01,915 --> 00:03:05,152 +他们无需安装 AVQT +或其它工具 + +52 +00:03:05,185 --> 00:03:07,321 +只要在 Safari 中 +打开报告即可 + +53 +00:03:09,056 --> 00:03:11,792 +所以我为大家演示下 +如何创建交互图 + +54 +00:03:11,825 --> 00:03:14,061 +以及如何使用其功能 + +55 +00:03:15,996 --> 00:03:18,365 +首先 我给大家看下帮助菜单 + +56 +00:03:18,398 --> 00:03:20,501 +我们新增了一个新的参数 +visualize + +57 +00:03:20,534 --> 00:03:22,970 +您可以用来创建报告 + +58 +00:03:23,003 --> 00:03:27,608 +这是 AVQT 指令 可评估 +我通过压缩创建的 + +59 +00:03:27,641 --> 00:03:32,045 +一段去年 WWDC 演示视频的质量 + +60 +00:03:32,079 --> 00:03:36,984 +然后 您可添加 visualize 参数 +它会创建一个报告 + +61 +00:03:37,017 --> 00:03:39,319 +完成后 您可看到 +HTML 报告文件的位置 + +62 +00:03:39,353 --> 00:03:42,756 +打印到标准输出 + +63 +00:03:42,789 --> 00:03:45,259 +这个文件在 Safari 中 +打开即可 + +64 +00:03:46,126 --> 00:03:50,364 +左边的表格展示了 +被分析视频的信息 + +65 +00:03:50,397 --> 00:03:53,133 +右边的包括设置 + +66 +00:03:53,166 --> 00:03:55,102 +和评估视频使用的参数 + +67 +00:03:57,905 --> 00:04:02,943 +这个表格展示了随着时间的 +帧级和片段级 AVQT 得分 + +68 +00:04:05,946 --> 00:04:08,015 +如果您对具体区间感兴趣 + +69 +00:04:08,048 --> 00:04:10,784 +只需放大就能获取更多信息 + +70 +00:04:12,252 --> 00:04:15,756 +在图表上悬停可为您提供 +该处更多信息 + +71 +00:04:15,789 --> 00:04:19,459 +如时间 AVQT 得分以及帧索引 + +72 +00:04:19,493 --> 00:04:21,361 +或该得分所属的片段 + +73 +00:04:23,263 --> 00:04:27,267 +缩小到主视图 您可以 +在表格任意位置双击 + +74 +00:04:30,537 --> 00:04:33,540 +会出现饼图展示被分析视频的 + +75 +00:04:33,574 --> 00:04:37,010 +AVQT 帧得分的分布 + +76 +00:04:37,044 --> 00:04:39,479 +它展示了五个品质类别的 +百分比和帧数量 + +77 +00:04:39,513 --> 00:04:44,184 +包括 “Bad” “Poor” “Fair” + +78 +00:04:44,218 --> 00:04:46,286 +“Good” 和 “Excellent” + +79 +00:04:48,155 --> 00:04:50,824 +底部的表格与顶部的类似 + +80 +00:04:50,858 --> 00:04:53,293 +只是展示了 PSNR 得分 + +81 +00:04:57,497 --> 00:05:01,034 +我们希望这一功能 +可以帮助您总结视频质量 + +82 +00:05:01,068 --> 00:05:03,704 +并识别可能的问题 + +83 +00:05:03,737 --> 00:05:06,707 +还有一个我非常高兴能为大家 +介绍的功能 + +84 +00:05:06,740 --> 00:05:09,376 +您现在可以指定您用于评估的 +参考和测试视频的 + +85 +00:05:09,409 --> 00:05:11,945 +时间窗口 + +86 +00:05:11,979 --> 00:05:16,416 +这可以聚焦于视频中 +一个指定场景或多个场景 + +87 +00:05:16,450 --> 00:05:20,754 +也可以对比暂时不一致的视频 + +88 +00:05:20,787 --> 00:05:24,992 +我们添加了四个新的指令行参数 +来帮助您精准指定 + +89 +00:05:25,025 --> 00:05:28,862 +想要分析的视频开始和结束部分 + +90 +00:05:30,063 --> 00:05:34,001 +我为大家展示下 +如何使用时间窗口的功能 + +91 +00:05:35,035 --> 00:05:37,971 +这是我在上一个 demo 中 +评估的视频 + +92 +00:05:38,005 --> 00:05:42,075 +这次 我想要评估视频的 +单一场景 + +93 +00:05:42,109 --> 00:05:44,745 +我可以这样来完成 + +94 +00:05:44,778 --> 00:05:48,749 +在 Quicktime 播放器中 +我开始查找该场景 + +95 +00:05:48,782 --> 00:05:51,318 +就是这个 + +96 +00:05:51,351 --> 00:05:54,221 +点击这里可以显示帧索引 + +97 +00:05:54,254 --> 00:05:58,659 +我使用方向键 +获取场景中的第一帧 + +98 +00:05:58,692 --> 00:06:00,394 +是 270 + +99 +00:06:00,427 --> 00:06:04,531 +重复同样的步骤 +找到场景的最后一帧 + +100 +00:06:04,565 --> 00:06:07,267 +是 486 帧 + +101 +00:06:07,301 --> 00:06:10,971 +现在 我们在 AVQT 中 +评估这个场景 + +102 +00:06:11,004 --> 00:06:13,707 +指令的第一部分和之前一样 + +103 +00:06:13,740 --> 00:06:18,011 +然后使用这些四个新添加的 +指令行参数 + +104 +00:06:18,045 --> 00:06:21,415 +添加从 QuickTime 播放器中 +获取的开始和结束帧索引 + +105 +00:06:23,951 --> 00:06:26,887 +我现在有了这个场景的 +AVQT 得分了 + +106 +00:06:28,922 --> 00:06:31,892 +运行这个指令 +比处理整个视频更快 + +107 +00:06:31,925 --> 00:06:34,494 +然后只要看这个场景的得分即可 + +108 +00:06:34,528 --> 00:06:37,831 +我们相信这增加了 +AVQT 的灵活性 + +109 +00:06:37,865 --> 00:06:41,235 +说到灵活性 +我们也可以扩展 + +110 +00:06:41,268 --> 00:06:44,371 +这个版本 +raw YUV 格式的支持 + +111 +00:06:44,404 --> 00:06:47,508 +AVQT 支持 +所有 AVFoundation 视频格式 + +112 +00:06:47,541 --> 00:06:51,578 +除此之外 它也支持 +raw YUV 视频 + +113 +00:06:51,612 --> 00:06:54,214 +这可启用为从未压缩的视频记分 + +114 +00:06:54,248 --> 00:06:56,183 +如原始摄像头源 + +115 +00:06:56,216 --> 00:06:59,152 +它对评估生态系外压缩 +和解码的视频 + +116 +00:06:59,186 --> 00:07:02,456 +也同样有用 + +117 +00:07:02,489 --> 00:07:06,293 +今年 我们增加支持的 raw YUV +总共支持 20 种 + +118 +00:07:06,326 --> 00:07:11,398 +色度二次采样和色彩深度格式 + +119 +00:07:11,431 --> 00:07:13,567 +值得注意的是 +“reference fourcc” + +120 +00:07:13,600 --> 00:07:16,570 +和 “test fourcc” 已弃用 + +121 +00:07:16,603 --> 00:07:19,706 +我们用两种独立的标记组 +来代替 + +122 +00:07:19,740 --> 00:07:22,709 +一个是色度二次采样 +另一个是色彩深度 + +123 +00:07:24,111 --> 00:07:26,880 +这一功能可让您在 +无需预处理的情况下 + +124 +00:07:26,914 --> 00:07:28,982 +评估更多视频 + +125 +00:07:31,084 --> 00:07:34,755 +AVQT 是于 WWDC 2021 +首次推出的 + +126 +00:07:34,788 --> 00:07:37,724 +用户对该工具的兴趣日渐增长 + +127 +00:07:37,758 --> 00:07:40,160 +我们收到了数不胜数的 +评论和需求 + +128 +00:07:40,194 --> 00:07:44,097 +最常见的需求是 +增加支持 Linux + +129 +00:07:44,131 --> 00:07:48,702 +今天 我们很高兴地宣布 +AVQT 现已可以 Linux 中使用 + +130 +00:07:50,571 --> 00:07:54,808 +我们知道这可以让人们 +评估存储在云端的内容 + +131 +00:07:54,842 --> 00:07:59,780 +或在 Linux 的服务器压缩的视频 +而无需转移拷贝视频 + +132 +00:07:59,813 --> 00:08:03,851 +我们还与 macOS 一起 +公布了支持多个 Linux 平台的 + +133 +00:08:03,884 --> 00:08:07,988 +Linux AVQT beta 版 + +134 +00:08:08,021 --> 00:08:12,492 +无外部依赖所以部署很简单 + +135 +00:08:12,526 --> 00:08:15,229 +基本上是即插即用 + +136 +00:08:15,262 --> 00:08:18,198 +您可参考 AVQT 程序包中的 +README 文件 + +137 +00:08:18,232 --> 00:08:21,468 +以了解更多关于所支持的 +Linux 平台和版本的信息 + +138 +00:08:22,903 --> 00:08:25,806 +AVQT Linux 版本的设计 +与 macOS 版本 + +139 +00:08:25,839 --> 00:08:28,208 +有同样的外观和特性 + +140 +00:08:28,242 --> 00:08:31,211 +它为指令行标记使用相同的命名 + +141 +00:08:31,245 --> 00:08:34,648 +生成相同格式的输出文件 + +142 +00:08:34,681 --> 00:08:38,118 +Linux 版本支持 +macOS 工具最新版本中的 + +143 +00:08:38,151 --> 00:08:41,221 +20 种 raw 格式 + +144 +00:08:41,255 --> 00:08:44,858 +查看条件参数 +在 Linux beta 版中不可用 + +145 +00:08:44,892 --> 00:08:46,793 +但未来会启用 + +146 +00:08:48,295 --> 00:08:51,331 +总结来说 有几个要点 + +147 +00:08:51,365 --> 00:08:56,570 +我们 WWDC 2021 推出的 +AVQT 视觉视频质量工具 + +148 +00:08:56,603 --> 00:08:59,840 +可在开发者门户中下载 + +149 +00:08:59,873 --> 00:09:03,177 +如果您还没用过这个工具 +那快去试试吧 + +150 +00:09:03,210 --> 00:09:06,613 +今年 我们在 AVQT 中 +新增了几个增强功能 + +151 +00:09:06,647 --> 00:09:10,684 +您现在可以用基于 HTML 的 +交互报告 将 AVQT 得分视觉化 + +152 +00:09:10,717 --> 00:09:14,688 +并将报告与您的同事分享 + +153 +00:09:14,721 --> 00:09:17,324 +您也可以使用新的 +“时间窗口”功能 + +154 +00:09:17,357 --> 00:09:20,160 +来查看视频中指定场景的质量 + +155 +00:09:20,194 --> 00:09:23,864 +最后 如果您的视频存储在云端 + +156 +00:09:23,897 --> 00:09:28,702 +且使用基于 Linux 的视频解码器 +AVQT 现在也可在 Linux 中使用 + +157 +00:09:28,735 --> 00:09:31,305 +感谢大家的观看 + diff --git a/zho/2022 Session 10151 Add accessibility to your Unity games.srt b/zho/2022 Session 10151 Add accessibility to your Unity games.srt new file mode 100644 index 0000000..f4038be --- /dev/null +++ b/zho/2022 Session 10151 Add accessibility to your Unity games.srt @@ -0,0 +1,1001 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,309 --> 00:00:12,112 +Eric Liang: 大家好 我是 Eric + +3 +00:00:12,145 --> 00:00:17,050 +我很高兴可以为大家分享 +如何为您的 Unity 游戏添加辅助功能 + +4 +00:00:18,085 --> 00:00:22,723 +辅助功能是为了让每个人都可以 +使用我们的产品 + +5 +00:00:22,756 --> 00:00:27,361 +今天我们为 Unity 开发者们 +提供的 Apple Accessibility 插件 + +6 +00:00:27,394 --> 00:00:31,398 +标志着我们向着无障碍游戏 +又前进了一大步 + +7 +00:00:31,431 --> 00:00:36,637 +为了让游戏支持辅助功能 +我们主要专注于三个 Apple 技术 + +8 +00:00:37,738 --> 00:00:43,210 +旁白 是一个帮助失明 +或低视力用户的屏幕阅读器 + +9 +00:00:43,243 --> 00:00:47,581 +它可以朗读屏幕上的内容 +用户也可以用自定义手势 + +10 +00:00:47,614 --> 00:00:50,617 +来与控件交互 + +11 +00:00:51,985 --> 00:00:55,522 +切换控制 让运动控制能力较弱的用户 + +12 +00:00:55,556 --> 00:00:59,593 +使用外部切换控制器来与设备交互 + +13 +00:00:59,626 --> 00:01:03,397 +还有动态字体 让用户可以 + +14 +00:01:03,430 --> 00:01:06,800 +根据自身的阅读能力 +来设置字体大小 + +15 +00:01:07,801 --> 00:01:10,904 +首先 克隆代码库 + +16 +00:01:10,938 --> 00:01:13,407 +运用代码库根目录下的构建脚本 + +17 +00:01:13,440 --> 00:01:17,344 +来构建所有 Apple 插件 + +18 +00:01:17,377 --> 00:01:20,914 +接着 这样会生成一个 Build 文件夹 +可以将其整合到 + +19 +00:01:20,948 --> 00:01:23,784 +您的 Unity 项目中 + +20 +00:01:23,817 --> 00:01:27,888 +最后 用 Unity Package Manager + +21 +00:01:27,921 --> 00:01:30,924 +将 Apple Accessibility 插件添加 +到您的项目中 + +22 +00:01:30,958 --> 00:01:35,362 +您还可以查看代码库中的文档 + +23 +00:01:35,395 --> 00:01:39,166 +以及观看介绍所有 Apple 的 +Unity 插件的视频课程 + +24 +00:01:39,199 --> 00:01:44,671 +“Plug-in and play: Add Apple frameworks +to your Unity game projects” 以获取更多细节 + +25 +00:01:45,539 --> 00:01:50,410 +现在您已经准备好了插件 +我将会从以下三个方面为大家讲解 + +26 +00:01:50,444 --> 00:01:53,313 +第一个是辅助功能元素 + +27 +00:01:53,347 --> 00:01:56,683 +这让您可以在游戏中 +增加辅助技术的支持 + +28 +00:01:56,717 --> 00:02:00,954 +如 旁白 或 切换控制 + +29 +00:02:00,988 --> 00:02:03,857 +接下来是 动态字体 + +30 +00:02:03,891 --> 00:02:08,095 +我们创建了这个易于使用的工具 +帮助您根据用户偏好设置 + +31 +00:02:08,128 --> 00:02:10,964 +来缩放字体 + +32 +00:02:10,998 --> 00:02:13,600 +还有 UI 适应性设置 + +33 +00:02:13,634 --> 00:02:18,772 +这些实用工具可以帮助您 +读取其它的用户偏好设置 + +34 +00:02:18,805 --> 00:02:21,775 +我们先来看下辅助功能元素 + +35 +00:02:22,876 --> 00:02:27,548 +我创建了一个简易的卡牌游戏 +来帮助解释这个概念 + +36 +00:02:27,581 --> 00:02:30,551 +您可以看到 您要点击 +“Flip”按钮 + +37 +00:02:30,584 --> 00:02:33,654 +来随机抽取两张卡牌 + +38 +00:02:33,687 --> 00:02:36,957 +然而 旁白 不会朗读 +屏幕上的文本 + +39 +00:02:36,990 --> 00:02:40,561 +而外部切换控制器也不会点击按钮 + +40 +00:02:40,594 --> 00:02:44,097 +因为现在屏幕上只有像素 + +41 +00:02:44,131 --> 00:02:49,136 +我们要帮助系统理解 +哪些是可以进行交互的 + +42 +00:02:49,169 --> 00:02:52,039 +辅助功能元素定义了辅助技术 + +43 +00:02:52,072 --> 00:02:55,542 +可以交互的部分 + +44 +00:02:57,244 --> 00:03:00,781 +文本 卡牌和屏幕上的按钮 + +45 +00:03:00,814 --> 00:03:03,750 +都应该是辅助功能元素 + +46 +00:03:03,784 --> 00:03:07,221 +我们可以用标签来描述 +每个元素 + +47 +00:03:07,254 --> 00:03:12,693 +旁白 会朗读标签 +这样用户能理解屏幕上的内容 + +48 +00:03:14,261 --> 00:03:17,064 +如果游戏支持多语言 + +49 +00:03:17,097 --> 00:03:19,466 +我们也应该对标签进行本地化 + +50 +00:03:21,535 --> 00:03:24,538 +现在 旁白 可以描述 +屏幕上的内容了 + +51 +00:03:24,571 --> 00:03:29,576 +但是它还不知道屏幕上 +还有一个可点击的按钮 + +52 +00:03:29,610 --> 00:03:32,346 +我们可以使用另一个属性 +称为“Traits” + +53 +00:03:32,379 --> 00:03:36,183 +来告知系统该元素的类型 + +54 +00:03:36,216 --> 00:03:39,186 +我们在这里添加 +“Button”的特性 + +55 +00:03:39,219 --> 00:03:43,156 +现在 旁白 会朗读 +“翻转 按钮” + +56 +00:03:43,190 --> 00:03:46,393 +然后外部切换控制器可以控制该按钮 + +57 +00:03:48,428 --> 00:03:53,800 +我们也可以添加在文本元素上 +添加“Static Text”特性 + +58 +00:03:53,834 --> 00:03:59,173 +“Static Text”特性通常是 +赋予标签和文本区域的 + +59 +00:03:59,206 --> 00:04:03,443 +这样 旁白 可以提供 +更好的文本交互体验 + +60 +00:04:04,878 --> 00:04:07,581 +除了“Button”和“Static Text”外 +还有很多特性 + +61 +00:04:07,614 --> 00:04:10,317 +是您可以探索的 + +62 +00:04:11,919 --> 00:04:15,422 +那卡牌应该用什么特性呢 + +63 +00:04:15,455 --> 00:04:21,094 +我们不需要给每个 +辅助功能元素都运用特性 + +64 +00:04:21,128 --> 00:04:24,464 +卡牌就不需要任何特性 + +65 +00:04:25,098 --> 00:04:28,168 +然而 卡牌上还有一个部分 + +66 +00:04:28,202 --> 00:04:31,071 +是 旁白 没有识别的 + +67 +00:04:31,104 --> 00:04:33,473 +那就是卡面值 + +68 +00:04:33,507 --> 00:04:38,078 +这里我们可以使用另一个属性 +称为“Value” + +69 +00:04:39,680 --> 00:04:44,184 +我们为每张卡牌添加了一个“Value”后 +旁白 现在可以朗读 + +70 +00:04:44,218 --> 00:04:47,654 +“卡牌 1 梅花 3” + +71 +00:04:47,688 --> 00:04:51,458 +“卡牌 2 梅花 A” + +72 +00:04:51,491 --> 00:04:53,260 +就是这样 + +73 +00:04:54,194 --> 00:04:58,065 +现在您已经理解了基本原理 +我们打开 Unity + +74 +00:04:58,098 --> 00:05:00,934 +来看下可以如何将其 +添加到我们的项目中 + +75 +00:05:02,336 --> 00:05:05,906 +现在我进入了游戏的 +Unity 编辑器环境下 + +76 +00:05:05,939 --> 00:05:08,275 +我已经为这个项目中 + +77 +00:05:08,308 --> 00:05:09,843 +添加了 Apple Accessibility 插件 + +78 +00:05:11,311 --> 00:05:15,649 +首先 我们有常规的场景对象 +如相机 + +79 +00:05:15,682 --> 00:05:19,386 +定向光和 UI 画布 + +80 +00:05:19,419 --> 00:05:22,756 +在 画布 下面 +有两个文本元素 + +81 +00:05:22,789 --> 00:05:24,925 +和一个按钮 + +82 +00:05:24,958 --> 00:05:28,428 +然后 我们有两个卡牌游戏对象 + +83 +00:05:31,798 --> 00:05:35,235 +每个都由两个网格组件组成 + +84 +00:05:35,269 --> 00:05:39,806 +卡牌的每一面都渲染了对应的正反面纹理 + +85 +00:05:39,840 --> 00:05:44,311 +我们从定义辅助功能元素开始吧 + +86 +00:05:44,344 --> 00:05:49,416 +这需要插件中的 +Accessibility Node 组件 + +87 +00:05:50,851 --> 00:05:55,055 +选中层级结构中应该设置辅助功能的 +所有对象 + +88 +00:05:57,925 --> 00:06:02,763 +添加 Accessibility Node 组件 +让它们成为辅助功能元素 + +89 +00:06:06,366 --> 00:06:08,502 +接下来 添加标签 + +90 +00:06:09,236 --> 00:06:12,072 +选择卡牌对象 + +91 +00:06:12,105 --> 00:06:15,676 +到右边的 +“Accessibility Node”组件 + +92 +00:06:15,709 --> 00:06:18,045 +找到“Label”字段 + +93 +00:06:19,213 --> 00:06:24,251 +确保 label 字段的复选框已选中 +以创建自定义标签 + +94 +00:06:26,186 --> 00:06:28,388 +然后输入“Card 1” + +95 +00:06:31,859 --> 00:06:35,329 +对于 Card 2 也做同样的操作 + +96 +00:06:40,434 --> 00:06:43,604 +文本和按钮也需要标签 + +97 +00:06:43,637 --> 00:06:47,975 +但如果我们用的是 Unity UI 的 +标准控件 + +98 +00:06:48,008 --> 00:06:52,546 +则不需要为它们提供一个显式的 +辅助功能标签 + +99 +00:06:52,579 --> 00:06:56,083 +插件 已经默认实现了 + +100 +00:06:57,384 --> 00:07:00,354 +接下来 我们要为按钮添加 +一个特性 + +101 +00:07:02,422 --> 00:07:05,492 +选择 Flip 按钮 + +102 +00:07:05,526 --> 00:07:09,229 +将“Traits”从“None” +修改为“Button” + +103 +00:07:13,567 --> 00:07:15,802 +选择两个文本元素 + +104 +00:07:18,138 --> 00:07:21,241 +将“Traits”修改为“Static Text” + +105 +00:07:23,911 --> 00:07:25,312 +好了 + +106 +00:07:25,345 --> 00:07:29,950 +最后 我们要为卡面值 +设置对应辅助功能数值 + +107 +00:07:29,983 --> 00:07:33,954 +由于卡牌是随机抽取的 +我需要添加脚本 + +108 +00:07:33,987 --> 00:07:36,023 +来动态设置卡面值 + +109 +00:07:37,424 --> 00:07:42,396 +选择两张卡牌 添加一个 +AccessibleCard 的新脚本 + +110 +00:07:44,831 --> 00:07:48,101 +首先 在我另一个 +C# 文件中 + +111 +00:07:48,135 --> 00:07:53,607 +所有卡牌正面都已经有了 +一个枚举称为 Playing Card + +112 +00:07:53,640 --> 00:07:57,578 +在我新的 AccessibleCard 这个 +Mono Behaviour 脚本中 + +113 +00:07:57,611 --> 00:07:59,847 +设置了一个关于卡牌类型的变量 + +114 +00:07:59,880 --> 00:08:03,350 +和一个关于卡面上下朝向的布尔值 + +115 +00:08:05,552 --> 00:08:10,457 +现在我们为这些卡牌 +添加 accessibilityValue + +116 +00:08:10,490 --> 00:08:15,762 +首先 获取附属于这个 gameObject 的 +accessibilityNode 组件 + +117 +00:08:17,064 --> 00:08:21,401 +接下来 +将 accessibilityValue 代理设置为 + +118 +00:08:21,435 --> 00:08:23,837 +动态返回卡面值的函数 + +119 +00:08:25,339 --> 00:08:28,809 +在函数中 如果卡面朝下 + +120 +00:08:28,842 --> 00:08:32,713 +会在 accessibilityValue 中 +返回“covered” + +121 +00:08:32,746 --> 00:08:36,817 +如果卡面朝上 我们会枚举 +所有卡面 + +122 +00:08:36,850 --> 00:08:41,822 +返回每张卡牌的描述 +如“黑桃 A” + +123 +00:08:41,855 --> 00:08:44,191 +就是这样 + +124 +00:08:44,224 --> 00:08:48,395 +现在我们来构建项目 +看下其实际运行情况 + +125 +00:08:48,428 --> 00:08:51,532 +这就是我们的游戏 +我们打开 旁白 + +126 +00:08:55,335 --> 00:08:57,804 +【自动语音: 旁白】 开启 +Eric 的游戏 + +127 +00:08:57,838 --> 00:08:59,740 +卡牌 2 面朝下 + +128 +00:08:59,773 --> 00:09:03,076 +【Eric】 我可以向右滑动 +来移动到下一个元素 + +129 +00:09:03,744 --> 00:09:05,546 +【自动语音】 卡牌 1 面朝下 + +130 +00:09:07,314 --> 00:09:08,982 +Eric 的卡牌游戏 + +131 +00:09:10,884 --> 00:09:12,386 +翻牌 + +132 +00:09:14,087 --> 00:09:16,256 +Flip 按钮 + +133 +00:09:16,290 --> 00:09:20,661 +【Eric】 您看现在所有五个对象 +都可以用 旁白 来访问 + +134 +00:09:20,694 --> 00:09:23,163 +太赞了 + +135 +00:09:23,197 --> 00:09:27,568 +当 旁白 开启时 +对这个要点击的按钮进行双击 + +136 +00:09:28,335 --> 00:09:30,504 +【自动语音】 翻牌 + +137 +00:09:30,537 --> 00:09:32,339 +【Eric】 我们再来看下卡牌 + +138 +00:09:34,441 --> 00:09:36,743 +【自动语音】 卡牌 1 梅花 2 + +139 +00:09:38,378 --> 00:09:40,681 +卡牌 2 梅花 A + +140 +00:09:40,714 --> 00:09:45,352 +【Eric】 旁白 现在可以正确 +朗读更新后的卡面值 + +141 +00:09:45,385 --> 00:09:46,386 +这样很酷 + +142 +00:09:46,420 --> 00:09:50,357 +我们现在可以为数百万的 +旁白 用户制作无障碍游戏了 + +143 +00:09:50,390 --> 00:09:52,326 +他们一定会很喜欢的 + +144 +00:09:52,359 --> 00:09:57,097 +还有使用外部切换控制器的用户 +也会玩我们的游戏 + +145 +00:09:57,130 --> 00:10:00,367 +这就是辅助功能元素 + +146 +00:10:00,400 --> 00:10:03,504 +接下来 我们来看下动态字体 + +147 +00:10:04,838 --> 00:10:07,975 +由于文本太小看不清 + +148 +00:10:08,008 --> 00:10:10,978 +对很多人来说 +玩游戏可能并不容易 + +149 +00:10:11,011 --> 00:10:14,748 +在 iOS 和 tvOS 中 每个人可以 + +150 +00:10:14,781 --> 00:10:17,985 +根据自身阅读能力 +在设置中调整合适的字体大小 + +151 +00:10:20,120 --> 00:10:23,423 +通过 Accessibility 插件 +您也可以读取该设置 + +152 +00:10:23,457 --> 00:10:28,095 +确保游戏的文本能 +按预期字体大小来显示 + +153 +00:10:30,264 --> 00:10:35,169 +我们根据游戏示例来看下 +动态字体是如何使用的 + +154 +00:10:36,370 --> 00:10:41,441 +创建一个 DynamicTextSize.cs 的 +Mono Behaviour脚本 + +155 +00:10:41,475 --> 00:10:46,213 +在开始函数中 首先将默认 +文本大小存储为变量 + +156 +00:10:47,181 --> 00:10:51,852 +然后在 OnEnable 函数中 +使用 AccessibilitySettings.onPreferredTextSizesChanged + +157 +00:10:51,885 --> 00:10:57,057 +来订阅 settingsChanged 事件 + +158 +00:10:57,891 --> 00:11:02,429 +这样用户在改变字体设置时 +我们可以马上更改 UI + +159 +00:11:03,830 --> 00:11:07,334 +接下来 +在 settingsChanged 函数中 + +160 +00:11:07,367 --> 00:11:11,205 +首先读取 +PreferredContentSizeMultiplier + +161 +00:11:11,238 --> 00:11:14,541 +然后乘以您的原始字体大小 + +162 +00:11:14,575 --> 00:11:17,544 +然后分配回 Text 元素 + +163 +00:11:18,512 --> 00:11:21,949 +在 Unity 编辑器中 +选择有 Text 元素的 + +164 +00:11:21,982 --> 00:11:25,052 +所有游戏对象 + +165 +00:11:25,085 --> 00:11:28,956 +添加我们刚刚创建的 +DynamicTextSize 组件 + +166 +00:11:32,492 --> 00:11:36,730 +现在我们的游戏都设置好 +动态字体支持了 + +167 +00:11:37,397 --> 00:11:41,168 +我们看实际的运行效果前 +我先给大家演示下 + +168 +00:11:41,201 --> 00:11:45,205 +一个快速测试游戏中 +动态字体的方法 + +169 +00:11:45,239 --> 00:11:49,376 +打开设置 找到控制中心 + +170 +00:11:54,214 --> 00:11:58,986 +向下滚动 直到看见字体大小 +将其添加到控制中心 + +171 +00:12:02,422 --> 00:12:06,827 +现在我们通过打开控制中心 +改变字体大小选项 + +172 +00:12:06,860 --> 00:12:08,996 +就能快速调整字体大小了 + +173 +00:12:17,905 --> 00:12:23,744 +很好 我改变字体大小时 +游戏也会实时改变字体大小 + +174 +00:12:24,811 --> 00:12:27,648 +控制中心中显示的 +字体百分比值 + +175 +00:12:27,681 --> 00:12:30,817 +正是我们从乘数读取的 + +176 +00:12:30,851 --> 00:12:35,689 +您也可以将这个设置 +应用到非文本对象中 + +177 +00:12:35,722 --> 00:12:39,226 +例如 在字体大小增加时 +我可以将卡牌正面素材 + +178 +00:12:39,259 --> 00:12:42,496 +替换为 Large Print + +179 +00:12:45,265 --> 00:12:50,137 +首先 我创建一个 +DynamicCardFaces 脚本 + +180 +00:12:50,170 --> 00:12:54,741 +然后和之前一样 +订阅 TextSizeChanged 事件 + +181 +00:12:55,809 --> 00:13:01,481 +这次不是读取乘数 +而是读取一个字体大小类别的枚举 + +182 +00:13:01,515 --> 00:13:05,619 +它被映射到控制中心滑块的刻度上 + +183 +00:13:05,652 --> 00:13:10,624 +有人选择大号字体的时候 +我就可以替换素材 + +184 +00:13:11,825 --> 00:13:14,728 +我只要在常规材质 + +185 +00:13:14,761 --> 00:13:16,563 +和大号印刷体材质之间选择即可 + +186 +00:13:17,464 --> 00:13:20,734 +现在 如果我们选择了 +非常大的字体 + +187 +00:13:26,273 --> 00:13:30,010 +用户可能会看到大号印刷体的卡牌 + +188 +00:13:30,043 --> 00:13:35,282 +对于低视力的用户来说 +这种卡牌正面的易读性很强 + +189 +00:13:36,783 --> 00:13:40,754 +最后 我跟大家分享下 +您可以用这个插件访问 + +190 +00:13:40,787 --> 00:13:43,223 +UI 适应性设置 + +191 +00:13:44,224 --> 00:13:48,662 +第一个设置是 Reduce Transparency + +192 +00:13:48,695 --> 00:13:52,933 +开启这个设置后 背景变成不透明 + +193 +00:13:52,966 --> 00:13:56,670 +而不是模糊或透明效果 + +194 +00:13:56,703 --> 00:14:01,108 +文本在这些效果下难以识别时 +该设置可以提高易读性 + +195 +00:14:02,042 --> 00:14:04,344 +调用 AccessibilitySettings. +IsReduceTransparencyEnabled + +196 +00:14:04,378 --> 00:14:08,482 +来查看这个偏好设置 + +197 +00:14:10,284 --> 00:14:13,887 +接下来是 +Increase Contrast 设置 + +198 +00:14:13,921 --> 00:14:18,926 +深灰色的开关会更显眼 + +199 +00:14:18,959 --> 00:14:23,230 +在整个设备中也会更易于识别 + +200 +00:14:24,464 --> 00:14:28,802 +您可以使用 +AccessibilitySettings.IsIncreaseContrastEnabled + +201 +00:14:28,836 --> 00:14:31,405 +来查看这一设置 + +202 +00:14:31,438 --> 00:14:35,442 +启用后即可增加 UI 对比度 + +203 +00:14:37,144 --> 00:14:40,614 +接下来是 Reduce Motion 设置 + +204 +00:14:40,647 --> 00:14:45,586 +有些人对手势很敏感 +正如我们在这个翻牌动画中一样 + +205 +00:14:46,854 --> 00:14:50,791 +Reduce Motion 启用时 +我们应该移除该动画 + +206 +00:14:51,892 --> 00:14:54,061 +我们看下实现的代码 + +207 +00:14:55,362 --> 00:15:00,701 +在我们的 CardController 脚本中 +有这个 Flip 函数 + +208 +00:15:00,734 --> 00:15:05,539 +首先我们看下用户的 +Reduce Motion 设置是否开启 + +209 +00:15:05,572 --> 00:15:11,211 +如果没有开启 我们应通过 +Coroutine 调用动画来翻牌 + +210 +00:15:12,145 --> 00:15:16,283 +否则就只是设置单纯旋转 而不带动画 + +211 +00:15:16,316 --> 00:15:17,851 +就这样 + +212 +00:15:17,885 --> 00:15:22,422 +现在对手势比较敏感的用户 +也能享受我们的游戏了 + +213 +00:15:23,357 --> 00:15:27,494 +回顾一下 首先通过克隆 +这个讲座资源关联的 + +214 +00:15:27,528 --> 00:15:31,932 +GitHub 数据库来 +开启 Apple 辅助功能插件 + +215 +00:15:33,000 --> 00:15:36,603 +添加辅助功能元素 +这样用户可以在游戏中 + +216 +00:15:36,637 --> 00:15:38,805 +使用 旁白 +和 切换控制 + +217 +00:15:40,007 --> 00:15:42,943 +用动态字体来调整字体大小 + +218 +00:15:44,478 --> 00:15:46,947 +检查 UI 适应性设置 + +219 +00:15:46,980 --> 00:15:50,250 +这样每个人都能对游戏 +有绝佳的体验 + +220 +00:15:51,385 --> 00:15:53,620 +感谢大家的参与 + +221 +00:15:53,654 --> 00:15:57,624 +我们很期待能看到您的游戏 + +222 +00:15:57,658 --> 00:16:00,961 +有完美的无障碍体验 + diff --git a/zho/2022 Session 10153 What's new in web accessibility.srt b/zho/2022 Session 10153 What's new in web accessibility.srt new file mode 100644 index 0000000..c14b754 --- /dev/null +++ b/zho/2022 Session 10153 What's new in web accessibility.srt @@ -0,0 +1,1327 @@ +1 +00:00:01,301 --> 00:00:07,307 +[古怪的音乐] + +2 +00:00:09,309 --> 00:00:10,978 +Tyler: 大家好 我是 Tyler + +3 +00:00:11,011 --> 00:00:14,214 +是来自 WebKit accessibility +团队的工程师 + +4 +00:00:14,248 --> 00:00:16,250 +在今天的讲座中 +我将带大家游览 + +5 +00:00:16,283 --> 00:00:19,520 +现代网络的辅助功能 +第一站是辅助技术的概览 + +6 +00:00:19,553 --> 00:00:21,922 +如屏幕阅读器 + +7 +00:00:23,090 --> 00:00:26,827 +然后 我们会介绍您如何 +在 Web Speech API 和 dialog 元素中 + +8 +00:00:26,860 --> 00:00:31,999 +使用如自定义控件 +语音合成标记语言 或简称 SSML 等工具 + +9 +00:00:32,032 --> 00:00:35,135 +构建丰富 可访问的 +网页 App 的方法 + +10 +00:00:36,503 --> 00:00:39,406 +我们先来看下辅助技术 + +11 +00:00:40,374 --> 00:00:43,710 +全球大约 1/7 的人有某种残疾 + +12 +00:00:43,744 --> 00:00:47,447 +影响他们与世界 设备 +和网络之间的互动 + +13 +00:00:48,015 --> 00:00:50,484 +不同年纪的人会经历 +不同时间长度 + +14 +00:00:50,517 --> 00:00:53,654 +不同严重程度的残疾 + +15 +00:00:53,687 --> 00:00:57,157 +Apple 构建了多种工具 +帮助用户以最佳的方式 + +16 +00:00:57,191 --> 00:01:00,027 +来与设备互动 + +17 +00:01:00,060 --> 00:01:04,765 +这些工具包括 VoiceOver +开关控制 语音控制 + +18 +00:01:04,798 --> 00:01:09,736 +全键盘访问 这些都为用户提供了 +不同的设备使用方式 + +19 +00:01:09,770 --> 00:01:12,005 +您可以查看去年的 + +20 +00:01:12,039 --> 00:01:13,674 +“Support Full Keyboard Access +in your iOS app”讲座 + +21 +00:01:13,707 --> 00:01:16,143 +以了解更多关于这些工具 +及其它方面的内容 + +22 +00:01:17,211 --> 00:01:19,813 +要了解这在网页上的 +实际使用感受 + +23 +00:01:19,847 --> 00:01:23,383 +我们用 VoiceOver 来处理 +一个样本测试评估网站 + +24 +00:01:23,417 --> 00:01:27,354 +在我的 iPad 上 通过连按三次 +顶部按钮来激活 VoiceOver + +25 +00:01:28,222 --> 00:01:31,358 +Siri: VoiceOver 开启 +Safari 浏览器显示侧边栏 按钮 + +26 +00:01:32,426 --> 00:01:36,797 +Tyler: 现在 激活 VoiceOver 后 +我可以轻触页面顶部来查看 + +27 +00:01:36,830 --> 00:01:38,966 +Siri: Pop Quiz 一级标题 + +28 +00:01:38,999 --> 00:01:41,935 +Tyler: 向右滑动以在页面的 +不同元素间跳转 + +29 +00:01:41,969 --> 00:01:46,940 +Siri: 第 1 题 / 共 6 题 +1/4 片披萨中 有多少片是总共有 8 片的 + +30 +00:01:46,974 --> 00:01:50,444 +2 片 单选按钮 未勾选 +第 1 个选项 共 4 个选项 + +31 +00:01:50,477 --> 00:01:51,478 +3 片 + +32 +00:01:51,512 --> 00:01:52,412 +4 片 + +33 +00:01:52,446 --> 00:01:53,514 +6 片 + +34 +00:01:53,547 --> 00:01:54,948 +下一题 按钮 + +35 +00:01:55,816 --> 00:01:58,552 +Tyler: 作为一个网页开发者 +有许多可供选择的工具 + +36 +00:01:58,585 --> 00:02:02,656 +让您的页面可被用户访问 +如 VoiceOver + +37 +00:02:02,689 --> 00:02:05,559 +例如 Safari 浏览器对语义 HTML 元素 +如按钮 标题 h1 到 h6 + +38 +00:02:05,592 --> 00:02:09,930 +表格元素 列表元素等 + +39 +00:02:09,963 --> 00:02:13,867 +都有内置的易访问性支持 + +40 +00:02:13,901 --> 00:02:16,803 +使用这些语义 HTML 元素 +应作为您的默认设置 + +41 +00:02:16,837 --> 00:02:20,174 +因为它能确保您的用户 +在所有浏览器上 + +42 +00:02:20,207 --> 00:02:22,776 +都有一致的 可访问的体验 + +43 +00:02:22,809 --> 00:02:27,047 +然而 有时语义 HTML 并不一定 +能完全满足您的需求 + +44 +00:02:27,080 --> 00:02:30,417 +需要用 JavaScript 来 +创建自定义组件 + +45 +00:02:30,450 --> 00:02:32,419 +如果是这种情况 您可能还需要 + +46 +00:02:32,452 --> 00:02:34,688 +使用 ARIA 属性 +来补充您的组件 + +47 +00:02:34,721 --> 00:02:38,425 +这样它们的语义才能恰当 +传达到辅助技术中 + +48 +00:02:38,458 --> 00:02:42,596 +这就引出了我们今天的 +第二个话题 自定义控件 + +49 +00:02:42,629 --> 00:02:45,933 +假如我们想要让这个披萨测试题 +更引人入胜 + +50 +00:02:45,966 --> 00:02:49,469 +其中一个方法是用自定义控件 +来替换单选按钮 + +51 +00:02:49,503 --> 00:02:53,473 +从而让用户通过轻触 +来添加和移动披萨切片 + +52 +00:02:54,274 --> 00:02:57,477 +这种自定义控件的标记符号 +以 div 和 ID 开始 + +53 +00:02:58,912 --> 00:03:02,716 +为了让用户通过轻触或点击组件 +就能进行交互 + +54 +00:03:02,749 --> 00:03:05,052 +我们需要添加一个 +点击事件监听器 + +55 +00:03:05,085 --> 00:03:07,921 +我们用构造器来创建一个 +新的 PizzaControl 类 + +56 +00:03:07,955 --> 00:03:09,556 +可以接受元素的 ID + +57 +00:03:10,691 --> 00:03:13,694 +我们通过 ID 获取该元素 +然后为其添加点击事件监听器 + +58 +00:03:15,195 --> 00:03:18,632 +该监听器根据轻触的位置 +计算新的切片数量 + +59 +00:03:18,665 --> 00:03:22,402 +然后将数量传递给调用更新的函数 +从而重新渲染控件 + +60 +00:03:22,436 --> 00:03:25,005 +这对一些用户来说很有用 +但并不是全部 + +61 +00:03:26,139 --> 00:03:28,775 +比如 对于有视力障碍的用户来说 + +62 +00:03:28,809 --> 00:03:31,345 +他们不知道要点击或轻触哪里 +那怎么办呢 + +63 +00:03:31,378 --> 00:03:34,314 +构建自定义组件时 我们一定要 +考虑到所有类型的 + +64 +00:03:34,348 --> 00:03:37,918 +辅助技术用户 +都会与我们的组件互动 + +65 +00:03:37,951 --> 00:03:40,621 +从这一点出发 创建可访问组件的 +第一步就是 + +66 +00:03:40,654 --> 00:03:44,391 +为其提供一个角色属性 +值为“slider” + +67 +00:03:44,424 --> 00:03:47,861 +我们的控件能完美地 +映射到 slider 模型 + +68 +00:03:47,895 --> 00:03:52,566 +有一个最小值 0 片 +和最大值 8 片 + +69 +00:03:52,599 --> 00:03:54,868 +当前值是 4 片 + +70 +00:03:55,602 --> 00:03:59,373 +我们还需要添加 tabindex 为 0 +确保使用键盘 + +71 +00:03:59,406 --> 00:04:02,142 +和其它非触屏界面的用户 +也能在组件上设定焦点 + +72 +00:04:03,443 --> 00:04:05,512 +我们也需要添加几个 +ARIA 属性 + +73 +00:04:06,547 --> 00:04:10,217 +Aria-valuemin 和 aria-valuemax +可提示辅助技术 + +74 +00:04:10,250 --> 00:04:12,853 +该 slider 的最小值 +和最大值 + +75 +00:04:14,054 --> 00:04:16,490 +这些属性与您在 +本机范围类型输入中使用的 + +76 +00:04:16,523 --> 00:04:19,026 +最小属性和最大属性类似 + +77 +00:04:20,527 --> 00:04:24,498 +接下来 我们添加 aria-valuenow +以传递控件的当前值 + +78 +00:04:25,899 --> 00:04:29,269 +我们还要使用 aria-valuetext +提供对当前值 + +79 +00:04:29,303 --> 00:04:31,505 +更有用的描述 即 4 片 + +80 +00:04:33,040 --> 00:04:35,876 +现在我们已经将控件设定为 +可定焦 slider + +81 +00:04:35,909 --> 00:04:37,911 +我们需要在辅助技术中 + +82 +00:04:37,945 --> 00:04:40,013 +处理控件值的更新 + +83 +00:04:40,047 --> 00:04:43,150 +在 iOS 中 VoiceOver 通过 +单指上滑来增加 slider + +84 +00:04:43,183 --> 00:04:45,986 +单指下滑减少 slider + +85 +00:04:46,019 --> 00:04:49,122 +从而帮助调整 sliders + +86 +00:04:49,156 --> 00:04:52,326 +Safari 浏览器提供了 +处理这些手势的简易方法 + +87 +00:04:52,359 --> 00:04:55,429 +当 VoiceOver 用户上滑 +定焦一个 slider 时 + +88 +00:04:55,462 --> 00:04:59,166 +Safari 浏览器自动模拟 +右箭头键事件 + +89 +00:04:59,199 --> 00:05:01,668 +同样的 +如果 VoiceOver 用户下滑 + +90 +00:05:01,702 --> 00:05:05,806 +定焦一个 slider 时 +则模拟左箭头键事件 + +91 +00:05:05,839 --> 00:05:09,109 +这些模拟事件的行为 +与真实键盘按键一样 + +92 +00:05:09,142 --> 00:05:11,912 +意味着它们可以通过 +键盘事件监听器来处理 + +93 +00:05:11,945 --> 00:05:13,814 +有了工具带的这一新知识 + +94 +00:05:13,847 --> 00:05:16,950 +我们可以为披萨控件 +添加一个键盘按下监听器 + +95 +00:05:16,984 --> 00:05:19,753 +如果激活的按键是右箭头 +或上箭头 + +96 +00:05:19,786 --> 00:05:23,390 +我们将会更新控件为 +当前切片数量加 1 + +97 +00:05:23,423 --> 00:05:26,960 +同样的 如果激活按键是 +左箭头或下箭头 + +98 +00:05:26,994 --> 00:05:30,531 +我们将会更新控件为 +当前切片数量减 1 + +99 +00:05:30,564 --> 00:05:34,401 +增加这个关键事件监听器 +不仅对 VoiceOver 用户有利 + +100 +00:05:34,434 --> 00:05:36,603 +也对全键盘访问用户有利 + +101 +00:05:36,637 --> 00:05:38,872 +他们可能会严重或完全依赖于 +您的网页 App + +102 +00:05:38,906 --> 00:05:40,541 +变得键盘可访问 + +103 +00:05:40,574 --> 00:05:42,709 +建立了两种事件监听器后 + +104 +00:05:42,743 --> 00:05:46,280 +我们现在也要定义更新的函数了 + +105 +00:05:46,313 --> 00:05:49,349 +首先 我们要限定所给的数值 +使其保持在 + +106 +00:05:49,383 --> 00:05:51,185 +0 至 8 的限值内 + +107 +00:05:51,218 --> 00:05:55,122 +将我们存储的切片数量状态 +更新为该值 + +108 +00:05:55,155 --> 00:05:58,959 +接下来 我们要确保更新了 +控件的视觉和 + +109 +00:05:58,992 --> 00:06:00,694 +ARIA 呈现 + +110 +00:06:00,727 --> 00:06:03,830 +当构建自定义组件时 +一条黄金规则是 如果您更新 + +111 +00:06:03,864 --> 00:06:06,200 +组件的视觉呈现 + +112 +00:06:06,233 --> 00:06:08,135 +也要考虑如何更新 + +113 +00:06:08,168 --> 00:06:09,503 +ARIA 呈现 + +114 +00:06:10,804 --> 00:06:13,540 +在这种情况下 我们需要 +同时更新 aria-valuenow + +115 +00:06:13,574 --> 00:06:15,209 +和 aria-valuetext 属性 + +116 +00:06:15,242 --> 00:06:18,512 +从而告知辅助技术用户 +新的控件状态 + +117 +00:06:19,980 --> 00:06:23,317 +首先要设置 aria-valuenow +为当前切片数量 + +118 +00:06:24,351 --> 00:06:27,921 +接下来 设置 set aria-valuetext +为更用户友好的 + +119 +00:06:27,955 --> 00:06:31,225 +切片数量描述方式 +加上“slice”或“slices” + +120 +00:06:32,192 --> 00:06:34,161 +好了 现在一切准备就绪 + +121 +00:06:34,194 --> 00:06:36,029 +我们回到测试评估网页 App + +122 +00:06:36,063 --> 00:06:38,031 +来看下 VoiceOver 下的 +用户体验 + +123 +00:06:38,065 --> 00:06:40,701 +我首先轻触披萨控件以定焦 + +124 +00:06:41,468 --> 00:06:43,704 +Siri: 4 片 可调整 + +125 +00:06:43,737 --> 00:06:45,772 +单指上滑或下滑以调整数值 + +126 +00:06:46,607 --> 00:06:49,276 +Tyler: 我们听到了 VoiceOver +说出了 slider 的初始值 + +127 +00:06:49,309 --> 00:06:52,045 +4 片 且这是可调整的 + +128 +00:06:52,079 --> 00:06:54,748 +跟着 VoiceOver 的提示 +我们可以上滑来增加 + +129 +00:06:54,781 --> 00:06:56,450 +选定切片的数量 + +130 +00:06:56,483 --> 00:06:59,152 +Siri: 5 片 6 片 + +131 +00:06:59,186 --> 00:07:02,222 +Tyler: 下滑来减少选定切片的数量 + +132 +00:07:02,256 --> 00:07:04,725 +Siri: 5 片 4 片 + +133 +00:07:04,758 --> 00:07:07,361 +Tyler: 这些变化就绪后 +我们的自定义 slider 组件 + +134 +00:07:07,394 --> 00:07:08,962 +辅助功能提升了 + +135 +00:07:09,930 --> 00:07:13,901 +现在 我们来看下您可以如何使用 +Web Speech API 中的 SSML + +136 +00:07:13,934 --> 00:07:16,970 +来为您的所有用户 +构建更丰富的体验 + +137 +00:07:17,604 --> 00:07:21,642 +Web Speech API 是由 +两个主要 JavaScript 界面组成的 + +138 +00:07:21,675 --> 00:07:23,911 +音频输入的 SpeechRecognition + +139 +00:07:23,944 --> 00:07:26,980 +以及文本-音频输出的 SpeechSynthesis + +140 +00:07:28,148 --> 00:07:30,117 +Web Speech 让您的网页 App +可提供语音辅助 + +141 +00:07:30,150 --> 00:07:33,120 +或纯语音交互界面 + +142 +00:07:34,288 --> 00:07:37,391 +这对有运动残疾的用户来说 +是很有利的 + +143 +00:07:37,424 --> 00:07:39,593 +因为他们可能无法使用 +其它方式的控件 + +144 +00:07:39,626 --> 00:07:41,962 +如鼠标 键盘或触屏 + +145 +00:07:42,696 --> 00:07:46,200 +Safari 浏览器中 SpeechSynthesis 的 +新功能就是可使用 SSML + +146 +00:07:46,233 --> 00:07:48,135 +从而改变您文本的朗读方式 + +147 +00:07:49,069 --> 00:07:51,905 +SSML 有众多功能 + +148 +00:07:51,939 --> 00:07:54,074 +例如 您可以使用 +break 元素 + +149 +00:07:54,107 --> 00:07:56,543 +来在讲话中插入 +您选择的暂停时长 + +150 +00:07:57,177 --> 00:08:01,215 +您会让您的用户吸气 和呼气 + +151 +00:08:02,216 --> 00:08:04,318 +使用 phoneme 元素 您可以控制 + +152 +00:08:04,351 --> 00:08:07,087 +单词的发音 如“tomayto” +和“tomahto”之间的区别 + +153 +00:08:08,755 --> 00:08:11,391 +prosody 元素让您可以 +操控朗读文本的音高 + +154 +00:08:11,425 --> 00:08:14,595 +语速和音量 + +155 +00:08:14,628 --> 00:08:18,065 +这些只是 SSML 众多功能中的 +沧海一粟 + +156 +00:08:18,098 --> 00:08:21,835 +您可以查看 w3.org 中的 +SSML 规范以了解更多信息 + +157 +00:08:22,703 --> 00:08:26,406 +我们来实际应用新发现的 +SSML 知识 + +158 +00:08:26,440 --> 00:08:29,009 +测试的最后一道问题 +我们让学生 + +159 +00:08:29,042 --> 00:08:31,645 +通过单选按钮来选择 +“the water” + +160 +00:08:31,678 --> 00:08:34,381 +西班牙语的正确翻译 + +161 +00:08:34,414 --> 00:08:36,783 +我们也可以将这个问题调整得 +更具吸引力 可以让用户 + +162 +00:08:36,817 --> 00:08:40,687 +点选按钮 通过文本-语音的方式 +来朗读和回答问题 + +163 +00:08:40,721 --> 00:08:43,056 +通过 SSML +用西班牙地区特性的语音 + +164 +00:08:43,090 --> 00:08:44,658 +来朗读西班牙词组 + +165 +00:08:45,526 --> 00:08:48,862 +我们首先创建按钮 +确保说话人的表情符号 + +166 +00:08:48,896 --> 00:08:51,265 +限制在一定范围内 +将 aria-hidden 设置为 true + +167 +00:08:51,298 --> 00:08:54,434 +因为表情符号的描述 +在这里并不一定有用 + +168 +00:08:56,036 --> 00:08:58,438 +接下来 我们创建一个 +helper JavaScript 函数 + +169 +00:08:58,472 --> 00:08:59,973 +称为 wrapWithSSML + +170 +00:09:00,007 --> 00:09:03,043 +它会选择一个词组 +用具有地区特性的语音来朗读 + +171 +00:09:04,144 --> 00:09:06,680 +我们先是用 break 元素 +构建 SSML 字符串 + +172 +00:09:06,713 --> 00:09:09,816 +从而在每个词组前插入 +短暂的停顿以强调 + +173 +00:09:10,884 --> 00:09:13,620 +通过 prosody 元素 +我们可以指定词组 + +174 +00:09:13,654 --> 00:09:15,756 +以默认语速 80% 的 +速度来朗读 + +175 +00:09:17,157 --> 00:09:19,459 +最后 我们使用 lang 元素 +来选择 + +176 +00:09:19,493 --> 00:09:22,596 +希望词组使用的 +特定地区特性声音 + +177 +00:09:24,198 --> 00:09:26,967 +现在我们为朗读问题按钮 +添加单击事件监听器 + +178 +00:09:27,000 --> 00:09:29,837 +以及构建内部 SSML 字符串 + +179 +00:09:29,870 --> 00:09:32,406 +首先将整个字符串 +都放置于 speak 元素内 + +180 +00:09:33,607 --> 00:09:36,476 +Speak 很重要 因为它可以 +提示合成处理器 + +181 +00:09:36,510 --> 00:09:39,046 +在这个范围内的所有内容 +都应通过 SSML 来处理 + +182 +00:09:40,447 --> 00:09:44,718 +加下来 我们加入问题 +“the water 西班牙语怎么说” + +183 +00:09:45,686 --> 00:09:47,855 +我们可以用 +wrapWithSSML helper 函数 + +184 +00:09:47,888 --> 00:09:50,090 +为需要翻译的词组添加强调 + +185 +00:09:50,123 --> 00:09:52,593 +确保其用英语地区语音来朗读 + +186 +00:09:53,594 --> 00:09:57,331 +四个可能的答案同样 +使用了 wrapWithSSML + +187 +00:09:57,364 --> 00:10:01,101 +提供强调 并提出使用 +西班牙地区语音来朗读的请求 + +188 +00:10:02,402 --> 00:10:05,739 +最后 我们可以用 SSML 字符串 +来创建新的 + +189 +00:10:05,772 --> 00:10:08,575 +SpeechSynthesisUtterance 对象 +并将其传送到 + +190 +00:10:08,609 --> 00:10:11,144 +SpeechSynthesis 方法视窗 +以朗读 + +191 +00:10:13,480 --> 00:10:15,582 +这些都准备就绪后 +我们看下在网页 App 中 + +192 +00:10:15,616 --> 00:10:17,184 +是怎样的体验 + +193 +00:10:17,217 --> 00:10:20,087 +在最后一道问题的页面中 +我轻触“Read question”按钮 + +194 +00:10:20,120 --> 00:10:21,855 +并听取语音 + +195 +00:10:21,889 --> 00:10:26,260 +Siri: “the water”西班牙语怎么说 + +196 +00:10:26,293 --> 00:10:28,295 +El agua + +197 +00:10:28,328 --> 00:10:30,564 +La abuela + +198 +00:10:30,597 --> 00:10:32,900 +La abeja + +199 +00:10:32,933 --> 00:10:34,902 +El árbol + +200 +00:10:34,935 --> 00:10:37,771 +Tyler: 多亏了 SSML +我们为学生创建了 + +201 +00:10:37,804 --> 00:10:38,839 +更引人入胜的体验 + +202 +00:10:39,973 --> 00:10:42,709 +网页另一个常用的设计模式 +是 modal + +203 +00:10:43,710 --> 00:10:47,147 +您的网页 Apps 中可能会 +将其用于注册或登陆表单 + +204 +00:10:47,181 --> 00:10:49,516 +来确认 dialogs 等等 + +205 +00:10:50,684 --> 00:10:52,953 +提供可访问 modal 体验的 +一个方法 + +206 +00:10:52,986 --> 00:10:55,489 +就是 aria-modal 属性 + +207 +00:10:55,522 --> 00:10:58,025 +使用 aria-modal="true" +Safari 浏览器会考虑 modal 以外 + +208 +00:10:58,058 --> 00:11:02,329 +所有被忽略的可访问元素 + +209 +00:11:02,362 --> 00:11:05,866 +最近 Safari 浏览器还新增了 +支持 dialog 元素的功能 + +210 +00:11:06,567 --> 00:11:09,503 +Dialog 通过标准定焦交互 + +211 +00:11:09,536 --> 00:11:12,239 +对 modal 关闭手势的创新处理 + +212 +00:11:12,272 --> 00:11:14,741 +如 iOS 上的 Escape 键 +和擦除手势等 + +213 +00:11:14,775 --> 00:11:18,145 +让提供可访问友好的 +modal 体验更为简单 + +214 +00:11:18,879 --> 00:11:21,748 +要看它们的实际运行情况 +我们将测试评估网页 App 上的 + +215 +00:11:21,782 --> 00:11:24,952 +“Show score”按钮改为 +打开带有结果的对话 + +216 +00:11:26,920 --> 00:11:30,324 +首先 我们需要创建 +dialog 元素 + +217 +00:11:30,357 --> 00:11:33,393 +标记符号可以是这样的 + +218 +00:11:33,427 --> 00:11:37,898 +我们为 dialog 赋予一个 ID +之后可以被 show score 按钮引用 + +219 +00:11:37,931 --> 00:11:40,834 +我们还将 dialog 的内容 +置入有 method dialog 的表单中 + +220 +00:11:41,935 --> 00:11:44,938 +这样操作后 任何提交类型的控件 +如我们的按钮 + +221 +00:11:44,972 --> 00:11:47,641 +都会导致对话关闭 + +222 +00:11:47,674 --> 00:11:50,878 +要打开 modal +我们还需要一点 JavaScript + +223 +00:11:50,911 --> 00:11:53,080 +我们在 Show Score 按钮上 +添加点击事件监听器 + +224 +00:11:53,113 --> 00:11:55,215 +在我们的 dialog 元素上 +调用 showModal() + +225 +00:11:57,484 --> 00:11:59,953 +现在我们已万事俱备 + +226 +00:11:59,987 --> 00:12:03,123 +VoiceOver 激活后 我轻触 +“Show score”按钮以定焦 + +227 +00:12:04,124 --> 00:12:05,459 +Siri: Show score 按钮 + +228 +00:12:06,460 --> 00:12:08,462 +Tyler: 然后 我在屏幕任意位置 + +229 +00:12:08,495 --> 00:12:10,531 +单指双击以点选按钮 + +230 +00:12:11,465 --> 00:12:14,301 +Siri: Show score 网页对话 +Close 按钮 + +231 +00:12:14,334 --> 00:12:16,270 +Tyler: 现在我们的 +modal 就完成了 + +232 +00:12:16,303 --> 00:12:19,573 +我可以左滑以在 modal 的内容上 +移动 从而听取分数 + +233 +00:12:19,606 --> 00:12:22,009 +Siri: 您答对了 6 个问题 +太棒了 + +234 +00:12:22,442 --> 00:12:24,878 +Tyler: 完成后 我可以通过右滑 + +235 +00:12:24,912 --> 00:12:26,280 +回到 close 按钮 + +236 +00:12:26,313 --> 00:12:28,649 +Siri: Close 按钮 + +237 +00:12:28,682 --> 00:12:31,084 +Tyler: 双击以关闭 modal + +238 +00:12:31,118 --> 00:12:32,886 +Siri: 未勾选 + +239 +00:12:32,920 --> 00:12:34,321 +Tyler: 如我之前提到 + +240 +00:12:34,354 --> 00:12:36,523 +dialog 元素可处理 +iOS 擦除手势 + +241 +00:12:36,557 --> 00:12:38,759 +从而立即关闭 modal + +242 +00:12:38,792 --> 00:12:42,129 +我给大家演示下 首先重新 +双击打开 modal + +243 +00:12:42,162 --> 00:12:44,398 +Siri: Show score 按钮 + +244 +00:12:44,431 --> 00:12:46,767 +网页对话 Close 按钮 + +245 +00:12:46,800 --> 00:12:48,335 +Tyler: 然后使用擦除手势 + +246 +00:12:48,368 --> 00:12:52,239 +双指快速在屏幕上向右 +向左 再向右移动 + +247 +00:12:53,540 --> 00:12:55,075 +Siri: Show score 按钮 + +248 +00:12:55,108 --> 00:12:57,044 +Tyler: 好了 这样我们就有了一个 +功能 modal + +249 +00:12:57,077 --> 00:12:59,079 +但我们还能做到更好 + +250 +00:12:59,112 --> 00:13:00,781 +您有没有注意到 +当我们打开 modal 时 + +251 +00:13:00,814 --> 00:13:04,418 +VoiceOver 只会朗读 +“网页对话 close 按钮” + +252 +00:13:04,451 --> 00:13:06,720 +在这种情况下 使用 aria-label +或 aria-labelledby 属性 + +253 +00:13:06,753 --> 00:13:09,556 +为辅助技术用户提供更多信息 + +254 +00:13:09,590 --> 00:13:12,860 +将会更有意义 + +255 +00:13:12,893 --> 00:13:15,829 +由于我们的 modal 内容很短 +只要告知用户 + +256 +00:13:15,863 --> 00:13:19,433 +他们答对了多少个问题即可 +我们用标签来完成 + +257 +00:13:19,466 --> 00:13:24,004 +首先 将 modal 内容 +用 ID 将其限制在一个范围 + +258 +00:13:24,037 --> 00:13:26,039 +然后 我们可以添加 +aria-labelledby 属性 + +259 +00:13:26,073 --> 00:13:28,509 +到 dialog pointing +到 modal 内容 ID + +260 +00:13:29,543 --> 00:13:32,412 +我们还要明确地把初始 +modal 定焦元素 + +261 +00:13:32,446 --> 00:13:34,848 +设置为带有自动定焦属性的 +close 按钮 + +262 +00:13:36,016 --> 00:13:38,852 +虽然这已经是这一简单 modal 的 +默认行为 + +263 +00:13:38,886 --> 00:13:41,421 +如果我们的 modal 有很多内容 +或更复杂 + +264 +00:13:41,455 --> 00:13:43,423 +有很多控件 那情况就不一样了 + +265 +00:13:44,591 --> 00:13:47,227 +例如 在有很多内容的 modal 中 + +266 +00:13:47,261 --> 00:13:51,164 +最好是在最上方的标题栏 +加入自动定焦 + +267 +00:13:51,198 --> 00:13:53,467 +作为 modal 作者 +您最为清楚什么内容 + +268 +00:13:53,500 --> 00:13:55,102 +会给您的用户带来完美体验 + +269 +00:13:56,303 --> 00:13:58,205 +有了我们的新属性 +我们再来看看 + +270 +00:13:58,238 --> 00:14:00,574 +在 VoiceOver 中的体验如何 + +271 +00:14:00,607 --> 00:14:03,177 +我首先单击 +Show score 按钮以定焦 + +272 +00:14:04,077 --> 00:14:05,112 +Siri: Show score 按钮 + +273 +00:14:06,613 --> 00:14:09,149 +Tyler: 然后双击来点选 + +274 +00:14:09,183 --> 00:14:13,387 +Siri: 您 6 个问题全部答对了 +太棒了 网页对话 close 按钮 + +275 +00:14:13,954 --> 00:14:15,822 +Tyler: 这个体验更完美 + +276 +00:14:15,856 --> 00:14:19,526 +多亏了 aria-labelledby +VoiceOver 用户马上就能听到他们的分数 + +277 +00:14:19,560 --> 00:14:21,828 +且已经定焦至 close 按钮 + +278 +00:14:21,862 --> 00:14:23,897 +他们可以直接双击 +以离开 modal + +279 +00:14:23,931 --> 00:14:26,834 +现在我们来总结下今天的讲座 + +280 +00:14:26,867 --> 00:14:29,903 +我希望大家都学到了如何构建 +丰富 可访问的网页 App 技术 + +281 +00:14:29,937 --> 00:14:32,472 +从而为您所有用户带来 +完美的体验 + +282 +00:14:33,373 --> 00:14:35,509 +请在最新的 Safari 浏览器中 +尝试这些功能 + +283 +00:14:35,542 --> 00:14:37,878 +如果有任何 bug +请登录 bugs.webkit.org + +284 +00:14:37,911 --> 00:14:39,913 +上传至 WebKit bug tracker + +285 +00:14:40,681 --> 00:14:44,251 +感谢大家参与今天这场 +简要的现代网页辅助功能旅程 + +286 +00:14:44,284 --> 00:14:46,787 +祝您的 WWDC 之旅一切顺利 + +287 +00:14:46,820 --> 00:14:48,889 +[古怪的音乐] + diff --git a/zho/2022 Session 10156 Meet ScreenCaptureKit.srt b/zho/2022 Session 10156 Meet ScreenCaptureKit.srt new file mode 100644 index 0000000..022970c --- /dev/null +++ b/zho/2022 Session 10156 Meet ScreenCaptureKit.srt @@ -0,0 +1,1047 @@ +1 +00:00:01,368 --> 00:00:07,374 +[古怪的音乐] + +2 +00:00:09,710 --> 00:00:11,211 +Ernest: 大家好 欢迎 + +3 +00:00:11,245 --> 00:00:13,480 +我是 Ernest +ScreenCaptureKit 团队的 + +4 +00:00:13,514 --> 00:00:15,382 +一名软件工程师 + +5 +00:00:15,415 --> 00:00:17,684 +在过去的几年中 + +6 +00:00:17,718 --> 00:00:20,787 +我们对远程协作的依赖度 +日益提高 + +7 +00:00:20,821 --> 00:00:22,990 +屏幕共享就是其中的 +常用功能之一 + +8 +00:00:25,659 --> 00:00:27,094 +最重要的是 + +9 +00:00:27,127 --> 00:00:31,532 +总的来说 使用如 +OBS Studio 录制 App 的 + +10 +00:00:31,565 --> 00:00:33,700 +流媒体游戏和内容创作 + +11 +00:00:33,734 --> 00:00:38,839 +已经成为了人们教育和娱乐 +持续增长的领域 + +12 +00:00:40,574 --> 00:00:43,177 +在这一概念下 我们创建了 +满足开发者们需求的 + +13 +00:00:43,210 --> 00:00:48,115 +高性能 稳定的屏幕捕获框架 + +14 +00:00:48,148 --> 00:00:49,616 +那就是 ScreenCaptureKit + +15 +00:00:51,618 --> 00:00:55,055 +ScreenCaptureKit 是 macOS 中 +一款全新框架 + +16 +00:00:55,088 --> 00:00:56,823 +专为帮助您搭建 + +17 +00:00:56,857 --> 00:00:59,259 +App 屏幕共享体验而设计 + +18 +00:01:00,227 --> 00:01:04,064 +ScreenCaptureKit 提供 +可让您选择 + +19 +00:01:04,097 --> 00:01:05,599 +想要捕获内容的 API + +20 +00:01:05,632 --> 00:01:10,170 +开发者可按 App 需要 +进行控制和切换 + +21 +00:01:10,204 --> 00:01:13,941 +所有的过滤程序和控制 +都可以实时更新 + +22 +00:01:15,409 --> 00:01:18,412 +该框架可以高品质 高性能 +提供高达屏幕显示的 + +23 +00:01:18,445 --> 00:01:22,916 +原生分辨率和帧率 + +24 +00:01:22,950 --> 00:01:26,186 +同时隐私安全 +通过全局守卫得以保障 + +25 +00:01:27,454 --> 00:01:31,425 +在这个讲座中 我会为您讲解 +如何开始 ScreenCaptureKit 框架 + +26 +00:01:32,559 --> 00:01:34,962 +您掌握基础知识后 可查看讲座 + +27 +00:01:34,995 --> 00:01:37,431 +将 ScreenCaptureKit +提升到全新境界 + +28 +00:01:37,464 --> 00:01:39,099 +以了解更高阶的内容 + +29 +00:01:40,501 --> 00:01:43,904 +首先 我先回顾下该框架的 +关键功能 + +30 +00:01:45,305 --> 00:01:48,942 +然后 我将于 API 概述中 +阐述 ScreenCaptureKit 的 + +31 +00:01:48,976 --> 00:01:50,177 +主要构造 + +32 +00:01:51,512 --> 00:01:54,214 +接着 我会为大家演示 +如何用过滤器和配置 + +33 +00:01:54,248 --> 00:01:55,749 +来配置您的 stream 流 + +34 +00:01:56,850 --> 00:01:59,453 +最后 我带大家看下如何将您 +App 的视频 + +35 +00:01:59,486 --> 00:02:01,889 +和音频样本流媒体化 + +36 +00:02:03,457 --> 00:02:05,959 +首先是 ScreenCaptureKit 的 +关键功能 + +37 +00:02:07,294 --> 00:02:11,331 +ScreenCaptureKit 可让您 +指定您想要共享或过滤的 + +38 +00:02:11,365 --> 00:02:13,467 +内容类型 + +39 +00:02:13,500 --> 00:02:17,804 +您可以捕获任意屏幕内容 +不管是屏幕显示 App + +40 +00:02:17,838 --> 00:02:22,910 +窗口以及音频的组合 + +41 +00:02:25,879 --> 00:02:29,149 +ScreenCaptureKit 支持 +多种开发者控制 + +42 +00:02:29,183 --> 00:02:33,787 +包括像素格式 色彩空间 + +43 +00:02:33,820 --> 00:02:37,424 +帧率 分辨率 + +44 +00:02:37,457 --> 00:02:41,862 +以及音频方面 也可控制 +采样率和通道数 + +45 +00:02:44,598 --> 00:02:47,100 +这些过滤程序和配置 + +46 +00:02:47,134 --> 00:02:49,436 +都可以实时调整 + +47 +00:02:49,469 --> 00:02:52,372 +为 App 设计 +提供了更高的灵活性 + +48 +00:02:54,174 --> 00:02:59,079 +为了发送高达 48kHz 立体声的 +音频样本 + +49 +00:02:59,112 --> 00:03:03,650 +以及高达您屏幕显示原始分辨率 +和帧率的视频 + +50 +00:03:03,684 --> 00:03:08,622 +ScreenCaptureKit 主要聚焦于性能 +并充分利用 Mac GPU 的能力 + +51 +00:03:08,655 --> 00:03:13,026 +却比当前屏幕捕获方式 +耗费更少的 CPU + +52 +00:03:13,060 --> 00:03:16,930 +当然 ScreenCaptureKit +非常注重隐私安全 + +53 +00:03:16,964 --> 00:03:21,335 +为使用该框架的所有 App +都提供全局隐私保障 + +54 +00:03:23,203 --> 00:03:27,941 +该框架在捕获视频和音频内容前 +会请求用户许可 + +55 +00:03:27,975 --> 00:03:31,144 +该选择也会存储于系统偏好中的 + +56 +00:03:31,178 --> 00:03:32,746 +屏幕录制隐私设置中 + +57 +00:03:34,181 --> 00:03:37,417 +现在您已经了解了 +ScreenCaptureKit 的基本内容 + +58 +00:03:37,451 --> 00:03:41,021 +我为大家演示下 API 中 +一些最重要的概念 + +59 +00:03:41,054 --> 00:03:44,358 +ScreenCaptureKit 框架 +主要以 SCStream 为中心 + +60 +00:03:45,559 --> 00:03:49,363 +SCStream 处理如开始 +和停止的控制 + +61 +00:03:49,396 --> 00:03:52,799 +与 SCShareableContent +SCContentFilter 和 + +62 +00:03:52,833 --> 00:03:57,104 +SCStreamConfiguration 一起创建 + +63 +00:03:58,172 --> 00:04:01,508 +这些对象决定您想要捕获的 +是什么内容 + +64 +00:04:01,542 --> 00:04:03,410 +以及您想要如何捕获它 + +65 +00:04:04,811 --> 00:04:09,216 +一旦创建并启动后 +媒体样本将会通过 + +66 +00:04:09,249 --> 00:04:12,853 +SCStreamOutput 协议 +发送到您的 App 中 + +67 +00:04:13,487 --> 00:04:15,589 +我稍后会进一步解释 + +68 +00:04:17,391 --> 00:04:22,596 +现在 我为大家演示下如何使用 API +在您 App 中配置 stream 流 + +69 +00:04:24,498 --> 00:04:28,368 +这些是配置 stream 流时 +您需要熟悉的对象 + +70 +00:04:30,137 --> 00:04:33,607 +这些对象确定了您捕获的 + +71 +00:04:33,640 --> 00:04:36,276 +内容 品质和性能 + +72 +00:04:37,845 --> 00:04:41,381 +首先我要看的 +是 SCShareableContent + +73 +00:04:44,318 --> 00:04:50,791 +在这个桌面 有窗口 +App 和屏幕显示本身 + +74 +00:04:52,259 --> 00:04:55,662 +ScreenCaptureKit 针对 +每个您可用于 + +75 +00:04:55,696 --> 00:04:58,699 +构建共享内容的部件 +都有对应的类 + +76 +00:05:01,001 --> 00:05:03,904 +首先 我们看下 SCDisplay + +77 +00:05:05,105 --> 00:05:10,043 +ScreenCaptureKit 将屏幕显示 +分类为 SCDisplays 只读属性 + +78 +00:05:10,077 --> 00:05:13,180 +包括显示标识符 + +79 +00:05:13,213 --> 00:05:16,717 +大小属性宽度和高度 + +80 +00:05:19,119 --> 00:05:23,223 +在屏幕显示中 可能会有不同的 +App 在运行 + +81 +00:05:23,257 --> 00:05:27,461 +每个都有 +对应的 SCRunningApplication + +82 +00:05:29,196 --> 00:05:31,865 +SCRunningApplication 中的 +App 级别信息 + +83 +00:05:31,899 --> 00:05:34,034 +有只读属性 + +84 +00:05:34,067 --> 00:05:36,770 +如 bundle 标识符 + +85 +00:05:36,803 --> 00:05:40,040 +App 名称及其进程标识符 + +86 +00:05:41,909 --> 00:05:45,579 +在这个例子中 +Keynote 和 Safari + +87 +00:05:45,612 --> 00:05:48,048 +各有一个 SCRunningApplication + +88 +00:05:49,249 --> 00:05:52,519 +当然 这些 App 都有窗口 + +89 +00:05:53,787 --> 00:05:56,957 +这些窗口都有 +对应的 SCWindow + +90 +00:05:56,990 --> 00:05:58,392 +包括定义窗口的只读属性 + +91 +00:05:58,425 --> 00:06:04,398 +比如窗口 id frame 标题 + +92 +00:06:04,431 --> 00:06:07,134 +窗口是否在屏幕上或最小化 + +93 +00:06:08,602 --> 00:06:11,705 +SCWindow 也会有一个 +所属 App + +94 +00:06:12,973 --> 00:06:16,009 +在这个情况下 +两个 Safari SCWindows + +95 +00:06:16,043 --> 00:06:18,212 +都会有一样的 +Safari 所属 App + +96 +00:06:22,015 --> 00:06:27,221 +SCWindows SCRunningApplications +和 SCDisplays 相结合 + +97 +00:06:27,254 --> 00:06:29,823 +为您提供在 SCShareableContent 中 + +98 +00:06:29,857 --> 00:06:32,059 +可以共享的潜在内容 + +99 +00:06:32,092 --> 00:06:36,063 +您可以获得设备中 +所有可共享内容的列表 + +100 +00:06:36,096 --> 00:06:38,765 +或者也可以指定某个参数 + +101 +00:06:41,168 --> 00:06:44,137 +假如您想要列出屏幕上 + +102 +00:06:44,171 --> 00:06:45,506 +所有 App 和窗口 + +103 +00:06:45,539 --> 00:06:48,208 +这样用户可以选择 +需要共享的内容 + +104 +00:06:49,009 --> 00:06:52,379 +ScreenCaptureKit 有一个 +简单的 API 来完成 + +105 +00:06:54,815 --> 00:06:57,985 +这个简短的代码片段 +是捕获示例代码 + +106 +00:06:58,018 --> 00:06:59,720 +可在 developer.apple.com 中找到 + +107 +00:07:00,754 --> 00:07:05,058 +只有屏幕上的窗口 +会通过 SCShareableContent 返回 + +108 +00:07:05,092 --> 00:07:11,265 +包括相关联的 SCWindows +SCApplications 和 SCDisplays + +109 +00:07:12,566 --> 00:07:14,635 +现在您有了可共享内容 + +110 +00:07:14,668 --> 00:07:16,170 +就可以创建一个过滤器了 + +111 +00:07:18,205 --> 00:07:21,942 +SCContentFilter 有 +两种主要类型 + +112 +00:07:21,975 --> 00:07:25,712 +显示器无关的窗口过滤器 +它可以捕获 + +113 +00:07:25,746 --> 00:07:28,882 +在多个显示器间移动的窗口 + +114 +00:07:28,916 --> 00:07:31,351 +以及依赖显示器的过滤器 + +115 +00:07:31,385 --> 00:07:36,356 +可以选择包含或排除 +指定的窗口或 App + +116 +00:07:37,357 --> 00:07:40,460 +要注意音频捕获只能 +在 App 级别上 + +117 +00:07:40,494 --> 00:07:41,962 +进行过滤 + +118 +00:07:43,063 --> 00:07:46,600 +我会给大家演示几个 +过滤程序的例子 + +119 +00:07:48,468 --> 00:07:51,205 +假如您只对共享 +keynote 窗口感兴趣 + +120 +00:07:53,473 --> 00:07:56,510 +您可以选择显示器无关的 +窗口过滤器 + +121 +00:07:56,543 --> 00:07:59,379 +从而在它跨屏幕移动时 +可以捕获对应的窗口 + +122 +00:08:00,614 --> 00:08:04,651 +即使您想要共享 +屏幕上的所有内容 + +123 +00:08:04,685 --> 00:08:07,487 +也可能会有一些内容 +是您想要排除在外的 + +124 +00:08:07,521 --> 00:08:11,058 +比如 您会想将 +自己的捕获 App 排除在外 + +125 +00:08:11,091 --> 00:08:13,727 +从而避免镜像嵌套效果 + +126 +00:08:16,330 --> 00:08:21,802 +有些窗口或 App 中可能还有 + +127 +00:08:21,835 --> 00:08:24,738 +您不想捕获的敏感信息 + +128 +00:08:24,771 --> 00:08:28,609 +这些场景都可通过 +SCContentFilter 来处理 + +129 +00:08:28,642 --> 00:08:31,111 +现在我们跳转到代码 +看下如何完成 + +130 +00:08:34,214 --> 00:08:36,617 +这是我之前展示的代码片段 + +131 +00:08:38,051 --> 00:08:40,587 +查询了可共享内容后 + +132 +00:08:40,621 --> 00:08:44,191 +代码会查找与捕获示例 App + +133 +00:08:44,224 --> 00:08:45,759 +bundle 标识符相同的 App + +134 +00:08:46,827 --> 00:08:51,498 +然后 依赖显示器的内容过滤器 +将 App 排除在 stream 流之外 + +135 +00:08:54,535 --> 00:08:58,472 +除了内容过滤器 +ScreenCaptureKit 提供 + +136 +00:08:58,505 --> 00:09:01,475 +高品质 高性能 可于 +每个 stream 流调整的控制 + +137 +00:09:02,943 --> 00:09:06,213 +这些控制可在 +SCStreamConfiguration 中设置 + +138 +00:09:08,182 --> 00:09:13,086 +有些视频控制包括 +输出分辨率 帧率 + +139 +00:09:13,120 --> 00:09:14,988 +以及是否显示鼠标光标 + +140 +00:09:16,723 --> 00:09:21,161 +在音频方面 您可以启用音频 +改变采样率 + +141 +00:09:21,195 --> 00:09:22,863 +调整通道数 + +142 +00:09:23,997 --> 00:09:28,001 +我会为大家演示一些 +应用这些参数的场景 + +143 +00:09:29,970 --> 00:09:34,141 +当共享文本清晰度更重要的 +低频运动屏幕内容时 + +144 +00:09:34,174 --> 00:09:37,211 +如票据或电子数据表 + +145 +00:09:37,244 --> 00:09:41,682 +设置捕获的输出分辨率 +为 4K 每秒 10 帧 + +146 +00:09:43,350 --> 00:09:45,752 +由于内容中不含有音频 + +147 +00:09:45,786 --> 00:09:47,454 +您也可以禁用音频 + +148 +00:09:48,522 --> 00:09:50,791 +但如果是高动态内容 + +149 +00:09:50,824 --> 00:09:53,827 +如共享最近假期的视频 + +150 +00:09:53,861 --> 00:09:57,264 +您应该以帧率优先 +而非分辨率 + +151 +00:09:57,297 --> 00:10:00,033 +将输出分辨率 +降低为 1080p + +152 +00:10:00,067 --> 00:10:02,769 +帧率增加为每秒 60 帧 + +153 +00:10:04,471 --> 00:10:07,107 +鼠标光标的移动可能会让人分心 + +154 +00:10:07,140 --> 00:10:08,742 +您可能会想隐藏光标 + +155 +00:10:10,344 --> 00:10:14,815 +您也可以启用音频捕获 +会更有沉浸式的体验感 + +156 +00:10:16,383 --> 00:10:19,353 +这些控制都可以 +在 SCStreamConfiguration 中 + +157 +00:10:19,386 --> 00:10:20,988 +通过不同的属性来设置 + +158 +00:10:24,424 --> 00:10:27,961 +这是共享高动态内容的 +一种可能的配置 + +159 +00:10:29,563 --> 00:10:34,034 +在这个示例代码中 捕获的 +输出分辨率设置为 1080p + +160 +00:10:34,935 --> 00:10:39,973 +然后 最小帧间隔设置为 +1/60 从而以每秒 60 帧的帧率 + +161 +00:10:40,007 --> 00:10:41,441 +进行捕获 + +162 +00:10:42,643 --> 00:10:45,979 +最后 stream 流配置 +会隐藏鼠标光标 + +163 +00:10:47,681 --> 00:10:52,719 +在音频方面 首先通过将 capturesAudio +设置为 true 以启用音频 + +164 +00:10:52,753 --> 00:10:58,125 +然后 设置采样率为 48kHz +通道数为 2 + +165 +00:11:00,027 --> 00:11:04,164 +有了 SCContentFilter +和 SCStreamConfiguration + +166 +00:11:04,198 --> 00:11:06,867 +您就有了 App 设置屏幕捕获 + +167 +00:11:06,900 --> 00:11:08,468 +所需的所有信息 + +168 +00:11:09,536 --> 00:11:12,339 +有了这些 您现在可以 +创建 SCStream 了 + +169 +00:11:15,342 --> 00:11:16,977 +我们回到概述 + +170 +00:11:18,212 --> 00:11:20,214 +您要用所需的过滤器和配置 + +171 +00:11:20,247 --> 00:11:22,583 +来初始化 stream 流 + +172 +00:11:23,784 --> 00:11:26,053 +您也可以传送可选代理 + +173 +00:11:26,086 --> 00:11:27,688 +来处理错误 + +174 +00:11:29,022 --> 00:11:33,427 +设置好后 您可以调用 startCapture +ScreenCaptureKit 在可用的时候 + +175 +00:11:33,460 --> 00:11:37,064 +会提供带采样的 SCStream + +176 +00:11:38,365 --> 00:11:43,237 +创建了过滤器和配置后 +启动 stream 流代码就易如反掌了 + +177 +00:11:43,270 --> 00:11:44,271 +我来给大家演示下 + +178 +00:11:47,307 --> 00:11:50,410 +同样的 有了您需要的 +过滤器和配置 + +179 +00:11:50,444 --> 00:11:52,980 +您就可以初始化 +SCStream 对象 + +180 +00:11:54,648 --> 00:11:59,119 +在捕获样本项目中 +self 作为错误处理代理传送 + +181 +00:12:01,054 --> 00:12:05,125 +创建 SCStream 后 +您现在可以调用 startCapture + +182 +00:12:06,894 --> 00:12:09,396 +您初始化 +和开始 stream 流后 + +183 +00:12:09,429 --> 00:12:12,599 +下一步就是通过 +App 获得媒体样本 + +184 +00:12:16,136 --> 00:12:19,239 +音频和视频样本都会以 +CMSampleBuffers 的形式 + +185 +00:12:19,273 --> 00:12:21,441 +发送到您的 App + +186 +00:12:22,910 --> 00:12:26,146 +为了从 stream 流中 +获取媒体样本 + +187 +00:12:26,180 --> 00:12:27,648 +您需要添加一个对象 + +188 +00:12:27,681 --> 00:12:31,385 +为 stream 流实现 +SCStreamOutput 协议 + +189 +00:12:32,553 --> 00:12:36,890 +当您添加 stream 流输出时 +可能也会指定一个处理队列 + +190 +00:12:38,825 --> 00:12:41,728 +这在您想要在特定队列中 +传送样本时会很有用 + +191 +00:12:41,762 --> 00:12:45,265 +无需额外的分发 + +192 +00:12:47,434 --> 00:12:51,038 +如果您没有指定队列 +将会使用默认队列 + +193 +00:12:54,775 --> 00:12:59,746 +stream 流已开始 输出已添加 +新样本准备好后 + +194 +00:12:59,780 --> 00:13:01,415 +ScreenCaptureKit 会提供 +一个回调函数 + +195 +00:13:02,683 --> 00:13:06,119 +现在 我给大家演示下 +如何用代码来获取媒体样本 + +196 +00:13:09,089 --> 00:13:12,793 +这是 SCStreamOutputProtocol 的实现 + +197 +00:13:12,826 --> 00:13:15,729 +在新媒体样本准备好后调用 + +198 +00:13:17,297 --> 00:13:21,068 +ScreenCaptureKit 将这些样本 +作为 CMSampleBuffers 来传送 + +199 +00:13:21,101 --> 00:13:23,837 +提供 stream 流和样本类型 + +200 +00:13:25,873 --> 00:13:31,078 +实现了样本缓冲处理程序后 +您只需要添加 stream 流输出 + +201 +00:13:32,713 --> 00:13:35,816 +这样 stream 流中的媒体样本 + +202 +00:13:35,849 --> 00:13:39,419 +有了您需要的内容和格式 + +203 +00:13:39,453 --> 00:13:41,355 +将会传送到您的 App + +204 +00:13:44,157 --> 00:13:48,128 +ScreenCaptureKit 以 +CMSampleBuffers 的形式传送样本 + +205 +00:13:48,161 --> 00:13:50,564 +那我们再来看下如何使用 + +206 +00:13:53,267 --> 00:13:57,304 +在视频方面 CMSampleBuffer +有 IOSurface 支持 + +207 +00:13:58,805 --> 00:14:00,974 +ScreenCaptureKit 也为 +SCStreamFrameInfo 中的 + +208 +00:14:01,008 --> 00:14:04,678 +CMSampleBuffer 提供附件 + +209 +00:14:06,980 --> 00:14:10,450 +附件可提供您收到的 +视频样本的信息 + +210 +00:14:12,219 --> 00:14:15,389 +检查 stream 当前状态下的 +帧状态 + +211 +00:14:15,422 --> 00:14:19,626 +complete 帧状态表示 +有一个新的视频帧 + +212 +00:14:19,660 --> 00:14:22,896 +idle 帧状态意味着 +视频样本没有改变 + +213 +00:14:22,930 --> 00:14:25,065 +所以没有新的 IOSurface + +214 +00:14:26,233 --> 00:14:30,637 +否则 所提供的样本 +与所有 CMSampleBuffer 一样 + +215 +00:14:30,671 --> 00:14:33,941 +您可以使用当前 +CMSampleBuffer 工具 + +216 +00:14:35,209 --> 00:14:39,079 +ScreenCaptureKit 的 API +可帮您获得过滤后屏幕的 + +217 +00:14:39,112 --> 00:14:40,647 +音频和视频内容 + +218 +00:14:41,481 --> 00:14:43,584 +最重要的是 该框架可提供 + +219 +00:14:43,617 --> 00:14:47,087 +许多不同的开发者控制 +从而匹配您 App 的需求 + +220 +00:14:48,455 --> 00:14:50,924 +我还讲到了一些基础知识 +能帮您开始创建 + +221 +00:14:50,958 --> 00:14:53,894 +不同的屏幕捕获体验 + +222 +00:14:56,463 --> 00:14:59,833 +有了全新推出的 ScreenCaptureKit +旧的捕获框架 + +223 +00:14:59,867 --> 00:15:04,571 +CGDisplayStream 和 CGWindowList +未来将会被弃用 + +224 +00:15:06,240 --> 00:15:08,075 +我希望大家和我一样 + +225 +00:15:08,108 --> 00:15:10,143 +对 ScreenCaptureKit 的推出 +感到激动不已 + +226 +00:15:11,845 --> 00:15:14,281 +您如果准备好了查看 +更多进阶话题 + +227 +00:15:14,314 --> 00:15:17,684 +请观看将 ScreenCaptureKit 提升到全新境界 +的相关内容 + +228 +00:15:18,785 --> 00:15:20,420 +感谢收看 + +229 +00:15:20,454 --> 00:15:22,523 +[古怪的音乐] + diff --git a/zho/2022 Session 10157 What's new in SF Symbols 4.srt b/zho/2022 Session 10157 What's new in SF Symbols 4.srt new file mode 100644 index 0000000..1c4f05f --- /dev/null +++ b/zho/2022 Session 10157 What's new in SF Symbols 4.srt @@ -0,0 +1,1283 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,943 --> 00:00:11,812 +Thalia: 大家好 我是 Thalia + +3 +00:00:11,845 --> 00:00:15,749 +今天我们将学习 SF Symbols 的新特性 + +4 +00:00:15,782 --> 00:00:20,120 +符号是最有效的图形化沟通方式之一 + +5 +00:00:20,153 --> 00:00:23,390 +如果您想要表达一种感觉 + +6 +00:00:23,423 --> 00:00:27,694 +一个物体 动作或概念 +符号是个不错的方法 + +7 +00:00:27,728 --> 00:00:30,564 +符号始终会被频繁使用 + +8 +00:00:30,597 --> 00:00:32,633 +成为我们的第二天性 + +9 +00:00:32,666 --> 00:00:35,435 +如果不依赖符号 我们就会发现 + +10 +00:00:35,469 --> 00:00:37,171 +很难驾驭周围的环境 + +11 +00:00:37,204 --> 00:00:41,441 +因此 它们成为界面设计的 +重要组成部分 + +12 +00:00:41,475 --> 00:00:45,846 +因为符号是帮助沟通的绝佳方式 + +13 +00:00:45,879 --> 00:00:50,684 +符号还可以带来诸多好处 例如可以作为交互方式 + +14 +00:00:50,717 --> 00:00:53,854 +可以节省空间 + +15 +00:00:53,887 --> 00:00:56,590 +增强审美吸引力 + +16 +00:00:56,623 --> 00:01:00,294 +以及通过用户友好来提升吸引力 + +17 +00:01:00,327 --> 00:01:04,965 +符号的伟大之处在于 +它可以超越多种语言 + +18 +00:01:04,998 --> 00:01:06,733 +它们可以是通用的 + +19 +00:01:06,767 --> 00:01:11,505 +因此 符号可以把人们团结在一起 +交流共同的思想 + +20 +00:01:11,538 --> 00:01:16,777 +帮助人们在更深的层次上接触他人 +而不仅仅是语言 + +21 +00:01:16,810 --> 00:01:20,681 +在 Apple 我们非常关心 +改善用户界面 + +22 +00:01:20,714 --> 00:01:22,816 +和整体体验 + +23 +00:01:22,850 --> 00:01:25,118 +这就是我们创建 SF Symbols 的原因 + +24 +00:01:25,152 --> 00:01:27,721 +一个庞大的图标库 + +25 +00:01:27,754 --> 00:01:32,292 +旨在与系统字体 San Francisco +无缝集成 + +26 +00:01:32,326 --> 00:01:35,796 +为在所有 Apple 平台上 +创建体验提供 + +27 +00:01:35,829 --> 00:01:39,867 +强大而灵活的设计资源 + +28 +00:01:39,900 --> 00:01:42,836 +SF Symbols 的设计考虑到了排版 + +29 +00:01:42,870 --> 00:01:47,307 +它具有很棒的功能 +例如不同的粗细 比例 轮廓 + +30 +00:01:47,341 --> 00:01:51,879 +和填充的变体 封装形状和对齐方式 + +31 +00:01:51,912 --> 00:01:55,682 +要了解更多关于这些功能的信息 +以及何时适合运用这些功能 + +32 +00:01:55,716 --> 00:02:00,687 +请查看去年 WWDC 上的视频 +让您快速了解这些功能 + +33 +00:02:00,721 --> 00:02:04,091 +今天 我们就来看看有哪些新增符号 + +34 +00:02:04,124 --> 00:02:07,261 +以及 New symbols 中的新类别 + +35 +00:02:07,294 --> 00:02:11,732 +在渲染模式中 +我们将回顾为符号添加颜色的好处 + +36 +00:02:11,765 --> 00:02:17,471 +有一个新配置 +来帮助使符号行为自动化 + +37 +00:02:17,504 --> 00:02:20,874 +有一个令人兴奋的新功能 +叫 可变颜色 + +38 +00:02:20,908 --> 00:02:25,579 +这个功能让我们可以通过颜色 +让符号更具动态性 + +39 +00:02:25,612 --> 00:02:30,150 +最后 有一种更有效的符号注释方法 + +40 +00:02:30,184 --> 00:02:33,687 +我们将在 统一注释 中 +了解更多信息 + +41 +00:02:33,720 --> 00:02:35,489 +我们开始吧 + +42 +00:02:35,522 --> 00:02:38,659 +SF Symbols 库每年都在不断增长 + +43 +00:02:38,692 --> 00:02:42,129 +有更新的类别和符号可供选择 + +44 +00:02:42,162 --> 00:02:44,331 +“家庭”当中有一些很棒的新增符号 + +45 +00:02:44,364 --> 00:02:48,869 +包括灯 百叶窗 窗户和门 + +46 +00:02:48,902 --> 00:02:52,806 +甚至还有电灯开关和电源插座 + +47 +00:02:52,840 --> 00:02:55,609 +有新的家具和电器 + +48 +00:02:55,642 --> 00:02:57,978 +新的健康符号 + +49 +00:02:58,011 --> 00:03:02,783 +今年 还有健身类的符号可供大家使用 + +50 +00:03:02,816 --> 00:03:06,153 +我们扩展了图标库中的货币符号 + +51 +00:03:06,186 --> 00:03:09,756 +有许多新对象可供选择 + +52 +00:03:09,790 --> 00:03:13,126 +当然 我们还在不断扩展本地化符号 + +53 +00:03:13,160 --> 00:03:18,699 +用新符号覆盖不同的指令 +以及从右到左的书写系统 + +54 +00:03:18,732 --> 00:03:21,835 +有 700 多个新符号可供选择 + +55 +00:03:21,869 --> 00:03:27,040 +使 SF Symbols 成为包含 +4000 个独特符号的库 + +56 +00:03:27,074 --> 00:03:28,876 +太棒了 + +57 +00:03:28,909 --> 00:03:32,513 +有了这些新功能 +我们想要帮助您浏览 + +58 +00:03:32,546 --> 00:03:34,982 +SF Symbols App 中的所有符号 + +59 +00:03:35,015 --> 00:03:39,486 +所以我们添加了五个 +我们认为是非常有用的新类别 + +60 +00:03:39,520 --> 00:03:41,989 +相机和照片 + +61 +00:03:42,022 --> 00:03:43,957 +辅助功能 + +62 +00:03:43,991 --> 00:03:46,026 +隐私和安全 + +63 +00:03:46,059 --> 00:03:49,496 +家庭和健身 + +64 +00:03:49,530 --> 00:03:53,367 +请记住 在 App 中 您始终可以选择 + +65 +00:03:53,400 --> 00:03:57,638 +最符合需求的符号 +来创建自己的符号集 + +66 +00:03:57,671 --> 00:04:02,075 +现在 我们快速回顾一下 +不同的渲染模式 + +67 +00:04:02,109 --> 00:04:04,778 +如您所知 在 SF Symbols 中 + +68 +00:04:04,811 --> 00:04:07,047 +有四种渲染模式可供选择 + +69 +00:04:07,080 --> 00:04:12,519 +每一种都能很好地控制 +如何将颜色应用到符号上 + +70 +00:04:12,553 --> 00:04:16,323 +单色是所有渲染模式中 +最中性的一种 + +71 +00:04:16,356 --> 00:04:18,825 +它呈现出统一的外观 + +72 +00:04:18,859 --> 00:04:21,428 +是最能体现 SF Symbols + +73 +00:04:21,461 --> 00:04:24,965 +排版特性的渲染方式 + +74 +00:04:24,998 --> 00:04:28,936 +分层是一种能呈现出微妙强调效果的 +渲染模式 + +75 +00:04:28,969 --> 00:04:32,606 +用单一的色调 +来提升整体美感 + +76 +00:04:32,639 --> 00:04:37,177 +我们可以通过突出符号最重要的形状 + +77 +00:04:37,211 --> 00:04:40,981 +或区分前景和背景元素来应用深度 + +78 +00:04:41,014 --> 00:04:44,618 +这样 我们通过强调符号的基本部分 + +79 +00:04:44,651 --> 00:04:48,589 +来创造一个视觉层次 + +80 +00:04:48,622 --> 00:04:52,893 +调色盘使用两种或更多对比色 + +81 +00:04:52,926 --> 00:04:54,895 +来赋予符号元素更多的 +突出性和通用性 + +82 +00:04:54,928 --> 00:04:57,598 +使符号具有更强的自定义性 + +83 +00:04:57,631 --> 00:05:01,468 +能与界面环境的配色更好地整合 + +84 +00:05:01,502 --> 00:05:05,172 +调色盘模式有助于符号在 +不牺牲整体美感的情况下 + +85 +00:05:05,205 --> 00:05:08,809 +提供对比鲜明的独特外观 + +86 +00:05:08,842 --> 00:05:12,779 +而多色模式是表示符号的固有 + +87 +00:05:12,813 --> 00:05:15,249 +或原生颜色的渲染模式 + +88 +00:05:15,282 --> 00:05:19,753 +这种渲染模式使用一系列 +可应用于符号的颜色 + +89 +00:05:19,786 --> 00:05:23,390 +来描述物理世界中物体的外观 + +90 +00:05:23,423 --> 00:05:25,692 +或者可以使用颜色 + +91 +00:05:25,726 --> 00:05:28,061 +来强调符号试图传达的含义 + +92 +00:05:28,095 --> 00:05:32,432 +当符号在 UI 中非常重要时 +您可以使用多色 + +93 +00:05:32,466 --> 00:05:38,038 +因为有助于创建与符号形式 +相关的颜色叙述 + +94 +00:05:38,071 --> 00:05:42,376 +到目前为止 +如果您没有明确指定渲染模式 + +95 +00:05:42,409 --> 00:05:44,478 +那么默认情况下将通过单色模式渲染 + +96 +00:05:44,511 --> 00:05:47,514 +但今年 我们让符号能够更容易 + +97 +00:05:47,548 --> 00:05:52,419 +以最能突出其独特特征的 +模式进行渲染 + +98 +00:05:52,452 --> 00:05:54,888 +符号现在具有首选渲染模式 + +99 +00:05:54,922 --> 00:05:57,624 +不同的符号可以具有不同的首选模式 + +100 +00:05:57,658 --> 00:06:01,495 +我们称这种行为为自动渲染 + +101 +00:06:01,528 --> 00:06:05,432 +选中后 它会为每个符号 +提供首选渲染模式配置 + +102 +00:06:05,465 --> 00:06:09,903 +而无需手动指定 + +103 +00:06:09,937 --> 00:06:12,639 +例如 当选择 自动 时 + +104 +00:06:12,673 --> 00:06:16,143 +相机滤镜符号将选择分层模式 + +105 +00:06:16,176 --> 00:06:20,514 +因为它是通过突出显示引用 + +106 +00:06:20,547 --> 00:06:23,917 +物理相机镜头和滤镜的半透明的 +不透明度 + +107 +00:06:23,951 --> 00:06:27,654 +来传达更精确的视觉呈现渲染模式 + +108 +00:06:27,688 --> 00:06:29,590 +这是另一个例子 + +109 +00:06:29,623 --> 00:06:31,692 +当选择 自动 时 + +110 +00:06:31,725 --> 00:06:36,263 +SharePlay 符号将选择分层模式 + +111 +00:06:36,296 --> 00:06:41,068 +这种样式使人的形状在前景中突出 + +112 +00:06:41,101 --> 00:06:44,838 +而波形在背景中是次要角色 + +113 +00:06:44,872 --> 00:06:48,108 +这再次强调了符号的概念 + +114 +00:06:48,141 --> 00:06:50,944 +因为 SharePlay 功能主要是 + +115 +00:06:50,978 --> 00:06:53,981 +一种与朋友和家人分享和联系的方式 + +116 +00:06:54,014 --> 00:06:57,918 +在大多数情况下 自动 是最好的选择 + +117 +00:06:57,951 --> 00:07:00,587 +但是您必须时刻注意环境 + +118 +00:07:00,621 --> 00:07:05,526 +例如 选择 自动 时 + +119 +00:07:05,559 --> 00:07:07,561 +AirPods Pro 符号将呈现为分层 + +120 +00:07:07,594 --> 00:07:10,731 +但在这种情况下 符号非常小 + +121 +00:07:10,764 --> 00:07:15,502 +在这个背景上呈现时对比度很低 + +122 +00:07:15,536 --> 00:07:19,606 +请记住 在特定环境中 + +123 +00:07:19,640 --> 00:07:24,678 +仍然可以明确指定渲染模式 +以实现符号间统一外观 + +124 +00:07:24,711 --> 00:07:28,215 +所以在这种情况下 +单色模式将是最好的选择 + +125 +00:07:28,248 --> 00:07:33,053 +因为它更易读 +并且小尺寸的细节更少 + +126 +00:07:33,086 --> 00:07:38,959 +因此 请始终确保指定 +最合适的渲染模式配置 + +127 +00:07:38,992 --> 00:07:42,529 +不同的渲染模式将颜色应用于符号 + +128 +00:07:42,563 --> 00:07:46,900 +以在各种情况下呈现视觉解决方案 + +129 +00:07:46,934 --> 00:07:51,438 +颜色是个强大的工具 +我们可以进一步探索 + +130 +00:07:51,471 --> 00:07:54,141 +有些符号在本质上更具活力 + +131 +00:07:54,174 --> 00:07:56,910 +如果我们分析它们的视觉表现 + +132 +00:07:56,944 --> 00:07:59,780 +可以注意到两个主要特征 + +133 +00:07:59,813 --> 00:08:05,385 +首先 它们的路径或形状 +传达了不同程度的强度 + +134 +00:08:05,419 --> 00:08:08,422 +其次 它们依靠颜色来传达 + +135 +00:08:08,455 --> 00:08:11,625 +随时间推移而变化的状态 + +136 +00:08:11,658 --> 00:08:14,361 +今年 我们通过引入名为 +可变颜色 的 + +137 +00:08:14,394 --> 00:08:18,432 +新功能来扩展颜色的使用 + +138 +00:08:18,465 --> 00:08:22,202 +我们将符号的矢量路径排列成层 + +139 +00:08:22,236 --> 00:08:25,606 +并按顺序组织这些层 + +140 +00:08:25,639 --> 00:08:29,576 +从而创建了一种通过这些层 +分配颜色的新方法 + +141 +00:08:29,610 --> 00:08:32,579 +这让我们能够随时间的推移 +传达不同程度的强度 + +142 +00:08:32,613 --> 00:08:34,882 +或传达序列 + +143 +00:08:34,915 --> 00:08:38,952 +这是由符号设计的本质决定的 + +144 +00:08:38,986 --> 00:08:42,256 +需要知道的一件重要的事情是 + +145 +00:08:42,289 --> 00:08:46,159 +在 可变颜色 中 +一些符号的所有路径都参与了序列 + +146 +00:08:46,193 --> 00:08:51,565 +但对于其他符号 +只有一些路径可以选择加入 + +147 +00:08:51,598 --> 00:08:54,601 +我们来看几个例子 + +148 +00:08:54,635 --> 00:08:58,772 +通过 可变颜色 +我们想让代表 iPhone 的路径 + +149 +00:08:58,805 --> 00:09:01,408 +退出变量序列 + +150 +00:09:01,441 --> 00:09:05,445 +并且我们希望突出显示 +代表无线电波的路径 + +151 +00:09:05,479 --> 00:09:09,917 +这将有助于区分描述手机 +无线电信号 + +152 +00:09:09,950 --> 00:09:12,920 +强度的不同阶段 + +153 +00:09:12,953 --> 00:09:16,924 +重要的是要知道 +我们定义了如何对路径进行分组 + +154 +00:09:16,957 --> 00:09:19,359 +例如 在这种情况下 + +155 +00:09:19,393 --> 00:09:23,030 +从左到右突出显示 +波形没有多大意义 + +156 +00:09:23,063 --> 00:09:26,767 +所以 我们可以按照最能 +传达无线电信号强度的 + +157 +00:09:26,800 --> 00:09:30,170 +顺序对路径进行分组 + +158 +00:09:30,204 --> 00:09:33,440 +两个较小的波在一层 + +159 +00:09:33,473 --> 00:09:36,743 +两个较大的波在另一层 + +160 +00:09:36,777 --> 00:09:41,915 +如前所述 手机不参与可变序列 + +161 +00:09:41,949 --> 00:09:46,486 +这一次 让我们看一个 +非常熟悉的符号 + +162 +00:09:46,520 --> 00:09:50,691 +在大多数情况下 +此符号与内置滑块配对 + +163 +00:09:50,724 --> 00:09:54,695 +该滑块与符号中表示的状态同步 + +164 +00:09:54,728 --> 00:09:57,631 +波形高亮显示它们的路径 + +165 +00:09:57,664 --> 00:10:00,434 +遵循用户控制滑块的序列 + +166 +00:10:00,467 --> 00:10:04,505 +增加或减少音量水平 + +167 +00:10:04,538 --> 00:10:06,340 +就像在 iPhone 的例子中 + +168 +00:10:06,373 --> 00:10:09,710 +有一个不参与序列的路径 + +169 +00:10:09,743 --> 00:10:12,546 +即扬声器的形状 + +170 +00:10:12,579 --> 00:10:15,883 +并且我们有参与序列的路径 + +171 +00:10:15,916 --> 00:10:19,820 +即定义音量强度的三个波 + +172 +00:10:19,853 --> 00:10:24,191 +低音量 中音量和高音量 + +173 +00:10:24,224 --> 00:10:27,027 +这些路径被组织成层 + +174 +00:10:27,060 --> 00:10:32,065 +选择的层可以选择可变颜色特性 + +175 +00:10:32,099 --> 00:10:35,936 +我们用百分比值表示它们的实力 + +176 +00:10:35,969 --> 00:10:38,105 +0% 是完全没有的 + +177 +00:10:38,138 --> 00:10:42,376 +任何高于 0% 的内容 +都会突出显示部分符号 + +178 +00:10:42,409 --> 00:10:48,582 +并且当数值接近 100% 时 +整个符号会完全突出显示 + +179 +00:10:48,615 --> 00:10:51,385 +要知道的一件重要的事情是 + +180 +00:10:51,418 --> 00:10:53,654 +可变颜色 并不是为了创造深度 + +181 +00:10:53,687 --> 00:10:58,125 +相反 它的目的是强调 +该符号可以表示的 + +182 +00:10:58,158 --> 00:11:00,561 +一系列步骤或阶段 + +183 +00:11:00,594 --> 00:11:03,497 +例如 假设我需要一个符号 + +184 +00:11:03,530 --> 00:11:06,366 +来表示房间内可容纳人数 + +185 +00:11:06,400 --> 00:11:08,969 +这个符号看起来很棒 + +186 +00:11:09,002 --> 00:11:11,638 +我们更详细地看一下 + +187 +00:11:11,672 --> 00:11:15,275 +我们不希望只突出显示符号的一部分 + +188 +00:11:15,309 --> 00:11:20,747 +相反 我们需要将符号看作 +一个序列或范围 + +189 +00:11:20,781 --> 00:11:23,283 +我的目标是涵盖不同的状态 + +190 +00:11:23,317 --> 00:11:25,352 +空房间 + +191 +00:11:25,385 --> 00:11:28,222 +房间里只有几个人 + +192 +00:11:28,255 --> 00:11:32,659 +有一半人 满屋子人 + +193 +00:11:32,693 --> 00:11:36,129 +所以现在 当我选择 可变颜色 时 + +194 +00:11:36,163 --> 00:11:38,699 +可以很容易地看到我试图传达的 + +195 +00:11:38,732 --> 00:11:41,602 +不同状态的图形表示 + +196 +00:11:41,635 --> 00:11:45,772 +可以选择进入该特性的 +路径数量没有限制 + +197 +00:11:45,806 --> 00:11:48,008 +可以只有一个 也可以有多个 + +198 +00:11:48,041 --> 00:11:52,012 +您可以决定什么是 +最适合自己需求的设计策略 + +199 +00:11:52,045 --> 00:11:56,617 +如果您想表示形状的强度级别 +这些形状遵循一个序列 + +200 +00:11:56,650 --> 00:11:59,920 +例如波形 射线 省略号和层 + +201 +00:11:59,953 --> 00:12:02,890 +可以使用 可变颜色 来实现 + +202 +00:12:02,923 --> 00:12:07,561 +可变颜色 是基于不透明度的 +它可以在所有的渲染模式下使用 + +203 +00:12:09,029 --> 00:12:14,168 +今年 我们通过在所有渲染模式中 +创建统一的层结构 + +204 +00:12:14,201 --> 00:12:18,705 +使自定义符号的注释更快 +更容易使用 + +205 +00:12:18,739 --> 00:12:21,775 +我喜欢烘焙 我正在考虑设计一个 + +206 +00:12:21,808 --> 00:12:23,977 +只包含纸杯蛋糕食谱的 App + +207 +00:12:24,011 --> 00:12:26,713 +我想创建自己的自定义符号 + +208 +00:12:26,747 --> 00:12:29,683 +所以我设计了一套 +可以满足我的需求 + +209 +00:12:29,716 --> 00:12:33,287 +这将是向大家展示如何使用 + +210 +00:12:33,320 --> 00:12:35,989 +统一层结构方法注释符号 + +211 +00:12:36,023 --> 00:12:40,194 +以及如何注释参与 +可变颜色 符号的绝佳机会 + +212 +00:12:40,227 --> 00:12:43,197 +我们以这两个为例 + +213 +00:12:43,230 --> 00:12:47,134 +在开始注释之前 +有一些事情需要考虑 + +214 +00:12:47,167 --> 00:12:52,472 +我们需要牢记层次结构 +并确保勾勒出 z-order + +215 +00:12:52,506 --> 00:12:58,545 +z-order 顺序是指符号中 +沿着 z 轴的路径顺序 + +216 +00:12:58,579 --> 00:13:02,583 +您还需要了解两个新概念 + +217 +00:13:02,616 --> 00:13:05,085 +绘制和擦除 + +218 +00:13:05,118 --> 00:13:08,989 +这些用于帮助定义层的渲染方式 + +219 +00:13:09,022 --> 00:13:12,559 +例如 这里有一个符号的路径 + +220 +00:13:12,593 --> 00:13:16,163 +代表一个正方形重叠在一个圆上 + +221 +00:13:16,196 --> 00:13:19,066 +当选择包含正方形的层时 + +222 +00:13:19,099 --> 00:13:21,068 +如果我们选择 Draw 选项 + +223 +00:13:21,101 --> 00:13:24,638 +层将绘制该层中包含的路径 + +224 +00:13:24,671 --> 00:13:26,974 +如果我们选择 Erase 选项 + +225 +00:13:27,007 --> 00:13:30,310 +将擦除包含该层的路径 + +226 +00:13:30,344 --> 00:13:33,347 +影响符号的渲染方式 + +227 +00:13:33,380 --> 00:13:36,149 +现在 我们开始给小蛋糕做注释 + +228 +00:13:36,183 --> 00:13:39,953 +作为第一步 我们需要按层组织路径 + +229 +00:13:39,987 --> 00:13:42,723 +以创建所需的层次结构 + +230 +00:13:42,756 --> 00:13:47,361 +如果我仔细分析它 +可以看到四种主要形状 + +231 +00:13:47,394 --> 00:13:50,564 +糖霜 纸杯蛋糕底座 + +232 +00:13:50,597 --> 00:13:53,033 +徽章和加号 + +233 +00:13:53,066 --> 00:13:56,403 +您可以在一个层中添加 +任意数量的路径 + +234 +00:13:56,436 --> 00:13:59,773 +所以在这种情况下 糖霜将由具有 + +235 +00:13:59,806 --> 00:14:02,476 +三个不同路径的层来定义 + +236 +00:14:02,509 --> 00:14:07,447 +其余层将由每个路径定义 + +237 +00:14:07,481 --> 00:14:12,085 +以这种方式组织形状 +让我们在为所有渲染模式 + +238 +00:14:12,119 --> 00:14:15,722 +注释结构时拥有更大的灵活性 + +239 +00:14:15,756 --> 00:14:18,892 +现在 我们将所需的所有信息 +集中在一个地方 + +240 +00:14:18,926 --> 00:14:21,428 +以便根据需要定制符号 + +241 +00:14:22,396 --> 00:14:26,166 +现在我们可以开始注释 +所有渲染模式了 + +242 +00:14:26,200 --> 00:14:28,735 +我们先看看 多色模式 + +243 +00:14:28,769 --> 00:14:31,038 +我已经设置好了形状 + +244 +00:14:31,071 --> 00:14:33,774 +所以只需要选择正确的颜色 + +245 +00:14:33,807 --> 00:14:36,210 +红丝绒是我最喜欢的口味 + +246 +00:14:36,243 --> 00:14:41,215 +所以我会选择白色的糖霜 +和红色的蛋糕底 + +247 +00:14:41,248 --> 00:14:44,818 +现在我将遵循 SF Symbols + +248 +00:14:44,852 --> 00:14:47,554 +为 多色模式 中的加号徽章 +定义的相同逻辑 + +249 +00:14:47,588 --> 00:14:50,824 +绿色代表徽章 白色代表加号 + +250 +00:14:50,858 --> 00:14:54,294 +好吧 目前为止看起来不错 + +251 +00:14:54,328 --> 00:14:56,296 +现在 我们专注于徽章 + +252 +00:14:56,330 --> 00:15:00,834 +这是统一注释方法更明显的地方 + +253 +00:15:00,868 --> 00:15:03,203 +我们已经定义了 多色模式 + +254 +00:15:03,237 --> 00:15:06,406 +现在让我们看看 分层和调色盘模式 + +255 +00:15:06,440 --> 00:15:09,843 +由于在这种渲染模式中 +使用了层次结构 + +256 +00:15:09,877 --> 00:15:12,379 +我希望徽章是首要 + +257 +00:15:12,412 --> 00:15:17,217 +将在黑色背景上将其渲染为白色 +就像他的那样 + +258 +00:15:17,251 --> 00:15:21,355 +现在我需要加号来擦除部分徽章 + +259 +00:15:21,388 --> 00:15:24,224 +这就是擦除选择有用的地方 + +260 +00:15:24,258 --> 00:15:27,394 +当层重叠时 我将能够看到 + +261 +00:15:27,427 --> 00:15:32,566 +按需要擦除形状的一部分渲染的徽章 + +262 +00:15:32,599 --> 00:15:36,170 +最后 我只需要 单色模式 注释 + +263 +00:15:36,203 --> 00:15:39,406 +因为这种渲染模式没有增加复杂度 + +264 +00:15:39,439 --> 00:15:41,308 +所以我会按照同样的逻辑 + +265 +00:15:41,341 --> 00:15:46,213 +让加号的形状擦除徽章形状的一部分 + +266 +00:15:46,246 --> 00:15:48,115 +我现在差不多完成了 + +267 +00:15:48,148 --> 00:15:50,918 +只需要一些额外的细节 + +268 +00:15:50,951 --> 00:15:53,987 +对于 分层和调色盘模式 我只需要 + +269 +00:15:54,021 --> 00:15:57,191 +将剩余的纸杯蛋糕形状标注为次要 + +270 +00:15:57,224 --> 00:16:01,528 +对于 调色盘模式 我会选择 +一种颜色来提供一些对比 + +271 +00:16:01,562 --> 00:16:04,364 +对于 单色模式 我只需要确保 + +272 +00:16:04,398 --> 00:16:07,668 +有剩余的形状选择绘制 + +273 +00:16:09,503 --> 00:16:11,038 +这就是我所需要的 + +274 +00:16:11,071 --> 00:16:14,942 +纸杯蛋糕已经准备好了 +可以定制所有渲染模式 + +275 +00:16:16,777 --> 00:16:19,213 +现在让我们看看厨房计时器 + +276 +00:16:19,246 --> 00:16:23,217 +这些路径代表了时间的流逝 +因为这是一个序列 + +277 +00:16:23,250 --> 00:16:27,221 +所以很适合加入 可变颜色 + +278 +00:16:27,254 --> 00:16:30,390 +我们可以使用相同的策略 +来注释这个符号 + +279 +00:16:30,424 --> 00:16:33,961 +但不需要将计时器路径 +分组在一个层中 + +280 +00:16:33,994 --> 00:16:37,764 +而是将它们分割成各自的层 + +281 +00:16:37,798 --> 00:16:40,367 +这是因为我们需要组织这些形状 + +282 +00:16:40,400 --> 00:16:42,703 +以便重新创造序列 + +283 +00:16:42,736 --> 00:16:47,307 +从而帮助我们传达符号的不同状态 + +284 +00:16:47,341 --> 00:16:51,745 +记住 可变颜色 +在所有渲染模式下都可以运行 + +285 +00:16:51,778 --> 00:16:55,015 +如果您想了解更多关于 +新的 可变颜色 功能 + +286 +00:16:55,048 --> 00:16:57,050 +和 SF Symbols App 的信息 + +287 +00:16:57,084 --> 00:17:02,523 +请查看 Paul 的演讲 +“Adopt Variable Color in SF Symbols” + +288 +00:17:02,556 --> 00:17:05,826 +您可以找到 +SF Symbols App 的新测试版 + +289 +00:17:05,859 --> 00:17:09,329 +在这里 您可以探究新的 +统一注释方法 + +290 +00:17:09,363 --> 00:17:13,100 +并访问数百个新符号 +和奇妙的新功能 + +291 +00:17:13,133 --> 00:17:17,671 +请查看 developer.apple.com/sf-symbols + +292 +00:17:17,704 --> 00:17:22,209 +从自动渲染行为 到 +可变颜色 动态特性 + +293 +00:17:22,242 --> 00:17:25,646 +SF Symbols 是在 UI 中实现符号时 + +294 +00:17:25,679 --> 00:17:28,682 +使用的极其强大的工具 + +295 +00:17:28,715 --> 00:17:32,486 +今年 SF Symbols 功能更加强大 + +296 +00:17:32,519 --> 00:17:36,223 +可以定义一系列的表达方式 + +297 +00:17:36,256 --> 00:17:37,891 +谢谢您今天加入我的行列 + +298 +00:17:37,925 --> 00:17:41,929 +希望您喜欢 +了解 SF Symbols 中的新功能 + diff --git a/zho/2022 Session 10159 Scale compute workloads across Apple GPUs.srt b/zho/2022 Session 10159 Scale compute workloads across Apple GPUs.srt new file mode 100644 index 0000000..5b76fb6 --- /dev/null +++ b/zho/2022 Session 10159 Scale compute workloads across Apple GPUs.srt @@ -0,0 +1,1707 @@ +1 +00:00:00,434 --> 00:00:06,440 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:11,478 +大家好 欢迎 + +3 +00:00:11,512 --> 00:00:13,413 +我是 Marco Giordano + +4 +00:00:13,447 --> 00:00:17,050 +是 Apple 的 +GPU 软件工程团队的成员 + +5 +00:00:17,084 --> 00:00:19,620 +在本期讲座中 我将给大家讲一下 + +6 +00:00:19,653 --> 00:00:23,357 +如何将工作负载分配到 +多个 Apple M1 GPU 上 + +7 +00:00:23,390 --> 00:00:26,727 +如果您从事复杂的计算工作 +想知道如何 + +8 +00:00:26,760 --> 00:00:31,031 +充分利用 Apple 芯片硬件 +并实现非常好的可扩展性 + +9 +00:00:31,064 --> 00:00:33,433 +那么这个演讲就是为您准备的 + +10 +00:00:33,467 --> 00:00:36,837 +我将首先讨论计算可扩展性的概念 + +11 +00:00:36,870 --> 00:00:42,276 +以及 App 如何自然地在 +M1 GPU 家族中扩展性能 + +12 +00:00:42,309 --> 00:00:45,846 +然后 我将一步一步地分享 +使用方法 + +13 +00:00:45,879 --> 00:00:48,782 +并讨论哪些工具可用于 + +14 +00:00:48,815 --> 00:00:52,252 +最大化您的工作负载的计算可扩展性 + +15 +00:00:52,286 --> 00:00:55,122 +让我们首先了解一下什么是可扩展性 + +16 +00:00:55,155 --> 00:00:57,991 +以及它为什么对您的工作负载很重要 + +17 +00:00:59,293 --> 00:01:02,829 +Apple M1 GPU +从开始就为可扩展而设计 + +18 +00:01:02,863 --> 00:01:08,535 +它能让您的工作负载 +在整个 SoC 家族中实现卓越的性能 + +19 +00:01:08,569 --> 00:01:13,407 +相同的 GPU +从 8 核 iPad 到 64 核 Mac Studio + +20 +00:01:13,440 --> 00:01:16,476 +都支持所有 Metal 3 功能 + +21 +00:01:17,544 --> 00:01:20,214 +为了利用高水平的可扩展性 + +22 +00:01:20,247 --> 00:01:24,551 +为 M1 优化过的 App +是一个很好的起点 + +23 +00:01:24,585 --> 00:01:29,089 +许多著名的高端 App 已经 +针对 Apple M1 进行了优化 + +24 +00:01:29,122 --> 00:01:33,260 +并在所有设备上都达到了 +出色的可扩展性 + +25 +00:01:34,962 --> 00:01:39,933 +例如 这里我们有 +Affinity Photo 和 DaVinci Resolve + +26 +00:01:39,967 --> 00:01:43,971 +后期制作行业的照片和视频编辑器 + +27 +00:01:44,004 --> 00:01:47,608 +这些 App 都达到了优秀可扩展性 + +28 +00:01:47,641 --> 00:01:53,447 +让我们来定义可扩展性的真正含义 +以及如何实现 “理想的” 可扩展性 + +29 +00:01:53,480 --> 00:01:58,385 +GPU 工作负载可扩展性 +是指通过增加 GPU 内核数量 + +30 +00:01:58,418 --> 00:02:01,555 +来提高性能的能力 + +31 +00:02:01,588 --> 00:02:04,658 +右边的图表显示了 App +随着GPU核心数的增加 + +32 +00:02:04,691 --> 00:02:07,194 +也在加速 + +33 +00:02:07,227 --> 00:02:10,964 +线性比例改进被认为是理想的 + +34 +00:02:12,232 --> 00:02:16,403 +然而 当您在做您的 App 时 +您可能会注意到一种类型的扩展 + +35 +00:02:16,436 --> 00:02:20,307 +它会进入一个平台期 +随扩展的回报逐渐减少 + +36 +00:02:20,340 --> 00:02:24,945 +或者由于 GPU 时间轴的间隙 +而根本无法扩展 + +37 +00:02:25,579 --> 00:02:29,983 +或者您可能会看到 +另一种类型的扩展 性能有所提高 + +38 +00:02:30,017 --> 00:02:32,819 +但在各阶段中并不统一 + +39 +00:02:32,853 --> 00:02:37,157 +有些地方工作负载 +会达到某些 GPU 限制 + +40 +00:02:37,191 --> 00:02:42,930 +比如这里的 24 到 32 核 +或 48 到 64 核 + +41 +00:02:44,431 --> 00:02:48,569 +您的目标是尽可能接近线性扩展 + +42 +00:02:48,602 --> 00:02:51,338 +我将向您展示识别瓶颈和实现 + +43 +00:02:51,371 --> 00:02:55,108 +您想要的结果的工具和技术 + +44 +00:02:56,276 --> 00:03:01,682 +在下个部分 我将讨论 +最大化 GPU 扩展性的方法 + +45 +00:03:01,715 --> 00:03:06,954 +对于每个工作负载 +首先应该确定瓶颈在哪里 + +46 +00:03:06,987 --> 00:03:11,225 +工作负载会受限于计算或带宽 + +47 +00:03:11,258 --> 00:03:14,027 +在优化过程中 + +48 +00:03:14,061 --> 00:03:16,930 +您可能会在两者之间来回切换 + +49 +00:03:16,964 --> 00:03:21,635 +如果您有受限于算力 +您可以尝试转移一些负载 + +50 +00:03:21,668 --> 00:03:26,039 +利用内存来减少计算 反之亦然 + +51 +00:03:26,073 --> 00:03:29,576 +当您扩充时 瓶颈可能会发生变化 + +52 +00:03:29,610 --> 00:03:32,379 +一个好的解决方案是 +使用像 MPS 或 MPSGraph + +53 +00:03:32,412 --> 00:03:34,982 +这样的 Apple 框架 + +54 +00:03:35,015 --> 00:03:37,184 +如果可以利用它们的原语 + +55 +00:03:37,217 --> 00:03:41,522 +我们就可以确保每个计算内核 +在所有硬件上都能运行得最好 + +56 +00:03:41,555 --> 00:03:44,725 +然而 您不能用 MPS 替换一切 + +57 +00:03:44,758 --> 00:03:48,529 +所以配置并理解您的工作负载 +至关重要 + +58 +00:03:50,297 --> 00:03:51,164 +我将首先介绍三个 +可以帮助最小化 GPU 间隙的事项 + +59 +00:03:54,868 --> 00:03:58,839 +改进工作分配 消除 GPU 时间轴间隙 + +60 +00:03:58,872 --> 00:04:01,508 +以及对原子操作的考虑 + +61 +00:04:02,476 --> 00:04:06,613 +然后 我将解释 +如何优化 GPU 限制 + +62 +00:04:06,647 --> 00:04:10,951 +首先调研工作负载的计算网格尺寸 + +63 +00:04:10,984 --> 00:04:13,387 +和内存布局的影响 + +64 +00:04:13,420 --> 00:04:18,892 +然后研究 Blender Cycles 中的 +一个特定示例 + +65 +00:04:18,926 --> 00:04:22,362 +首先专注于最小化 GPU 间隙 + +66 +00:04:22,396 --> 00:04:26,967 +这种扩展可能是 +GPU 没有被充分利用的结果 + +67 +00:04:27,000 --> 00:04:30,070 +GPU 时间轴上 +存在硬件空闲间隙 + +68 +00:04:32,139 --> 00:04:35,976 +让我们看看是否可以通过 +研究任务分布来改善可扩展性 + +69 +00:04:37,544 --> 00:04:41,715 +小的工作负载 +通常不会使整个 GPU 饱和 + +70 +00:04:41,748 --> 00:04:44,418 +而且内核同步也有一定的成本 + +71 +00:04:44,451 --> 00:04:47,955 +因此两者都可能妨碍适当的扩展性 + +72 +00:04:47,988 --> 00:04:53,093 +理解工作负载如何映射到硬件 +是非常重要的 + +73 +00:04:53,126 --> 00:04:54,928 +所以我们来讨论一下这一点 + +74 +00:04:55,696 --> 00:05:00,267 +工作负载以线程组 +3D 网格的形式分派 + +75 +00:05:00,300 --> 00:05:04,137 +线程组被均匀地分布到 +GPU 核心中 + +76 +00:05:04,171 --> 00:05:08,976 +并且可以访问GPU内核本地 +大小有限 但是非常快速的 + +77 +00:05:09,009 --> 00:05:11,945 +线程组内存 + +78 +00:05:12,913 --> 00:05:16,783 +单个线程组被进一步 +分解为 SIMD 组 + +79 +00:05:16,817 --> 00:05:21,088 +在不同的计算词汇中 +也称为 wave 或 warp + +80 +00:05:21,989 --> 00:05:26,059 +在计算管道状态对象上检查 +“threadExecutionWidth” + +81 +00:05:26,093 --> 00:05:28,161 +将返回 SIMD 并行宽度 + +82 +00:05:28,195 --> 00:05:31,765 +在所有 Apple GPU 上 +它都等于 32 + +83 +00:05:33,033 --> 00:05:37,337 +每个线程组最多可以 +有 1024 个线程 + +84 +00:05:37,371 --> 00:05:41,575 +线程可以共享最多 32K 的 +线程组内存 + +85 +00:05:42,876 --> 00:05:45,679 +为了保持 GPU 忙碌 +所有 GPU 核心 + +86 +00:05:45,712 --> 00:05:47,347 +都应该有足够的工作要做 + +87 +00:05:48,749 --> 00:05:51,618 +下面是一个要分派的网格的示例 + +88 +00:05:51,652 --> 00:05:54,555 +线程组会被分配到 GPU 集群中 + +89 +00:05:54,588 --> 00:05:58,091 +并分散到 GPU 核心中 + +90 +00:05:59,159 --> 00:06:01,228 +如果线程组太少 + +91 +00:06:01,261 --> 00:06:04,565 +工作负载就不会使机器完全饱和 + +92 +00:06:04,598 --> 00:06:06,033 +下面是解决这个问题的方法 + +93 +00:06:08,101 --> 00:06:11,438 +首先计算工作负载会产生多少线程 + +94 +00:06:11,471 --> 00:06:15,475 +大致查看分派是否会 +使整个机器饱和 + +95 +00:06:16,410 --> 00:06:22,082 +对于相对复杂的内核 +每着色器核心有 1K 到 2K 并发线程 + +96 +00:06:22,115 --> 00:06:24,651 +被认为是非常好的占用情况 + +97 +00:06:24,685 --> 00:06:30,591 +所以每个 GPU 核 +1 到 2K 线程是一个经验法则 + +98 +00:06:30,624 --> 00:06:35,596 +现在 如果有足够的工作 +使硬件完全饱和 就可以进行计算了 + +99 +00:06:35,629 --> 00:06:39,032 +这里的表显示了 +使不同 SoC 饱和的 + +100 +00:06:39,066 --> 00:06:41,301 +最低推荐线程数 + +101 +00:06:43,670 --> 00:06:45,739 +另一件需要考虑的事 +是避免使用不必要的 + +102 +00:06:45,772 --> 00:06:48,909 +大线程组尺寸 + +103 +00:06:48,942 --> 00:06:54,481 +更小的线程组可以更均匀地 +将负载映射到硬件 + +104 +00:06:54,515 --> 00:06:58,752 +使用更大的线程组可能会 +阻止更均匀的分布 + +105 +00:06:58,785 --> 00:07:01,588 +导致 GPU 核心不平衡 + +106 +00:07:02,890 --> 00:07:05,926 +最好使用能够很好地 +映射到工作负载的 + +107 +00:07:05,959 --> 00:07:07,995 +SIMD 宽度的最小倍数 + +108 +00:07:08,629 --> 00:07:12,165 +通过使用更小的线程组 +GPU 有更多的机会 + +109 +00:07:12,199 --> 00:07:14,668 +更好地平衡其工作负载 + +110 +00:07:16,170 --> 00:07:19,039 +请经常使用 Xcode +或 Instruments GPU 工具 + +111 +00:07:19,072 --> 00:07:21,942 +检查您的内核运行时性能 + +112 +00:07:23,443 --> 00:07:28,882 +例如 在这个 GPU 捕获中 +有一个内核在执行一些计算 + +113 +00:07:28,916 --> 00:07:32,653 +占用率很低 这是意料之外的 + +114 +00:07:32,686 --> 00:07:36,089 +编译器统计数据显示 +最大理论占用率是100% + +115 +00:07:36,123 --> 00:07:40,060 +这是 Xcode 14 中的新数据 + +116 +00:07:40,093 --> 00:07:43,997 +这表明可能没有足够的线程 实际上 + +117 +00:07:44,031 --> 00:07:48,569 +我们可以看到 +算法开始分派越来越少的线程 + +118 +00:07:48,602 --> 00:07:50,604 +不再使机器饱和 + +119 +00:07:51,805 --> 00:07:54,975 +占用率低可能还有其他几个原因 + +120 +00:07:55,008 --> 00:08:01,014 +要了解所有细节 请查看演讲 +Metal Compute on MacBook Pro Tech talk + +121 +00:08:01,849 --> 00:08:05,152 +好了 现在工作负载已经正确分配 + +122 +00:08:05,185 --> 00:08:08,655 +是时候确保 GPU 一直忙碌了 + +123 +00:08:09,957 --> 00:08:13,393 +低利用率的 GPU +永远不会带来理想的扩展性 + +124 +00:08:13,427 --> 00:08:18,131 +最糟糕的情况是让 GPU 闲置 + +125 +00:08:18,165 --> 00:08:21,768 +GPU 时间轴间隙 +会导致 GPU 空闲 + +126 +00:08:23,971 --> 00:08:26,807 +考虑一下这个例子 + +127 +00:08:26,840 --> 00:08:30,110 +这是一个因为 CPU +和 GPU 之间的工作序列化 + +128 +00:08:30,143 --> 00:08:34,248 +导致只使用了 50% GPU 的工作负载 + +129 +00:08:34,281 --> 00:08:39,152 +在这种情况下 +总的任务时间是 CPU 和 GPU + +130 +00:08:39,186 --> 00:08:41,455 +无重叠的工作总和 + +131 +00:08:42,489 --> 00:08:46,727 +GPU 核数加倍会使 +GPU 轨迹完成速度更快 + +132 +00:08:46,760 --> 00:08:49,796 +但 CPU 轨迹不会受影响 + +133 +00:08:49,830 --> 00:08:56,103 +整体性能只提高了 33% +与理想的扩展性相差甚远 + +134 +00:08:57,237 --> 00:09:02,676 +如果 GPU 核心再次翻倍 +GPU 上的工作负载甚至会更快 + +135 +00:09:02,709 --> 00:09:08,315 +但总体延迟只比原来减少了 60% + +136 +00:09:08,348 --> 00:09:13,053 +因此在这种情况下 +GPU 核心的扩展带来的回报被抵消 + +137 +00:09:13,086 --> 00:09:16,089 +这远非理想 让我们解决它吧 + +138 +00:09:17,858 --> 00:09:23,397 +M1 Pro 的 Instrument trace 显示了 +很大的 GPU 时间间隔 + +139 +00:09:23,430 --> 00:09:26,667 +这明显将阻止适当的扩展 + +140 +00:09:28,035 --> 00:09:31,738 +在 M1 Ultra 上 相同的工作负载 +确实更快一些 + +141 +00:09:31,772 --> 00:09:34,441 +但 GPU 空闲时间变长了 + +142 +00:09:34,474 --> 00:09:38,278 +工作负载不能很好地扩展 + +143 +00:09:38,312 --> 00:09:41,348 +大间隙是因为 CPU 在命令缓冲区上 + +144 +00:09:41,381 --> 00:09:44,651 +使用 waitUntilCompleted 同步引起的 + +145 +00:09:45,552 --> 00:09:49,189 +在改变了等待逻辑 +并移除序列化之后 + +146 +00:09:49,223 --> 00:09:53,327 +GPU 得到了充分的利用 +这是非常棒的 + +147 +00:09:54,661 --> 00:09:56,029 +比较工作负载 + +148 +00:09:56,063 --> 00:09:57,030 +扩展前后的情况 + +149 +00:09:57,064 --> 00:09:58,765 +我们可以得出结论 + +150 +00:09:58,799 --> 00:10:01,635 +扩展性已经更加接近理想状态了 + +151 +00:10:03,403 --> 00:10:06,773 +在前面的例子中 +完全移除 CPU/GPU 同步 + +152 +00:10:06,807 --> 00:10:09,810 +是可能的 + +153 +00:10:09,843 --> 00:10:15,482 +但由于您的 App 的性质 +这并非总是如此 + +154 +00:10:15,516 --> 00:10:20,587 +还有其他方法可以减少空闲时间 + +155 +00:10:20,621 --> 00:10:23,724 +使用 MTLSharedEvents 来通知 CPU + +156 +00:10:23,757 --> 00:10:27,961 +输送更多的工作 +考虑使用 GPU 驱动的编码 + +157 +00:10:27,995 --> 00:10:30,497 +并使用并发调度 + +158 +00:10:30,531 --> 00:10:35,335 +所以让我们来讨论一下 +那些最小化 GPU 时间间隔的方法 + +159 +00:10:35,369 --> 00:10:37,905 +它们中的一些可能适合您的工作流程 + +160 +00:10:39,139 --> 00:10:44,378 +等待 CPU 完成 GPU +会导致扩展性不理想 + +161 +00:10:44,411 --> 00:10:46,947 +如果您的 App +正在使用 WaitUntilCompleted + +162 +00:10:46,980 --> 00:10:50,584 +您可能会想尝试 +使用 MTLSharedEvents 代替 + +163 +00:10:51,919 --> 00:10:54,555 +MTLSharedEvent 具有较低的开销 + +164 +00:10:54,588 --> 00:10:57,724 +可以帮助您减少时间间隔 + +165 +00:10:57,758 --> 00:10:58,959 +接下来要考虑的事情是 + +166 +00:10:58,992 --> 00:11:01,228 +工作负载管线化 + +167 +00:11:02,329 --> 00:11:04,498 +如果算法拥有下一批处理 + +168 +00:11:04,531 --> 00:11:06,633 +所需的数据 + +169 +00:11:06,667 --> 00:11:09,937 +那么在等待 MTLSharedEvent 之前 +就可以提前 + +170 +00:11:09,970 --> 00:11:12,973 +对一批或多批进行编码 + +171 +00:11:13,006 --> 00:11:15,843 +通过这样做 GPU 就不会无事可做 + +172 +00:11:15,876 --> 00:11:18,312 +并且总是有工作要处理 + +173 +00:11:19,713 --> 00:11:23,116 +如果工作不能在同一个队列上 +提前编码 + +174 +00:11:23,150 --> 00:11:26,787 +那么可以考虑使用第二个队列 +来重叠工作 + +175 +00:11:26,820 --> 00:11:30,424 +使用多个队列会允许您 +提交独立的工作 + +176 +00:11:30,457 --> 00:11:33,026 +并且不会在等待事件时 + +177 +00:11:33,060 --> 00:11:35,462 +使其他提交线程暂停 + +178 +00:11:35,495 --> 00:11:40,067 +这样 GPU 就有机会 +继续接收和处理工作 + +179 +00:11:41,602 --> 00:11:46,807 +在某些情况下 算法可以 +直接从 GPU 编码工作 + +180 +00:11:47,841 --> 00:11:49,576 +使用间接命令缓冲区 + +181 +00:11:49,610 --> 00:11:53,380 +可以将下一批编码 +直接转移到 GPU 上 + +182 +00:11:53,413 --> 00:11:56,416 +避免了同步的需求 + +183 +00:11:56,450 --> 00:12:00,153 +要了解更多 +关于间接命令缓冲区的细节 + +184 +00:12:00,187 --> 00:12:02,456 +请查看 “Modern Rendering with Metal” + +185 +00:12:02,489 --> 00:12:06,527 +该工作负载现在消除或尽可能减少了 + +186 +00:12:06,560 --> 00:12:09,763 +CPU 和 GPU 之间高代价的同步 + +187 +00:12:09,796 --> 00:12:15,035 +但即使 GPU 时间线很繁忙 +扩展挑战也仍然存在 + +188 +00:12:15,068 --> 00:12:17,137 +让我们来看看 + +189 +00:12:17,171 --> 00:12:19,973 +这个图来自图像处理工作负载 + +190 +00:12:20,007 --> 00:12:23,744 +在这里 每次处理 1 帧图像 + +191 +00:12:23,777 --> 00:12:28,982 +大量的连续计算串行调度 +也会限制扩展性 + +192 +00:12:29,016 --> 00:12:31,718 +GPU 很忙 但是内核同步 + +193 +00:12:31,752 --> 00:12:36,223 +是有成本的 +此外 每次分派都会有一个小的增量 + +194 +00:12:36,256 --> 00:12:38,392 +用于在还未饱和的内核上 + +195 +00:12:38,425 --> 00:12:41,361 +继续分配线程组 + +196 +00:12:41,395 --> 00:12:45,032 +同样地 当线程组完成并停用时 + +197 +00:12:45,065 --> 00:12:49,303 +可能会没有足够的工作 +使核心完全饱和 + +198 +00:12:49,336 --> 00:12:54,174 +在这种情况下 建议 +尽可能使独立的工作互相重叠 + +199 +00:12:54,208 --> 00:12:56,810 +让我们来看一个直观的例子 + +200 +00:12:56,844 --> 00:13:00,747 +我们有一个工作负载 +在一个接一个地处理两个图像 + +201 +00:13:00,781 --> 00:13:04,017 +正常情况下 内核之间需要进行同步 + +202 +00:13:04,051 --> 00:13:07,688 +然而 这并不是安排工作的唯一方法 + +203 +00:13:07,721 --> 00:13:13,327 +您可以使用并发分派 +使两个图像的独立工作互相交错 + +204 +00:13:13,360 --> 00:13:16,730 +在这里 由于并发调度 + +205 +00:13:16,763 --> 00:13:19,299 +驱动程序能够交错不同的工作 + +206 +00:13:19,333 --> 00:13:22,402 +我们可以看到 +以前连续的两个内核 + +207 +00:13:22,436 --> 00:13:27,140 +现在被独立的工作分开了 + +208 +00:13:27,174 --> 00:13:30,644 +但是 当您使用 +MTLDispatchTypeConcurrent 时 + +209 +00:13:30,677 --> 00:13:33,780 +必须手动设置障碍 + +210 +00:13:33,814 --> 00:13:38,118 +并发分派使驱动程序 +能够更紧密地打包工作 + +211 +00:13:38,151 --> 00:13:42,222 +隐藏依赖内核之间的 +大部分同步成本 + +212 +00:13:42,256 --> 00:13:47,427 +并衔接了不同内核的起始增量和结束 + +213 +00:13:47,461 --> 00:13:50,764 +这种优化大大提高了 +从 M1 Max + +214 +00:13:50,797 --> 00:13:55,402 +到 M1 Ultra 的 +工作负载性能和扩展性 + +215 +00:13:55,435 --> 00:13:59,506 +与之前的扩展性相比 两个图像交错时 +工作负载运行速度提高了 30% + +216 +00:13:59,540 --> 00:14:04,811 +3 个图像并行时 +运行速度提高了 70% + +217 +00:14:07,014 --> 00:14:11,652 +仔细考虑内核正在执行的 +原子操作很重要 + +218 +00:14:11,685 --> 00:14:15,422 +让我们确保它以最有效的方式使用 + +219 +00:14:15,455 --> 00:14:19,126 +原子操作允许以安全的方式 + +220 +00:14:19,159 --> 00:14:22,229 +从多个线程读取和写入数据 + +221 +00:14:22,262 --> 00:14:26,333 +全局原子在整个 GPU 中是一致的 + +222 +00:14:26,366 --> 00:14:29,937 +当许多线程试图读写相同的全局值时 + +223 +00:14:29,970 --> 00:14:32,472 +这会导致争用 + +224 +00:14:32,506 --> 00:14:38,445 +增加 GPU 核心的数量不能改变它 +实际上还会导致更多的竞争 + +225 +00:14:38,478 --> 00:14:41,682 +让我们通过一个例子 +来研究如何改进算法中的 + +226 +00:14:41,715 --> 00:14:44,051 +原子行为 + +227 +00:14:45,719 --> 00:14:49,356 +这是一个归约算法 +会将缓冲区中的 + +228 +00:14:49,389 --> 00:14:51,792 +所有值都加起来 + +229 +00:14:51,825 --> 00:14:54,928 +最简单的方法是在主内存中 +为每个线程 + +230 +00:14:54,962 --> 00:14:57,464 +执行一个原子加操作 + +231 +00:14:57,497 --> 00:15:02,603 +但是 这并不理想 因为这会 +给主内存中的单个值带来很大的压力 + +232 +00:15:02,636 --> 00:15:08,008 +直接导致每个内存写入操作的序列化 + +233 +00:15:09,376 --> 00:15:11,945 +硬件提供了两个方式来帮助处理 + +234 +00:15:11,979 --> 00:15:14,381 +原子内存竞争 + +235 +00:15:14,414 --> 00:15:16,950 +SIMD 组指令和线程组原子 + +236 +00:15:18,585 --> 00:15:24,291 +prefix_exclusive sum 和 simd_min 等 +SIMD 指令 + +237 +00:15:24,324 --> 00:15:28,161 +允许在 SIMD 组之间通过寄存器 +进行操作和交换内存 + +238 +00:15:28,195 --> 00:15:31,932 +而不需要往返于内存 + +239 +00:15:31,965 --> 00:15:35,769 +线程组原子由线程组内存完成 + +240 +00:15:35,802 --> 00:15:38,839 +每个 GPU 核心都有自己的 +线程组内存 + +241 +00:15:38,872 --> 00:15:42,476 +使得可以按照 GPU 核的数量进行扩展 + +242 +00:15:42,509 --> 00:15:46,847 +让我们看看这两个特性 +能如何帮助您改善工作负载 + +243 +00:15:48,549 --> 00:15:50,617 +这里我们有同样的归约问题 + +244 +00:15:50,651 --> 00:15:54,321 +但是这次它开始使用一个 +SIMD 组指令 + +245 +00:15:54,354 --> 00:15:56,390 +一个包含内存求和 + +246 +00:15:56,423 --> 00:16:01,094 +这样的操作将把 SIMD 组中 +所有数字的总和 + +247 +00:16:01,128 --> 00:16:03,664 +留在最后一个线程中 + +248 +00:16:03,697 --> 00:16:08,001 +然后 每个 simd 组中的 +最后一个线程可以在线程组内存中 + +249 +00:16:08,035 --> 00:16:12,739 +执行单个原子加操作 +将所有 simd 组归约到 + +250 +00:16:12,773 --> 00:16:14,908 +线程组内存中的单个值 + +251 +00:16:14,942 --> 00:16:19,246 +通过这种方式 +使用 SIMD 组指令和线程组内存 + +252 +00:16:19,279 --> 00:16:24,484 +在完全不使用主内存的情况下 +完成了整个线程组的归约 + +253 +00:16:24,518 --> 00:16:28,488 +每一组将能够独立并行归约 + +254 +00:16:29,823 --> 00:16:32,926 +现在每个线程组已经归约到一个值 + +255 +00:16:32,960 --> 00:16:35,229 +每个线程组可以在主内存中 + +256 +00:16:35,262 --> 00:16:37,898 +执行一个原子 + +257 +00:16:37,931 --> 00:16:39,666 +这不仅使每个线程组 + +258 +00:16:39,700 --> 00:16:41,201 +只需要一个原子 + +259 +00:16:41,235 --> 00:16:43,136 +而且由于线程组 + +260 +00:16:43,170 --> 00:16:44,771 +在不同的时间完成 + +261 +00:16:44,805 --> 00:16:47,107 +它会随着时间的推移分散原子 + +262 +00:16:47,140 --> 00:16:50,677 +从而进一步减少内存争用 + +263 +00:16:50,711 --> 00:16:54,114 +总结一下 +要最大限度地提高原子的效率 + +264 +00:16:54,147 --> 00:16:59,119 +请尝试利用内存局部性 +尝试使用 SIMD 组操作 + +265 +00:16:59,152 --> 00:17:02,756 +以及利用线程组内存原子 + +266 +00:17:02,789 --> 00:17:07,628 +所有这些都将极大程度 +帮助减少妨碍扩展性的原子操作压力 + +267 +00:17:08,829 --> 00:17:15,035 +现在 GPU 间隙已经修复 +是时候看看扩展性是否更接近理想了 + +268 +00:17:15,068 --> 00:17:19,706 +Xcode 和 Metal System Trace 中的 +GPU 限制器 + +269 +00:17:19,740 --> 00:17:25,179 +有助于优化 GPU 核心 +执行管道中的瓶颈和低效 + +270 +00:17:25,212 --> 00:17:28,382 +例如 低效的内存访问模式 + +271 +00:17:28,415 --> 00:17:33,020 +总是导致末级缓存 +或 Memory Management Unit + +272 +00:17:33,053 --> 00:17:36,723 +也就是 MMU 限制很高 +而利用率则很低 + +273 +00:17:36,757 --> 00:17:43,497 +首先要解决的是调整线程组 +和内存布局方法 + +274 +00:17:43,530 --> 00:17:46,200 +减少内存跨度和发散的关键 + +275 +00:17:46,233 --> 00:17:50,537 +是要清楚地理解 +工作负载内存访问模式 + +276 +00:17:50,571 --> 00:17:54,007 +包括空间和时间上的模式 + +277 +00:17:54,041 --> 00:17:58,312 +一旦理解了这一点 +就有两种可能的调整方向 + +278 +00:17:58,345 --> 00:18:01,915 +重新组织数据布局 +以提高数据访问局部性 + +279 +00:18:01,949 --> 00:18:05,953 +或者调整访问模式 +以更好地匹配数据布局 + +280 +00:18:05,986 --> 00:18:09,056 +并提高内存和缓存局部性 + +281 +00:18:09,089 --> 00:18:10,490 +让我们来看一个例子 + +282 +00:18:12,659 --> 00:18:16,663 +这有一个内存缓冲区 +数据是横向排列的 + +283 +00:18:16,697 --> 00:18:18,732 +一行接着一行 + +284 +00:18:18,765 --> 00:18:21,802 +然而 当调度计算内核时 + +285 +00:18:21,835 --> 00:18:24,404 +通常会有一个类似 2D 的模式 + +286 +00:18:24,438 --> 00:18:27,374 +其中分布着方形的线程组 + +287 +00:18:27,407 --> 00:18:29,843 +这在很大程度上是空间局部化的 + +288 +00:18:29,877 --> 00:18:34,414 +这种访问模式和数据布局 +对于数据局部性来说不是很合适 + +289 +00:18:36,216 --> 00:18:39,653 +例如 当第一个 SIMD 组访问数据时 + +290 +00:18:39,686 --> 00:18:42,322 +请求被打包在缓存线中 + +291 +00:18:42,356 --> 00:18:44,992 +大部分缓存线不会被使用 + +292 +00:18:45,025 --> 00:18:50,063 +但是仍然会占用缓存空间 + +293 +00:18:50,097 --> 00:18:53,100 +要重新排列数据 +以更好地适应访问模式 + +294 +00:18:53,133 --> 00:18:56,837 +例如 它不跨越整行 + +295 +00:18:56,870 --> 00:18:59,940 +而是被局部化为条带 + +296 +00:19:01,008 --> 00:19:04,144 +使用这种新的内存布局 +线程组将能够利用 + +297 +00:19:04,178 --> 00:19:07,080 +在缓存线中请求的大部分数据 + +298 +00:19:07,114 --> 00:19:11,585 +从而减少分化并提高缓存效率 + +299 +00:19:12,586 --> 00:19:16,089 +另一种选择是改变 +3D 网格的分配方式 + +300 +00:19:16,123 --> 00:19:19,126 +以更好地适应当前的数据布局 + +301 +00:19:19,159 --> 00:19:23,664 +尝试调整线程组的大小 +来创建能更好地映射到内存布局的组 + +302 +00:19:23,697 --> 00:19:27,768 +例如 一个更偏向矩形的 + +303 +00:19:27,801 --> 00:19:29,670 +形状 + +304 +00:19:29,703 --> 00:19:33,440 +在这种情况下 +访问模式与内存布局保持一致 + +305 +00:19:33,473 --> 00:19:36,977 +从而提供了更高的缓存效率 + +306 +00:19:37,010 --> 00:19:41,415 +您可能需要尝试找到 +最适合您的工作负载的方法 + +307 +00:19:41,448 --> 00:19:44,418 +有时 您可能需要做出权衡 + +308 +00:19:44,451 --> 00:19:49,756 +牺牲线程发散性来换取内存位置 +或者反过来 + +309 +00:19:49,790 --> 00:19:54,661 +更改数据布局 网格分派 +或它们的组合 + +310 +00:19:54,695 --> 00:19:57,631 +每个工作负载和访问模式都是不相同 + +311 +00:20:00,100 --> 00:20:03,270 +现在您已经了解了 +改善内存位置的方法 + +312 +00:20:03,303 --> 00:20:06,273 +让我们看看 Blender Cycles 中 +更具体的例子 + +313 +00:20:08,408 --> 00:20:13,680 +Cycles 是 Blender 用于 +产品渲染的基于物理的路径追踪器 + +314 +00:20:13,714 --> 00:20:17,885 +它旨在为生产需要 +提供开箱即用的具有艺术控制 + +315 +00:20:17,918 --> 00:20:22,422 +和灵活的着色节点的基于物理的结果 + +316 +00:20:24,258 --> 00:20:30,230 +这个 Instrument trace 清楚地显示了 +低读带宽 高最高 GPU 限制器 + +317 +00:20:30,264 --> 00:20:34,368 +高缓存限制器 +和低末级缓存利用率 + +318 +00:20:36,170 --> 00:20:41,975 +把握带宽和 MMU 限制器 +对于扩展性是很重要的 + +319 +00:20:42,009 --> 00:20:45,679 +如果您的最高限制器 +是末级缓存或 MMU + +320 +00:20:45,712 --> 00:20:50,551 +您就需要减少您的内存跨度 +并最大化数据局部性 + +321 +00:20:50,584 --> 00:20:52,152 +让我们看一个例子 + +322 +00:20:53,887 --> 00:20:57,958 +Cycle 使用数据排序来减少分化 + +323 +00:20:57,991 --> 00:21:01,762 +它通过按材质类型 +对光线碰撞进行分类来实现这点 + +324 +00:21:01,795 --> 00:21:04,131 +这利于减少线程分化 + +325 +00:21:04,164 --> 00:21:07,401 +但是它增加了空间内存分化 + +326 +00:21:07,434 --> 00:21:11,004 +导致了高 MMU 限制器 + +327 +00:21:11,038 --> 00:21:14,641 +为了解决这一点 我们尝试了 +在排序之前对内存范围进行分区 + +328 +00:21:14,675 --> 00:21:17,711 +以增加数据的局部性 + +329 +00:21:17,744 --> 00:21:18,579 +让我们设想一下 + +330 +00:21:18,612 --> 00:21:24,051 +当光线被射入场景以模拟光的传播时 + +331 +00:21:24,084 --> 00:21:28,055 +它们会击中物体 +而数据则被收集到缓冲区中 + +332 +00:21:28,088 --> 00:21:30,958 +在交点上 我们能知道很多东西 + +333 +00:21:30,991 --> 00:21:34,728 +被击中的材料类型 +比如玻璃 金属等等 + +334 +00:21:34,761 --> 00:21:39,099 +交点的位置 光线等等 + +335 +00:21:39,132 --> 00:21:43,303 +为了简单起见 我们只关注材料类型 + +336 +00:21:43,337 --> 00:21:45,906 +这是内存缓冲区中的材料 + +337 +00:21:47,341 --> 00:21:49,910 +由于每次射线命中都会收集大量数据 + +338 +00:21:49,943 --> 00:21:53,380 +内存缓冲区可能会变得相当大 + +339 +00:21:53,413 --> 00:21:55,616 +为了避免移动大量内存 + +340 +00:21:55,649 --> 00:22:00,521 +要填充索引列表并对其进行排序 + +341 +00:22:00,554 --> 00:22:03,957 +在排序之后 相同材料类型的索引 + +342 +00:22:03,991 --> 00:22:06,560 +现在被包装在了一起 + +343 +00:22:06,593 --> 00:22:11,932 +SIMD 组可以开始 +加载索引并处理材料了 + +344 +00:22:11,965 --> 00:22:15,269 +SIMD 组将使用索引 + +345 +00:22:15,302 --> 00:22:16,837 +加载原始缓冲区中的相应数据 + +346 +00:22:18,472 --> 00:22:22,576 +但是 simd 组 +将在整个内存范围内读取数据 + +347 +00:22:22,609 --> 00:22:25,279 +这会给 MMU 带来了压力 + +348 +00:22:25,312 --> 00:22:27,981 +让我们来研究一下新方法 + +349 +00:22:28,015 --> 00:22:31,985 +内存范围被划分在一个理想的分区中 + +350 +00:22:32,019 --> 00:22:36,390 +这个分区不允许混合 +来自不同分区的索引 + +351 +00:22:36,423 --> 00:22:41,962 +在排序时 很明显 +访问的数据范围被限制在分区中 + +352 +00:22:41,995 --> 00:22:46,733 +而不是像以前那样 +跨越整个内存范围 + +353 +00:22:46,767 --> 00:22:52,739 +这是线程分化 +和内存分化之间的权衡和平衡 + +354 +00:22:52,773 --> 00:22:55,609 +理想的分区数量和大小 + +355 +00:22:55,642 --> 00:22:58,078 +高度依赖于工作负载 + +356 +00:22:58,111 --> 00:23:02,216 +您可能需要进行实验 +看看哪种方法效果最好 + +357 +00:23:02,249 --> 00:23:07,421 +让我们以另一个 metal system trace 为例 +看看工作负载是否有所改善 + +358 +00:23:07,454 --> 00:23:11,124 +在这里 我们看到了优化版本的 +限制条件和使用情况 + +359 +00:23:11,158 --> 00:23:17,364 +最高性能限制器下降了 +末级缓存限制器也下降了 + +360 +00:23:17,397 --> 00:23:22,436 +因此 带宽和着色器运行时间 +有了显著改善 + +361 +00:23:22,469 --> 00:23:24,137 +让我们看看改进了多少 + +362 +00:23:24,171 --> 00:23:28,976 +最高限制器和 LLC 限制器 +减少了约 20% + +363 +00:23:29,009 --> 00:23:32,145 +这意味着数据流更加高效 + +364 +00:23:32,179 --> 00:23:35,215 +GPU 读取带宽显著增加 + +365 +00:23:35,249 --> 00:23:38,652 +允许更多数据推送到 GPU 核心 + +366 +00:23:39,987 --> 00:23:43,557 +总的来说 在这个实验中 +增加内存局部性 + +367 +00:23:43,590 --> 00:23:48,896 +可以提高 10% 到 30% 的性能 +具体是多少取决于实际情况 + +368 +00:23:48,929 --> 00:23:54,034 +这只是许多 +改进内存访问模式方法中的一个例子 + +369 +00:23:54,067 --> 00:23:58,472 +请不断试验 +优化最高性能限制器 + +370 +00:23:58,505 --> 00:24:02,476 +GPU 工具有更多 +有用的计数器帮助优化 + +371 +00:24:03,677 --> 00:24:08,916 +Xcode 在编译器统计窗口中 +提供了一个新的理论占用率 + +372 +00:24:08,949 --> 00:24:15,556 +Xcode 和 Instruments 现在都有 +几个 MMU 相关限制器和计数器 + +373 +00:24:15,589 --> 00:24:20,060 +特别是新 MMU 限制器 +MMU 占用率计数 + +374 +00:24:20,093 --> 00:24:23,130 +和 MMU TLB 缺失率计数 + +375 +00:24:24,431 --> 00:24:27,301 +我今天讲了很多内容 + +376 +00:24:27,334 --> 00:24:31,972 +我讨论了 GPU 的可扩展性 +以及放大时瓶颈如何转移 + +377 +00:24:32,005 --> 00:24:36,009 +还有这些工具能如何帮助您 +发现并解决与可缩放性相关的问题 + +378 +00:24:36,043 --> 00:24:40,147 +我还讨论了您可能需要 +如何进行试验并做出权衡 + +379 +00:24:40,180 --> 00:24:43,417 +以为您的应用获得最佳结果 + +380 +00:24:43,450 --> 00:24:47,855 +我期待看到所有开发者的 +优秀的 App 能够 + +381 +00:24:47,888 --> 00:24:48,956 +在 Apple 芯片上完美扩展 + +382 +00:24:48,989 --> 00:24:50,624 +感谢收看 + diff --git a/zho/2022 Session 10160 Program Metal in C++ with metal-cpp.srt b/zho/2022 Session 10160 Program Metal in C++ with metal-cpp.srt new file mode 100644 index 0000000..31514e6 --- /dev/null +++ b/zho/2022 Session 10160 Program Metal in C++ with metal-cpp.srt @@ -0,0 +1,2222 @@ +1 +00:00:00,100 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,676 +♪ + +3 +00:00:09,676 --> 00:00:11,311 +大家好 我叫 Keyi Yu + +4 +00:00:11,311 --> 00:00:14,014 +是 Metal Ecosystem +团队的工程师 + +5 +00:00:14,014 --> 00:00:17,017 +很高兴今天能在此 +为您介绍 metal-cpp + +6 +00:00:17,017 --> 00:00:21,955 +metal-cpp 专门服务于想要 +在 Apple 平台 + +7 +00:00:21,955 --> 00:00:25,058 +创作 Metal App 的 C++ 用户 + +8 +00:00:25,058 --> 00:00:27,594 +metal-cpp 是一个低开销库 + +9 +00:00:27,594 --> 00:00:31,698 +可以将 C++ App 连接到 Metal + +10 +00:00:31,698 --> 00:00:35,702 +首先大致介绍一下 metal-cpp + +11 +00:00:35,702 --> 00:00:39,706 +及其工作原理 +然后我还会详细介绍下 + +12 +00:00:39,706 --> 00:00:43,310 +Objective-C 对象的生命周期 + +13 +00:00:43,310 --> 00:00:47,781 +C++ 和 Objective-C 处理 +生命周期的方式有些差异 + +14 +00:00:47,781 --> 00:00:52,219 +我会介绍该如何处理这些差异 + +15 +00:00:52,219 --> 00:00:55,756 +Xcode 和 metal-cpp +有些很棒的实用程序 + +16 +00:00:55,756 --> 00:00:58,392 +可以帮助您管理 App 中的 + +17 +00:00:58,392 --> 00:01:01,094 +对象生命周期 + +18 +00:01:01,094 --> 00:01:05,098 +最后 我将展示如何集成 C++ 代码 + +19 +00:01:05,098 --> 00:01:09,102 +和 Objective-C 类 + +20 +00:01:09,102 --> 00:01:13,340 +首先来说说 metal-cpp +及其工作原理 + +21 +00:01:13,340 --> 00:01:16,343 +Metal 为 Apple 平台上 +加速图形处理和运算 + +22 +00:01:16,343 --> 00:01:20,314 +奠定了基础 使您的 App 和游戏得以 + +23 +00:01:20,314 --> 00:01:23,317 +充分利用 GPU 的强大功能 + +24 +00:01:23,317 --> 00:01:26,553 +最初设计 metal-cpp 时使用的是 + +25 +00:01:26,553 --> 00:01:29,323 +Objective-C 的强大功能及惯例 + +26 +00:01:29,323 --> 00:01:34,061 +但如果您的代码库用的是 C++ +则可能需要另外桥接(bridge) + +27 +00:01:34,061 --> 00:01:37,464 +您的代码和 +Metal 的 Objective-C 代码 + +28 +00:01:37,464 --> 00:01:40,000 +metal-cpp 应运而生! + +29 +00:01:40,000 --> 00:01:43,337 +metal-cpp 能够充当 +C++ App 和 Objective-C Metal + +30 +00:01:43,337 --> 00:01:45,606 +之间的枢纽 + +31 +00:01:45,606 --> 00:01:48,208 +当 App 中应用了 metal-cpp + +32 +00:01:48,208 --> 00:01:51,678 +您就可以在 C++ 中 +使用 Metal 类和函数 + +33 +00:01:51,678 --> 00:01:54,915 +此外 在运行时 +metal-cpp 也可以帮助 + +34 +00:01:54,915 --> 00:01:56,450 +调用 Objective-C 函数 + +35 +00:01:56,450 --> 00:02:00,521 +metal-cpp 是轻量级的 +Metal C++ 包装器 + +36 +00:02:00,521 --> 00:02:03,657 +之所以说轻量级 +是因为 metal-cpp 已经成为了 + +37 +00:02:03,657 --> 00:02:07,628 +带有内联函数调用的仅头文件库 + +38 +00:02:07,628 --> 00:02:11,331 +能够通过达到 C++ + +39 +00:02:11,331 --> 00:02:14,835 +调用 Objective-C API +的一对一映射 + +40 +00:02:14,835 --> 00:02:16,770 +实现 100% Metal API 覆盖率 + +41 +00:02:16,770 --> 00:02:20,007 +为此 metal-cpp 包装了 Foundation + +42 +00:02:20,007 --> 00:02:22,442 +和 CoreAnimation 框架的部分内容 + +43 +00:02:22,442 --> 00:02:24,711 +由于 metal-cpp 已 +在 Apache 2 许可下开源 + +44 +00:02:24,711 --> 00:02:27,214 +因此您可以修改库并轻松将其 + +45 +00:02:27,214 --> 00:02:29,650 +添加到您的 App + +46 +00:02:29,650 --> 00:02:32,853 +metal-cpp 能够使用 C + +47 +00:02:32,853 --> 00:02:35,622 +直接调用 Objective-C 运行时 + +48 +00:02:35,622 --> 00:02:38,959 +该机制与 Objective-C 编译器用于 + +49 +00:02:38,959 --> 00:02:42,963 +执行 Objective-C 方法 +的机制完全相同 + +50 +00:02:42,963 --> 00:02:47,167 +所以这个包装器增加的开销不多 + +51 +00:02:47,167 --> 00:02:51,438 +由于 metal-cpp 实现了 +C++ 对 Objective-C 调用的 + +52 +00:02:51,438 --> 00:02:53,440 +一对一映射 + +53 +00:02:53,440 --> 00:02:57,077 +它也遵循相同的 +Cocoa 内存管理规则 + +54 +00:02:57,077 --> 00:02:59,947 +这个问题稍后会详谈 + +55 +00:02:59,947 --> 00:03:02,216 +这种一对一映射还能够让 + +56 +00:03:02,216 --> 00:03:05,319 +连贯衔接所有开发者工具 + +57 +00:03:05,319 --> 00:03:10,791 +包括 GPU 帧捕获和 Xcode 调试器 + +58 +00:03:10,791 --> 00:03:13,760 +屏幕上是用 metal-cpp 绘制三角形 + +59 +00:03:13,760 --> 00:03:15,696 +所需的一系列调用 + +60 +00:03:15,696 --> 00:03:19,499 +如果您已熟悉掌握 C++ +现在正是学习 Metal 的好时机 + +61 +00:03:19,499 --> 00:03:22,870 +语言语法不会成为您的学习障碍 + +62 +00:03:22,870 --> 00:03:26,306 +如果您已经 +在 Objective-C 中使用过 Metal + +63 +00:03:26,306 --> 00:03:29,443 +在函数调用方面 + +64 +00:03:29,443 --> 00:03:31,912 +Metal 的 Objective-C 接口 +和 metal-cpp + +65 +00:03:31,912 --> 00:03:33,780 +两者差别很小 + +66 +00:03:33,780 --> 00:03:38,852 +让我来演示下 +metal-cpp 的操作有多简便 + +67 +00:03:38,852 --> 00:03:41,555 +首先 创建一个命令缓冲区 + +68 +00:03:41,555 --> 00:03:45,259 +填写供 GPU 执行的命令 + +69 +00:03:45,259 --> 00:03:48,495 +可以简单将 C++ 原始指针 + +70 +00:03:48,495 --> 00:03:51,665 +作为 Objective-C ID 的映射 + +71 +00:03:51,665 --> 00:03:54,234 +然后创建一个渲染命令编码器 + +72 +00:03:54,234 --> 00:03:57,504 +用命令缓冲区编写渲染命令 + +73 +00:03:57,504 --> 00:04:00,541 +C++ 函数渲染命令编码器 + +74 +00:04:00,541 --> 00:04:02,643 +和 Objective-C 函数中的 + +75 +00:04:02,643 --> 00:04:06,980 +带描述符的渲染命令编码器 +是一样的 + +76 +00:04:06,980 --> 00:04:09,750 +唯一的区别是编程语言的 + +77 +00:04:09,750 --> 00:04:11,552 +名称惯例 + +78 +00:04:11,552 --> 00:04:14,321 +接着设置一个渲染管道状态对象 + +79 +00:04:14,321 --> 00:04:17,257 +其中包含顶点 片段着色器 + +80 +00:04:17,257 --> 00:04:19,860 +以及其他各种渲染状态 + +81 +00:04:19,860 --> 00:04:24,631 +然后 对绘制调用进行编码 +以绘制三角形 + +82 +00:04:24,631 --> 00:04:25,999 +然后给出指示 + +83 +00:04:25,999 --> 00:04:29,403 +表明渲染命令的编码已经完成 + +84 +00:04:29,403 --> 00:04:33,340 +我展示了可绘制对象 +因此三角形会显示在屏幕上 + +85 +00:04:33,340 --> 00:04:36,410 +最后 提交了命令缓冲区 + +86 +00:04:36,410 --> 00:04:40,848 +来告诉 GPU 可以开始执行命令了 + +87 +00:04:40,848 --> 00:04:43,784 +显然 metal-cpp 和 +Objective-C Metal + +88 +00:04:43,784 --> 00:04:45,485 +两者几乎一模一样 + +89 +00:04:45,485 --> 00:04:48,155 +有了 metal-cpp 您无需担心 + +90 +00:04:48,155 --> 00:04:49,957 +语言语法会带来问题 + +91 +00:04:49,957 --> 00:04:52,726 +您可以直接查看 Metal 文档 + +92 +00:04:52,726 --> 00:04:56,463 +来学习 Metal 的概念和用法 + +93 +00:04:56,463 --> 00:04:58,098 +您可能已经测试过 + +94 +00:04:58,098 --> 00:05:00,501 +之前用过的这个延迟光照示例了 + +95 +00:05:00,501 --> 00:05:03,704 +现在 该延迟光照示例有了新版本 + +96 +00:05:03,704 --> 00:05:06,206 +支持使用 metal-cpp + +97 +00:05:06,206 --> 00:05:09,510 +希望这可以帮助您在实践中学习 +如何使用 metal-cpp + +98 +00:05:09,510 --> 00:05:11,078 +进行编码 + +99 +00:05:11,078 --> 00:05:13,380 +我也很高兴为您带来 + +100 +00:05:13,380 --> 00:05:17,851 +一系列应用了 Metal API 的 +渐进的 C++ 示例 + +101 +00:05:17,851 --> 00:05:21,488 +让我来展示如何用它完成不同的任务 + +102 +00:05:25,158 --> 00:05:28,695 +现在您对 metal-cpp 有了一点了解 + +103 +00:05:28,695 --> 00:05:30,464 +您该如何在实践中应用呢? + +104 +00:05:30,464 --> 00:05:32,933 +我们去年发布了 metal-cpp + +105 +00:05:32,933 --> 00:05:35,302 +您可以在这个网页找到下载资料 + +106 +00:05:35,302 --> 00:05:36,937 +和说明 + +107 +00:05:36,937 --> 00:05:39,907 +让我来为您示范一下步骤 + +108 +00:05:39,907 --> 00:05:41,909 +下载 metal-cpp 后 + +109 +00:05:41,909 --> 00:05:44,878 +您需要告知 Xcode 其路径 + +110 +00:05:44,878 --> 00:05:49,616 +请看 我把 metal-cpp +放到了当前项目下 + +111 +00:05:49,616 --> 00:05:53,020 +然后 需要将 C++17 或更高版本 + +112 +00:05:53,020 --> 00:05:56,990 +设置为 C++ 语言方言 + +113 +00:05:56,990 --> 00:05:59,860 +接下来 在项目中添加三个框架 + +114 +00:05:59,860 --> 00:06:03,997 +Foundation QuartzCore 和 Metal + +115 +00:06:03,997 --> 00:06:05,532 +还有最后一件事 + +116 +00:06:05,532 --> 00:06:09,336 +完成后才能使用 +这些框架的 C++ 接口 + +117 +00:06:09,336 --> 00:06:12,139 +metal-cpp 中有三个头文件 + +118 +00:06:12,139 --> 00:06:14,842 +由于 metal-cpp 是只有头文件的库 + +119 +00:06:14,842 --> 00:06:17,444 +您需要在导入头文件之前 + +120 +00:06:17,444 --> 00:06:19,847 +生成头文件的实现 + +121 +00:06:19,847 --> 00:06:24,985 +为此需要定义三个宏: +NS_PRIVATE_IMPLEMENTATION + +122 +00:06:24,985 --> 00:06:29,656 +CA_PRIVATE_IMPLEMENTATION +和 MTL_PRIVATE_IMPLEMENTATION + +123 +00:06:29,656 --> 00:06:32,693 +如果您好奇 metal-cpp 在后台 + +124 +00:06:32,693 --> 00:06:33,994 +对宏的作用 + +125 +00:06:33,994 --> 00:06:37,631 +请查看 metal-cpp 文件夹 +中的桥接头文件 + +126 +00:06:37,631 --> 00:06:39,499 +头文件可以单独使用 + +127 +00:06:39,499 --> 00:06:42,169 +也可被放入一个单独的头文件 + +128 +00:06:42,169 --> 00:06:45,072 +您可以随时在需要时导入头文件 + +129 +00:06:45,072 --> 00:06:48,909 +但请记住 不要重复定义 NS、CA + +130 +00:06:48,909 --> 00:06:52,746 +或 MTL_PRIVATE_IMPLEMENTATION 宏 + +131 +00:06:52,746 --> 00:06:56,950 +否则可能导致重复定义错误 + +132 +00:06:56,950 --> 00:06:59,286 +为了高效使用 metal-cpp + +133 +00:06:59,286 --> 00:07:02,322 +您需要了解 Cocoa 的内存管理规则 + +134 +00:07:02,322 --> 00:07:05,425 +学习如何利用功能强大的实用程序来 + +135 +00:07:05,425 --> 00:07:07,995 +管理对象生命周期 +以及学习如何设计 + +136 +00:07:07,995 --> 00:07:10,497 +与其他框架接口时 + +137 +00:07:10,497 --> 00:07:12,733 +的 App 架构 + +138 +00:07:12,733 --> 00:07:16,336 +先说对象生命周期管理 + +139 +00:07:16,336 --> 00:07:18,639 +在 App 运行期间 + +140 +00:07:18,639 --> 00:07:21,909 +您通常需要分配和释放内存 + +141 +00:07:21,909 --> 00:07:24,811 +还需要管理命令缓冲区 + +142 +00:07:24,811 --> 00:07:27,214 +管道对象和资源 + +143 +00:07:27,214 --> 00:07:29,183 +为了辅助管理这段内存 + +144 +00:07:29,183 --> 00:07:33,020 +Objective-C 和 Cocoa 对象 +包含了一个引用计数 + +145 +00:07:33,020 --> 00:07:36,089 +metal-cpp 中也是同样 + +146 +00:07:36,089 --> 00:07:39,026 +引用计数可以帮助您管理内存 + +147 +00:07:39,026 --> 00:07:40,627 +应用引用计数之后 + +148 +00:07:40,627 --> 00:07:43,597 +所有对象都将包含 +一个 retainCount 属性 + +149 +00:07:43,597 --> 00:07:45,732 +App 中的组件能够增加计数 + +150 +00:07:45,732 --> 00:07:48,569 +使其正在交互的对象保持活跃 + +151 +00:07:48,569 --> 00:07:51,305 +等完成后再减少对象 + +152 +00:07:51,305 --> 00:07:53,473 +当 retainCount 达到 0 时 + +153 +00:07:53,473 --> 00:07:56,176 +运行时将释放对象 + +154 +00:07:56,176 --> 00:07:59,279 +Objective-C 中有两类引用计数 + +155 +00:07:59,279 --> 00:08:02,616 +一种称为手动引用计数(Manual Retain-Release) +即 MRR + +156 +00:08:02,616 --> 00:08:06,253 +另一个是自动引用计数 (Automatic Reference Counting) +即 ARC + +157 +00:08:06,253 --> 00:08:08,689 +使用 ARC 功能编译代码时 + +158 +00:08:08,689 --> 00:08:11,258 +编译器将采用您创建的引用 + +159 +00:08:11,258 --> 00:08:13,293 +并自动将调用插入到 + +160 +00:08:13,293 --> 00:08:16,430 +底层的内存管理机制 + +161 +00:08:16,430 --> 00:08:20,234 +metal-cpp 对象需要手动保留和释放 + +162 +00:08:20,234 --> 00:08:23,303 +因此 您需要了解 Cocoa 惯例 + +163 +00:08:23,303 --> 00:08:26,974 +才能知道保留和释放对象的时机 + +164 +00:08:26,974 --> 00:08:31,478 +与在 C++ 中创建对象不同 +metal-cpp 对象 + +165 +00:08:31,478 --> 00:08:34,948 +既不会被用 new 创建 +也不会被用 delete 销毁 + +166 +00:08:34,948 --> 00:08:38,785 +在 Cocoa 惯例中 +您创建的任何对象 + +167 +00:08:38,785 --> 00:08:43,423 +凡是以 alloc、new、copy +mutableCopy 或 create 开头的方法创建 + +168 +00:08:43,423 --> 00:08:45,893 +都归您所有 + +169 +00:08:45,893 --> 00:08:49,563 +您可以行使所有权来保留获得对象 + +170 +00:08:49,563 --> 00:08:53,333 +当您不再需要该对象时 +则必须放弃对这一对象 + +171 +00:08:53,333 --> 00:08:54,868 +的所有权 + +172 +00:08:54,868 --> 00:08:58,972 +您可以立即或稍后释放该对象 + +173 +00:08:58,972 --> 00:09:02,476 +对于不归您所有的对象 +您不能放弃其所有权 + +174 +00:09:02,476 --> 00:09:05,913 +否则可能导致 double free 漏洞 + +175 +00:09:05,913 --> 00:09:08,081 +接下来 我将进行展示一个 + +176 +00:09:08,081 --> 00:09:10,150 +Cocoa 惯例的示例 + +177 +00:09:10,150 --> 00:09:14,154 +在 A 类中 某个方法 +使用了 alloc 来创建对象 + +178 +00:09:14,154 --> 00:09:16,757 +并用 init 初始化此对象 + +179 +00:09:16,757 --> 00:09:20,961 +请注意 永远不要 +在一个对象上两次调用 init + +180 +00:09:20,961 --> 00:09:22,896 +A 类取得所有权 + +181 +00:09:22,896 --> 00:09:25,832 +获得了释放该对象的权力 + +182 +00:09:25,832 --> 00:09:29,303 +现在 该对象的 retainCount 为 1 + +183 +00:09:29,303 --> 00:09:33,373 +接下来 B 类 +使用 retain 来获取对象 + +184 +00:09:33,373 --> 00:09:35,976 +并获得了该对象的所有权 + +185 +00:09:35,976 --> 00:09:39,279 +到目前为止 这里有两个对象共享着 + +186 +00:09:39,279 --> 00:09:42,583 +这个橙色方块对象的所有权 + +187 +00:09:42,583 --> 00:09:44,651 +retainCount 增加 1 + +188 +00:09:46,520 --> 00:09:49,356 +A 类不再需要这个对象 + +189 +00:09:49,356 --> 00:09:53,126 +所以 A 类应该手动调用释放 + +190 +00:09:53,126 --> 00:09:56,830 +结果 retainCount 减 1 + +191 +00:09:56,830 --> 00:10:00,067 +现在 拥有该对象的只有 B 类了 + +192 +00:10:00,067 --> 00:10:03,670 +好的 最后 B 类也想释放这个对象 + +193 +00:10:03,670 --> 00:10:08,375 +现在 retainCount 为 0 +于是运行时释放对象 + +194 +00:10:08,375 --> 00:10:11,144 +换一种情况 假设 B 类的方法 + +195 +00:10:11,144 --> 00:10:13,514 +返回了一个对象 + +196 +00:10:13,514 --> 00:10:16,617 +但在其余程序中 您仍然需要此对象 + +197 +00:10:16,617 --> 00:10:19,553 +换句话说 虽然您想放弃 + +198 +00:10:19,553 --> 00:10:22,222 +B 类方法对象的所有权 + +199 +00:10:22,222 --> 00:10:26,226 +但您不希望该对象被立即释放 + +200 +00:10:26,226 --> 00:10:30,264 +在这种情况下 则需要 +在 B 类中调用 autorelease + +201 +00:10:30,264 --> 00:10:33,333 +调用 autorelease 后 +retainCount 仍为 1 + +202 +00:10:33,333 --> 00:10:36,837 +也就是说 之后仍然可以使用该对象 + +203 +00:10:36,837 --> 00:10:38,238 +来思考一下: + +204 +00:10:38,238 --> 00:10:41,575 +既然 B 类不再拥有该对象 + +205 +00:10:41,575 --> 00:10:44,578 +那么该由谁来释放呢? + +206 +00:10:44,578 --> 00:10:47,581 +Foundation 框架 +提供了一个重要对象 + +207 +00:10:47,581 --> 00:10:49,650 +也就是 AutoreleasePool + +208 +00:10:49,650 --> 00:10:54,388 +Autorelease API 将对象 +放入 AutoreleasePool + +209 +00:10:54,388 --> 00:10:58,992 +于是现在 AutoreleasePool +获得了对象的所有权 + +210 +00:10:58,992 --> 00:11:02,029 +当 AutoreleasePool 被销毁时 + +211 +00:11:02,029 --> 00:11:04,798 +会减少接收者的 retainCount + +212 +00:11:04,798 --> 00:11:08,836 +您不一定需要手动创建自动释放对象 + +213 +00:11:08,836 --> 00:11:11,305 +Metal 本身便自带了几个 + +214 +00:11:11,305 --> 00:11:13,473 +自动释放对象 + +215 +00:11:13,473 --> 00:11:16,176 +所有创建临时对象的方法 + +216 +00:11:16,176 --> 00:11:18,212 +都可以将它们添加到 AutoreleasePool + +217 +00:11:18,212 --> 00:11:21,014 +只需在后台调用 autorelease 即可 + +218 +00:11:21,014 --> 00:11:24,718 +AutoreleasePool 会负责释放对象 + +219 +00:11:24,718 --> 00:11:27,321 +换句话说 有了 AutoreleasePool 的帮助 + +220 +00:11:27,321 --> 00:11:30,157 +您可以更从容地进行编码 + +221 +00:11:30,157 --> 00:11:33,527 +您可以为主 App 设置 AutoreleasePool + +222 +00:11:33,527 --> 00:11:36,430 +我们也鼓励您在较小范围内 + +223 +00:11:36,430 --> 00:11:38,932 +创建和管理额外的 AutoreleasePool + +224 +00:11:38,932 --> 00:11:41,401 +来减少您程序的工作集 + +225 +00:11:41,401 --> 00:11:45,205 +您还需要为创建的每个线程 +使用AutoreleasePool + +226 +00:11:45,205 --> 00:11:48,509 +这是一个使用 AutoreleasePool + +227 +00:11:48,509 --> 00:11:51,078 +和自动释放对象的示例 + +228 +00:11:51,078 --> 00:11:53,680 +在该示例中 一个 AutoreleasePool + +229 +00:11:53,680 --> 00:11:57,918 +由 alloc 创建 +此时您拥有其所有权 + +230 +00:11:57,918 --> 00:12:00,587 +且需要您手动释放 + +231 +00:12:00,587 --> 00:12:03,290 +现在我们有了一个 AutoreleasePool + +232 +00:12:03,290 --> 00:12:05,125 +正如之前说过的 + +233 +00:12:05,125 --> 00:12:07,928 +您需要创建一个命令缓冲区 + +234 +00:12:07,928 --> 00:12:11,131 +由于不是用 alloc 或 create 创建 + +235 +00:12:11,131 --> 00:12:13,567 +您对其没有所有权 + +236 +00:12:13,567 --> 00:12:19,706 +相反 它是由 Metal 创建的+ +自动释放对象 + +237 +00:12:19,706 --> 00:12:22,943 +该命令缓冲区将被放入 AutoreleasePool + +238 +00:12:22,943 --> 00:12:26,613 +由 AutoreleasePool 来负责释放 + +239 +00:12:26,613 --> 00:12:28,182 +直到释放 AutoreleasePool 之前 + +240 +00:12:28,182 --> 00:12:31,552 +您都可以随意使用它 + +241 +00:12:31,552 --> 00:12:35,656 +接着 您需要创建一个 +RenderPassDescriptor + +242 +00:12:35,656 --> 00:12:39,193 +该 RenderPassDescriptor 也将同样被放入 + +243 +00:12:39,193 --> 00:12:40,394 +AutoreleasePool + +244 +00:12:40,394 --> 00:12:43,197 +与 RenderCommandEncoder 相同 + +245 +00:12:43,197 --> 00:12:46,900 +它也是一个由 Metal 创建的 +自动释放对象 + +246 +00:12:46,900 --> 00:12:49,937 +不要忘记这个 currentDrawable 对象 + +247 +00:12:49,937 --> 00:12:53,607 +它也会被放入 AutoreleasePool 中 + +248 +00:12:53,607 --> 00:12:56,944 +在这段代码的最后 +我使用了 pPool-release + +249 +00:12:56,944 --> 00:12:59,112 +来释放 AutoreleasePool + +250 +00:12:59,112 --> 00:13:02,115 +在被释放之前 AutoreleasePool + +251 +00:13:02,115 --> 00:13:04,651 +会释放拥有的所有对象 + +252 +00:13:04,651 --> 00:13:07,921 +在这种情况下 它会释放 +CommandBuffer + +253 +00:13:07,921 --> 00:13:12,059 +RenderPassDescriptor +RenderCommandEncoder + +254 +00:13:12,059 --> 00:13:14,061 +和当前可绘制对象 + +255 +00:13:14,061 --> 00:13:16,864 +最后再释放 AutoreleasePool + +256 +00:13:16,864 --> 00:13:19,533 +目前为止 您已经了解了 Cocoa 惯例 + +257 +00:13:19,533 --> 00:13:22,669 +自动释放对象和 AutoreleasePool + +258 +00:13:22,669 --> 00:13:26,440 +只有正确管理对象生命周期 + +259 +00:13:26,440 --> 00:13:29,843 +才能避免内存泄漏和僵尸对象 + +260 +00:13:29,843 --> 00:13:32,613 +而我们恰好为您提供了合适的工具 + +261 +00:13:32,613 --> 00:13:35,015 +可以避免及排除这些问题 + +262 +00:13:35,015 --> 00:13:37,184 +我将专注于两个实用程序: + +263 +00:13:37,184 --> 00:13:40,587 +NS::SharedPtr 和 NSZombie + +264 +00:13:40,587 --> 00:13:44,458 +NS::SharedPtr 是新增的实用程序 +可以帮助您管理 + +265 +00:13:44,458 --> 00:13:46,627 +对象生命周期 + +266 +00:13:46,627 --> 00:13:48,996 +可以在 Foundation 框架下的 + +267 +00:13:48,996 --> 00:13:51,064 +metal-cpp 文件夹中找到它 + +268 +00:13:51,064 --> 00:13:53,333 +请注意 它和 std:shared_ptr + +269 +00:13:53,333 --> 00:13:55,269 +并不完全相同 + +270 +00:13:55,269 --> 00:13:59,640 +它不依赖于 C++ 标准库 + +271 +00:13:59,640 --> 00:14:03,043 +且没有额外的存储引用计数的成本 + +272 +00:14:03,043 --> 00:14:05,779 +这就是 NS::SharedPtr + +273 +00:14:05,779 --> 00:14:08,615 +其转移和保留函数能够清晰表达 + +274 +00:14:08,615 --> 00:14:11,485 +消耗一个对象的意图 + +275 +00:14:11,485 --> 00:14:13,921 +转移函数能够在 +不增加指针引 referenceCount 的情况下 + +276 +00:14:13,921 --> 00:14:16,757 +创建一个 SharedPtr + +277 +00:14:16,757 --> 00:14:21,028 +来将所有权高效转移到 SharedPtr + +278 +00:14:21,028 --> 00:14:25,532 +保留函数能够向传入的对象 +发送保留命令 + +279 +00:14:25,532 --> 00:14:28,101 +您可以使用此功能来让 + +280 +00:14:28,101 --> 00:14:29,937 +AutoreleasePool 中的对象保持活动 + +281 +00:14:29,937 --> 00:14:32,539 +并用其来表示 指针所有者 + +282 +00:14:32,539 --> 00:14:36,543 +在被指对象的生命周期内 +拥有既得利益 + +283 +00:14:36,543 --> 00:14:38,412 +您可以如您所想 +通过 get 和 operator- + +284 +00:14:38,412 --> 00:14:42,749 +来访问底层对象 + +285 +00:14:42,749 --> 00:14:45,752 +SharedPtr 也能够按您所需 + +286 +00:14:45,752 --> 00:14:48,789 +复制、移动构造及赋值 + +287 +00:14:48,789 --> 00:14:51,525 +复制操作会增加 retainCount + +288 +00:14:51,525 --> 00:14:54,561 +而移动操作速度迅速 +且不影响 retainCount + +289 +00:14:54,561 --> 00:14:56,430 +一般情况下 + +290 +00:14:56,430 --> 00:14:59,600 +SharedPtrs 只会向被指对象 + +291 +00:14:59,600 --> 00:15:02,035 +发送一个释放命令 + +292 +00:15:02,035 --> 00:15:03,704 +只要您想 也可以通过调用分离函数 + +293 +00:15:03,704 --> 00:15:06,240 +避免这种情况 + +294 +00:15:06,240 --> 00:15:07,708 +回到正题 + +295 +00:15:07,708 --> 00:15:10,177 +了解传输或保留这两种指针创建方法 + +296 +00:15:10,177 --> 00:15:14,748 +之间的区别非常重要 + +297 +00:15:14,748 --> 00:15:17,084 +对于 TransferPtr 来说 + +298 +00:15:17,084 --> 00:15:22,789 +假设这里有一个 MRR 对象 +引用计数为 1 + +299 +00:15:22,789 --> 00:15:25,359 +在将它传递给 TransferPtr 函数后 + +300 +00:15:25,359 --> 00:15:28,328 +SharedPtr 将取得对象的所有权 + +301 +00:15:28,328 --> 00:15:30,964 +但它的 retainCount 不会改变 + +302 +00:15:30,964 --> 00:15:32,799 +当指针超出范围时 + +303 +00:15:32,799 --> 00:15:34,868 +SharedPtr 的析构函数便会运行 + +304 +00:15:34,868 --> 00:15:37,638 +并在 MRR 对象上调用释放函数 + +305 +00:15:37,638 --> 00:15:40,140 +将 retainCount 减为 0 + +306 +00:15:40,140 --> 00:15:43,277 +另一个函数是 NS::RetainPtr + +307 +00:15:43,277 --> 00:15:46,013 +当您想将对象留下备用 + +308 +00:15:46,013 --> 00:15:47,781 +而不是现在释放时 + +309 +00:15:47,781 --> 00:15:50,217 +就应该使用 NS::RetainPtr + +310 +00:15:50,217 --> 00:15:55,389 +以这个 MRR 对象为例 +retainCount 数是 1 + +311 +00:15:55,389 --> 00:15:58,025 +在将它传递给 RetainPtr 函数之后 + +312 +00:15:58,025 --> 00:16:00,727 +retainCount 加一 + +313 +00:16:00,727 --> 00:16:02,262 +超出范围后 + +314 +00:16:02,262 --> 00:16:06,500 +该 RetainPtr 调用 +释放此 MRR 对象的函数 + +315 +00:16:06,500 --> 00:16:09,102 +所以 retainCount 是 1 + +316 +00:16:09,102 --> 00:16:12,406 +一般来说 +NS::TransferPtr 会为您 + +317 +00:16:12,406 --> 00:16:13,941 +取得一个对象的所有权 + +318 +00:16:13,941 --> 00:16:17,444 +而 NS::RetainPtr 会帮您 + +319 +00:16:17,444 --> 00:16:20,747 +在不想释放对象时保留该对象 + +320 +00:16:20,747 --> 00:16:24,017 +当您将对象传递给这两个函数 + +321 +00:16:24,017 --> 00:16:27,321 +NS::TransferPtr +不会改变引用计数 + +322 +00:16:27,321 --> 00:16:31,558 +但是 NS::RetainPtr 将 +使引用计数增加 1 + +323 +00:16:31,558 --> 00:16:34,494 +因为 NS::RetainPtr 会在后台 +为您调用保留函数 + +324 +00:16:34,494 --> 00:16:36,830 +这两个函数的析构函数 + +325 +00:16:36,830 --> 00:16:39,499 +都为传入的对象调用释放 + +326 +00:16:39,499 --> 00:16:43,270 +因此 引用计数减 1 + +327 +00:16:43,270 --> 00:16:45,572 +如果引用计数为 0 + +328 +00:16:45,572 --> 00:16:48,208 +该对象将在运行时被释放 + +329 +00:16:48,208 --> 00:16:51,745 +这是 NS::TransferPtr 的示例 + +330 +00:16:51,745 --> 00:16:53,480 +说起渲染通道 + +331 +00:16:53,480 --> 00:16:55,682 +我之前用它画了个三角形 + +332 +00:16:55,682 --> 00:16:58,485 +我需要这个渲染管道状态 + +333 +00:16:58,485 --> 00:17:02,356 +以下是创建渲染管道状态对象的调用 + +334 +00:17:02,356 --> 00:17:05,792 +这些是渲染管道描述符需要的属性 + +335 +00:17:05,792 --> 00:17:07,928 +根据 Cocoa 惯例 + +336 +00:17:07,928 --> 00:17:12,199 +凡是以 new 和 alloc 开头的调用 + +337 +00:17:12,199 --> 00:17:14,067 +其对象都归我所有 + +338 +00:17:14,067 --> 00:17:17,604 +所以我需要为这些对象手动调用释放 + +339 +00:17:17,604 --> 00:17:20,941 +但使用 NS::SharedPtr 后 +就不需要我来为这些 MRR 对象 + +340 +00:17:20,941 --> 00:17:23,043 +调用释放了 + +341 +00:17:23,043 --> 00:17:27,748 +因为 NS::SharedPtrs +拥有这些对象的所有权 + +342 +00:17:27,748 --> 00:17:33,220 +看这里 我将原始指针传递 +给了 TransferPtr 函数 + +343 +00:17:33,220 --> 00:17:36,290 +完成后 我在上一页中 +示范的操作就没有必要了 + +344 +00:17:36,290 --> 00:17:38,725 +现在无需我来调用释放 + +345 +00:17:38,725 --> 00:17:40,661 +如果您熟悉 ARC + +346 +00:17:40,661 --> 00:17:44,364 +可能会发现 一起使用 +MRR 与 NS::SharedPtr + +347 +00:17:44,364 --> 00:17:46,400 +体验和使用 ARC 十分相似 + +348 +00:17:46,400 --> 00:17:48,468 +您可能会在手动处理内存时 + +349 +00:17:48,468 --> 00:17:50,537 +遇到释放后使用错误 + +350 +00:17:50,537 --> 00:17:52,840 +如果您尝试使用已经释放的对象 + +351 +00:17:52,840 --> 00:17:55,209 +就有可能出现这类报错 + +352 +00:17:55,209 --> 00:17:58,312 +NSZombie 可以有效检查出这类错误 + +353 +00:17:58,312 --> 00:18:00,314 +当出现释放后使用错误时 + +354 +00:18:00,314 --> 00:18:04,451 +NSZombie 将触发断点 +为您提供堆栈跟踪 + +355 +00:18:04,451 --> 00:18:06,486 +您可以很容易地运用带有环境变量 + +356 +00:18:06,486 --> 00:18:08,322 +来启用 Zombies + +357 +00:18:08,322 --> 00:18:11,225 +只需将 NSZombieEnabled +设为 YES 即可 + +358 +00:18:11,225 --> 00:18:13,827 +或者 如果您使用的是 Xcode + +359 +00:18:13,827 --> 00:18:16,029 +则可以在 scheme 中 +启用 Zombies + +360 +00:18:16,029 --> 00:18:18,432 +让我来演示一下工作原理 + +361 +00:18:18,432 --> 00:18:21,835 +我现在想创建一个 +具有相同渲染管道设置的 + +362 +00:18:21,835 --> 00:18:25,072 +新渲染管道状态对象 + +363 +00:18:25,072 --> 00:18:28,842 +所以在这个 +newRenderPipelineState 函数中 + +364 +00:18:28,842 --> 00:18:32,813 +我重用了 pDesc 对象 + +365 +00:18:34,815 --> 00:18:38,685 +点击运行后 Xcode 触发断点 + +366 +00:18:38,685 --> 00:18:40,888 +并显示堆栈跟踪 + +367 +00:18:40,888 --> 00:18:43,724 +这意味着有哪里出了问题 + +368 +00:18:43,724 --> 00:18:47,194 +嗯 出什么问题了? + +369 +00:18:47,194 --> 00:18:54,001 +也许 NSZombie 可以帮上忙 +于是我在 scheme 中启用了 NSZombie + +370 +00:18:57,004 --> 00:19:01,308 +当我再次运行程序时 +NSZombie 会触发断点 + +371 +00:19:01,308 --> 00:19:04,244 +在控制台输出中有了些新东西: + +372 +00:19:04,244 --> 00:19:09,183 +“message sent to deallocated instance” +(消息已发送到已释放实例) + +373 +00:19:09,183 --> 00:19:12,886 +哦 原来是因为我重用了 +一个已经释放的对象 + +374 +00:19:12,886 --> 00:19:16,256 +这个对象就是渲染管道描述符 + +375 +00:19:16,256 --> 00:19:19,026 +所以我只能在释放之前 + +376 +00:19:19,026 --> 00:19:21,228 +使用这个渲染管道描述符 + +377 +00:19:21,228 --> 00:19:24,097 +顺着这样的步骤 问题就解决了 + +378 +00:19:24,097 --> 00:19:28,035 +收看今年的演讲 +“Profile and optimize your game’s memory” + +379 +00:19:28,035 --> 00:19:31,271 +您可以了解更多工具和细节 + +380 +00:19:31,271 --> 00:19:34,608 +比如说 该如何在 +Instruments 内存分配中 + +381 +00:19:34,608 --> 00:19:37,144 +跟踪 retainCount + +382 +00:19:37,144 --> 00:19:40,547 +欢迎您随时查看 Apple +平台上的其他工具 + +383 +00:19:40,547 --> 00:19:43,450 +您会找到不是可以 帮助您调试游戏 + +384 +00:19:43,450 --> 00:19:45,619 +提高性能的工具 + +385 +00:19:45,619 --> 00:19:50,457 +您已经了解了该如何在 metal-cpp +中管理对象生命周期 + +386 +00:19:50,457 --> 00:19:53,493 +但您可能仍有与其他框架交互的需求 + +387 +00:19:53,493 --> 00:19:56,697 +比如说 游戏控制器和音频 + +388 +00:19:56,697 --> 00:19:59,233 +Objective-C 也同样可以实现 + +389 +00:19:59,233 --> 00:20:01,535 +该如何与这些 API 交互 + +390 +00:20:01,535 --> 00:20:05,706 +并设计出简明的 App 架构呢? + +391 +00:20:05,706 --> 00:20:09,176 +假设您用 Objective-C +写了一个 ViewController + +392 +00:20:09,176 --> 00:20:13,280 +而编写渲染器时却用了 +C++ 和 metal-cpp + +393 +00:20:13,280 --> 00:20:16,316 +那么您需要就需要 +从 ViewController + +394 +00:20:16,316 --> 00:20:18,318 +调用渲染器方法 比如绘制 + +395 +00:20:18,318 --> 00:20:22,222 +挑战之处在于 +需要将两种语言分开的同时 + +396 +00:20:22,222 --> 00:20:25,626 +让两种语言协同工作 + +397 +00:20:25,626 --> 00:20:29,029 +想要解决 就需要创建一个适配器类 + +398 +00:20:29,029 --> 00:20:32,966 +使其从 Objective-C +文件中调用 C++ + +399 +00:20:32,966 --> 00:20:37,137 +这样做之后 您便可以 +在想要实现功能的文件中 + +400 +00:20:37,137 --> 00:20:40,440 +专门使用 Objective-C 或 C++ + +401 +00:20:40,440 --> 00:20:41,642 +举个例子 + +402 +00:20:41,642 --> 00:20:45,579 +在 Objective-C 中 +创建一个 RendererAdapter + +403 +00:20:45,579 --> 00:20:48,048 +在执行过程中 + +404 +00:20:48,048 --> 00:20:51,451 +我添加了一个 Objective-C 方法 +方便我从 ViewController 里 + +405 +00:20:51,451 --> 00:20:53,887 +直接调用它 + +406 +00:20:53,887 --> 00:20:55,622 +在界面内 + +407 +00:20:55,622 --> 00:21:00,460 +我声明了一个指向 +渲染器对象的 C++ 指针 + +408 +00:21:00,460 --> 00:21:02,796 +在方法主体内部 + +409 +00:21:02,796 --> 00:21:07,000 +我直接调用了渲染器的 C++ 方法 + +410 +00:21:07,000 --> 00:21:10,003 +该方法需要将 MTK:View + +411 +00:21:10,003 --> 00:21:13,674 +作为 C++ 对象放入绘制方法中 + +412 +00:21:13,674 --> 00:21:18,011 +也就是说 +通过使用 __bridge 关键字 + +413 +00:21:18,011 --> 00:21:20,113 +视图被强制转换成了 C++ 类型 + +414 +00:21:20,113 --> 00:21:23,417 +关于这个强制转换 +我会之后再详细说明 + +415 +00:21:23,417 --> 00:21:27,888 +与之相对 您需要做的 +则是调用 MTKView + +416 +00:21:27,888 --> 00:21:32,626 +其编写工具是渲染器的 Objective-C +而渲染器则由 C++ 编写 + +417 +00:21:32,626 --> 00:21:35,062 +这也同样具有挑战性 + +418 +00:21:35,062 --> 00:21:39,132 +想要解决 同样需要 +创建一个适配器类 + +419 +00:21:39,132 --> 00:21:41,969 +有了这个类 在 C++ 文件中 + +420 +00:21:41,969 --> 00:21:47,040 +您可以使用 C++ 接口 +调用 Objective-C 方法 + +421 +00:21:47,040 --> 00:21:50,944 +比如说 创建一个 ViewAdapter 类 + +422 +00:21:50,944 --> 00:21:53,881 +这个接口我是用 C++ 编写的 + +423 +00:21:53,881 --> 00:21:55,549 +所以在渲染器类中 + +424 +00:21:55,549 --> 00:21:58,919 +我可以轻松调用 C++ 视图方法 + +425 +00:21:58,919 --> 00:22:00,554 +在执行过程中 + +426 +00:22:00,554 --> 00:22:03,757 +我从 MTKView 调用了 +Objective-C 方法 + +427 +00:22:03,757 --> 00:22:08,395 +包括 currentDrawable +和 depthStencilTexture + +428 +00:22:08,395 --> 00:22:11,698 +您可能看到了 +这里有些 __bridge 关键字 + +429 +00:22:11,698 --> 00:22:14,401 +是用来在 metal-cpp 对象 +和 Objective-C 对象 + +430 +00:22:14,401 --> 00:22:16,403 +之间进行转换的 + +431 +00:22:16,403 --> 00:22:18,005 +正如在一开始说过的 + +432 +00:22:18,005 --> 00:22:21,441 +metal-cpp 对象需要 +手动保留和释放 + +433 +00:22:21,441 --> 00:22:24,178 +而 Objective-C 创建的对象 + +434 +00:22:24,178 --> 00:22:27,047 +使用的是自动引用计数 + +435 +00:22:27,047 --> 00:22:30,817 +您需要在 MRR 和 ARC 之间 + +436 +00:22:30,817 --> 00:22:33,787 +来回移动对象 + +437 +00:22:33,787 --> 00:22:35,522 +以下是三种类型的桥式转换 + +438 +00:22:35,522 --> 00:22:39,560 +可以帮助您在 Objective-C +和 C++ 之间进行转换 + +439 +00:22:39,560 --> 00:22:42,563 +还可以帮助您转移对象所有权 + +440 +00:22:42,563 --> 00:22:45,465 +_bridge 转换可以在 Objective-C +和 metal cpp 对象之间 + +441 +00:22:45,465 --> 00:22:47,734 +进行强制转换 + +442 +00:22:47,734 --> 00:22:52,105 +之间不进行所有权转移 + +443 +00:22:52,105 --> 00:22:55,742 +__bridge_retained 可以将 +Objective-C 指针 + +444 +00:22:55,742 --> 00:23:00,747 +强制转换为 metal-cpp 指针 +并从 ARC 获得所有权 + +445 +00:23:00,747 --> 00:23:03,750 +__bridge_transfer 能够 +将 metal cpp 指针 + +446 +00:23:03,750 --> 00:23:07,754 +移动到 Objective-C 并 +将所有权转移给 ARC + +447 +00:23:07,754 --> 00:23:10,190 +回到我们的问题 +您需要在 metal-cpp 对象 + +448 +00:23:10,190 --> 00:23:13,794 +和 Objective-C 对象之间进行转换 + +449 +00:23:13,794 --> 00:23:16,263 +如果所有权没有发生转移 + +450 +00:23:16,263 --> 00:23:18,732 +您可以使用 __bridge 转换 + +451 +00:23:18,732 --> 00:23:23,003 +如果您想将对象从 metal-cpp +转换为 Objective-C + +452 +00:23:23,003 --> 00:23:25,706 +并将所有权转移给 Objective-C + +453 +00:23:25,706 --> 00:23:29,076 +则应该使用 +__bridge_transfer 转换 + +454 +00:23:29,076 --> 00:23:32,446 +如果您想将对象从 Objective-C +转换为 metal-cpp + +455 +00:23:32,446 --> 00:23:34,915 +并从 ARC 中移出所有权 + +456 +00:23:34,915 --> 00:23:37,284 +则应该使用 +__bridge_retained 转换 + +457 +00:23:37,284 --> 00:23:40,087 +假设一个情景中 +我必须使用 MetalKit + +458 +00:23:40,087 --> 00:23:42,389 +来利用资产加载代码 + +459 +00:23:42,389 --> 00:23:45,492 +也就是说 在我的 C++ App 中 + +460 +00:23:45,492 --> 00:23:49,162 +我需要一个纹理 +来充当 metal-cpp 对象 + +461 +00:23:49,162 --> 00:23:53,467 +但它是由 Objective-C 方法创建的 + +462 +00:23:53,467 --> 00:23:57,137 +我需要想办法将所有权转出 ARC + +463 +00:23:57,137 --> 00:23:59,606 +方便我手动释放它 + +464 +00:23:59,606 --> 00:24:00,841 +在这种情况下 + +465 +00:24:00,841 --> 00:24:06,046 +我需要选用 +__bridge_retained 转移 + +466 +00:24:06,046 --> 00:24:10,017 +这有个从目录加载纹理的 C++ 函数 + +467 +00:24:10,017 --> 00:24:13,820 +我现在想返回一个 metal-cpp 纹理 + +468 +00:24:13,820 --> 00:24:16,823 +但在里面 我在 MetalKit 中调用了 + +469 +00:24:16,823 --> 00:24:19,760 +一些 Objective-C 函数 + +470 +00:24:19,760 --> 00:24:23,931 +我需要定义纹理加载器所需的选项 + +471 +00:24:23,931 --> 00:24:29,069 +接着 我通过从 MetalKit +调用 Objective-C 方法 + +472 +00:24:29,069 --> 00:24:31,171 +创建了一个纹理加载器 + +473 +00:24:31,171 --> 00:24:35,475 +有了加载器之后 +我可以创建一个纹理对象 + +474 +00:24:35,475 --> 00:24:38,378 +并从目录中加载纹理 + +475 +00:24:38,378 --> 00:24:41,348 +这个方法也属于 MetalKit 的 + +476 +00:24:41,348 --> 00:24:43,217 +Objective-C 方法 + +477 +00:24:43,217 --> 00:24:46,453 +现在 我有了一个 +Objective-C 类型的纹理 + +478 +00:24:46,453 --> 00:24:49,923 +我需要将其转换为 metal-cpp 对象 + +479 +00:24:49,923 --> 00:24:52,192 +并将其从 ARC 中取出 + +480 +00:24:52,192 --> 00:24:54,995 +将步骤都铭记于心后 +就可以动手编写代码了 + +481 +00:24:54,995 --> 00:24:58,665 +让我来展示一下桥式转换 +的工作原理吧 + +482 +00:24:58,665 --> 00:25:01,668 +第一步是定义纹理加载器需要的 + +483 +00:25:01,668 --> 00:25:03,904 +纹理加载器选项 + +484 +00:25:03,904 --> 00:25:07,808 +可以放心将 metal-cpp +存储模式和使用方法 + +485 +00:25:07,808 --> 00:25:09,743 +转换为 Objective-C 类型 + +486 +00:25:09,743 --> 00:25:13,947 +因为 metal-cpp 类型 +对它们的定义为相同值 + +487 +00:25:13,947 --> 00:25:16,850 +请看 我现在创建了一个纹理加载器 + +488 +00:25:16,850 --> 00:25:20,254 +我有了一个 metal-cpp 对象的设备 + +489 +00:25:20,254 --> 00:25:24,758 +现在需要将它传递 +给 initWithDevice 方法 + +490 +00:25:24,758 --> 00:25:28,962 +由于 metal-cpp 对象 +属于 Objective-C 对象 + +491 +00:25:28,962 --> 00:25:31,732 +因此可以像 toll-free 对象 +一样进行转换 + +492 +00:25:31,732 --> 00:25:35,202 +所有权没有进行转让 + +493 +00:25:35,202 --> 00:25:37,304 +现在我使用了纹理加载器选项 + +494 +00:25:37,304 --> 00:25:39,940 +和一个纹理加载器来创建纹理 + +495 +00:25:39,940 --> 00:25:44,478 +我想将加载的纹理 +作为 metal-cpp 对象返回 + +496 +00:25:44,478 --> 00:25:46,813 +因此 我需要将其转出 ARC + +497 +00:25:46,813 --> 00:25:50,617 +并转换为相应的指针类型 + +498 +00:25:50,617 --> 00:25:53,253 +可以通过 __bridge_retained +转换完成 + +499 +00:25:53,253 --> 00:25:55,289 +之后 我就可以将这个纹理 + +500 +00:25:55,289 --> 00:25:57,424 +作为任意 metal-cpp 对象 + +501 +00:25:57,424 --> 00:26:00,027 +我要负责释放该对象 + +502 +00:26:00,027 --> 00:26:03,931 +在本节视频 +我介绍了可以在您的程序中 + +503 +00:26:03,931 --> 00:26:06,433 +帮助您处理两种不同语言的 + +504 +00:26:06,433 --> 00:26:08,302 +适配器模式 + +505 +00:26:08,302 --> 00:26:13,040 +我还展示了如何通过 +三种类型的桥接转换 + +506 +00:26:13,040 --> 00:26:15,175 +实现 Objective-C 和 C++ 交互 + +507 +00:26:15,175 --> 00:26:18,712 +总的说来 metal-cpp +是一个非常高效的 + +508 +00:26:18,712 --> 00:26:22,583 +轻量级 Metal C++ 包装器 + +509 +00:26:22,583 --> 00:26:26,286 +我还介绍了 在使用 metal-cpp 时 + +510 +00:26:26,286 --> 00:26:29,022 +该如何管理对象生命周期 + +511 +00:26:29,022 --> 00:26:31,558 +又该如何用简便的方式 + +512 +00:26:31,558 --> 00:26:32,960 +与 Objective-C 交互 + +513 +00:26:32,960 --> 00:26:37,164 +以及我们的开发者工具 +能为您的调试提供哪些帮助 + +514 +00:26:37,164 --> 00:26:41,568 +请下载 metal-cpp +体验众多效果惊人的范例吧! + +515 +00:26:41,568 --> 00:26:44,204 +看看在 Metal 的辅助下 +您能做出怎样的创造 + +516 +00:26:44,204 --> 00:26:47,207 +我们期待能看到您的 C++ App + +517 +00:26:47,207 --> 00:26:49,576 +在所有 Apple 平台上运行 + +518 +00:26:49,576 --> 00:26:51,411 +感谢收看! + +519 +00:26:51,411 --> 00:26:55,616 +♪ + diff --git a/zho/2022 Session 10162 Transform your geometry with Metal mesh shaders.srt b/zho/2022 Session 10162 Transform your geometry with Metal mesh shaders.srt new file mode 100644 index 0000000..9ce7cf8 --- /dev/null +++ b/zho/2022 Session 10162 Transform your geometry with Metal mesh shaders.srt @@ -0,0 +1,1369 @@ +1 +00:00:01,034 --> 00:00:07,040 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:11,411 +大家好 我是 Andrei + +3 +00:00:11,445 --> 00:00:15,282 +是 Metal Frameworks 团队的 +GPU 软件工程师 + +4 +00:00:15,315 --> 00:00:19,686 +今天 我很高兴能为大家介绍 +我们新推出的 Metal 网格着色器 + +5 +00:00:19,720 --> 00:00:23,290 +网格着色器是 Metal 中 +全新灵活的管线 + +6 +00:00:23,323 --> 00:00:26,927 +可用于 GPU 驱动的 +几何元素生成和处理 + +7 +00:00:26,960 --> 00:00:31,231 +它可以提高顶点/片元管线 +增加灵活性 + +8 +00:00:31,265 --> 00:00:34,968 +消除顶点处理限制 + +9 +00:00:35,002 --> 00:00:38,605 +它有多重应用 包括但不限于 + +10 +00:00:38,639 --> 00:00:41,108 +细粒度几何裁剪 + +11 +00:00:41,141 --> 00:00:44,478 +GPU 上可扩展程序化几何体创建 + +12 +00:00:44,511 --> 00:00:47,080 +允许自定义几何输入 + +13 +00:00:47,114 --> 00:00:49,283 +如压缩顶点流 + +14 +00:00:49,316 --> 00:00:52,553 +meshlet 和复杂程序化算法 + +15 +00:00:52,586 --> 00:00:55,289 +这三点也是我今天想要分享的内容 + +16 +00:00:55,322 --> 00:00:59,359 +首先 我会介绍 +Metal 网格着色器是什么 + +17 +00:00:59,393 --> 00:01:03,430 +然后 我会为大家展示两个 +网格着色器的使用案例 + +18 +00:01:03,463 --> 00:01:06,800 +网格着色器对生成 +程序化几何体极为有效 + +19 +00:01:06,834 --> 00:01:09,102 +如渲染程式化头发 + +20 +00:01:09,136 --> 00:01:13,207 +网格着色器也可以帮助 +改善场景处理和渲染 + +21 +00:01:13,240 --> 00:01:15,909 +最常见的一个例子就是 +使用网格着色器 + +22 +00:01:15,943 --> 00:01:18,979 +来进行 GPU 驱动的 +meshlet 裁剪 + +23 +00:01:19,012 --> 00:01:21,348 +我们先介绍下网格着色器 + +24 +00:01:21,381 --> 00:01:23,383 +这个是 Stanford Bunny + +25 +00:01:23,417 --> 00:01:27,855 +代表了您在 GPU 上 +可以渲染的典型网格 + +26 +00:01:27,888 --> 00:01:31,458 +为了渲染该网格 顶点和索引数据 + +27 +00:01:31,491 --> 00:01:34,962 +首先要放入设备内存中 + +28 +00:01:34,995 --> 00:01:39,733 +然后 您要使用渲染指令编码器 +来执行绘制调用 + +29 +00:01:39,766 --> 00:01:44,304 +传统渲染管线包含三个基础阶段 + +30 +00:01:44,338 --> 00:01:49,176 +一个可编程的顶点着色阶段 +一个固定函数光栅化阶段 + +31 +00:01:49,209 --> 00:01:52,346 +以及一个可编程的片元着色阶段 + +32 +00:01:52,379 --> 00:01:54,848 +顶点着色阶段从设备内存中 +提取几何体 + +33 +00:01:54,882 --> 00:01:57,751 +作为输入并进一步处理 + +34 +00:01:57,784 --> 00:02:00,888 +光栅化程序生成屏幕空间片元 + +35 +00:02:00,921 --> 00:02:04,391 +片元着色器将其着色 +并生成最终图像 + +36 +00:02:04,424 --> 00:02:08,862 +这种管线自始至终都能 +很好地服务于这个目标 + +37 +00:02:08,896 --> 00:02:13,300 +然而 它缺乏灵活性且有一定的限制 + +38 +00:02:13,333 --> 00:02:15,335 +我们来看一个例子 + +39 +00:02:15,369 --> 00:02:19,606 +假设您想要在 GPU 上 +生成程序化几何体 + +40 +00:02:19,640 --> 00:02:25,179 +比如您决定在这个兔子上 +添加程序化毛发 + +41 +00:02:25,212 --> 00:02:30,117 +我给大家演示下传统几何管线中 +这个任务是如何完成的 + +42 +00:02:30,150 --> 00:02:33,487 +传统方法中 要生成程序化几何体 + +43 +00:02:33,520 --> 00:02:37,057 +您还要有计算指令编码器 + +44 +00:02:37,090 --> 00:02:40,627 +来调度计算内核 + +45 +00:02:40,661 --> 00:02:44,064 +计算内核将原始网格作为输入 + +46 +00:02:44,097 --> 00:02:49,036 +生成程序化几何体 +并将其输出存回设备内存 + +47 +00:02:49,069 --> 00:02:52,806 +然后 您可以使用渲染指令编码器 +来执行绘制调用 + +48 +00:02:52,840 --> 00:02:57,444 +将程序化几何体作为输入 +生成最终图像 + +49 +00:02:57,477 --> 00:03:00,547 +这一方法需要两个指令编码器 + +50 +00:03:00,581 --> 00:03:03,050 +且需要您分配额外内存 + +51 +00:03:03,083 --> 00:03:05,519 +来存储程序化几何体 + +52 +00:03:05,552 --> 00:03:09,056 +如果是间接绘制调用 +或扩散系数高的情况下 + +53 +00:03:09,089 --> 00:03:13,327 +该内存会非常高 且难以预测 + +54 +00:03:13,360 --> 00:03:18,799 +两个编码器之间还有一个屏障 +使 GPU 间的工作序列化 + +55 +00:03:18,832 --> 00:03:21,735 +Metal 网格着色器 +则可以解决以上所有问题 + +56 +00:03:21,768 --> 00:03:24,538 +网格着色器是一个 +全新的几何管线 + +57 +00:03:24,571 --> 00:03:29,209 +用两个可编程的新阶段 +替换了顶点着色阶段 + +58 +00:03:29,243 --> 00:03:32,179 +对象着色阶段和网格着色阶段 + +59 +00:03:32,212 --> 00:03:36,383 +在这个例子中 对象着色器 +将几何体作为输入 + +60 +00:03:36,416 --> 00:03:40,087 +对其进行处理 输出我们称为 +“payload” 的数据 + +61 +00:03:40,120 --> 00:03:41,955 +到网格着色器中 + +62 +00:03:41,989 --> 00:03:45,058 +该数据可由您自行决定 + +63 +00:03:45,092 --> 00:03:50,264 +网格着色器则会使用该数据 +来生成程序化几何体 + +64 +00:03:50,297 --> 00:03:54,635 +该程序化几何体仅在 +绘制调用中存在 + +65 +00:03:54,668 --> 00:03:58,338 +所以并不会要求您 +分配任何设备内存 + +66 +00:03:58,372 --> 00:04:02,075 +它是管线式的 直接到光栅化程序 + +67 +00:04:02,109 --> 00:04:06,613 +然后到片元着色器 +生成最终图像 + +68 +00:04:06,647 --> 00:04:10,517 +网格绘制调用使用 +与传统绘制调用一样类型的 + +69 +00:04:10,551 --> 00:04:12,819 +渲染指令编码器来运行 + +70 +00:04:12,853 --> 00:04:16,924 +网格绘制调用和传统绘制调用 +可以混合和匹配使用 + +71 +00:04:16,957 --> 00:04:20,527 +现在 我们来看下两个 +新的可编程阶段 + +72 +00:04:22,029 --> 00:04:23,964 +与顶点着色器相比 + +73 +00:04:23,997 --> 00:04:27,634 +对象和网格着色器 +都与计算内核相近 + +74 +00:04:27,668 --> 00:04:30,571 +它们是在线程组栅格中启动的 + +75 +00:04:30,604 --> 00:04:33,941 +每个线程组都是独立的线程栅格 + +76 +00:04:33,974 --> 00:04:37,878 +如同计算线程 它们可以相互沟通 + +77 +00:04:37,911 --> 00:04:41,949 +另外 每个对象线程组 +可以生成一个网格栅格 + +78 +00:04:41,982 --> 00:04:45,819 +以编程方式确定 +它启动网格栅格的大小 + +79 +00:04:45,853 --> 00:04:48,255 +提供足够的灵活性 + +80 +00:04:48,288 --> 00:04:53,293 +每个对象线程组将 payload 数据 +传送给它生成的网格栅格 + +81 +00:04:53,327 --> 00:04:57,231 +如其名称所示 +对象阶段处理的是对象 + +82 +00:04:57,264 --> 00:05:01,201 +对象是一个抽象的概念 +您可以根据需求来定义 + +83 +00:05:01,235 --> 00:05:04,705 +可以是场景模型 +场景模型的一部分 + +84 +00:05:04,738 --> 00:05:09,743 +比如 您想要生成程序化几何体的 +空间区域 + +85 +00:05:09,776 --> 00:05:12,546 +网格阶段的设计是为了搭建网格 + +86 +00:05:12,579 --> 00:05:15,516 +直接向光栅化程序 +发送几何体数据 + +87 +00:05:15,549 --> 00:05:19,987 +接下来两个例子能展示 +对象和网格之间的关系 + +88 +00:05:20,020 --> 00:05:23,657 +第一个使用了网格着色器 +来进行毛发渲染 + +89 +00:05:23,690 --> 00:05:28,262 +为了将任务简化一些 +我用了简易的平面 而不是兔子模型 + +90 +00:05:28,295 --> 00:05:32,432 +要生成一撮毛发 +我将输入几何体划分为分块 + +91 +00:05:32,466 --> 00:05:35,636 +每个分块会计算一层细节 + +92 +00:05:35,669 --> 00:05:38,405 +以及需要生成的发丝数量 + +93 +00:05:38,438 --> 00:05:41,742 +然后生成独立的发丝 + +94 +00:05:41,775 --> 00:05:45,112 +我为大家演示下如何在这个平面上 +用网格着色器 + +95 +00:05:45,145 --> 00:05:46,780 +程序化地生成毛发 + +96 +00:05:46,813 --> 00:05:49,016 +平面可以划分为分块 + +97 +00:05:49,049 --> 00:05:52,252 +每个分块对应一个对象线程组 + +98 +00:05:52,286 --> 00:05:55,722 +每个对象线程组可计算 +发丝数量 + +99 +00:05:55,756 --> 00:05:59,693 +为每根发丝生成曲线控制点 + +100 +00:05:59,726 --> 00:06:01,762 +这个会成为 payload + +101 +00:06:01,795 --> 00:06:04,765 +然后 我们的对象线程组 +启动网格栅格 + +102 +00:06:04,798 --> 00:06:08,202 +每个网格线程组代表一根发丝 + +103 +00:06:08,235 --> 00:06:11,538 +每个网格线程组输出网格 +到光栅化程序 + +104 +00:06:11,572 --> 00:06:14,308 +新的几何体管线让您可以 + +105 +00:06:14,341 --> 00:06:16,476 +将几何处理更紧密地映射到硬件 + +106 +00:06:16,510 --> 00:06:21,782 +并让您可以充分利用 +GPU 提供的所有线程 + +107 +00:06:21,815 --> 00:06:25,552 +在网格渲染管线中 +输入几何体按对象着色栅格 + +108 +00:06:25,586 --> 00:06:27,487 +划分分块 + +109 +00:06:27,521 --> 00:06:31,525 +每个对象着色线程组 +可以独立生成 payload + +110 +00:06:31,558 --> 00:06:33,260 +并启动网格栅格 + +111 +00:06:33,293 --> 00:06:37,464 +每个来自栅格的 +网格着色线程组生成 metal::mesh + +112 +00:06:37,497 --> 00:06:41,034 +它在剩余的渲染管线中 +被进一步处理 + +113 +00:06:41,068 --> 00:06:46,006 +我们仔细看看每个阶段 +生成的数据 + +114 +00:06:46,039 --> 00:06:48,709 +payload 在对象着色器中定义 + +115 +00:06:48,742 --> 00:06:51,245 +每个对象线程组 +向其生成的网格栅格 + +116 +00:06:51,278 --> 00:06:55,349 +传送到自定义 payload + +117 +00:06:55,382 --> 00:07:00,187 +如果渲染头发 payload 包含 +曲线控制点 + +118 +00:07:00,220 --> 00:07:03,924 +同时 网格着色器 +通过新的 metal::mesh 类型 + +119 +00:07:03,957 --> 00:07:08,795 +输出顶点和图元数据 +稍后我会详细解释 + +120 +00:07:09,963 --> 00:07:12,332 +对象和网格阶段输出接下来管线 + +121 +00:07:12,366 --> 00:07:15,369 +所需的网格数据 + +122 +00:07:15,402 --> 00:07:18,572 +与传统管线中的顶点输出相似 + +123 +00:07:18,605 --> 00:07:21,708 +光栅化程序首先处理网格数据 + +124 +00:07:21,742 --> 00:07:25,546 +然后执行片元着色器 + +125 +00:07:25,579 --> 00:07:30,184 +我们详细看下如何配置 +毛发渲染网格管线 + +126 +00:07:30,217 --> 00:07:34,755 +首先 将要用毛发覆盖的平面 +划分分块 + +127 +00:07:34,788 --> 00:07:38,025 +每个分块对应一个对象线程组 + +128 +00:07:38,058 --> 00:07:41,228 +对象线程组决定网格栅格大小 + +129 +00:07:41,261 --> 00:07:45,332 +将向网格传送的 +payload 数据初始化 + +130 +00:07:45,365 --> 00:07:50,771 +在这个情况下 该分块中有 6 根发丝 +与每根发丝的 + +131 +00:07:50,804 --> 00:07:53,740 +曲线 payload 数据一起 +生成 3x2 网格栅格 + +132 +00:07:54,408 --> 00:07:57,077 +每个线程组生成独特的 +网格栅格大小 + +133 +00:07:57,110 --> 00:07:59,913 +下一个线程组只需要生成 + +134 +00:07:59,947 --> 00:08:01,615 +4 根发丝 + +135 +00:08:01,648 --> 00:08:03,750 +所以与那 4 根发丝初始化的 + +136 +00:08:03,784 --> 00:08:07,654 +曲线 payload 数据一起 +所以设置 2x2 网格 + +137 +00:08:07,688 --> 00:08:11,592 +这就是这一实现方法的 +对象着色器 + +138 +00:08:11,625 --> 00:08:14,361 +object 属性已添加到 Metal 中 + +139 +00:08:14,394 --> 00:08:17,564 +以指定对象着色器的代码 + +140 +00:08:17,598 --> 00:08:21,235 +除了 payload 属性 +和 object_data 地址空间 + +141 +00:08:21,268 --> 00:08:24,738 +允许 payload 参数 +使用于着色器之外 + +142 +00:08:26,139 --> 00:08:31,378 +mesh_grid_properties 参数 +用于编码网格栅格大小 + +143 +00:08:31,411 --> 00:08:34,214 +下一步是管线初始化 + +144 +00:08:34,248 --> 00:08:38,018 +首先 分配网格渲染管线描述符 + +145 +00:08:38,051 --> 00:08:43,991 +然后初始化对象函数 +并制定所需的 payload 长度 + +146 +00:08:44,024 --> 00:08:47,494 +与每线程组的线程最大数量 + +147 +00:08:47,528 --> 00:08:50,430 +对象着色器上有一些限制 + +148 +00:08:50,464 --> 00:08:54,434 +Payload 格式和内容 +全部可以自定义 + +149 +00:08:54,468 --> 00:08:58,939 +然而 payload 大小不能超过 +16KB 的限值 + +150 +00:08:58,972 --> 00:09:01,542 +同时 每个对象线程组生成的 +网格线程组 + +151 +00:09:01,575 --> 00:09:06,013 +最大数量不能超过 1024 + +152 +00:09:06,046 --> 00:09:08,882 +对象着色阶段准备好后 +下一步就是 + +153 +00:09:08,916 --> 00:09:11,718 +初始化网格着色阶段 + +154 +00:09:11,752 --> 00:09:15,222 +网格着色器让用户定义 payload +以作为输入 + +155 +00:09:15,255 --> 00:09:19,860 +在这个例子中 +payload 是一套曲线控制点 + +156 +00:09:19,893 --> 00:09:22,529 +每个网格线程组 +生成一个 metal::mesh + +157 +00:09:22,563 --> 00:09:25,098 +也就是一根发丝 + +158 +00:09:25,132 --> 00:09:29,236 +网格着色器的输出网格 +必须有 metal::mesh 类型 + +159 +00:09:29,269 --> 00:09:33,640 +metal::mesh 是 Metal 中的内置结构 +可为您提供输出顶点和图元数据 + +160 +00:09:33,674 --> 00:09:38,879 +到光栅化程序 +和片元着色器的界面 + +161 +00:09:38,912 --> 00:09:43,784 +每个 metal::mesh 定义一个 +顶点数据类型 就像 + +162 +00:09:43,817 --> 00:09:45,319 +顶点着色器的输出类型 + +163 +00:09:45,352 --> 00:09:49,356 +一个图元数据类型 +顶点的最大数值 + +164 +00:09:49,389 --> 00:09:51,725 +图元的最大数值 + +165 +00:09:51,758 --> 00:09:57,364 +最后 网格拓扑 +不管是点 线还是三角 + +166 +00:09:57,397 --> 00:10:00,968 +Metal 着色语言通过增加的 +mesh 属性 + +167 +00:10:01,001 --> 00:10:04,004 +指定什么代码是网格着色器 + +168 +00:10:04,037 --> 00:10:07,841 +metal::mesh 用于 +网格着色器中的输出结构 + +169 +00:10:09,943 --> 00:10:13,213 +网格着色器对 GPU 驱动的 +几何体处理很有效 + +170 +00:10:13,247 --> 00:10:15,849 +因为它们能让您动态 +生成这些 metal::mesh + +171 +00:10:15,883 --> 00:10:18,318 +用于光栅化程序 + +172 +00:10:18,352 --> 00:10:21,455 +网格着色器用 metal::mesh +作为其优势 + +173 +00:10:21,488 --> 00:10:24,324 +这样您可以在处理过程中 +加入更多渲染指令 + +174 +00:10:24,358 --> 00:10:27,027 +而无需额外计算通道 + +175 +00:10:27,060 --> 00:10:31,265 +编码网格在同一个线程组的 +线程之间完成 + +176 +00:10:31,298 --> 00:10:35,836 +在这个例子中 线程组的 +前 9 条线程可以编码发丝的顶点 + +177 +00:10:35,869 --> 00:10:39,873 +索引和图元数据 + +178 +00:10:39,907 --> 00:10:45,279 +线程 0 到 4 每个都在网格中 +编码一个顶点 + +179 +00:10:45,312 --> 00:10:50,017 +线程组中的剩余线程 +不编码网格中的顶点 + +180 +00:10:50,050 --> 00:10:55,355 +接下来 所有 9 条线程将 1 条索引 +编码到网格目录中 + +181 +00:10:57,291 --> 00:11:03,697 +接下来 前 3 条线程 +为 3 个三角形编码图元数据 + +182 +00:11:03,730 --> 00:11:07,234 +剩余的线程不编码任何 +图元数据 + +183 +00:11:07,267 --> 00:11:12,940 +最后 1 条线程会为网格 +编码图元数量 + +184 +00:11:12,973 --> 00:11:16,076 +我为大家演示下 +这个网格着色器的源代码 + +185 +00:11:16,109 --> 00:11:19,780 +网格着色器会组织为 +尽可能避免 + +186 +00:11:19,813 --> 00:11:23,283 +线程间的分化 遵循顶点 + +187 +00:11:23,317 --> 00:11:26,486 +索引和图元数据的编码步骤 + +188 +00:11:26,520 --> 00:11:28,856 +最后是图元数量的步骤 + +189 +00:11:30,858 --> 00:11:34,394 +我们回到初始化网格管线 +描述符 + +190 +00:11:34,428 --> 00:11:37,764 +网格管线描述符设置了 +网格函数 + +191 +00:11:37,798 --> 00:11:41,301 +和每网格线程组的最大线程 + +192 +00:11:41,335 --> 00:11:45,239 +metal::mesh 结构有一些 +限制是需要严守的 + +193 +00:11:45,272 --> 00:11:47,841 +Metal 的网格着色器 +有以下限制 + +194 +00:11:47,875 --> 00:11:54,414 +Metal::mesh 支持高达 256 个顶点 +以及高达 512 个图元 + +195 +00:11:54,448 --> 00:11:58,352 +metal::mesh 总大小 +不可超过 16KB + +196 +00:11:58,385 --> 00:12:01,255 +现在网格栅格 +已经生成 metal::mesh + +197 +00:12:01,288 --> 00:12:06,493 +它们随后会被带到光栅化程序中 +最后运行片元着色器 + +198 +00:12:06,527 --> 00:12:09,530 +所以 与传统渲染管线类似 + +199 +00:12:09,563 --> 00:12:13,066 +片元函数在网格管线 +描述符上设置 + +200 +00:12:13,100 --> 00:12:15,502 +初始化描述符后 + +201 +00:12:15,536 --> 00:12:18,572 +管线状态已通过 + +202 +00:12:18,605 --> 00:12:22,209 +makeRenderPipelineState(descriptor:) 方法 + +203 +00:12:22,242 --> 00:12:23,744 +在 Metal 设备创建 + +204 +00:12:23,777 --> 00:12:29,082 +编码网格管线和编码 +传统绘制调用很接近 + +205 +00:12:29,116 --> 00:12:31,718 +管线在编码器上设置 + +206 +00:12:31,752 --> 00:12:34,788 +管线的每个阶段都有资源绑定 + +207 +00:12:34,821 --> 00:12:38,258 +在这个例子中 绑定资源有 + +208 +00:12:38,292 --> 00:12:40,861 +对象阶段的对象缓冲区 + +209 +00:12:40,894 --> 00:12:42,629 +网格阶段的纹理 + +210 +00:12:42,663 --> 00:12:46,667 +片元阶段的片元缓冲区 + +211 +00:12:46,700 --> 00:12:51,872 +接下来 我定义几个启动 +网格管线所需的常量 + +212 +00:12:51,905 --> 00:12:54,141 +对象栅格尺寸 + +213 +00:12:54,174 --> 00:12:56,643 +每对象线程组的线程数量 + +214 +00:12:56,677 --> 00:12:59,546 +每网格线程组的线程数量 + +215 +00:12:59,580 --> 00:13:02,149 +以及通过新的 +drawMeshThreadgroups 方法 + +216 +00:13:02,182 --> 00:13:04,718 +使用这些常量来编码绘制 + +217 +00:13:04,751 --> 00:13:07,754 +用于渲染平面毛发的相同方法 + +218 +00:13:07,788 --> 00:13:09,823 +可以应用到整个兔子上 + +219 +00:13:09,857 --> 00:13:13,360 +通过网格管线 +程序化地生成毛发 + +220 +00:13:13,393 --> 00:13:16,630 +接下来 我们看下使用 +网格着色器的另一种方法 + +221 +00:13:16,663 --> 00:13:19,233 +网格着色器可以用 +Meshlet 裁剪高效处理 + +222 +00:13:19,266 --> 00:13:23,003 +以及渲染大量几何体 + +223 +00:13:23,036 --> 00:13:26,373 +这一技术的基础就在于 +将场景网格划分为 + +224 +00:13:26,406 --> 00:13:28,909 +称为 meshlet 的小块 + +225 +00:13:33,213 --> 00:13:36,884 +将场景几何体划分为 meshlet +增加了场景的粒度 + +226 +00:13:36,917 --> 00:13:39,753 +可以执行更高效 更深入的裁剪 + +227 +00:13:39,786 --> 00:13:42,856 +这也可以极大地减少 +几何体开销 + +228 +00:13:42,890 --> 00:13:44,858 +利用 meshlet 粒度处理 + +229 +00:13:44,892 --> 00:13:47,594 +可允许高效的遮挡和裁剪算法 + +230 +00:13:47,628 --> 00:13:51,632 +如屏幕空间遮挡裁剪 +和法线过滤程序 + +231 +00:13:51,665 --> 00:13:54,835 +您可以使用网格着色器 +来执行全 GPU 驱动的裁剪 + +232 +00:13:54,868 --> 00:13:56,069 +和渲染管线 + +233 +00:13:56,937 --> 00:13:59,873 +这是传统 GPU 驱动的管线 + +234 +00:13:59,907 --> 00:14:02,476 +可用一种计算和一条渲染通道 + +235 +00:14:02,509 --> 00:14:05,779 +运行场景处理和渲染 + +236 +00:14:05,812 --> 00:14:07,748 +该场景数据可划分为 meshlet + +237 +00:14:07,781 --> 00:14:10,150 +并用于计算通道 + +238 +00:14:10,184 --> 00:14:12,853 +从而负责视锥体剔除 + +239 +00:14:12,886 --> 00:14:14,188 +LOD 选择 + +240 +00:14:14,221 --> 00:14:17,157 +以及将绘制编码到设备内存中 + +241 +00:14:17,191 --> 00:14:20,561 +然后渲染通道为场景 +执行绘制指令 + +242 +00:14:20,594 --> 00:14:23,030 +然后生成最终图像 + +243 +00:14:23,063 --> 00:14:27,334 +通过使用网格着色器 +可以移除同步点 + +244 +00:14:27,367 --> 00:14:31,138 +通过将两条通道 +合并到一个网格着色分发 + +245 +00:14:31,171 --> 00:14:33,607 +避免中间绘制指令 + +246 +00:14:33,640 --> 00:14:35,375 +我为大家演示下操作过程 + +247 +00:14:35,409 --> 00:14:37,878 +这是单一渲染通道 + +248 +00:14:37,911 --> 00:14:39,947 +可执行网格着色分发 + +249 +00:14:39,980 --> 00:14:42,149 +对象着色器运行视锥体剔除 + +250 +00:14:42,182 --> 00:14:45,586 +为每个可见的 meshlet +计算 LOD + +251 +00:14:45,619 --> 00:14:50,257 +网格着色器的 payload 是 +应编码的 meshlet IDs 列表 + +252 +00:14:50,290 --> 00:14:53,527 +然后 网格着色器编码用于光栅化 + +253 +00:14:53,560 --> 00:14:55,863 +和着色的 metal::mesh 对象 + +254 +00:14:55,896 --> 00:14:58,465 +然后最终图像在 +片元着色器中着色 + +255 +00:14:58,498 --> 00:15:00,801 +与传统管线一样 + +256 +00:15:00,834 --> 00:15:02,536 +几何体处理完全在 + +257 +00:15:02,569 --> 00:15:04,304 +网格线程组指令内 + +258 +00:15:04,338 --> 00:15:05,973 +和单一编码器内完成 + +259 +00:15:06,006 --> 00:15:08,242 +不再需要通过中间缓冲区 + +260 +00:15:08,275 --> 00:15:09,810 +存储这些绘制指令 + +261 +00:15:09,843 --> 00:15:12,746 +因为三角形数据 +会通过网格着色器编码 + +262 +00:15:13,881 --> 00:15:15,983 +我们现在来看下裁剪 + +263 +00:15:16,016 --> 00:15:19,152 +尤其是 meshlet 裁剪的执行 + +264 +00:15:19,186 --> 00:15:22,956 +该场景包含代表模型的形状 + +265 +00:15:22,990 --> 00:15:27,628 +在这个操作中 场景的每个模型 +都会变成对象栅格的一部分 + +266 +00:15:27,661 --> 00:15:30,564 +网格栅格由对象着色线程组生成 + +267 +00:15:30,597 --> 00:15:32,299 +包含 meshlet + +268 +00:15:32,332 --> 00:15:35,636 +模型表面的三角小块 + +269 +00:15:35,669 --> 00:15:38,038 +新的几何体管线灵活性很高 + +270 +00:15:38,071 --> 00:15:41,708 +您可以选择如何将场景 +映射到对象栅格上 + +271 +00:15:41,742 --> 00:15:45,379 +在这个例子中 我将每个模型 +都映射到对象线程组上 + +272 +00:15:45,412 --> 00:15:48,982 +但您可以使用更符合 +您任务所需的映射 + +273 +00:15:49,016 --> 00:15:51,919 +现在 对象着色器可以用视锥 + +274 +00:15:51,952 --> 00:15:53,554 +来确定 meshlet 的可见性 + +275 +00:15:53,587 --> 00:15:58,058 +只分派在最终图像上可显示的内容 + +276 +00:15:58,091 --> 00:16:00,794 +我们来看场景中的两个模型 + +277 +00:16:00,827 --> 00:16:04,498 +对象着色器基于确定的 +可见度来启动网格栅格 + +278 +00:16:04,531 --> 00:16:09,570 +然后 网格着色器处理 meshlet +并构建 metal::mesh + +279 +00:16:09,603 --> 00:16:12,773 +可编程的网格栅格大小 +可以灵活调度 + +280 +00:16:12,806 --> 00:16:16,410 +所以只有可见的 meshlet +能经由网格着色器处理 + +281 +00:16:16,443 --> 00:16:21,315 +这可以减少在后续管线中 +处理不可见几何体的时间 + +282 +00:16:21,348 --> 00:16:25,485 +固定函数光栅化程序只接收 +可见的表面 + +283 +00:16:25,519 --> 00:16:27,621 +而且可以减少处理和裁剪 + +284 +00:16:27,654 --> 00:16:29,957 +不可见几何体的时间 + +285 +00:16:30,791 --> 00:16:35,262 +最后 可编程片元着色器被调用 +生成最终图像 + +286 +00:16:35,996 --> 00:16:38,465 +如您所见 新几何体管线 +可供您处理 + +287 +00:16:38,498 --> 00:16:41,101 +各种不同的问题 + +288 +00:16:41,134 --> 00:16:45,439 +如创建程序化网格 +或让您的绘制调用更高效 + +289 +00:16:45,472 --> 00:16:48,308 +正如这个 meshlet 裁剪样本 +展示的一样 + +290 +00:16:48,342 --> 00:16:52,346 +Metal 现在包含了创新灵活的 +全新几何体管线 + +291 +00:16:52,379 --> 00:16:56,283 +创建程序化几何更为简单 + +292 +00:16:56,316 --> 00:16:59,253 +正如头发渲染例子演示的一样 + +293 +00:16:59,286 --> 00:17:02,489 +另外 单一渲染通道中 +GPU 驱动的 + +294 +00:17:02,523 --> 00:17:04,691 +工作可能性得以扩展 + +295 +00:17:04,725 --> 00:17:08,529 +无需额外计算通道或中间缓冲区 + +296 +00:17:08,562 --> 00:17:10,964 +正如在 meshlet 裁剪 demo 中 +看到的一样 + +297 +00:17:11,899 --> 00:17:16,270 +这个全新的几何体管线 +在 Family7 和 Mac2 设备中均可用 + +298 +00:17:18,138 --> 00:17:21,575 +为了帮助您开始 +网格着色器的学习和操作 + +299 +00:17:21,608 --> 00:17:24,344 +Apple 开发者网站 +有示例代码 + +300 +00:17:24,378 --> 00:17:27,080 +展示了如何使用新的 API + +301 +00:17:27,114 --> 00:17:29,583 +我很期待看到您 +如何使用这一功能 + +302 +00:17:29,616 --> 00:17:32,853 +利用 Apple GPU 强大的并行性 + +303 +00:17:32,886 --> 00:17:35,022 +来适应您几何体处理的需求 + +304 +00:17:35,055 --> 00:17:36,857 +感谢收看 + diff --git a/zho/2022 Session 102 Platforms State of the Union.srt b/zho/2022 Session 102 Platforms State of the Union.srt new file mode 100644 index 0000000..f003294 --- /dev/null +++ b/zho/2022 Session 102 Platforms State of the Union.srt @@ -0,0 +1,5625 @@ +1 +00:00:00,334 --> 00:00:07,574 +♪ ♪ + +2 +00:00:09,243 --> 00:00:17,251 +♪ ♪ + +3 +00:00:22,356 --> 00:00:27,861 +欢迎来到 WWDC 2022 +State of the Union + +4 +00:00:27,895 --> 00:00:31,498 +我们总是兴奋地迎接 WWDC +因为它提供了非常好的契机 + +5 +00:00:31,532 --> 00:00:33,600 +让我们可以与你们所有人沟通 + +6 +00:00:33,634 --> 00:00:35,602 +分享我们最近的工作进展 + +7 +00:00:35,636 --> 00:00:39,940 +以及更好地理解 +你们需要我们的开发者平台提供什么 + +8 +00:00:39,973 --> 00:00:43,477 +你们作为开发者所做的工作太了不起了 + +9 +00:00:43,510 --> 00:00:48,015 +你们将奇思妙想变成现实 + +10 +00:00:48,048 --> 00:00:51,585 +将用户体验推向新高度 + +11 +00:00:51,618 --> 00:00:55,455 +而我们想帮助大家 +让你们的想法走得更远 + +12 +00:00:55,489 --> 00:00:58,592 +我们已经在 Keynote 主题演讲中涵盖了 + +13 +00:00:58,625 --> 00:01:02,296 +iPhone、iPad、Mac、Apple Watch +和 Apple TV 上的一些新功能 + +14 +00:01:02,329 --> 00:01:05,265 +还有 Apple 芯片令人难以置信的强大性能 + +15 +00:01:05,299 --> 00:01:09,069 +助力大家把最有雄心的想法变为现实 + +16 +00:01:09,102 --> 00:01:13,240 +我们今天要讲的内容很多 +首先来讲一些更新 + +17 +00:01:13,273 --> 00:01:17,678 +今年早些时候 我们开启了全新的 +Apple Developer Center + +18 +00:01:17,711 --> 00:01:20,981 +让大家和 Apple 的工程师和设计师 + +19 +00:01:21,014 --> 00:01:24,484 +一起沟通与协作 +且就在 Apple Park + +20 +00:01:24,518 --> 00:01:28,455 +去年秋天 +有成千上万跟你们一样的开发者在世界各地 + +21 +00:01:28,488 --> 00:01:30,657 +参加了我们全新的线上 Tech Talks + +22 +00:01:30,691 --> 00:01:36,463 +我们用 5 种语言在线直播了 +来自 11 个国家的数百场现场活动 + +23 +00:01:36,496 --> 00:01:38,899 +对我们来说 +Tech Talks 系列最棒的地方之一 + +24 +00:01:38,932 --> 00:01:40,300 +就是一对一会面 + +25 +00:01:40,334 --> 00:01:43,871 +这给我们提供了绝佳的机会 +了解大家的工作 + +26 +00:01:43,904 --> 00:01:46,773 +分享一些建议和指导 + +27 +00:01:46,807 --> 00:01:49,343 +去年秋季我们推出了 +Swift Playgrounds 4 + +28 +00:01:49,376 --> 00:01:53,247 +让大家有能力可以构建 app +并直接提交至 App Store + +29 +00:01:53,280 --> 00:01:55,148 +还提供了对 SwiftUI 的支持 + +30 +00:01:55,182 --> 00:01:59,653 +使其成为用于测试 +和 UI 原型设计的绝佳工具 + +31 +00:01:59,686 --> 00:02:02,489 +当然还有 Xcode Cloud + +32 +00:02:02,523 --> 00:02:04,124 +我们打造 Xcode Cloud 是为了帮助大家 + +33 +00:02:04,157 --> 00:02:07,294 +更快更容易地打造更好的 app + +34 +00:02:07,327 --> 00:02:09,630 +它是一项持续集成与交付服务 + +35 +00:02:09,663 --> 00:02:14,234 +且内置于 Xcode 采用云托管 + +36 +00:02:14,268 --> 00:02:18,205 +Xcode Cloud 支持所有 Apple 平台的开发 + +37 +00:02:18,238 --> 00:02:21,141 +它集成了 TestFlight 和 +App Store Connect + +38 +00:02:21,175 --> 00:02:24,545 +以及所有主要基于 Git 的源代码提供程序 + +39 +00:02:24,578 --> 00:02:30,150 +它甚至拥有各种 REST API +协助联结开发过程中的其他方面 + +40 +00:02:30,184 --> 00:02:34,121 +并保有高度的安全性 +来保护着你和你的项目 + +41 +00:02:34,154 --> 00:02:36,523 +我非常高兴地宣布 + +42 +00:02:36,557 --> 00:02:41,595 +Xcode Cloud 从今天起正式推出 + +43 +00:02:41,628 --> 00:02:43,997 +我们认为几乎每个开发团队 + +44 +00:02:44,031 --> 00:02:45,699 +都能从 Xcode Cloud 获益 + +45 +00:02:45,732 --> 00:02:49,937 +因此我们将其定价置在 +所有规模的开发者都可以使用的水平 + +46 +00:02:49,970 --> 00:02:53,340 +我们将提供每月 25 小时的订阅 + +47 +00:02:53,373 --> 00:02:56,610 +给所有 Apple Developer +Program 用户免费使用 + +48 +00:02:56,643 --> 00:02:59,179 +持续到 2023 年底 + +49 +00:02:59,213 --> 00:03:04,885 +大家还可以从 Developer app 中 +订阅任意一级 Xcode Cloud 服务 + +50 +00:03:04,918 --> 00:03:06,353 +今夏晚些时候推出 + +51 +00:03:06,386 --> 00:03:10,791 +今天 我们要来谈三大主题 + +52 +00:03:10,824 --> 00:03:15,829 +首先 我们想分享一下 +我们对 Apple 平台开发的愿景 + +53 +00:03:15,863 --> 00:03:19,666 +我们平台目前现状 +以及我们未来前进的方向 + +54 +00:03:19,700 --> 00:03:22,135 +然后 我们会分享一些激动人心的新方式 + +55 +00:03:22,169 --> 00:03:26,507 +让你开发的各种 app 与 Apple 平台的系统体验 +相互整合 + +56 +00:03:26,540 --> 00:03:30,310 +最后 我们要讨论各种强大的全新 API + +57 +00:03:30,344 --> 00:03:34,882 +并向大家展示它们可以如何 +帮助你的 app 实现更强大的功能 + +58 +00:03:34,915 --> 00:03:37,851 +首先看看我们对开发者平台的愿景 + +59 +00:03:37,885 --> 00:03:39,419 +以及它是如何持续进化的 + +60 +00:03:39,453 --> 00:03:42,456 +下面请 Josh 为你介绍 + +61 +00:03:43,323 --> 00:03:46,560 +优秀的开发者平台可以提供 + +62 +00:03:46,593 --> 00:03:49,696 +不同编程语言、框架和工具间的深度整合 + +63 +00:03:49,730 --> 00:03:52,232 +当三者完全相辅相成时 + +64 +00:03:52,266 --> 00:03:54,868 +我们就可以确保 +常见的任务可以轻松完成 + +65 +00:03:54,902 --> 00:03:57,137 +并且将实现不常见的任务也变为可能 + +66 +00:03:57,738 --> 00:04:01,175 +把这点做好 +可以缩短开发一款优质 app 要走的路 + +67 +00:04:01,208 --> 00:04:03,210 +并造福所有人 + +68 +00:04:03,243 --> 00:04:05,946 +用户可以获得一致的体验 + +69 +00:04:05,979 --> 00:04:08,715 +就像总是感觉到顺滑的滚动浏览 + +70 +00:04:08,749 --> 00:04:13,420 +而你也可以把时间和精力 +专注在构建你的 app 与众不同的地方 + +71 +00:04:13,453 --> 00:04:16,456 +随着设计的演变 +以及硬件的持续发展 + +72 +00:04:16,490 --> 00:04:20,360 +过去的前沿技术在今天变成了基础 + +73 +00:04:20,394 --> 00:04:23,864 +Objective-C 语言 +AppKit 和 UIKit 框架 + +74 +00:04:23,897 --> 00:04:27,801 +以及 Interface Builder +已经赋能多代开发者 + +75 +00:04:27,835 --> 00:04:30,370 +这些技术是为彼此而构建的 + +76 +00:04:30,404 --> 00:04:33,707 +并将在未来很长的一段时间内 +继续为我们提供良好的服务 + +77 +00:04:33,740 --> 00:04:37,411 +但随着时间推移 +新的抽象成为了必要 + +78 +00:04:37,444 --> 00:04:40,581 +过去一段时间 +大家已经看到我们在很努力地定义 + +79 +00:04:40,614 --> 00:04:44,985 +下一代紧密集成的语言、框架和工具 + +80 +00:04:45,018 --> 00:04:48,889 +这就是 Swift、SwiftUI 和 +Xcode Previews + +81 +00:04:49,857 --> 00:04:52,459 +在这样的开发平台上紧密集成 + +82 +00:04:52,492 --> 00:04:56,363 +需要这三部分一同设计和演变 + +83 +00:04:56,396 --> 00:04:59,466 +并相互驱动、带动 + +84 +00:04:59,499 --> 00:05:04,771 +Swift Result Builder 的灵感 +来自于 SwiftUI 的组成结构 + +85 +00:05:04,805 --> 00:05:09,910 +SwiftUI 的声明式视图 +背靠 Swift 值类型 + +86 +00:05:09,943 --> 00:05:15,716 +而 Xcode Previews 是专门为这两者而设计 +也是依靠这两者运行的 + +87 +00:05:15,749 --> 00:05:19,920 +他们之间相辅相成 +带来了我们迄今最优秀的开发平台 + +88 +00:05:19,953 --> 00:05:25,425 +今年 Swift、SwiftUI 和 Xcode +都有精彩的更新 + +89 +00:05:25,459 --> 00:05:27,461 +进一步实现我们的愿景 + +90 +00:05:27,494 --> 00:05:31,765 +让大家更容易地开发出色的 app +并适用于我们所有的软件平台 + +91 +00:05:31,798 --> 00:05:33,934 +而这一切都要从 Swift 开始 + +92 +00:05:33,967 --> 00:05:37,738 +现在请 Swift 团队的 Ben 为大家介绍 + +93 +00:05:39,907 --> 00:05:47,915 +♪ ♪ + +94 +00:05:49,650 --> 00:05:52,920 +Swift 具备了快速、现代与安全的特性 + +95 +00:05:52,953 --> 00:05:55,956 +它结合了强类型语言的速度 + +96 +00:05:55,989 --> 00:05:58,992 +以及易于阅读和编写的表达式语法 + +97 +00:05:59,026 --> 00:06:02,963 +它的设计消除了多种类别的编程错误 + +98 +00:06:02,996 --> 00:06:07,067 +Swift 绝对是在我们各个设备上 +开发 app 的最佳语言 + +99 +00:06:07,901 --> 00:06:09,536 +Swift 以开源形式在 Swift.org 上开发而成 + +100 +00:06:09,570 --> 00:06:13,407 +Swift.org 上有很棒的贡献者 + +101 +00:06:13,440 --> 00:06:15,209 +他们通过 Diversity in Swift + +102 +00:06:15,242 --> 00:06:18,212 +和 Swift Mentorship Program +等倡议互相支持 + +103 +00:06:18,245 --> 00:06:21,515 +并推动 Swift 的发展 +通过相关主题工作小组 + +104 +00:06:21,548 --> 00:06:24,384 +如 Swift on Server +和 C++ 互操作性等 + +105 +00:06:25,352 --> 00:06:27,921 +在过去一年 Swift 变得更加优秀 + +106 +00:06:27,955 --> 00:06:30,224 +包括增强了并发功能 + +107 +00:06:30,257 --> 00:06:33,260 +还推出了让 Swift 更易于读写的升级 + +108 +00:06:33,293 --> 00:06:35,329 +帮你定制工作流的工具 + +109 +00:06:35,362 --> 00:06:37,931 +以及惊人的后台性能提升 + +110 +00:06:37,965 --> 00:06:39,466 +这一切始于去年 + +111 +00:06:39,499 --> 00:06:41,535 +我们推出 Swift 并发功能的时候 + +112 +00:06:42,169 --> 00:06:47,307 +Swift 并发功能 +极大地简化了并行运行代码的读写 + +113 +00:06:47,341 --> 00:06:50,777 +仅第一年就在 App Store 中获得 +超过 40000 个 app 采用 + +114 +00:06:50,811 --> 00:06:52,779 +这可说是一项巨大的成就 + +115 +00:06:53,247 --> 00:06:57,918 +因为这对你的 app 代码库来说 +是一项根本且重要的提升 + +116 +00:06:57,951 --> 00:07:00,420 +所以现在可以将具有 Swift 并发的代码 + +117 +00:07:00,454 --> 00:07:04,424 +部署到过去三年内发布的 +所有操作系统上 + +118 +00:07:04,458 --> 00:07:08,529 +Swift 并发功能还带来了异步序列 + +119 +00:07:08,562 --> 00:07:11,231 +今年更为大家带来了全新的开源包 + +120 +00:07:11,265 --> 00:07:15,569 +将为 Swift 丰富的现有序列算法 +带来并发支持 + +121 +00:07:15,602 --> 00:07:17,938 +这称为异步算法 + +122 +00:07:17,971 --> 00:07:23,410 +例如 Swift 的序列协议支持 zip 算法 +可将两个序列组合在一起 + +123 +00:07:23,443 --> 00:07:28,081 +而异步算法则可以 +将两个异步序列组合在一起 + +124 +00:07:28,115 --> 00:07:31,885 +因为异步序列是直接集成在 Swift 语言中 + +125 +00:07:31,919 --> 00:07:34,755 +所以它们使用的是如“for”循环 +为大家所熟悉的结构 + +126 +00:07:34,788 --> 00:07:36,823 +而由于有 async/await 语法 + +127 +00:07:36,857 --> 00:07:38,825 +这看起来就像普通的直线代码 + +128 +00:07:38,859 --> 00:07:42,496 +你还可以使用熟悉的 try/catch 匹配符 +处理问题 + +129 +00:07:42,529 --> 00:07:46,633 +如网络上异步数据流的网络故障 + +130 +00:07:46,667 --> 00:07:49,369 +异步序列的一个关键之处在于 + +131 +00:07:49,403 --> 00:07:52,206 +它们是如何随着时间的推移传递数据值 + +132 +00:07:52,739 --> 00:07:57,311 +Swift 现在包含一套新的时钟类型 +用于表示时间单位 + +133 +00:07:57,344 --> 00:08:01,682 +而异步算法则在此基础上 +提供多种基于时间的算法 + +134 +00:08:01,715 --> 00:08:03,183 +就像这里的 throttle + +135 +00:08:03,217 --> 00:08:06,787 +可以减慢序列的更新 + +136 +00:08:06,820 --> 00:08:11,191 +Swift 的并发模型旨在让异步代码 + +137 +00:08:11,225 --> 00:08:13,961 +像同步代码一样简便且安全地进行编写 + +138 +00:08:13,994 --> 00:08:16,864 +其中很重要的一部分是 +Swift 的 actor 模型 + +139 +00:08:16,897 --> 00:08:19,800 +actor 让你可以使用线程安全 + +140 +00:08:19,833 --> 00:08:23,337 +并发执行的代码隔离数据 + +141 +00:08:23,370 --> 00:08:27,741 +Swift 可防止你意外于并行线程之间分享该状态 + +142 +00:08:27,774 --> 00:08:30,310 +定义一个主要的错误来源 + +143 +00:08:31,211 --> 00:08:35,649 +通过 async/await 即可简单高效地 +在不同 actors 之间传递信息 + +144 +00:08:35,682 --> 00:08:39,453 +现在 Swift 通过 +distributed actors + +145 +00:08:39,486 --> 00:08:41,221 +让 actor 隔离更进一步 + +146 +00:08:41,255 --> 00:08:45,859 +distributed actors 可在多个进程 +或设备间通信 + +147 +00:08:45,893 --> 00:08:48,929 +用“distributed”关键词标记 + +148 +00:08:48,962 --> 00:08:51,431 +那些可以远程访问的 actors 和方法 + +149 +00:08:51,465 --> 00:08:54,535 +无论是在你 Mac 上的独立进程之间 + +150 +00:08:54,568 --> 00:08:56,904 +还是不同设备间的点对点通信 + +151 +00:08:56,937 --> 00:09:00,541 +亦或者是从一个设备 +与你用 Swift on Server 编写的后端对话 + +152 +00:09:01,909 --> 00:09:06,079 +就像 actor 可以帮助 Swift +按照指定顺序访问你的数据来访问它们 + +153 +00:09:06,113 --> 00:09:09,349 +distributed actors +使用一种可插拔运输机制 + +154 +00:09:09,383 --> 00:09:12,553 +帮助 Swift 让数据在跨进程的场景可用 + +155 +00:09:12,819 --> 00:09:15,622 +Swift 编译器随后可以执行检查 + +156 +00:09:15,656 --> 00:09:19,159 +确保 distributed 环境中的行为是正确的 + +157 +00:09:19,193 --> 00:09:22,863 +让你可以继续开发你想要的功能 + +158 +00:09:23,297 --> 00:09:26,400 +distributed actors +和其他并发功能显示出 + +159 +00:09:26,433 --> 00:09:29,870 +Swift 代码的读写可以多么容易 + +160 +00:09:29,903 --> 00:09:33,106 +当增强功能被深度整合在语法中时 + +161 +00:09:33,140 --> 00:09:38,645 +下面由 Ken 来给大家介绍 +Swift 易用性的增强 + +162 +00:09:38,679 --> 00:09:42,316 +字符串是任何编程语言中 +最重要的功能之一 + +163 +00:09:42,349 --> 00:09:45,652 +但处理字符串可能会 +常常让人感到沮丧 + +164 +00:09:46,453 --> 00:09:48,322 +在开发者的工作中 + +165 +00:09:48,355 --> 00:09:53,260 +可能会碰到需要从类似这样的字符串中 +提取信息的时候 + +166 +00:09:53,293 --> 00:09:56,797 +编写解析字符串的代码很容易出错 + +167 +00:09:56,830 --> 00:09:58,799 +需要追踪很多细节 + +168 +00:09:58,832 --> 00:10:01,935 +而且最后生成的代码 +很难读懂及修改 + +169 +00:10:02,803 --> 00:10:06,473 +正则表达式是应对这一挑战的 +强大解决方式 + +170 +00:10:06,507 --> 00:10:09,810 +让你可以描述你期望在字符串中 +看到的匹配符 + +171 +00:10:09,843 --> 00:10:13,914 +并说明你想抓取哪些信息 + +172 +00:10:13,947 --> 00:10:20,387 +今年 Swift 将大幅提升 +有关正则表达式的开发者体验 + +173 +00:10:20,420 --> 00:10:23,390 +首先是推出一个 +全新的正则表达式字面值 + +174 +00:10:24,558 --> 00:10:26,393 +它们直接内置于语言当中 + +175 +00:10:26,426 --> 00:10:28,862 +Swift 编译器可以检查其是否正确 + +176 +00:10:28,896 --> 00:10:31,665 +在你用正则表达式提取信息时 + +177 +00:10:31,698 --> 00:10:34,134 +它们会解锁 Swift 类型系统的力量 + +178 +00:10:34,168 --> 00:10:39,206 +并且它们充分利用了 Swift +一流的 Unicode 支持 + +179 +00:10:39,239 --> 00:10:40,908 +我们一起来看一看 + +180 +00:10:40,941 --> 00:10:42,609 +我在开发一款叫 Food Truck 的 app + +181 +00:10:42,643 --> 00:10:46,413 +它可以管理从接单到追踪销售的所有环节 + +182 +00:10:46,446 --> 00:10:49,383 +有些订单是以字符串的形式出现的 +充满了数据 + +183 +00:10:49,416 --> 00:10:53,120 +正则表达式特别适合 +从中提取我想要的信息 + +184 +00:10:53,153 --> 00:10:56,857 +而在 Playground 中进行实验 +再合适不过了 + +185 +00:10:56,890 --> 00:10:58,926 +我先创建一个正则表达式字面值 + +186 +00:11:00,227 --> 00:11:02,229 +现在输入表达式 + +187 +00:11:02,262 --> 00:11:04,298 +提取下单人信息 + +188 +00:11:04,331 --> 00:11:05,866 +甜甜圈类型 + +189 +00:11:05,899 --> 00:11:07,968 +以及甜甜圈数量 + +190 +00:11:08,001 --> 00:11:10,771 +在我输入时 +正则表达式被语法高亮显示 + +191 +00:11:10,804 --> 00:11:14,041 +这有助于我确认表达式是正确的 + +192 +00:11:14,074 --> 00:11:14,942 +现在我来试试看 + +193 +00:11:16,109 --> 00:11:17,978 +使用上面的订单字符串 + +194 +00:11:18,011 --> 00:11:20,347 +并寻找正则表达式的第一个匹配项 + +195 +00:11:21,481 --> 00:11:24,318 +当我运行 Playground 时 +就可以通过内联结果 + +196 +00:11:24,351 --> 00:11:28,288 +看到正则表达式具体匹配到了 +字符串的哪些部分 + +197 +00:11:28,322 --> 00:11:31,258 +这里它就找到了我想要的信息 + +198 +00:11:31,291 --> 00:11:34,661 +Swift 的全新正则表达式支持 +并不止这些 + +199 +00:11:34,695 --> 00:11:36,396 +随着字面值变得越来越复杂 + +200 +00:11:36,430 --> 00:11:39,633 +就像这里 +它匹配的是日志文件的一部分 + +201 +00:11:39,666 --> 00:11:43,670 +Swift 提供了一种更好的方式 +来处理这些匹配符 + +202 +00:11:43,704 --> 00:11:45,305 +即正则表达式生成器 + +203 +00:11:46,773 --> 00:11:49,576 +可以很容易地用它把字面值转换为生成器 + +204 +00:11:50,377 --> 00:11:52,179 +现在我得到了代码 + +205 +00:11:52,212 --> 00:11:55,616 +这些代码更易读懂和修改 + +206 +00:11:55,649 --> 00:11:58,418 +我甚至还可以进一步简化它 + +207 +00:11:58,452 --> 00:12:00,854 +这里我在找的是一个十六进制的数字 + +208 +00:12:00,888 --> 00:12:03,390 +我可以用新的 +hexDigitCharacterClass + +209 +00:12:03,423 --> 00:12:06,493 +让我的意图更加明确 + +210 +00:12:06,527 --> 00:12:11,865 +这个生成器语法让我可以 +轻松创建和扩展表达式 + +211 +00:12:11,899 --> 00:12:14,601 +得到我想要的结果 + +212 +00:12:15,102 --> 00:12:19,606 +这就是强大的 Swift 中 +正则表达式所带来的全新开发者体验 + +213 +00:12:20,174 --> 00:12:21,742 +除了字符串语法 + +214 +00:12:21,775 --> 00:12:27,614 +Swift 也在透过对泛型语言特性的改进 +使其变得更加易于读写 + +215 +00:12:27,915 --> 00:12:30,984 +泛型为你每天使用的 Swift 功能提供支持 + +216 +00:12:31,018 --> 00:12:32,152 +比如数组类型 + +217 +00:12:32,186 --> 00:12:35,789 +它可以容纳任何类型的元素 +从字符串到你自定义的类型 + +218 +00:12:35,822 --> 00:12:42,563 +泛型代码使用占位符的概念来代替另一种类型 +可待之后再确定 + +219 +00:12:42,596 --> 00:12:45,432 +通过清除对类型的假设 + +220 +00:12:45,465 --> 00:12:48,068 +你可以更清楚地表达代码的意图 + +221 +00:12:48,101 --> 00:12:50,604 +并使其容易重复使用 + +222 +00:12:50,637 --> 00:12:53,307 +但这也可能使你的代码更难以阅读 + +223 +00:12:53,841 --> 00:12:58,779 +举例来说 如果你想以函数参数的形式 +处理一个宽泛的歌曲集合 + +224 +00:12:58,812 --> 00:13:02,216 +你就需要写出相当多的代码来表达这个意图 + +225 +00:13:03,050 --> 00:13:07,054 +如今在 Swift 中 +编写接受一些歌曲集合的函数 + +226 +00:13:07,087 --> 00:13:12,025 +就像使用关键词 some +告诉 Swift 参数是什么一样简单 + +227 +00:13:12,059 --> 00:13:15,562 +可以用更少的代码表达同样的意思 + +228 +00:13:15,596 --> 00:13:19,166 +在其它情况下 +你可能需要更多的动态行为 + +229 +00:13:19,199 --> 00:13:22,202 +比如这个音乐库的播放列表阵列 + +230 +00:13:22,236 --> 00:13:25,739 +它可能需要包含不同类型的歌曲集合 + +231 +00:13:25,772 --> 00:13:28,509 +譬如说歌曲集或歌曲阵列 + +232 +00:13:28,542 --> 00:13:31,278 +新的关键词 any +就可以在这种情况下帮上大忙了 + +233 +00:13:31,311 --> 00:13:33,547 +关键词 any 内置于 Swift 当中 + +234 +00:13:33,580 --> 00:13:38,018 +让你可以表达 +一个可以容纳任何歌曲集合的类型 + +235 +00:13:38,051 --> 00:13:41,355 +它也与通用函数无缝衔接 + +236 +00:13:41,388 --> 00:13:45,325 +透过采用熟悉的语法和更自然的关键词 + +237 +00:13:45,359 --> 00:13:48,662 +使用 Swift 编写泛型代码将更加轻而易举 + +238 +00:13:48,695 --> 00:13:52,466 +与 Swift 语言内置功能同等重要的 + +239 +00:13:52,499 --> 00:13:54,868 +就是为它而构建的相关工具了 + +240 +00:13:54,902 --> 00:13:58,772 +Swift Package Manager +让你可以轻松处理 app 的依赖项 + +241 +00:13:58,805 --> 00:14:01,074 +并可利用来自世界各地开发者 + +242 +00:14:01,108 --> 00:14:03,710 +所发布的优秀软件包 + +243 +00:14:03,744 --> 00:14:07,948 +迄今为止 这些开发者们 +已经发布了数以千计的 Swift 软件包 + +244 +00:14:07,981 --> 00:14:11,652 +提供代码来解决从验证到网络服务 +再到数据管理 + +245 +00:14:11,685 --> 00:14:14,955 +专业图形和可重复使用的 UI 组件 +各种疑难杂症 + +246 +00:14:14,988 --> 00:14:17,457 +今年 Swift Package Manager + +247 +00:14:17,491 --> 00:14:22,896 +将新增全新的 Package Plugins +来扩充你创建和构建代码的方式 + +248 +00:14:22,930 --> 00:14:26,400 +Plugins 是可以如同任何其他依赖项 + +249 +00:14:26,433 --> 00:14:28,902 +轻易地添加进项目的 Swift 软件包 + +250 +00:14:28,936 --> 00:14:32,339 +它们在运行新的 checkout 时 +自动下载并构建 + +251 +00:14:32,372 --> 00:14:35,008 +不过它们不是你 app 中的代码 + +252 +00:14:35,042 --> 00:14:36,743 +而是帮助你构建 app 的代码 + +253 +00:14:37,678 --> 00:14:41,281 +Package Plugins 可从命令行 +或 Xcode 中调用 + +254 +00:14:41,315 --> 00:14:44,585 +可以是构建阶段的一部分 +也可按需调用 + +255 +00:14:44,618 --> 00:14:46,653 +它们在沙盒环境中运行 + +256 +00:14:46,687 --> 00:14:50,157 +在读取或修改代码前会请求你的许可 + +257 +00:14:50,858 --> 00:14:54,428 +使用 Package Plugins 扩展你的工作流 +将可拥有无限的可能性 + +258 +00:14:54,461 --> 00:14:57,064 +你可以用它们检查和格式化你的代码 + +259 +00:14:57,097 --> 00:14:58,498 +并使用像 SwiftLint 和 SwiftFormat +这样的软件包 + +260 +00:14:58,532 --> 00:15:00,901 +来确保你的代码符合团队的风格指南 + +261 +00:15:00,934 --> 00:15:04,938 +或者用 Sourcery 等工具在构建时 +自动生成源代码 + +262 +00:15:04,972 --> 00:15:07,174 +或者做任何其他有助于你完成工作的事 + +263 +00:15:07,808 --> 00:15:10,677 +Package Plugins 可以 +很好地扩展 Xcode + +264 +00:15:10,711 --> 00:15:12,913 +仅需写一点 Swift 代码 + +265 +00:15:12,946 --> 00:15:14,548 +你可以透过以下两种方式来实现 + +266 +00:15:14,581 --> 00:15:17,484 +有按需使用的命令插件 + +267 +00:15:17,518 --> 00:15:20,654 +还有构建插件 +供你随时需进行项目构建时使用 + +268 +00:15:20,687 --> 00:15:22,689 +回到我们的 Food Truck app + +269 +00:15:22,723 --> 00:15:24,992 +这里是我创建的一个命令插件的代码 + +270 +00:15:26,627 --> 00:15:29,897 +我的团队对代码有种独特的审美 + +271 +00:15:29,930 --> 00:15:32,733 +我们喜欢让导入的语句按字符串长度排序 + +272 +00:15:32,766 --> 00:15:34,768 +由短到长 + +273 +00:15:34,801 --> 00:15:38,639 +由于 Package Plugins +就是用于定制和控制的 + +274 +00:15:38,672 --> 00:15:42,075 +我们创建了一个命令插件 +采用 SwiftFormat 来处理这个需求 + +275 +00:15:43,110 --> 00:15:45,812 +它可以找到所有本地修改的文件 + +276 +00:15:45,846 --> 00:15:48,148 +然后对导入进行排序 + +277 +00:15:48,182 --> 00:15:52,252 +这是一个我正在编辑的文件 +最上面的导入是尚未排序的 + +278 +00:15:52,286 --> 00:15:54,988 +我在整个项目中运行命令插件 + +279 +00:15:55,022 --> 00:15:58,525 +我可以选择任何数量的运行目标 +这里我就在全部目标上运行 + +280 +00:15:59,059 --> 00:16:01,295 +如果我愿意 +甚至还可以审查命令插件的代码 + +281 +00:16:01,328 --> 00:16:02,796 +我准备好了 +直接来运行这个命令 + +282 +00:16:03,564 --> 00:16:06,466 +就这么简单 +插件就会在我的文件上运行 + +283 +00:16:07,100 --> 00:16:10,070 +它找到了所有本地修改的文件 + +284 +00:16:10,103 --> 00:16:12,506 +然后以长度排序 + +285 +00:16:12,539 --> 00:16:15,542 +使用插件 能做的可不止是格式化 + +286 +00:16:15,576 --> 00:16:18,412 +你可以生成源代码、使用 git + +287 +00:16:18,445 --> 00:16:21,648 +甚至是使用自己的自定义错误和警告提示 + +288 +00:16:21,682 --> 00:16:25,052 +我还有另一个插件 +可以确保把我的代码很好被记录管理 + +289 +00:16:25,085 --> 00:16:29,122 +这是一个构建插件 +基于开源的 SwiftLint 软件包 + +290 +00:16:29,890 --> 00:16:33,727 +所以当我在构建的时候 +就可以轻松看到代码中 + +291 +00:16:33,760 --> 00:16:36,196 +所有需要添加文档的地方 + +292 +00:16:36,230 --> 00:16:40,000 +而且构建插件将一直延伸到 Xcode Cloud + +293 +00:16:40,033 --> 00:16:42,503 +可以作为每个构建的一部分运行 + +294 +00:16:42,536 --> 00:16:44,271 +有了 Swift Package Plugins + +295 +00:16:44,304 --> 00:16:46,607 +我和我的团队可以在本地和 Xcode Cloud + +296 +00:16:46,640 --> 00:16:49,576 +创建我们的命令 以及自定义我们的构建 + +297 +00:16:49,610 --> 00:16:51,945 +并与他人分享这些插件 + +298 +00:16:51,979 --> 00:16:55,182 +这仅需透过几行强大的 Swift 代码即可完成 + +299 +00:16:55,215 --> 00:16:57,618 +这就是 Package Plugins 的简要介绍 + +300 +00:16:57,651 --> 00:17:00,220 +它有各种方式来大幅提升你的开发工作流 + +301 +00:17:00,254 --> 00:17:04,324 +最后 Swift 还迎来了一些惊人的后台改进 + +302 +00:17:04,358 --> 00:17:06,293 +现在能以前所未有的速度构建 Swift 项目 + +303 +00:17:06,326 --> 00:17:10,864 +依靠新的并行化大幅提升链接时间可快达两倍 + +304 +00:17:10,898 --> 00:17:12,733 +并且 Swift 并发运行时间 + +305 +00:17:12,766 --> 00:17:15,502 +现在更紧密地与软件系统整合 + +306 +00:17:15,536 --> 00:17:18,672 +更好地确保异步任务的优先级 + +307 +00:17:18,705 --> 00:17:21,175 +帮助你的 app 保持高效和及时响应 + +308 +00:17:21,208 --> 00:17:26,413 +最后 用 Swift 编写的 app +在 iOS 16 上启动时间大大缩短 + +309 +00:17:26,446 --> 00:17:30,918 +像是 Lyft 和 Airbnb 等 app 的启动速度提升 +可仅为过去的一半 + +310 +00:17:30,951 --> 00:17:33,053 +这得益于动态链接器的改进 + +311 +00:17:33,086 --> 00:17:35,055 +有了这些后台的提升 + +312 +00:17:35,088 --> 00:17:36,723 +工具的新能力 + +313 +00:17:36,757 --> 00:17:39,760 +更加易于读写的演进版语法 + +314 +00:17:39,793 --> 00:17:41,628 +以及对并发功能的改进 + +315 +00:17:41,662 --> 00:17:44,665 +现在正是用 Swift 开发的最佳时机 + +316 +00:17:44,698 --> 00:17:49,636 +Swift 绝对是最佳语言用来 +开发跨我们所有设备的 app + +317 +00:17:49,670 --> 00:17:53,473 +但语言只是你构建优质 app 所需的一部分 + +318 +00:17:53,507 --> 00:17:57,477 +你必须把语言和强大的 +用户界面框架搭配起来 + +319 +00:17:57,511 --> 00:17:59,646 +下面由 Eliza 来给大家进一步说明 + +320 +00:17:59,680 --> 00:18:02,649 +强大的 UI 框架可以提供抽象 + +321 +00:18:02,683 --> 00:18:05,152 +让你更轻松地描述界面 + +322 +00:18:05,185 --> 00:18:08,188 +填充数据 以及保持更新 + +323 +00:18:08,222 --> 00:18:10,490 +它应该具有很好的扩展性 +适用于不同的复杂环境 + +324 +00:18:10,524 --> 00:18:13,060 +而且 它应该是为你的目标平台设计的 + +325 +00:18:13,093 --> 00:18:15,829 +让你可以充分利用设备的能力 + +326 +00:18:15,863 --> 00:18:20,868 +UI 框架应该助你一臂之力 +使你的 app 感到亲切且直观 + +327 +00:18:20,901 --> 00:18:23,704 +它应该让你可以轻松创建标准控制件 + +328 +00:18:23,737 --> 00:18:25,472 +和本地交互匹配模式 + +329 +00:18:25,506 --> 00:18:28,075 +并支持高级定制功能 + +330 +00:18:28,108 --> 00:18:30,477 +它还需要有富有表现力的 API + +331 +00:18:30,511 --> 00:18:33,413 +让你可以快速建立你的想法的原型 + +332 +00:18:33,447 --> 00:18:35,849 +并在一系列设备上看到结果 + +333 +00:18:36,416 --> 00:18:38,986 +SwiftUI 就可以提供这一切 且不止于此 + +334 +00:18:39,019 --> 00:18:42,456 +与 Swift 一样 SwiftUI 的设计旨在 + +335 +00:18:42,489 --> 00:18:44,491 +提供开发 app 的最佳方式 + +336 +00:18:44,525 --> 00:18:48,295 +它采用声明式语法 易于读写 + +337 +00:18:48,328 --> 00:18:52,766 +你只需描述界面的样子 而不是如何构建界面 + +338 +00:18:53,767 --> 00:18:56,336 +而这就是 SwiftUI 可发挥的空间 + +339 +00:18:56,370 --> 00:18:59,439 +为每个平台提供智能默认值 + +340 +00:18:59,473 --> 00:19:02,776 +SwiftUI 会自动保持界面的更新 + +341 +00:19:02,809 --> 00:19:05,412 +确保界面随底层数据模型的改动而变化 + +342 +00:19:05,445 --> 00:19:08,749 +因此你的 app 的 UI +永远不会陷入不一致的状态 + +343 +00:19:09,583 --> 00:19:13,153 +SwiftUI 为你处理所有这些细节 + +344 +00:19:13,187 --> 00:19:17,224 +这样你就可以把时间和精力专注在 +构建你的 app 与众不同的地方 + +345 +00:19:17,257 --> 00:19:20,861 +编写新的 UI 框架是一项巨大的工程 + +346 +00:19:20,894 --> 00:19:25,432 +自从推出 SwiftUI 以来 +我们持续扩大 SwiftUI 的 API 类型 + +347 +00:19:25,465 --> 00:19:27,000 +且都是基于大家的反馈 + +348 +00:19:27,668 --> 00:19:33,006 +今年 我们将让你在现有的各种 app 中 +逐步采用 SwiftUI 变得更容易 + +349 +00:19:33,040 --> 00:19:37,211 +同时我们还对它的性能和灵活性 +带来可观的提升 + +350 +00:19:37,244 --> 00:19:39,613 +首先是 app 导航 + +351 +00:19:39,646 --> 00:19:41,949 +一直以来 使用 SwiftUI + +352 +00:19:41,982 --> 00:19:46,286 +即可轻松创建许多 app 中 +常见的导航层次结构 + +353 +00:19:46,320 --> 00:19:49,523 +SwiftUI 在今年将会扩展这方面的支持 + +354 +00:19:49,556 --> 00:19:52,125 +推出全新的导航 API + +355 +00:19:52,693 --> 00:19:56,730 +新的导航 API 可以让你更容易地创建 + +356 +00:19:56,763 --> 00:19:59,466 +最适合你 app 需求的导航风格 + +357 +00:19:59,499 --> 00:20:03,604 +通过对 app 视图呈现的强大编程控制 + +358 +00:20:03,637 --> 00:20:06,373 +你可以轻松保存或选择恢复 + +359 +00:20:06,406 --> 00:20:10,177 +甚至替换导航栏的全部内容 + +360 +00:20:10,210 --> 00:20:13,313 +这在处理重要行为时十分有用 + +361 +00:20:13,347 --> 00:20:15,549 +如设置 app 的启动状态 + +362 +00:20:15,582 --> 00:20:18,385 +管理尺寸类别间的过渡 + +363 +00:20:18,418 --> 00:20:20,053 +以及对深度链接的响应 + +364 +00:20:20,988 --> 00:20:23,724 +SwiftUI 的另一项巨大改进 + +365 +00:20:23,757 --> 00:20:26,927 +是可以让你更好地控制 app 界面的布局 + +366 +00:20:27,661 --> 00:20:31,899 +许多 app 的界面可以用 SwiftUI 的 + +367 +00:20:31,932 --> 00:20:34,701 +水平或垂直元素堆栈模型来描述 + +368 +00:20:34,735 --> 00:20:37,404 +虽然这个模型可以处理很多常见布局 + +369 +00:20:37,437 --> 00:20:40,174 +但有时你需要更加灵活的工具 + +370 +00:20:40,207 --> 00:20:43,076 +今年 我们将加入全新的 grid API + +371 +00:20:43,110 --> 00:20:48,415 +让你轻松设置多行与多列排列的网格布局 + +372 +00:20:48,448 --> 00:20:50,951 +透过全新的自定义布局 API + +373 +00:20:50,984 --> 00:20:53,987 +将可让你的布局更上层楼 + +374 +00:20:54,021 --> 00:20:56,990 +自定义布局 API 带来了灵活性 + +375 +00:20:57,024 --> 00:20:59,593 +让你可以随心所欲设置你想要的布局 + +376 +00:20:59,626 --> 00:21:01,862 +例如 你可以创建流动式布局 + +377 +00:21:01,895 --> 00:21:05,299 +让视图像报纸内容一样排列 + +378 +00:21:05,332 --> 00:21:08,402 +当需要更多空间时 +将内容自动延伸至下一栏 + +379 +00:21:08,435 --> 00:21:12,406 +或者你可以创建放射式布局 +把视图做成圆环 + +380 +00:21:12,439 --> 00:21:13,941 +就像手表表盘的数字一样 + +381 +00:21:14,675 --> 00:21:19,379 +自定义布局 API 让你可以 +轻松重复使用你的布局逻辑 + +382 +00:21:19,413 --> 00:21:22,182 +使你的视图代码更简单 更易读 + +383 +00:21:22,216 --> 00:21:25,185 +SwiftUI 还在不断发展 + +384 +00:21:25,219 --> 00:21:27,521 +为你提供更多类型的界面元素 + +385 +00:21:27,554 --> 00:21:30,591 +比如通过半屏表单来展示二级页面 + +386 +00:21:30,624 --> 00:21:32,593 +并可以上下滑动 + +387 +00:21:32,626 --> 00:21:37,397 +有助于在较小的屏幕快速获取信息 + +388 +00:21:37,431 --> 00:21:39,933 +例如 SwiftUI 现在支持共享表单 + +389 +00:21:39,967 --> 00:21:41,668 +让你的 app 可以轻松利用 + +390 +00:21:41,702 --> 00:21:44,838 +用户设备上的所有共享扩展 + +391 +00:21:44,872 --> 00:21:49,009 +全新的 Transferable 协议支持共享表单 + +392 +00:21:49,042 --> 00:21:52,746 +并为传输 app 数据引入了一个安全类型的 API + +393 +00:21:53,747 --> 00:21:58,485 +为了让你更轻松地在现有 app 中 +逐步采用 SwiftUI + +394 +00:21:58,519 --> 00:22:03,390 +我们还推出了一个可以托管 SwiftUI 视图的 +特殊集合视图单元格 + +395 +00:22:03,423 --> 00:22:06,493 +如果你在 UIKit app 中已有一个集合视图 + +396 +00:22:06,527 --> 00:22:10,597 +那你现在就可以使用 SwiftUI 的声明式语法 +编写自定义单元格 + +397 +00:22:10,631 --> 00:22:15,102 +这些单元格与 UIKit 紧密集成 +支持轻扫动作 + +398 +00:22:15,135 --> 00:22:19,072 +单元格背景 +以及 UICollectionView 的其他功能 + +399 +00:22:19,106 --> 00:22:21,942 +今天 我们还要推出一个全新的框架 + +400 +00:22:21,975 --> 00:22:23,510 +更好地补充 SwiftUI + +401 +00:22:23,544 --> 00:22:26,880 +来让你能够呈现更多的界面 + +402 +00:22:26,914 --> 00:22:28,882 +下面请 Jo 给大家介绍 + +403 +00:22:28,916 --> 00:22:31,051 +数据在当今的世界随处可见 + +404 +00:22:31,084 --> 00:22:33,287 +数据可以帮助我们理解并做出决策 + +405 +00:22:33,320 --> 00:22:34,888 +以及发现新的视角 + +406 +00:22:34,922 --> 00:22:37,558 +一个精心设计、容易获取的数据可视化呈现 + +407 +00:22:37,591 --> 00:22:39,893 +能够以清晰自然的方式 + +408 +00:22:39,927 --> 00:22:42,462 +向用户传达复杂的信息 + +409 +00:22:42,496 --> 00:22:44,631 +赋能于他们的日常生活 + +410 +00:22:45,465 --> 00:22:48,535 +比如帮助显示他们健康的变化趋势 + +411 +00:22:48,569 --> 00:22:51,672 +强调他们个人目标的进度 + +412 +00:22:51,705 --> 00:22:53,640 +以及协助他们为未来做好准备 + +413 +00:22:54,308 --> 00:22:57,144 +今天 我们要推出一个新的框架 + +414 +00:22:57,177 --> 00:23:00,414 +帮助你的用户来解读 app 中的数据 + +415 +00:23:00,447 --> 00:23:03,717 +这就是 Swift Charts + +416 +00:23:03,750 --> 00:23:07,187 +Swift Charts 是一个可高度自定义的图表框架 + +417 +00:23:07,221 --> 00:23:08,889 +它基于 SwiftUI + +418 +00:23:08,922 --> 00:23:12,626 +可以轻松创建精美的可视化图表 + +419 +00:23:12,659 --> 00:23:15,762 +它使用与 SwiftUI 相同的声明式语法 + +420 +00:23:15,796 --> 00:23:19,433 +可轻松读写传达视觉信息的代码 + +421 +00:23:20,400 --> 00:23:23,170 +Swift Charts 让你可以自定义信息的呈现方式 + +422 +00:23:23,203 --> 00:23:25,439 +最大程度地符合你 app 的需求 + +423 +00:23:25,472 --> 00:23:28,008 +创建各种图表 从线图和柱状图 + +424 +00:23:28,041 --> 00:23:32,279 +到更复杂的热力图和流线图 + +425 +00:23:32,312 --> 00:23:34,147 +以及很多其他类型的图表 + +426 +00:23:35,182 --> 00:23:38,118 +由于 Swift Charts +是在 SwiftUI 的基础上所建立 + +427 +00:23:38,151 --> 00:23:40,654 +所以图表提供了非常好的辅助功能支持 + +428 +00:23:40,687 --> 00:23:43,924 +例如绝佳的、开箱即用的旁白体验 + +429 +00:23:43,957 --> 00:23:46,059 +并可轻松自定义 + +430 +00:23:46,093 --> 00:23:49,997 +以 SwiftUI 为基础也意味着 +你可以对图表进行动画处理 + +431 +00:23:50,030 --> 00:23:53,367 +给 app 提供你想要的外观和感觉 + +432 +00:23:53,400 --> 00:23:57,704 +当然 Swift Charts 支持我们所有的设备 + +433 +00:23:57,738 --> 00:23:59,806 +回到我们的 Food Truck app + +434 +00:23:59,840 --> 00:24:01,875 +这里就是在全面重新设计过的 Xcode 预览区中 + +435 +00:24:01,909 --> 00:24:05,312 +呈现美观的全新 Swift Charts 图表 + +436 +00:24:05,345 --> 00:24:09,349 +同时我还用了新的多列 SwiftUI 表格视图 + +437 +00:24:09,383 --> 00:24:12,719 +我来给大家展示一下 +创建这个图表有多么容易 + +438 +00:24:12,753 --> 00:24:14,087 +在我滚动页面时 + +439 +00:24:14,121 --> 00:24:17,357 +你可以在源代码编辑器中 +看到这个很棒的全新结构化标题 + +440 +00:24:17,391 --> 00:24:20,227 +这让我可以很容易看到我正在编辑的地方 + +441 +00:24:21,261 --> 00:24:22,696 +这里是图表的代码 + +442 +00:24:22,729 --> 00:24:26,600 +这其实是一个堆叠的柱状图 +但真的是看不出来差别 + +443 +00:24:26,633 --> 00:24:29,503 +我们来给每种甜甜圈一个不同的颜色 + +444 +00:24:30,871 --> 00:24:34,341 +如果我们把每种甜甜圈的条柱 +并排放在一起 + +445 +00:24:34,374 --> 00:24:36,677 +可能会更容易比较各种甜甜圈 + +446 +00:24:37,945 --> 00:24:40,681 +我非常喜欢的是 进行这些大的改动 + +447 +00:24:40,714 --> 00:24:43,050 +仅需几个简单的 modifier + +448 +00:24:43,083 --> 00:24:45,552 +我们还可以自定义样式 + +449 +00:24:45,586 --> 00:24:48,522 +让这些条柱对应甜甜圈的颜色 + +450 +00:24:48,555 --> 00:24:52,125 +我们甚至可以用另一个 modifier +给条柱添加注解 + +451 +00:24:53,327 --> 00:24:54,795 +看起来很棒 + +452 +00:24:54,828 --> 00:24:56,730 +预览现在默认是实时的 + +453 +00:24:56,763 --> 00:24:59,533 +所以我可以立即与视图进行互动 + +454 +00:24:59,566 --> 00:25:01,268 +我来更改一下排序 + +455 +00:25:01,301 --> 00:25:04,204 +看看条柱精美的动画 + +456 +00:25:04,238 --> 00:25:07,074 +而所有繁重的工作 +都是由 Swift Charts 来完成的 + +457 +00:25:07,107 --> 00:25:08,976 +我们来抓取更多数据 + +458 +00:25:09,009 --> 00:25:12,980 +图和表都会自动随模型的变化更新 + +459 +00:25:13,013 --> 00:25:17,184 +图甚至会重新计算 Y 轴 +反映出新的总计值 + +460 +00:25:17,217 --> 00:25:19,019 +让我再给大家看一张图 + +461 +00:25:19,052 --> 00:25:22,556 +我在这里做了一个线图 +我们把它添加到视图里 + +462 +00:25:22,589 --> 00:25:25,025 +我直接跳到实施 + +463 +00:25:25,058 --> 00:25:29,096 +Swift Charts 的线图有些很酷的选项 + +464 +00:25:29,129 --> 00:25:31,865 +我们可以为每种甜甜圈添加符号 + +465 +00:25:31,899 --> 00:25:34,134 +可以为线添加注解 + +466 +00:25:34,168 --> 00:25:38,672 +甚至可以采用各种差值策略平滑曲线 + +467 +00:25:38,705 --> 00:25:40,941 +我们这里用 catmullRom + +468 +00:25:40,974 --> 00:25:43,443 +最后 通过提供我自己的映射 + +469 +00:25:43,477 --> 00:25:45,579 +覆盖图表比例样式 + +470 +00:25:45,612 --> 00:25:49,082 +这样会使图表与 app 的配色方案更吻合 + +471 +00:25:49,116 --> 00:25:50,584 +非常棒 + +472 +00:25:50,617 --> 00:25:53,320 +重新设计的预览区使我比以往更容易看到 + +473 +00:25:53,353 --> 00:25:56,056 +我的视图在不同环境中的样子 + +474 +00:25:56,089 --> 00:25:58,292 +通过点击画布上的按钮 + +475 +00:25:58,325 --> 00:26:01,094 +我可以看到深色和浅色模式下的视图 + +476 +00:26:01,128 --> 00:26:04,631 +甚至可以看到所有的屏幕方向中的布局 + +477 +00:26:04,665 --> 00:26:07,367 +一个额外的预览都不用添加 + +478 +00:26:07,401 --> 00:26:09,870 +我们来放大看看横向模式 + +479 +00:26:09,903 --> 00:26:13,040 +看起来我的 UI 有点问题 + +480 +00:26:13,073 --> 00:26:14,441 +有几个控制按钮在屏幕之外 + +481 +00:26:14,474 --> 00:26:17,578 +而且图表的长宽比也很别扭 + +482 +00:26:17,611 --> 00:26:20,881 +我们来看看这个布局是在哪里描述的 + +483 +00:26:20,914 --> 00:26:24,218 +这里这些视图在一个隐含的 VStack 里 + +484 +00:26:25,352 --> 00:26:28,922 +今年 SwiftUI 中有些强大的全新 API + +485 +00:26:28,956 --> 00:26:31,391 +可以创建更多的灵活布局 + +486 +00:26:31,425 --> 00:26:34,027 +这里我来用 ViewThatFits + +487 +00:26:34,061 --> 00:26:36,263 +这会根据可用空间 + +488 +00:26:36,296 --> 00:26:39,266 +在垂直和水平堆栈之间切换 + +489 +00:26:40,667 --> 00:26:42,302 +这样看起来好多了 + +490 +00:26:42,336 --> 00:26:43,670 +现在把这个视图连接起来 + +491 +00:26:43,704 --> 00:26:45,639 +从主屏幕导航到这里 + +492 +00:26:46,673 --> 00:26:49,810 +我用的是 SwiftUI 全新的导航分屏浏览 + +493 +00:26:49,843 --> 00:26:51,612 +操作起来非常方便 + +494 +00:26:51,645 --> 00:26:55,082 +分屏浏览有一个侧边栏 可以追踪选择 + +495 +00:26:55,115 --> 00:27:00,521 +它还有个 NavigationStack +其内容随着侧边栏选择的变化进而调整 + +496 +00:27:00,554 --> 00:27:01,922 +我来跳到侧边栏 + +497 +00:27:01,955 --> 00:27:04,992 +为我们的甜甜圈冠军视图 +添加导航链接 + +498 +00:27:05,025 --> 00:27:07,494 +然后 就可以在这个互动预览中试试看 + +499 +00:27:08,262 --> 00:27:10,664 +我想在横向模式中看一下分屏浏览 + +500 +00:27:10,697 --> 00:27:12,933 +那我就用新的画布设置 + +501 +00:27:12,966 --> 00:27:15,202 +来旋转实时预览 + +502 +00:27:15,235 --> 00:27:16,837 +很棒 + +503 +00:27:16,870 --> 00:27:19,406 +我对它在 iPad 上的效果很满意 + +504 +00:27:19,439 --> 00:27:21,675 +但我现在想把它也带到 Mac 上 + +505 +00:27:21,708 --> 00:27:24,978 +而这只需点击几下即可做到 + +506 +00:27:25,012 --> 00:27:27,481 +我想充分利用 Mac SDK + +507 +00:27:27,514 --> 00:27:28,949 +所以我在这里使用原生 + +508 +00:27:31,218 --> 00:27:33,554 +因为我的 app 背后只有一个目标 + +509 +00:27:33,587 --> 00:27:35,589 +我可以共用几乎所有的代码 + +510 +00:27:35,622 --> 00:27:39,026 +而 SwiftUI 会让我的 app +在每个平台上看起来都很棒 + +511 +00:27:39,059 --> 00:27:42,429 +我也可以轻松添加针对不同设备的功能 + +512 +00:27:42,462 --> 00:27:45,299 +对 Mac app 我们来添加 +一个 menuBarExtra + +513 +00:27:45,332 --> 00:27:47,267 +这就是你屏幕右上角那些 + +514 +00:27:47,301 --> 00:27:49,002 +有用的小图标 + +515 +00:27:49,036 --> 00:27:52,072 +比如 Wi-Fi 和聚焦 + +516 +00:27:52,105 --> 00:27:55,142 +SwiftUI 为此提供了新的 API + +517 +00:27:55,175 --> 00:27:57,244 +我只需把它添加到我 app 的主体 + +518 +00:27:57,277 --> 00:27:59,146 +现在我们来为 Mac 运行试试看 + +519 +00:28:02,683 --> 00:28:06,553 +我们的甜甜圈冠军视图在 Mac 上 +看起来很棒 + +520 +00:28:06,587 --> 00:28:08,589 +这里就是那个 menuBarExtra + +521 +00:28:08,622 --> 00:28:09,990 +很方便 + +522 +00:28:10,023 --> 00:28:12,292 +这就是对 Swift Charts 的简要介绍 + +523 +00:28:12,326 --> 00:28:15,762 +以及 SwiftUI 和 Xcode 即将带来 +部分增强功能的说明 + +524 +00:28:15,796 --> 00:28:17,631 +现在交回给 Josh + +525 +00:28:17,664 --> 00:28:20,834 +我们正越来越多地使用 SwiftUI + +526 +00:28:20,868 --> 00:28:23,403 +并覆盖了我们的各个 app 和系统界面 + +527 +00:28:23,437 --> 00:28:25,973 +例如 iOS 新的锁定屏幕小组件 + +528 +00:28:26,006 --> 00:28:29,243 +就是由 SwiftUI 全新设计的 + +529 +00:28:29,276 --> 00:28:32,179 +而新的 Font Book app 也是用它 +完全重写的 + +530 +00:28:32,212 --> 00:28:36,283 +还有看起来很现代、超前的 +全新 macOS 系统设置 app + +531 +00:28:36,316 --> 00:28:37,818 +也是用它构建的 + +532 +00:28:37,851 --> 00:28:40,988 +Swift 和 SwiftUI 从一开始的设计目的 + +533 +00:28:41,021 --> 00:28:45,759 +就是用统一的原生语言和 API +适用于 Apple 的各个平台 + +534 +00:28:45,792 --> 00:28:48,629 +只需学习一次 即可用在所有地方 + +535 +00:28:48,662 --> 00:28:51,798 +无论你的愿景是在 Apple Watch 上 + +536 +00:28:51,832 --> 00:28:53,834 +提供一目了然的快速信息访问 + +537 +00:28:53,867 --> 00:28:57,104 +为 MacBook Pro 和 iPad 提供生产力工具 + +538 +00:28:57,137 --> 00:28:59,006 +在 iPhone 上提供新的体验 + +539 +00:28:59,039 --> 00:29:01,408 +还是为 Apple TV 提供新的放松方式 + +540 +00:29:01,441 --> 00:29:03,911 +Swift、SwiftUI 和 Xcode + +541 +00:29:03,944 --> 00:29:07,614 +提供了新一代的整合开发平台 + +542 +00:29:07,648 --> 00:29:10,884 +帮你开发的 app 适用于我们所有的产品 + +543 +00:29:10,918 --> 00:29:12,519 +如果你先前已开发的 app + +544 +00:29:12,553 --> 00:29:15,989 +同样也可以轻松地逐步采用这些新技术 + +545 +00:29:16,023 --> 00:29:19,526 +如果你是我们平台的新手 +或者要开始开发新的 app + +546 +00:29:19,560 --> 00:29:23,664 +最好的构建方式就是直接使用 +Swift 和 SwiftUI + +547 +00:29:23,697 --> 00:29:25,899 +当然 这只是个开始 + +548 +00:29:25,933 --> 00:29:29,870 +我们也在不断改进平台的用户体验 + +549 +00:29:29,903 --> 00:29:32,706 +为你们提供更多与用户互动的方式 + +550 +00:29:32,739 --> 00:29:35,075 +下面请 Sebastien 给你们来详细介绍 + +551 +00:29:36,376 --> 00:29:38,412 +开发 app 就是将各种想法 + +552 +00:29:38,445 --> 00:29:41,148 +代码和 API 转变为用户体验 + +553 +00:29:41,181 --> 00:29:42,482 +而最好的 app + +554 +00:29:42,516 --> 00:29:45,752 +就是能满足用户当下需求的 app + +555 +00:29:45,786 --> 00:29:49,456 +我们创建了各种方式 +让用户体验不仅限于你的 app 里 + +556 +00:29:49,489 --> 00:29:53,126 +更整合到不同 Apple 设备的系统体验中 + +557 +00:29:53,927 --> 00:29:57,664 +这段旅程从各种扩展方式开始 +以及与共享表单的整合 + +558 +00:29:57,698 --> 00:29:59,399 +还有自定义键盘 + +559 +00:29:59,433 --> 00:30:02,736 +最近 还增加了让你的 app 使用小组件 + +560 +00:30:02,769 --> 00:30:06,039 +在主屏幕显示关键信息的能力 + +561 +00:30:06,073 --> 00:30:07,875 +今年将有众多新的方式 + +562 +00:30:07,908 --> 00:30:10,978 +将你的 app 与我们各平台的系统体验相整合 + +563 +00:30:11,011 --> 00:30:15,482 +这要从锁定屏幕开始 +锁定屏幕得到了有史以来最大的更新 + +564 +00:30:15,516 --> 00:30:19,019 +我们重新设计了锁定屏幕的外观和运作方式 + +565 +00:30:19,052 --> 00:30:23,390 +为你的创意和各种 app +提供另一个与用户互动的地方 + +566 +00:30:23,423 --> 00:30:25,792 +让 Robert 来给大家介绍详情 + +567 +00:30:34,268 --> 00:30:35,802 +重新设计锁定屏幕的目的 + +568 +00:30:35,836 --> 00:30:38,805 +是让它更加个性化、更美观 + +569 +00:30:38,839 --> 00:30:40,674 +同时提高日常实用性 + +570 +00:30:40,707 --> 00:30:43,443 +在这个过程中 我们知道我们需要 + +571 +00:30:43,477 --> 00:30:46,413 +把小组件的强大功能 带到全新的锁定屏幕上 + +572 +00:30:46,446 --> 00:30:50,484 +小组件带来了出色的方式 +突出你 app 里的关键信息 + +573 +00:30:50,517 --> 00:30:53,487 +让用户一目了然 + +574 +00:30:53,520 --> 00:30:57,157 +它们让用户能够直接从主屏幕轻松获取 + +575 +00:30:57,191 --> 00:30:58,559 +丰富、及时的信息 + +576 +00:30:59,226 --> 00:31:02,796 +每当举起 iPhone 最先看到的就是锁定屏幕 + +577 +00:31:02,829 --> 00:31:05,432 +这里一直是查看日期时间 + +578 +00:31:05,465 --> 00:31:07,334 +了解重要信息的地方 + +579 +00:31:07,367 --> 00:31:11,038 +在思考如何以最佳的形式 +在这里显示更多信息时 + +580 +00:31:11,071 --> 00:31:13,574 +我们不用绞尽脑汁去寻找设计灵感 + +581 +00:31:14,208 --> 00:31:18,078 +Apple Watch 上的复杂功能已经提供了 +一目了然、相关 + +582 +00:31:18,111 --> 00:31:19,546 +最即时的信息 + +583 +00:31:19,580 --> 00:31:22,349 +并在用户需要时美观呈现这些内容 + +584 +00:31:23,016 --> 00:31:25,719 +这种设计语言自然地延伸到 iOS + +585 +00:31:25,752 --> 00:31:28,622 +恰如其分地出现在新的锁定屏幕上 + +586 +00:31:28,655 --> 00:31:31,825 +因此 利用 WidgetKit 我们将一些相同的设计 + +587 +00:31:31,859 --> 00:31:34,962 +带来锁定屏幕上的小组件 包括 Circular + +588 +00:31:34,995 --> 00:31:39,666 +可以展示一张小图、仪表或几个字符的文字 + +589 +00:31:39,700 --> 00:31:43,370 +Circular 小组件非常适合展示出 +你今天活动量是否已经足够 + +590 +00:31:43,403 --> 00:31:45,506 +还是需要出去跑跑步 + +591 +00:31:45,539 --> 00:31:48,175 +Rectangular 提供一个大画布 + +592 +00:31:48,208 --> 00:31:51,578 +可显示像天气预报这样的内容 + +593 +00:31:51,612 --> 00:31:54,515 +Inline 是一种强大的展示信息的方式 + +594 +00:31:54,548 --> 00:31:58,919 +可在 iPhone 的时钟上方 +显示少量文本和 SF 符号 + +595 +00:31:58,952 --> 00:32:02,990 +旁边是系统提供的日期字符串 +如 6 日星期一 + +596 +00:32:03,023 --> 00:32:08,328 +对了 所有这些小组件都可在 +iOS 和 watchOS 上使用 + +597 +00:32:08,362 --> 00:32:10,330 +因为从 watchOS 9 开始 + +598 +00:32:10,364 --> 00:32:13,567 +复杂功能也由 WidgetKit 提供支持 + +599 +00:32:13,600 --> 00:32:16,170 +这是首次可以在两个平台上 + +600 +00:32:16,203 --> 00:32:20,107 +使用相同的代码生成一目了然的数据 + +601 +00:32:20,140 --> 00:32:23,177 +WidgetKit 为你自动管理平台差异 + +602 +00:32:23,210 --> 00:32:25,479 +默认使用适合的系统字体 + +603 +00:32:25,512 --> 00:32:29,283 +并为锁定屏幕上的小组件上色 +提供最大的可读性 + +604 +00:32:29,316 --> 00:32:32,786 +具体如何使用 WidgetKit 以相同的代码 +为 iPhone 锁定屏幕 + +605 +00:32:32,819 --> 00:32:35,589 +和 Apple Watch 复杂功能创建小组件 + +606 +00:32:35,622 --> 00:32:37,524 +将由 Michael 为大家介绍 + +607 +00:32:39,793 --> 00:32:41,495 +无论是在 iPhone 锁定屏幕上创建小组件 + +608 +00:32:41,528 --> 00:32:44,798 +还是打造 Apple Watch 上的复杂功能 +都可以用 WidgetKit 轻松实现 + +609 +00:32:44,831 --> 00:32:47,401 +如果你已经做了主屏幕小组件 +那你就已经完成了大部分工作 + +610 +00:32:47,434 --> 00:32:49,870 +包括数据和时间线的更新方式 + +611 +00:32:49,903 --> 00:32:52,406 +在我们的 Food Truck app 中 +我们已经有了 systemSmall 小组件 + +612 +00:32:52,439 --> 00:32:54,107 +用户可以添加到主屏幕上 + +613 +00:32:54,141 --> 00:32:56,977 +查看他们今天已经完成了多少订单配额 + +614 +00:32:57,010 --> 00:32:59,513 +这类信息就非常适合显示在锁定屏幕 + +615 +00:32:59,546 --> 00:33:01,748 +或是手表表盘的复杂功能中 + +616 +00:33:01,782 --> 00:33:03,984 +我们先来建立 Circular 系列 + +617 +00:33:05,485 --> 00:33:08,255 +首先要在 Supported Families 阵列中 +声明对它的支持 + +618 +00:33:09,389 --> 00:33:12,025 +你可以看到我们在这里用了一些平台条件 + +619 +00:33:12,059 --> 00:33:15,762 +这是因为我们希望这个小组件能继续 +利用 systemSmall + +620 +00:33:15,796 --> 00:33:19,366 +支持 macOS 和 iOS +但 watchOS 无法使用这个系列 + +621 +00:33:20,200 --> 00:33:22,336 +于是我们增加了一个枚举值来定义这个视图 + +622 +00:33:24,004 --> 00:33:28,041 +我们使用仪表来显示 +从 0 到每日配额的订单量 + +623 +00:33:28,075 --> 00:33:30,844 +这样用户就能快速并且一目了然地看到进展 + +624 +00:33:31,678 --> 00:33:34,648 +我们在中间以文本形式显示当前订单量 + +625 +00:33:34,681 --> 00:33:37,217 +并显示一个甜甜圈符号 +好了 + +626 +00:33:37,251 --> 00:33:39,152 +我们在 Xcode Previews 中看看效果 + +627 +00:33:40,721 --> 00:33:41,755 +很棒 + +628 +00:33:41,788 --> 00:33:42,956 +在锁定屏幕上看起来很自然 + +629 +00:33:43,924 --> 00:33:45,826 +如果想一目了然地显示更多细节 + +630 +00:33:45,859 --> 00:33:48,328 +我们还可以添加对 Rectangular 系列的支持 + +631 +00:33:51,932 --> 00:33:54,735 +我们建一个 VStack 来实现这个视图 + +632 +00:33:54,768 --> 00:33:57,104 +首先给所展示的数据一个标题 + +633 +00:33:57,137 --> 00:33:58,805 +还有同样的甜甜圈符号 + +634 +00:33:59,506 --> 00:34:01,775 +将字体设置为标题样式 + +635 +00:34:01,808 --> 00:34:04,278 +这样在两个平台上都有很美观的效果 + +636 +00:34:04,311 --> 00:34:07,414 +然后用 widgetAccentable +modifier 确保它着重显示 + +637 +00:34:07,447 --> 00:34:10,784 +由于 Rectangular 系列提供了更多空间 + +638 +00:34:10,817 --> 00:34:13,554 +我们可以显示一个很酷的 +自定义分段式仪表 + +639 +00:34:13,587 --> 00:34:18,592 +同时让仪表标签显示 +当前订单数和每日配额 + +640 +00:34:18,625 --> 00:34:20,160 +回到画布 + +641 +00:34:20,194 --> 00:34:22,796 +我们也可以在预览中看到 +Rectangular 小组件 + +642 +00:34:22,829 --> 00:34:25,132 +我真的非常喜欢这个仪表 + +643 +00:34:25,165 --> 00:34:26,934 +现在我们来看看这个小组件 + +644 +00:34:26,967 --> 00:34:30,437 +在手表表盘以 Circular +复杂功能显示是什么效果 + +645 +00:34:32,573 --> 00:34:34,341 +相当好 所有信息都显示了 + +646 +00:34:34,374 --> 00:34:36,844 +但对复杂功能来说 我们还需考虑 + +647 +00:34:36,877 --> 00:34:38,145 +全彩渲染模式 + +648 +00:34:38,178 --> 00:34:41,248 +这是 Xcode Previews 中的默认模式 + +649 +00:34:41,281 --> 00:34:45,419 +我们来调整一下 +给每个仪表添加一点色调 + +650 +00:34:46,687 --> 00:34:49,756 +再给 Rectangular 标题添加一个前景色 + +651 +00:34:51,592 --> 00:34:53,093 +要在全彩中强调显示 + +652 +00:34:53,126 --> 00:34:56,697 +我们可以用环境属性检查渲染模式 + +653 +00:34:56,730 --> 00:35:00,133 +并在 Circular 和 +Rectangular 视图中 + +654 +00:35:00,167 --> 00:35:04,872 +用甜甜圈表情符号替换甜甜圈符号 + +655 +00:35:04,905 --> 00:35:06,139 +看起来很棒 + +656 +00:35:06,173 --> 00:35:08,041 +利用预览中的新变体 UI + +657 +00:35:08,075 --> 00:35:11,078 +完全无需创建任何代码 +我们可以改变预览颜色 + +658 +00:35:12,179 --> 00:35:14,181 +甚至同时预览多个颜色 + +659 +00:35:14,948 --> 00:35:18,018 +由于我们使用了默认的间距 +系统字体样式 + +660 +00:35:18,051 --> 00:35:19,620 +并适应了渲染模式 + +661 +00:35:19,653 --> 00:35:23,123 +同样的视图在锁定屏幕和手表表盘上 +看起来都相当自然 + +662 +00:35:23,156 --> 00:35:26,793 +如刚所示都是使用同样的代码 +就可以轻松制作 + +663 +00:35:26,827 --> 00:35:30,564 +iOS 16 全新锁定屏幕的小组件 +以及 watchOS 9 的复杂功能 + +664 +00:35:30,597 --> 00:35:33,800 +但这并不是唯一一种把 WidgetKit 的能力 +带到锁定屏幕的方式 + +665 +00:35:33,834 --> 00:35:35,435 +下面请 Matt 给大家介绍 + +666 +00:35:36,003 --> 00:35:37,070 +利用 WidgetKit + +667 +00:35:37,104 --> 00:35:39,806 +你可以让用户获取一目了然的信息 + +668 +00:35:39,840 --> 00:35:42,309 +但他们有时需要实时更新的信息 + +669 +00:35:42,342 --> 00:35:44,945 +或是与他们当前关心的活动或事件有关的信息 + +670 +00:35:44,978 --> 00:35:46,446 +这时该怎么做呢 + +671 +00:35:46,480 --> 00:35:51,118 +为此 我们正在探索一个新的功能 +称为实时活动 + +672 +00:35:51,151 --> 00:35:53,320 +实时活动让你更容易实时获取 + +673 +00:35:53,353 --> 00:35:55,122 +与正在发生的事情相关的信息 + +674 +00:35:55,155 --> 00:35:56,723 +直接显示在锁定屏幕上 + +675 +00:35:56,757 --> 00:36:00,027 +比如比赛的最新得分 + +676 +00:36:00,060 --> 00:36:03,497 +叫车进程或体能训练进度 + +677 +00:36:03,530 --> 00:36:06,066 +直接显示在锁定屏幕上并且实时更新 + +678 +00:36:06,099 --> 00:36:09,703 +就像小组件一样 你可以用 +WidgetKit 创建实时活动 + +679 +00:36:09,736 --> 00:36:12,406 +差别在于实时活动所呈现的信息和状态 + +680 +00:36:12,439 --> 00:36:14,208 +是实时更新的 + +681 +00:36:14,241 --> 00:36:16,210 +由于它们是用 SwiftUI 构建的 + +682 +00:36:16,243 --> 00:36:19,580 +你甚至可以将状态间的更新做成动画 + +683 +00:36:19,613 --> 00:36:21,615 +这些更新确保你的实时活动 + +684 +00:36:21,648 --> 00:36:25,452 +在用户浏览时显示最新的信息 + +685 +00:36:25,485 --> 00:36:30,490 +实时活动将于今年晚些时候 +在 iOS 16 更新中开始提供 + +686 +00:36:30,524 --> 00:36:32,993 +这就是全新锁定屏幕的最新进展 + +687 +00:36:33,026 --> 00:36:34,094 +这些超棒的更新 + +688 +00:36:34,127 --> 00:36:38,398 +可以让你在用户最需要的时候 +为他们提供一目了然的信息 + +689 +00:36:39,132 --> 00:36:42,603 +接下来 我们来谈一谈增强协作体验的全新方式 + +690 +00:36:42,636 --> 00:36:44,938 +由 Pierre 来给大家介绍 + +691 +00:36:44,972 --> 00:36:46,974 +协作同步是非常重要的 无论是在 + +692 +00:36:47,007 --> 00:36:50,511 +iOS、iPadOS 还是 macOS 上 + +693 +00:36:50,544 --> 00:36:53,380 +这在很大程度上是得益于大量丰富的 app + +694 +00:36:53,413 --> 00:36:55,015 +很多正是由你们来开发的 + +695 +00:36:55,048 --> 00:36:57,885 +来支持所有远距离协作的团队们 + +696 +00:36:57,918 --> 00:37:01,588 +工作上的协作 例如 Airtable 中的产品路线图 + +697 +00:37:01,622 --> 00:37:06,226 +还有娱乐上的协作 +例如在 Redfin 上寻找你的梦想家园 + +698 +00:37:06,260 --> 00:37:08,095 +无论是工作还是娱乐 + +699 +00:37:08,128 --> 00:37:11,265 +协作通常从对话开始 + +700 +00:37:11,298 --> 00:37:13,800 +通过全新的 Messages +Collaboration API + +701 +00:37:13,834 --> 00:37:16,970 +你可以把 app 的现有协作体验 + +702 +00:37:17,004 --> 00:37:18,772 +融入信息 app 和 FaceTime 通话 + +703 +00:37:18,805 --> 00:37:21,708 +当用户在你的 app 中分享内容链接时 + +704 +00:37:21,742 --> 00:37:25,412 +这个 API 可以让你更轻松地 +将连接标记为协作性的 + +705 +00:37:25,445 --> 00:37:27,514 +以实现无缝的体验 + +706 +00:37:27,548 --> 00:37:29,650 +我们提供你所需的标识符 + +707 +00:37:29,683 --> 00:37:32,152 +这样你可以在接收方轻点链接加入时 + +708 +00:37:32,186 --> 00:37:33,987 +立即提供访问权 + +709 +00:37:34,021 --> 00:37:36,924 +当然 这都是在不影响隐私的前提下进行的 + +710 +00:37:36,957 --> 00:37:40,994 +信息身份和 app 身份将保持私密 不会被分享 + +711 +00:37:41,028 --> 00:37:44,831 +最棒的是 你可以用你的 app 很可能已经在用的 + +712 +00:37:44,865 --> 00:37:47,301 +现有技术来实现这一点 + +713 +00:37:47,334 --> 00:37:51,471 +只需一个对象 用户就可以发起协作 + +714 +00:37:51,505 --> 00:37:54,575 +有两种他们已经很熟悉的方式来进行操作 + +715 +00:37:54,608 --> 00:37:57,277 +一是共享表单 我们已经提供更新 + +716 +00:37:57,311 --> 00:37:59,446 +将协作放在非常重要的位置 + +717 +00:37:59,479 --> 00:38:01,014 +二是通过拖放 + +718 +00:38:01,048 --> 00:38:03,750 +分享你想协作的内容 + +719 +00:38:03,784 --> 00:38:06,954 +仅需直接将内容拖到信息 app 的对话中 + +720 +00:38:06,987 --> 00:38:10,557 +一旦协作开始 你甚至可以把内容更新通知 + +721 +00:38:10,591 --> 00:38:14,061 +直接发布在信息 app 的对话中 + +722 +00:38:14,094 --> 00:38:17,798 +只需几行代码 用户就可以回到 +你的 app 中进行协作 + +723 +00:38:17,831 --> 00:38:21,034 +仅需在信息 app 中轻点一下 + +724 +00:38:21,068 --> 00:38:22,703 +利用协作弹窗 + +725 +00:38:22,736 --> 00:38:27,908 +用户可以从你的 app 里 +直接回到信息 app 或 FaceTime 通话中 + +726 +00:38:27,941 --> 00:38:29,943 +利用 Messages +Collaboration API + +727 +00:38:29,977 --> 00:38:33,780 +你的 app 可以深度整合到信息 app +和 FaceTime 通话的架构中 + +728 +00:38:33,814 --> 00:38:37,684 +我们给你的用户提供强大的通信工具 + +729 +00:38:37,718 --> 00:38:40,754 +这样你就可以专注于你的 app + +730 +00:38:40,787 --> 00:38:42,422 +提供强大的协作工具 + +731 +00:38:42,456 --> 00:38:46,860 +这将提升 iOS、iPadOS +和 macOS 上的协作功能 + +732 +00:38:46,894 --> 00:38:48,695 +创造一致的体验 + +733 +00:38:48,729 --> 00:38:52,399 +它深深扎根于协作者之间的联系 + +734 +00:38:52,432 --> 00:38:53,934 +无论是用于工作还是娱乐 + +735 +00:38:53,967 --> 00:38:56,470 +接下来 Ari 将给大家介绍 + +736 +00:38:56,503 --> 00:38:59,072 +一个新的框架 App Intents + +737 +00:38:59,106 --> 00:39:02,609 +我非常高兴可以给各位介绍 App Intents 框架 + +738 +00:39:02,643 --> 00:39:05,245 +它把你的 app 的功能开放给系统 + +739 +00:39:05,279 --> 00:39:09,183 +这样用户就可以通过 Siri 和快捷指令 +自动使用这些功能 + +740 +00:39:09,216 --> 00:39:11,552 +人们喜欢在使用 app 时使用快捷指令 + +741 +00:39:11,585 --> 00:39:15,022 +快捷指令让用户可以快速完成任务 +仅需询问 Siri + +742 +00:39:15,055 --> 00:39:18,325 +或快速轻点主屏幕上的快捷指令 + +743 +00:39:18,358 --> 00:39:21,428 +让我们惊叹的是用户组合使用 app 的能力 + +744 +00:39:21,461 --> 00:39:25,299 +用自定义快捷指令 +把它们组合成新的功能 + +745 +00:39:25,332 --> 00:39:29,703 +目前 用户必须先手动添加快捷指令 +之后才能使用它们 + +746 +00:39:29,736 --> 00:39:34,041 +我们在 iOS 16 中将通过新的 +App Intents 框架 把这个过程自动化 + +747 +00:39:35,075 --> 00:39:39,112 +App Intents 与快捷指令一起 +形成 app 快捷指令 + +748 +00:39:39,146 --> 00:39:41,281 +供用户直接通过 Siri 使用 + +749 +00:39:41,315 --> 00:39:43,116 +无需预先设置 + +750 +00:39:43,150 --> 00:39:46,386 +可以说 “嘿 Siri 用 Roomba 打扫厨房” + +751 +00:39:46,420 --> 00:39:47,988 +而且不只是 Siri + +752 +00:39:48,021 --> 00:39:49,990 +app 快捷指令让你的用户 + +753 +00:39:50,023 --> 00:39:52,693 +可以在整个系统中使用你的 app 的功能 + +754 +00:39:52,726 --> 00:39:56,330 +像是在聚焦中 当用户搜索你的 app 时 + +755 +00:39:56,363 --> 00:39:58,532 +你的快捷指令也会显示出来 + +756 +00:39:58,565 --> 00:40:02,302 +并且你的快捷指令会被 +直接推荐在 app 推荐下面 + +757 +00:40:02,336 --> 00:40:06,306 +无需采用任何额外 API 如 donations + +758 +00:40:06,340 --> 00:40:09,409 +你的快捷指令还会立即出现在 +快捷指令 app 中 + +759 +00:40:09,443 --> 00:40:11,512 +用户可以轻点运行 + +760 +00:40:12,179 --> 00:40:17,584 +App Intents 是我们在 iOS 10 中引入的 +SiriKit Intents 框架的下一步 + +761 +00:40:17,618 --> 00:40:21,021 +如果你用各种 intent +来整合小组件或是 domain + +762 +00:40:21,054 --> 00:40:22,389 +比如媒体或信息 + +763 +00:40:22,422 --> 00:40:25,626 +你应该继续使用 SiriKit Intents 框架 + +764 +00:40:25,659 --> 00:40:29,062 +但对为 Siri 和快捷指令 +构建自定义 intent 的开发者 + +765 +00:40:29,096 --> 00:40:31,298 +你应该升级至 App Intents + +766 +00:40:31,331 --> 00:40:34,501 +你可以在 Xcode 中轻松 +升级到 App Intents + +767 +00:40:34,535 --> 00:40:37,804 +仅需点击 intent 定 +义文件中的 Convert 按钮 + +768 +00:40:37,838 --> 00:40:40,841 +Xcode 会生成对等的 App Intents 源代码 + +769 +00:40:40,874 --> 00:40:43,310 +然后你用你的 intent 处理代码来填补空白 + +770 +00:40:43,343 --> 00:40:46,580 +用 App Intents 进行开发真的非常容易 + +771 +00:40:46,613 --> 00:40:49,716 +因为它是为 Swift 特意设计的 + +772 +00:40:49,750 --> 00:40:52,085 +所以需要的代码要少得多 + +773 +00:40:52,119 --> 00:40:55,455 +你所写的 Swift 代码 就是唯一的数据源 + +774 +00:40:55,489 --> 00:40:57,758 +也没有需要同步保留 额外的 intent 定义文件 + +775 +00:40:57,791 --> 00:41:00,060 +或代码生成 + +776 +00:41:00,093 --> 00:41:02,696 +并且这些代码很容易添加到你的项目中 + +777 +00:41:02,729 --> 00:41:05,232 +你不需要重新设计你的代码库 + +778 +00:41:05,265 --> 00:41:08,335 +哪怕你有 Objective-C 代码 +你仍然可以在 App Intents 中使用它们 + +779 +00:41:08,368 --> 00:41:09,970 +只要用 Swift 代码封装一下 + +780 +00:41:10,003 --> 00:41:13,373 +一个 app intent 表示用户在你的 app 中 +可以做的事情 + +781 +00:41:13,407 --> 00:41:16,610 +并且使从你的 app 外完成该操作成为可能 + +782 +00:41:16,643 --> 00:41:19,346 +你可以定义 intent 并添加 app 快捷指令 + +783 +00:41:19,379 --> 00:41:21,048 +仅需几行代码 + +784 +00:41:21,081 --> 00:41:23,250 +我们来一起试一试 + +785 +00:41:23,283 --> 00:41:25,953 +回到 Food Truck app +我这里有个很棒的图表视图 + +786 +00:41:25,986 --> 00:41:30,557 +可以让我看到不同时间段内 +最畅销的五种甜甜圈 + +787 +00:41:30,591 --> 00:41:32,459 +比如今天或本周 + +788 +00:41:32,492 --> 00:41:34,628 +我想把它显示给 Siri 和快捷指令 + +789 +00:41:34,661 --> 00:41:37,397 +这样用户就可以飞快地调出它 + +790 +00:41:37,431 --> 00:41:40,834 +首先 在 Xcode 中 我进入 +一个新的 Swift 文件 + +791 +00:41:40,868 --> 00:41:44,171 +导入 App Intents 和 SwiftUI 框架 + +792 +00:41:45,672 --> 00:41:47,541 +然后给这个 intent 下定义 + +793 +00:41:47,574 --> 00:41:50,878 +要通过定义一个符合 AppIntent 协议的结构 + +794 +00:41:50,911 --> 00:41:53,247 +我来给它加一个 title + +795 +00:41:53,280 --> 00:41:57,251 +再添加一个 parameter +来定义具体哪个时间段的趋势 + +796 +00:41:57,284 --> 00:42:01,221 +它使用的是已经在我的代码库中 +定义的时间框架枚举 + +797 +00:42:01,255 --> 00:42:04,925 +我需要扩展它 以符合 AppEnum 协议 + +798 +00:42:04,958 --> 00:42:08,662 +这样我们就可以为每个枚举情况 +提取人类可读的名称 + +799 +00:42:08,695 --> 00:42:11,064 +如 “今天” 和 “本周” + +800 +00:42:11,098 --> 00:42:15,569 +接下来 在 intent 这里 +加上 perform 方法 + +801 +00:42:15,602 --> 00:42:19,640 +这里 返回的是一个包含 SwiftUI 视图的结果 + +802 +00:42:19,673 --> 00:42:22,643 +我还可以加入一个对话或输出值 + +803 +00:42:22,676 --> 00:42:26,380 +我希望用户可以自动使用这个 intent +而不用设置 + +804 +00:42:26,413 --> 00:42:28,115 +所以我要定义一个 app 快捷指令 + +805 +00:42:30,017 --> 00:42:32,719 +这包括用户可以对 Siri 说的短语 + +806 +00:42:32,753 --> 00:42:34,488 +好调用这个 intent + +807 +00:42:34,521 --> 00:42:38,258 +这个短语必须包括 app 的名称作为变量 + +808 +00:42:38,292 --> 00:42:40,894 +我还包括了时间段参数 + +809 +00:42:40,928 --> 00:42:43,964 +所以用户可以说 “Food Truck 今日趋势” + +810 +00:42:43,997 --> 00:42:46,967 +或 “Food Truck 本周趋势” + +811 +00:42:47,000 --> 00:42:50,470 +我需要做的最后一件事 +就是让用户可以发现这个快捷指令 + +812 +00:42:50,504 --> 00:42:52,673 +用户需要在某个时候看到这个短语 + +813 +00:42:52,706 --> 00:42:54,474 +以便知道他们可以对 Siri 说什么 + +814 +00:42:54,508 --> 00:42:57,778 +所以我就切换到前五甜甜圈视图文件 + +815 +00:42:57,811 --> 00:42:59,546 +就是我们刚刚看的那个 + +816 +00:42:59,580 --> 00:43:01,648 +我在这里添加一个 SiriTip + +817 +00:43:03,217 --> 00:43:07,387 +现在我就可以构建并运行这个 app +然后在我的手机上试试看 + +818 +00:43:07,421 --> 00:43:08,455 +我们来试一试 + +819 +00:43:10,958 --> 00:43:13,594 +我可以看到快捷指令出现在了快捷指令 app 中 + +820 +00:43:13,627 --> 00:43:15,863 +每个参数值都有变量 + +821 +00:43:15,896 --> 00:43:19,433 +我可以轻点运行一个 + +822 +00:43:19,466 --> 00:43:22,769 +也可通过说那句短语 从 Siri 运行 + +823 +00:43:22,803 --> 00:43:24,838 +“Food Truck 今日趋势” + +824 +00:43:26,640 --> 00:43:30,010 +我还可以说 “Food Truck 本周趋势” + +825 +00:43:32,279 --> 00:43:34,681 +当用户进到 app 的前五视图时 + +826 +00:43:34,715 --> 00:43:36,783 +他们会看到我们在底部添加的这个提示 + +827 +00:43:36,817 --> 00:43:40,320 +从而了解对 Siri 说什么可以使用该功能 + +828 +00:43:40,354 --> 00:43:43,657 +最后 用户在聚焦中搜索该 app 时 + +829 +00:43:43,690 --> 00:43:45,759 +可以访问这些功能 就像这样 + +830 +00:43:47,995 --> 00:43:50,130 +非常有用 + +831 +00:43:50,163 --> 00:43:53,100 +App Intents 让你前所未有地轻松打造 + +832 +00:43:53,133 --> 00:43:58,772 +各种 app 功能 整合于系统体验中 +并跨越各个平台 + +833 +00:43:58,805 --> 00:44:01,275 +下面 Ricky 将给大家带来一些 + +834 +00:44:01,308 --> 00:44:03,210 +关于认证技术的重大进展 + +835 +00:44:03,877 --> 00:44:05,445 +从我们记事开始 + +836 +00:44:05,479 --> 00:44:08,048 +我们就一直在创建和使用密码 + +837 +00:44:08,081 --> 00:44:10,250 +但密码有着严重的问题 + +838 +00:44:10,284 --> 00:44:14,421 +如网络钓鱼、多账号使用同一密码、网站泄露 + +839 +00:44:14,454 --> 00:44:18,091 +好消息是 我们可以携起手来解决这一问题 + +840 +00:44:18,125 --> 00:44:21,161 +现在 我们用通行密钥就可以了 + +841 +00:44:21,195 --> 00:44:24,131 +通行密钥将简化你的认证流程 + +842 +00:44:24,164 --> 00:44:27,434 +解决密码的首要安全问题 + +843 +00:44:27,467 --> 00:44:30,737 +通行密钥的设计理念让它无比易用 + +844 +00:44:30,771 --> 00:44:34,274 +通行密钥复用了之前的自动填充信息界面 + +845 +00:44:34,308 --> 00:44:37,778 +并使用面容 ID 和触控 ID 进行生物识别验证 + +846 +00:44:37,811 --> 00:44:41,448 +这些元素创造了从密码的无缝过渡 + +847 +00:44:41,481 --> 00:44:44,985 +同时大大提升了安全性 + +848 +00:44:45,018 --> 00:44:47,187 +让我们来看看通行密钥的实际应用 + +849 +00:44:47,988 --> 00:44:50,090 +用通行密钥设置账户的话 + +850 +00:44:50,123 --> 00:44:52,359 +我就不需要创建密码了 + +851 +00:44:52,392 --> 00:44:57,497 +我在这里输入用户名 +并将通行密钥保存到我的 iCloud 钥匙串中 + +852 +00:44:57,531 --> 00:45:01,969 +这个通行密钥就安全同步到 +我所有其他 Apple 设备上了 + +853 +00:45:02,002 --> 00:45:06,106 +重新登录是一件轻而易举的事 + +854 +00:45:06,139 --> 00:45:09,309 +面容 ID 验证 就搞定 + +855 +00:45:09,343 --> 00:45:12,546 +通行密钥建立在开放的行业标准上 + +856 +00:45:12,579 --> 00:45:14,281 +且各个平台都在持续采用 + +857 +00:45:14,314 --> 00:45:17,584 +我可以用我刚刚在 iPhone 上创建的通行密钥 + +858 +00:45:17,618 --> 00:45:21,088 +在我朋友的 PC 上登录 Food Truck 网站 + +859 +00:45:21,121 --> 00:45:25,192 +在网站上 输入我的用户名 +点击提交 + +860 +00:45:25,225 --> 00:45:28,896 +选择用手机登陆 + +861 +00:45:28,929 --> 00:45:31,331 +扫描二维码 + +862 +00:45:31,365 --> 00:45:36,570 +让 PC 和 iPhone 建立安全连接 + +863 +00:45:36,603 --> 00:45:39,139 +登录成功 + +864 +00:45:39,173 --> 00:45:42,543 +在我自己 Mac 的 Safari 浏览器上 +登录更加简单 + +865 +00:45:42,576 --> 00:45:45,612 +我的通行密钥已经在这里了 +得益于 iCloud 钥匙串 + +866 +00:45:45,646 --> 00:45:49,283 +所以我可以直接从网站的用户名栏登录 + +867 +00:45:49,316 --> 00:45:53,120 +将通行密钥整合到现有登录流程中非常容易 + +868 +00:45:53,153 --> 00:45:57,424 +例如 这个网站的用户名栏允许我用通行密钥登录 + +869 +00:45:57,457 --> 00:45:59,092 +也可用密码登录 + +870 +00:45:59,126 --> 00:46:03,864 +如果我输入一个有密码的账号的用户名 + +871 +00:46:03,897 --> 00:46:05,432 +我也可以快速登录 + +872 +00:46:05,465 --> 00:46:08,235 +使用通行密钥 出力的是设备 + +873 +00:46:08,268 --> 00:46:10,604 +而且每次都是安全的 + +874 +00:46:10,637 --> 00:46:12,139 +创建通行密钥时 + +875 +00:46:12,172 --> 00:46:16,977 +设备会生成一个独特密钥 +专用于创建它的网站或 app + +876 +00:46:17,010 --> 00:46:19,713 +并且这个密钥会受到生物识别的保护 + +877 +00:46:19,746 --> 00:46:22,282 +不可能有弱通行密钥 + +878 +00:46:22,316 --> 00:46:25,219 +这些密钥不会被遗忘、无法重新使用 +或者被猜出来 + +879 +00:46:25,252 --> 00:46:28,388 +通行密钥的基础是公钥加密技术 + +880 +00:46:28,422 --> 00:46:32,092 +这让服务器端的凭证泄露成为历史 + +881 +00:46:32,125 --> 00:46:35,429 +不同于之前 在服务器上存储加盐哈希密码 + +882 +00:46:35,462 --> 00:46:40,567 +存在泄漏和被破解的风险 +现在只需要将对应的公钥保存在上面 + +883 +00:46:40,601 --> 00:46:43,103 +公钥被设计为真正公开的 + +884 +00:46:43,136 --> 00:46:45,405 +对黑客完全没有价值 + +885 +00:46:45,439 --> 00:46:49,209 +这极大地降低了你作为网站所有者的风险 + +886 +00:46:49,243 --> 00:46:52,179 +还有非常重要的一点 + +887 +00:46:52,212 --> 00:46:55,215 +有了通行密钥 +我们今天所知的凭证钓鱼将不复存在 + +888 +00:46:55,249 --> 00:46:59,453 +消除了用户面临的头号安全漏洞 + +889 +00:46:59,486 --> 00:47:03,524 +通行密钥与设置它们的网站或 app 有内在联系 + +890 +00:47:03,557 --> 00:47:07,828 +因此 用户永远不会被骗在错误的网站上 +使用他们的通行密钥 + +891 +00:47:07,861 --> 00:47:09,530 +而且 与密码不同的是 + +892 +00:47:09,563 --> 00:47:12,366 +将通行密钥输入或复制到 + +893 +00:47:12,399 --> 00:47:14,501 +看上去非常逼真的假网站是不可能的 + +894 +00:47:14,535 --> 00:47:18,238 +甚至不可能将任何信息泄露给偷看到你密码的人 + +895 +00:47:18,272 --> 00:47:21,141 +把这一切放在一起时 +我们看到的就是 + +896 +00:47:21,175 --> 00:47:23,644 +账户安全的崭新时代 + +897 +00:47:23,677 --> 00:47:27,748 +在你的 app 和网站里支持 通行密钥仅需几步 + +898 +00:47:27,781 --> 00:47:31,084 +首先 教你的帐户后端存储公钥 + +899 +00:47:31,118 --> 00:47:33,687 +并发出身份验证挑战 + +900 +00:47:33,720 --> 00:47:36,190 +然后 在网站和 app 中 + +901 +00:47:36,223 --> 00:47:38,058 +给用户提供通行密钥 + +902 +00:47:38,091 --> 00:47:42,329 +并采用 API 来创建新的通行密钥以及用它登录 + +903 +00:47:42,362 --> 00:47:46,934 +通行密钥基于 Web 认证标准 + +904 +00:47:46,967 --> 00:47:49,870 +这个标准是跨行业的平台供应商和服务所有者 + +905 +00:47:49,903 --> 00:47:53,407 +共同努力的结果 + +906 +00:47:53,440 --> 00:47:56,610 +这标准本身非常成熟 +并且有详细的对应文档 + +907 +00:47:56,643 --> 00:47:59,112 +通行密钥非常适合它 + +908 +00:47:59,146 --> 00:48:02,683 +所有这一切已经准备就绪 +你现在就可开始构建 + +909 +00:48:02,716 --> 00:48:06,453 +新一代的安全保护 流畅的用户体验 + +910 +00:48:06,486 --> 00:48:10,824 +并能在转换过渡期与密码顺畅地使用 + +911 +00:48:10,858 --> 00:48:12,459 +交回给你 Sebastien + +912 +00:48:12,492 --> 00:48:15,195 +大家刚刚看到的是一些最新的方式 + +913 +00:48:15,229 --> 00:48:19,733 +能让你的 app 整合到 +跨我们所有平台的系统体验中 + +914 +00:48:19,766 --> 00:48:24,137 +除了这些可以整合的特性 +还有大量新的 API 和框架 + +915 +00:48:24,171 --> 00:48:25,672 +跨我们所有的平台 + +916 +00:48:25,706 --> 00:48:29,476 +能在今年为你和你的 app 带来更多的可能性 + +917 +00:48:30,310 --> 00:48:32,312 +我想先给大家介绍一些 + +918 +00:48:32,346 --> 00:48:35,782 +然后再更深入讲解另外几个 + +919 +00:48:35,816 --> 00:48:38,418 +我们先来看 iPadOS + +920 +00:48:38,452 --> 00:48:42,923 +有了 iPadOS 16 你可以打造出 +iPad 上各类前所未有的强大 app + +921 +00:48:42,956 --> 00:48:46,326 +并且带来和桌面级 app 一致的体验 + +922 +00:48:46,360 --> 00:48:49,930 +例如流畅的查找和替换体验用于 UI 文本视图 + +923 +00:48:49,963 --> 00:48:52,132 +让你打造的 app 可以直接调用 + +924 +00:48:52,165 --> 00:48:54,434 +以及对导航栏、工具栏 + +925 +00:48:54,468 --> 00:48:56,403 +文档菜单的更新 + +926 +00:48:56,436 --> 00:48:59,339 +它们会让你的用户能更轻松地管理文档 + +927 +00:48:59,373 --> 00:49:01,575 +以及自定义他们的体验 + +928 +00:49:01,608 --> 00:49:05,746 +为了让 iPad 更好地与其他硬件搭配使用 + +929 +00:49:05,779 --> 00:49:07,748 +我们为 iPad 推出了 DriverKit + +930 +00:49:07,781 --> 00:49:11,285 +解锁 M1 芯片的惊人性能 + +931 +00:49:11,318 --> 00:49:13,987 +它与目前在 Mac 上可用的 API 相同 + +932 +00:49:14,021 --> 00:49:18,358 +让你可以轻松地向更多用户提供对 + +933 +00:49:18,392 --> 00:49:21,261 +USB、音频和 PCI 设备的支持 + +934 +00:49:22,596 --> 00:49:25,532 +此外 watchOS 也正在为各类 app 创造新的机会 + +935 +00:49:25,566 --> 00:49:28,702 +通过与各类系统服务 更深层度的整合 + +936 +00:49:28,735 --> 00:49:31,238 +watchOS 9 的 CallKit 框架 + +937 +00:49:31,271 --> 00:49:33,740 +包括一个新的 VoIP 背景模式 + +938 +00:49:33,774 --> 00:49:37,211 +让 app 可以直接从 Apple Watch 上 +发起语音通话 + +939 +00:49:37,244 --> 00:49:41,882 +带来熟悉的用户体验 +正如 FaceTime 音频通话和打电话那样 + +940 +00:49:41,915 --> 00:49:46,687 +通过蓝牙连接的医疗设备获得了 +更强大的连接能力和数据传输 + +941 +00:49:46,720 --> 00:49:50,290 +能在检测到危急情况时及时发出提示 + +942 +00:49:51,692 --> 00:49:55,629 +tvOS 16 为你提供了新的方法 +来创造连接性的体验 + +943 +00:49:55,662 --> 00:49:57,397 +让你把 Apple TV 上的 app + +944 +00:49:57,431 --> 00:50:01,902 +与附近设备上的 iPhone、iPad +或 Apple Watch app 相连 + +945 +00:50:01,935 --> 00:50:05,072 +这样 锻炼可以使用 Apple Watch 的运动数据 + +946 +00:50:05,105 --> 00:50:06,740 +或者你可以把 iPhone 或 iPad + +947 +00:50:06,773 --> 00:50:10,177 +用作回合制游戏的自定义手柄 + +948 +00:50:10,210 --> 00:50:14,147 +tvOS 负责管理设备的发现和连接 + +949 +00:50:14,181 --> 00:50:16,450 +所以你的 app 甚至无需在另一部设备上运行 + +950 +00:50:16,483 --> 00:50:18,719 +事实上 如果你的 app 还没被安装 + +951 +00:50:18,752 --> 00:50:23,757 +用户会被自动提示从 App Store下载它 + +952 +00:50:23,790 --> 00:50:27,694 +对于手机和 iPad +还有提供给广告商的新工具 + +953 +00:50:27,728 --> 00:50:31,465 +我们知道 有效的广告对大家的很多业务很重要 + +954 +00:50:31,498 --> 00:50:34,401 +这就是为什么我们创建了 SKAdNetwork + +955 +00:50:34,434 --> 00:50:37,204 +这是一个帮助广告网络和广告商的 API + +956 +00:50:37,237 --> 00:50:40,574 +可在不追踪用户的前提下衡量广告活动的指标 + +957 +00:50:40,607 --> 00:50:44,945 +我们很高兴看到许多第三方广告网络都采用了它 + +958 +00:50:44,978 --> 00:50:47,681 +我们听到了广告网络和开发者的反馈 + +959 +00:50:47,714 --> 00:50:51,151 +并在今年对 SKAdNetwork 进行了一些改进 + +960 +00:50:51,185 --> 00:50:53,020 +回应了许多强烈要求的功能 + +961 +00:50:53,053 --> 00:50:55,489 +为大家提供极大的灵活性 + +962 +00:50:55,522 --> 00:50:58,659 +同时不影响隐私 + +963 +00:50:59,793 --> 00:51:02,362 +在 iPhone 和 iPad 上 有些很酷的新功能 + +964 +00:51:02,396 --> 00:51:07,034 +基于增强现实和激光雷达扫描仪 +用到了 ScanKit 与 RoomPlan + +965 +00:51:07,067 --> 00:51:13,607 +这些 API 让你的 app 以 USD 和 USDZ +格式创建信息丰富的 3D 参数化房间模型 + +966 +00:51:13,640 --> 00:51:16,743 +你可以创建各种工作流和体验 + +967 +00:51:16,777 --> 00:51:20,347 +从建筑和设计 到零售、酒店行业 + +968 +00:51:20,380 --> 00:51:23,951 +这些模型包括了家具分类 + +969 +00:51:23,984 --> 00:51:29,423 +包括沙发、橱柜、电视等类别 +没错 甚至还有厨房水槽 + +970 +00:51:29,456 --> 00:51:31,225 +去年 我们推出了专注模式 + +971 +00:51:31,258 --> 00:51:33,927 +适用于 iPhone、iPad +Mac 和 Apple Watch + +972 +00:51:33,961 --> 00:51:39,633 +让你的 app 根据用户的专注模式去管理通知 + +973 +00:51:39,666 --> 00:51:43,170 +今年 我们将通过专注模式过滤条件 +进一步加强这项功能 + +974 +00:51:43,203 --> 00:51:46,773 +专注模式过滤条件建立在 App Intents 之上 + +975 +00:51:46,807 --> 00:51:50,377 +让你根据用户当前的专注模式调整 app 的内容 + +976 +00:51:50,410 --> 00:51:53,213 +例如 app 可以创建专注模式过滤条件 + +977 +00:51:53,247 --> 00:51:57,818 +在用户设置为工作模式时 仅显示工作账号 + +978 +00:51:57,851 --> 00:52:01,388 +而这些例子仅是冰山一角 + +979 +00:52:01,421 --> 00:52:04,458 +在各个层面都有新的工具和 API + +980 +00:52:04,491 --> 00:52:06,093 +为你提供所需要的功能 + +981 +00:52:06,126 --> 00:52:08,362 +让你的 app 更进一步 + +982 +00:52:08,395 --> 00:52:11,098 +以及创造全新的 app 和体验 + +983 +00:52:11,131 --> 00:52:13,534 +下面 我们来深入讲解一下 + +984 +00:52:13,567 --> 00:52:14,902 +首先就是 Metal + +985 +00:52:14,935 --> 00:52:18,038 +这项技术将各种体验带入全新境界 + +986 +00:52:18,071 --> 00:52:20,941 +更多详情 请 Sarah 来介绍 + +987 +00:52:20,974 --> 00:52:27,981 +♪ ♪ + +988 +00:52:29,249 --> 00:52:32,286 +Metal 是个强大的图形处理和计算 API + +989 +00:52:32,319 --> 00:52:34,888 +帮助你打造出令人惊叹的各类游戏和专业级 app + +990 +00:52:34,922 --> 00:52:36,423 +覆盖 Apple 的各个平台 + +991 +00:52:36,456 --> 00:52:38,325 +Metal 让你可以充分利用 Apple 打造的 + +992 +00:52:38,358 --> 00:52:41,895 +带来突破性能的图形处理器和统一内存系统 + +993 +00:52:41,929 --> 00:52:46,700 +覆盖搭载了 Apple 芯片的最新 +iPhone、iPad、Mac 产品线 + +994 +00:52:46,733 --> 00:52:50,771 +今年 我们将推出 Metal 3 + +995 +00:52:50,804 --> 00:52:52,506 +带来强大的新功能 + +996 +00:52:52,539 --> 00:52:55,275 +助你以更高的帧率渲染沉浸式画面 + +997 +00:52:55,309 --> 00:52:58,312 +并将计算性能推向新高 + +998 +00:52:58,345 --> 00:53:01,014 +例如 机器学习框架 Pytorch + +999 +00:53:01,048 --> 00:53:03,183 +将迎来巨大的性能提升 + +1000 +00:53:03,217 --> 00:53:05,085 +它现在使用新的 Metal 后端 + +1001 +00:53:05,118 --> 00:53:07,554 +使用图形处理器来进行机器学习训练 + +1002 +00:53:07,588 --> 00:53:10,257 +当然最受关注的领域就是游戏 + +1003 +00:53:10,290 --> 00:53:12,192 +首先是游戏加载 + +1004 +00:53:12,226 --> 00:53:14,494 +这是游戏体验的一个关键因素 + +1005 +00:53:14,528 --> 00:53:17,197 +会影响启动时间和新关卡加载 + +1006 +00:53:17,231 --> 00:53:19,900 +现在的游戏带来细节丰富的游戏体验 + +1007 +00:53:19,933 --> 00:53:22,269 +基于高画质的素材 + +1008 +00:53:22,302 --> 00:53:26,273 +将这些素材快速地从硬盘加载到图形处理器 +是件有挑战的事 + +1009 +00:53:26,306 --> 00:53:30,177 +通常 游戏会在加载画面时进行素材加载 + +1010 +00:53:30,210 --> 00:53:32,679 +一种加快游戏启动的方式 + +1011 +00:53:32,713 --> 00:53:34,815 +是加载并绘制一个较低质量的版本 + +1012 +00:53:34,848 --> 00:53:37,484 +直到高质量的视觉画面加载完毕 + +1013 +00:53:37,518 --> 00:53:39,620 +这并不是理想的游戏体验 + +1014 +00:53:39,653 --> 00:53:43,156 +因为用户会更长时间看到低画质 + +1015 +00:53:43,190 --> 00:53:46,260 +Metal 3 带来了快速资源加载 + +1016 +00:53:46,293 --> 00:53:47,628 +基于 Metal IO API + +1017 +00:53:47,661 --> 00:53:51,431 +利用 Apple 图形处理器的统一内存架构 + +1018 +00:53:51,465 --> 00:53:53,100 +减少加载开销 + +1019 +00:53:53,133 --> 00:53:57,871 +确保每台 Apple 芯片 +Mac 所配的高速 SSD 存储 + +1020 +00:53:57,905 --> 00:54:01,575 +在队列中有足够的请求 从而最大限度地提高通量 + +1021 +00:54:01,608 --> 00:54:04,878 +这个新的 API 会提供更快更一致的性能 + +1022 +00:54:04,912 --> 00:54:07,814 +从而把更多的时间留给理想画质的绘制 + +1023 +00:54:09,149 --> 00:54:12,152 +除了将资源从硬盘加载到内存以外 + +1024 +00:54:12,186 --> 00:54:14,955 +着色器编译也会影响游戏加载 + +1025 +00:54:14,988 --> 00:54:19,193 +着色器总是需要根据用户的 +独特硬件配置进行编译 + +1026 +00:54:19,226 --> 00:54:22,129 +由于 PC 硬件种类繁多 + +1027 +00:54:22,162 --> 00:54:24,464 +这通常需要在运行时完成 + +1028 +00:54:24,498 --> 00:54:27,734 +这种游戏中的编译会影响玩家体验 + +1029 +00:54:27,768 --> 00:54:31,338 +导致掉帧、帧率下降、加载时间延长 + +1030 +00:54:31,371 --> 00:54:35,375 +相比之下 Apple 芯片和 +Metal 3 的设计相辅相成 + +1031 +00:54:35,409 --> 00:54:37,144 +支持所有 Apple 设备 + +1032 +00:54:37,177 --> 00:54:39,546 +现在 有了离线着色器编译 + +1033 +00:54:39,580 --> 00:54:43,183 +你可以在项目构建时 +生成图形处理器着色器二进制文件 + +1034 +00:54:43,217 --> 00:54:46,153 +让你能够消除游戏中的着色器编译 + +1035 +00:54:46,186 --> 00:54:49,389 +减少加载时间 提升渲染性能 + +1036 +00:54:49,423 --> 00:54:54,127 +游戏的另一个重点是提供丰富 +充满细节的素材 + +1037 +00:54:54,161 --> 00:54:57,331 +提高游戏图形视觉保真度的一个方法是 + +1038 +00:54:57,364 --> 00:55:01,335 +生成更复杂的几何网格 + +1039 +00:55:01,368 --> 00:55:03,871 +之前是在中央处理器上进行界面评估 + +1040 +00:55:03,904 --> 00:55:06,340 +生成几何图形 + +1041 +00:55:06,373 --> 00:55:08,442 +再提交给图形处理器进行渲染 + +1042 +00:55:08,475 --> 00:55:11,078 +挑战在于 这可能会带来延迟 + +1043 +00:55:11,111 --> 00:55:13,447 +并占用不可预测的内存空间 + +1044 +00:55:13,480 --> 00:55:16,483 +Metal 3 引入了新的 +Mesh Shading API + +1045 +00:55:16,517 --> 00:55:22,289 +让你能够从一个渲染通道中 +精确控制优化的几何处理管线 + +1046 +00:55:22,322 --> 00:55:25,192 +对象着色器决定生成多少网格 + +1047 +00:55:25,225 --> 00:55:27,461 +网格着色器生成实际的几何图像 + +1048 +00:55:27,494 --> 00:55:29,897 +然后直接发给光栅化渲染器 + +1049 +00:55:29,930 --> 00:55:33,267 +避免了多次内存访问 提高了性能 + +1050 +00:55:33,300 --> 00:55:36,069 +玩家也希望以最高的帧率 + +1051 +00:55:36,103 --> 00:55:37,838 +看到这些令人惊叹的视觉效果 + +1052 +00:55:37,871 --> 00:55:41,074 +但以超高分辨率渲染高级图像 + +1053 +00:55:41,108 --> 00:55:42,809 +可能会耗费宝贵的毫秒 + +1054 +00:55:42,843 --> 00:55:46,079 +MetalFX 上采样功能帮你以每帧更短的时间 + +1055 +00:55:46,113 --> 00:55:47,781 +来渲染沉浸式画面 + +1056 +00:55:47,814 --> 00:55:49,349 +它是这样运作的 + +1057 +00:55:49,383 --> 00:55:52,819 +以前 你会以原始分辨率渲染全帧 + +1058 +00:55:52,853 --> 00:55:56,256 +但图形处理器的渲染时间可能无法达到目标帧时间 + +1059 +00:55:56,290 --> 00:56:00,093 +现在 你能以较低的分辨率 +渲染同样的复杂场景 + +1060 +00:56:00,127 --> 00:56:03,197 +从而满足目标帧时间 +然后利用 MetalFX 框架 + +1061 +00:56:03,230 --> 00:56:07,668 +执行时间抗锯齿 并上采样至目标分辨率 + +1062 +00:56:07,701 --> 00:56:10,637 +有了 Apple 芯片和 Metal 3 优化的功能 + +1063 +00:56:10,671 --> 00:56:13,106 +游戏将在 Mac 上前所未有地大放异彩 + +1064 +00:56:13,140 --> 00:56:14,808 +游戏开发者也表示赞同 + +1065 +00:56:14,842 --> 00:56:18,245 +许多顶尖的游戏工作室正在着手 +将他们的游戏带到 Mac 上 + +1066 +00:56:18,278 --> 00:56:21,281 +比如 Grid Legends 利用 Apple 芯片 + +1067 +00:56:21,315 --> 00:56:23,617 +助你全速前进 + +1068 +00:56:23,650 --> 00:56:27,387 +而 Resident Evil Village +使用 MetalFX 上采样等功能 + +1069 +00:56:27,421 --> 00:56:31,358 +以最高分辨率提供美到惊心动魄的画面 + +1070 +00:56:31,391 --> 00:56:33,961 +还有 No Man's Sky +利用 Metal 3 的优势 + +1071 +00:56:33,994 --> 00:56:37,564 +在 Mac 和 iPad 上探索丰富、广阔的世界 + +1072 +00:56:37,598 --> 00:56:42,336 +Metal 3 令人难以置信 +它将提升你的 app 的性能 + +1073 +00:56:42,369 --> 00:56:44,605 +以及提供惊艳的游戏体验 + +1074 +00:56:44,638 --> 00:56:49,109 +现在 我们来看看 MapKit 的发展方向 +请 Kathy 给大家介绍 + +1075 +00:56:49,142 --> 00:56:51,278 +无论你是要导航前往你最喜欢的餐厅 + +1076 +00:56:51,311 --> 00:56:52,980 +计划下一个假期 + +1077 +00:56:53,013 --> 00:56:55,849 +还是只是在地图上查看 +你最喜欢的美食车停在哪里 + +1078 +00:56:55,883 --> 00:57:00,487 +我们都无比依赖我们的设备 +帮我们探索周边的世界 + +1079 +00:57:00,521 --> 00:57:04,391 +MapKit 是帮助用户探索和导航的好方法 + +1080 +00:57:04,424 --> 00:57:07,361 +它提供了丰富而灵活的地图和位置服务 + +1081 +00:57:07,394 --> 00:57:11,465 +由 Apple 地图驱动 开发者可免费使用 + +1082 +00:57:11,498 --> 00:57:15,669 +利用 MapKit 你可以在你的 app 中 +显示地图或卫星图像 + +1083 +00:57:15,702 --> 00:57:17,604 +找到并调出兴趣点 + +1084 +00:57:17,638 --> 00:57:19,239 +添加注释和覆盖物 + +1085 +00:57:19,273 --> 00:57:21,408 +获取路线等等 + +1086 +00:57:21,441 --> 00:57:23,844 +MapKit 由我们的全新地图提供支持 + +1087 +00:57:23,877 --> 00:57:26,246 +经过 Apple 彻底重新设计 + +1088 +00:57:26,280 --> 00:57:28,248 +它提供了更好的细节和准确性 + +1089 +00:57:28,282 --> 00:57:31,952 +并能为你的 app 带来有用的地图和位置服务 + +1090 +00:57:31,985 --> 00:57:34,421 +在 iOS 16 中 我们将在新地图的基础上 + +1091 +00:57:34,454 --> 00:57:37,191 +推出有史以来对 MapKit 最大的更新 + +1092 +00:57:37,224 --> 00:57:42,029 +首先是向所有开发者提供 +3D City Experience + +1093 +00:57:42,062 --> 00:57:45,032 +你的 app 用户将能看到令人难以置信的细节 + +1094 +00:57:45,065 --> 00:57:47,801 +包括 3D 高度信息、转弯车道 + +1095 +00:57:47,835 --> 00:57:49,269 +人行横道、自行车道等 + +1096 +00:57:49,303 --> 00:57:52,039 +还有惊人的手工打造的 3D 地标 + +1097 +00:57:52,072 --> 00:57:54,508 +如金门大桥或渡轮大厦 + +1098 +00:57:54,541 --> 00:57:57,411 +地图的新增细节让你可以提供 + +1099 +00:57:57,444 --> 00:58:01,181 +前所未有的背景和精确度 + +1100 +00:58:01,215 --> 00:58:06,887 +例如 你可以在人行横道和自行车道起始点间 +显示一个兴趣点 + +1101 +00:58:06,920 --> 00:58:09,156 +没有其他数字地图能让你做到这一点 + +1102 +00:58:09,189 --> 00:58:12,359 +而我们可以让你非常轻松地实现它 + +1103 +00:58:12,392 --> 00:58:14,261 +为了给大家展示 我们来创造一个体验 + +1104 +00:58:14,294 --> 00:58:20,400 +让用户利用新地图的细节 +轻松找到他们最喜欢的美食车停在哪里 + +1105 +00:58:20,434 --> 00:58:25,038 +像这样的地图视图会在可用时 +自动获得 3D City Experience + +1106 +00:58:25,072 --> 00:58:28,242 +只需将部署目标设置为 iOS 16 即可 + +1107 +00:58:28,275 --> 00:58:31,578 +接下来 我可以用非常详细的地图 + +1108 +00:58:31,612 --> 00:58:35,315 +来显示美食车的确切位置 + +1109 +00:58:35,349 --> 00:58:39,353 +MapKit 拥有强大的控件 +让我们在 3D 空间中定位相机 + +1110 +00:58:39,386 --> 00:58:42,122 +以创建精确的地图视图 + +1111 +00:58:42,155 --> 00:58:44,658 +这里 我可以选择我们希望被放大的距离 + +1112 +00:58:44,691 --> 00:58:48,762 +通过将相机的中心坐标距离设置为 600 米即可 + +1113 +00:58:48,795 --> 00:58:51,999 +通过调整俯仰和朝向 倾斜相机查看 3D 视图 + +1114 +00:58:52,032 --> 00:58:55,002 +你可以看到令人惊叹的有用细节 +如转弯车道 + +1115 +00:58:55,035 --> 00:58:57,771 +人行横道 甚至还有树木 + +1116 +00:58:57,804 --> 00:59:00,474 +默认情况下 高度信息将被压平 + +1117 +00:59:00,507 --> 00:59:03,410 +为了帮助用户了解他们将遇到的地形 + +1118 +00:59:03,443 --> 00:59:07,814 +我可以用 preferredConfiguration +将 elevationStyle 设置为 ‘realistic’ + +1119 +00:59:07,848 --> 00:59:09,783 +以包含 3D 高度信息 + +1120 +00:59:10,851 --> 00:59:15,255 +从 MapKit 的路线规划 API 中 +添加注释或路线源时 + +1121 +00:59:15,289 --> 00:59:17,457 +MapKit 会自动处理高度信息 + +1122 +00:59:17,491 --> 00:59:19,927 +并会通过将其置于 3D 地形之上 + +1123 +00:59:19,960 --> 00:59:23,830 +调整注释或路线 + +1124 +00:59:23,864 --> 00:59:26,466 +通过添加慢速平移 为相机朝向进行动画处理 + +1125 +00:59:26,500 --> 00:59:29,736 +可以让地图视图变得生动 + +1126 +00:59:29,770 --> 00:59:31,438 +当用户切换到深色模式时 + +1127 +00:59:31,471 --> 00:59:34,241 +地图也会与 UI 的其他部分一同调整 + +1128 +00:59:34,274 --> 00:59:39,646 +我们非常高兴能通过 iOS 16 +向开发者提供这项沉浸式的体验 + +1129 +00:59:39,680 --> 00:59:43,817 +此外 我们还将另一个很受欢迎的 +Apple 地图功能带到了 MapKit + +1130 +00:59:43,851 --> 00:59:45,452 +那就是 四处看看 + +1131 +00:59:45,485 --> 00:59:48,956 +这是一种从视平线角度探索世界的好方法 + +1132 +00:59:48,989 --> 00:59:52,392 +提供了高分辨率的 3D 图像和流畅的动画 + +1133 +00:59:52,426 --> 00:59:55,295 +用户只需轻点就可在街道上移动 + +1134 +00:59:56,997 --> 00:59:59,900 +我可以在地图下面添加一个静态的 +四处看看预览 + +1135 +00:59:59,933 --> 01:00:03,604 +仅需放入一个 View Controller +并指定 MapItem + +1136 +01:00:03,637 --> 01:00:07,241 +四处看看视图会自动插入正确的位置 + +1137 +01:00:07,274 --> 01:00:09,610 +用户轻点预览时 我可以选择提供 + +1138 +01:00:09,643 --> 01:00:11,512 +全屏的四处看看视图 + +1139 +01:00:11,545 --> 01:00:13,480 +用户可以看到地址 + +1140 +01:00:13,514 --> 01:00:15,349 +图像采集日期 + +1141 +01:00:15,382 --> 01:00:17,584 +还能通过轻点自由移动 + +1142 +01:00:17,618 --> 01:00:20,420 +更好地了解周边环境 + +1143 +01:00:20,454 --> 01:00:23,223 +还有一项新的、呼声很高的功能 + +1144 +01:00:23,257 --> 01:00:26,026 +将在 iOS 16 中登陆 MapKit + +1145 +01:00:26,059 --> 01:00:28,295 +Apple Maps Server API + +1146 +01:00:28,328 --> 01:00:30,163 +Maps Server API 是 REST 接口 + +1147 +01:00:30,197 --> 01:00:33,367 +支持 MapKit 最常用功能中的四项 + +1148 +01:00:33,400 --> 01:00:36,537 +地理编码 可将经纬度转换为地址 + +1149 +01:00:36,570 --> 01:00:38,872 +逆地理编码 实现的是相反的功能 + +1150 +01:00:38,906 --> 01:00:41,608 +将地址转换为 GPS 坐标 + +1151 +01:00:41,642 --> 01:00:44,111 +搜索 以及到达时间 + +1152 +01:00:44,144 --> 01:00:46,914 +我们新的 Maps Server API + +1153 +01:00:46,947 --> 01:00:51,385 +能让你自己的后端服务更丰富 性能更强 + +1154 +01:00:51,418 --> 01:00:55,989 +当然 MapKit 建立在与 Apple 地图相同的 +隐私保护基础上 + +1155 +01:00:56,023 --> 01:00:59,226 +不会将用户的数据与他们的身份关联起来 + +1156 +01:00:59,259 --> 01:01:01,895 +也不会保留用户去过的地方的历史 + +1157 +01:01:01,929 --> 01:01:05,499 +这就是对 iOS 16 中 +MapKit 新功能的简单介绍 + +1158 +01:01:05,532 --> 01:01:08,936 +现在轮到介绍天气了 +至少是如何将天气建入你的 app + +1159 +01:01:08,969 --> 01:01:10,637 +交给 Novall + +1160 +01:01:10,671 --> 01:01:14,975 +我们今天宣布了要把天气 app +带到 iPad 和 Mac 上 + +1161 +01:01:15,008 --> 01:01:17,377 +并推出强大的新功能 + +1162 +01:01:17,411 --> 01:01:21,081 +包括恶劣天气通知、丰富的细节视图 + +1163 +01:01:21,114 --> 01:01:25,018 +以及未来十天的每小时温度和降水预报 + +1164 +01:01:25,052 --> 01:01:29,256 +等各种各样的体验 跨各个 Apple 设备和平台 + +1165 +01:01:29,289 --> 01:01:32,659 +这些体验也将因我们提供的天气数据而优化提升 + +1166 +01:01:32,693 --> 01:01:35,295 +无论是向 Siri 询问今天的天气预报 + +1167 +01:01:35,329 --> 01:01:38,232 +还是绕过水灾区域重新规划导航路线 + +1168 +01:01:38,265 --> 01:01:42,035 +所有这一切都内置于我们的 Apple 天气服务中 + +1169 +01:01:42,069 --> 01:01:45,372 +Apple 天气提供了世界级的全球天气预报 + +1170 +01:01:45,405 --> 01:01:48,041 +利用高分辨率气象模型 + +1171 +01:01:48,075 --> 01:01:50,911 +结合机器学习和预测算法 + +1172 +01:01:50,944 --> 01:01:53,447 +Apple 天气提供当前天气 + +1173 +01:01:53,480 --> 01:01:56,517 +10 天内的每小时预报、每日预报 + +1174 +01:01:56,550 --> 01:02:00,354 +以及历史天气 方便你评估数据趋势 + +1175 +01:02:00,387 --> 01:02:03,090 +在一些国家和地区还提供 + +1176 +01:02:03,123 --> 01:02:06,860 +恶劣天气警报和每分钟降水信息 + +1177 +01:02:06,894 --> 01:02:10,330 +预报功能包括未来 10 天的每小时温度 + +1178 +01:02:10,364 --> 01:02:15,068 +降水、紫外线指数预报 以及更多信息 + +1179 +01:02:15,102 --> 01:02:19,173 +所有这些数据都可通过 WeatherKit 获取到 + +1180 +01:02:19,206 --> 01:02:23,210 +WeatherKit 是原生的 Swift API +适用于所有 Apple 平台 + +1181 +01:02:23,243 --> 01:02:25,612 +并且是一个可以从任何地方使用的 REST API + +1182 +01:02:25,646 --> 01:02:29,449 +这些 API 可以提供准确、超本地化的天气预报 + +1183 +01:02:29,483 --> 01:02:33,787 +为你的用户提供信息 +帮助他们保持安全 做好准备 + +1184 +01:02:33,820 --> 01:02:36,190 +我来通过一个简短的演示向你介绍 + +1185 +01:02:36,223 --> 01:02:39,593 +通过 WeatherKit 很棒的 Swift API +获取天气信息多么容易 + +1186 +01:02:39,626 --> 01:02:41,862 +我们再回到 Food Truck app + +1187 +01:02:41,895 --> 01:02:44,231 +为了确保我的顾客不被雨淋 + +1188 +01:02:44,264 --> 01:02:47,968 +我设置的 app 能推荐一个天空晴朗的停车点 + +1189 +01:02:48,001 --> 01:02:50,470 +我来展示一下我是如何获得天气信息的 + +1190 +01:02:50,504 --> 01:02:53,240 +我这里有一份安全停车点的清单 + +1191 +01:02:53,273 --> 01:02:56,109 +我已在 Xcode 中添加了 WeatherKit 功能 + +1192 +01:02:56,143 --> 01:02:58,545 +仅需几行代码即可 + +1193 +01:02:58,579 --> 01:03:01,648 +利用 Swift 并发功能 请求天气信息非常简单 + +1194 +01:03:01,682 --> 01:03:06,019 +我们调用 weather(for:) on WeatherService +并传入位置 + +1195 +01:03:06,053 --> 01:03:11,391 +然后我就可以获得我的 app 所需的相关数据 +如天气状况 + +1196 +01:03:11,425 --> 01:03:17,898 +降水、云层覆盖 + +1197 +01:03:17,931 --> 01:03:21,068 +现在我有了每个停车位所需的数据 + +1198 +01:03:21,101 --> 01:03:22,369 +在我运行 app 时 + +1199 +01:03:22,402 --> 01:03:26,740 +我的自定义视图就已经更新为 +推荐一个天空晴朗的位置 + +1200 +01:03:28,509 --> 01:03:30,777 +你可以通过各种方式使用天气数据 + +1201 +01:03:30,811 --> 01:03:33,714 +让你的 app 提供更好的体验 + +1202 +01:03:33,747 --> 01:03:36,617 +你可能会用天气预报帮你管理库存 + +1203 +01:03:36,650 --> 01:03:40,587 +预测冰淇淋馅甜甜圈在大热天会很受欢迎 + +1204 +01:03:40,621 --> 01:03:43,123 +所以你该多备一些冰淇淋 + +1205 +01:03:43,156 --> 01:03:45,292 +为我们的美食车获取天气数据仅需这样简单的操作 + +1206 +01:03:45,325 --> 01:03:48,595 +大家可以用 WeatherKit 做的事还有更多 + +1207 +01:03:48,629 --> 01:03:50,964 +与 Apple 对隐私保护的承诺一致 + +1208 +01:03:50,998 --> 01:03:54,201 +位置信息仅用于提供天气预报 + +1209 +01:03:54,234 --> 01:03:57,504 +不会与任何个人身份信息相关联 + +1210 +01:03:57,538 --> 01:04:00,374 +并且永不分享或出售 + +1211 +01:04:00,407 --> 01:04:02,509 +保护隐私是我们共同的责任 + +1212 +01:04:02,543 --> 01:04:05,279 +通过 WeatherKit 你可以获得准确的天气数据 + +1213 +01:04:05,312 --> 01:04:08,081 +同时保护用户隐私 + +1214 +01:04:08,115 --> 01:04:11,251 +因为我们想让大家很容易就能 +开始使用 WeatherKit + +1215 +01:04:11,285 --> 01:04:15,722 +所以我们将每月 50 万次 +weather(for:location) API 调用 + +1216 +01:04:15,756 --> 01:04:18,358 +包含在你们的 Apple +Developer Program 订阅中 + +1217 +01:04:18,392 --> 01:04:22,095 +需求量更大的开发者 +将可购买额外的服务级别 + +1218 +01:04:22,129 --> 01:04:24,665 +今年秋天起即可从开发者 app 中购买 + +1219 +01:04:24,698 --> 01:04:26,800 +这就是 WeatherKit + +1220 +01:04:26,834 --> 01:04:30,904 +由 Apple 天气服务提供的准确、超本地化的天气预报 + +1221 +01:04:30,938 --> 01:04:35,642 +我们将从 Beta 测试版开始 +现在就可以在所有平台上使用 + +1222 +01:04:35,676 --> 01:04:39,913 +你可以有很多有创意的方法 +将 WeatherKit 用在你的 app 中 + +1223 +01:04:39,947 --> 01:04:41,715 +现在交给 Ryan 来给我们介绍 + +1224 +01:04:41,748 --> 01:04:44,351 +你的 app 可以通过实况文本看到什么 + +1225 +01:04:44,384 --> 01:04:47,054 +我们的用户非常喜欢实况文本 + +1226 +01:04:47,087 --> 01:04:48,522 +我们也听到你们中的很多人 + +1227 +01:04:48,555 --> 01:04:50,757 +都想把它加入到你们的 app 中 + +1228 +01:04:50,791 --> 01:04:54,127 +因此 今年我们将通过两个新的 API +扩展 VisionKit + +1229 +01:04:54,161 --> 01:04:56,330 +让你们可以做到这一点 + +1230 +01:04:57,631 --> 01:05:01,702 +实况文本 API 解锁了分析图像内容的能力 + +1231 +01:05:01,735 --> 01:05:04,371 +让用户可以与照片和暂停视频帧中的 + +1232 +01:05:04,404 --> 01:05:07,374 +文字和二维码互动 + +1233 +01:05:07,407 --> 01:05:08,775 +并提供快速操作 + +1234 +01:05:08,809 --> 01:05:10,844 +这样你的用户仅需轻点 + +1235 +01:05:10,878 --> 01:05:13,380 +即可根据相关数据完成操作 + +1236 +01:05:13,413 --> 01:05:15,749 +它非常适合任何显示视觉媒体的 app + +1237 +01:05:15,782 --> 01:05:19,386 +如 Apollo for Reddit 或 Vimeo + +1238 +01:05:19,419 --> 01:05:23,757 +而 Data Scanner API 则解锁了 +分析实时摄像头画面的能力 + +1239 +01:05:23,790 --> 01:05:27,694 +它极大地简化了扫描文本和条码的流程 + +1240 +01:05:27,728 --> 01:05:31,331 +你所需要做的就是添加覆盖物或自定义控件 + +1241 +01:05:31,365 --> 01:05:35,169 +使实况摄像头体验符合你 app 的需求 + +1242 +01:05:35,202 --> 01:05:39,139 +这特别适合依赖二维码的消费类 app + +1243 +01:05:39,173 --> 01:05:42,543 +或者是企业 app 如仓库后区库存管理 + +1244 +01:05:42,576 --> 01:05:44,211 +取货和包装送货服务 + +1245 +01:05:44,244 --> 01:05:45,679 +以及自助结账机 + +1246 +01:05:46,547 --> 01:05:48,982 +实况文本 API 和数据扫描 API + +1247 +01:05:49,016 --> 01:05:51,652 +支持自动检测 9 种语言 + +1248 +01:05:51,685 --> 01:05:54,655 +包括今年新增的日文和韩文 + +1249 +01:05:55,656 --> 01:05:59,293 +这些 VisionKit API 将多年的计算机视觉创新 + +1250 +01:05:59,326 --> 01:06:02,396 +带给你的 app 且仅需几行代码 + +1251 +01:06:02,429 --> 01:06:04,431 +下面交给 Jenny 来为各位展示 + +1252 +01:06:04,464 --> 01:06:07,935 +给大家快速展示一下 +回到我们超棒的快闪 Food Truck app + +1253 +01:06:07,968 --> 01:06:11,471 +我们正在做一个促销活动 +如果用户在社交频道发布一张照片 + +1254 +01:06:11,505 --> 01:06:15,209 +手持带有 #freedonut 标签 +和他们在 app 上的地址的牌子 + +1255 +01:06:15,242 --> 01:06:18,212 +我们就会把车开到他们的地址 +赠送一个免费甜甜圈 + +1256 +01:06:18,245 --> 01:06:20,147 +我们来看看我们甜甜圈的社交频道 + +1257 +01:06:20,180 --> 01:06:22,416 +我们想把实况文本功能添加到图片上 + +1258 +01:06:22,449 --> 01:06:25,652 +这样司机就可以提取文本 获得送餐地址 + +1259 +01:06:26,453 --> 01:06:29,223 +这就到新的实况文本 API 派上用场的时候了 + +1260 +01:06:29,256 --> 01:06:32,326 +我可以很容易地在我的视图上面 +添加一个 ImageInteraction + +1261 +01:06:32,359 --> 01:06:35,896 +这将会添加一个实况文本按钮 +并且支持快速操作 + +1262 +01:06:35,929 --> 01:06:39,132 +实况文本按钮通常位于右下角 + +1263 +01:06:39,166 --> 01:06:41,401 +但我的 app 中已经有个爱心按钮了 + +1264 +01:06:41,435 --> 01:06:44,238 +所以我可以使用自定义嵌入物调整它的位置 + +1265 +01:06:44,271 --> 01:06:48,275 +我还可以设置按钮的配置 +自定义按钮风格 + +1266 +01:06:48,308 --> 01:06:50,577 +让它与我的 app 更匹配 + +1267 +01:06:50,611 --> 01:06:54,848 +现在我已经添加好了 我可以轻点实况文本按钮 + +1268 +01:06:54,882 --> 01:06:56,316 +选择文本 + +1269 +01:06:56,350 --> 01:06:58,919 +或者用快速操作轻松抓取地址 + +1270 +01:07:00,487 --> 01:07:03,657 +我很喜欢的是用户不用学习新的交互模式 + +1271 +01:07:03,690 --> 01:07:08,295 +因为它提供了与实况文本相同的易用性 + +1272 +01:07:08,328 --> 01:07:10,430 +UI 都是一致且熟悉的 + +1273 +01:07:10,464 --> 01:07:12,499 +与操作系统充分整合 + +1274 +01:07:12,533 --> 01:07:16,503 +但我还是可以调整位置 +哪怕我已经有了自己的自定义 UI + +1275 +01:07:17,237 --> 01:07:19,273 +当然 就像任何优秀送餐 app 一样 + +1276 +01:07:19,306 --> 01:07:22,476 +我们也希望为顾客提供最好的服务 + +1277 +01:07:22,509 --> 01:07:25,479 +确保他们得到正确的甜甜圈 + +1278 +01:07:25,512 --> 01:07:28,982 +所以 我们通过二维码追踪甜甜圈订单 + +1279 +01:07:29,016 --> 01:07:33,420 +使用新的数据扫描 API +我可以轻松添加该功能 + +1280 +01:07:33,453 --> 01:07:35,923 +让它成为与顾客互动的第一步 + +1281 +01:07:35,956 --> 01:07:38,025 +现在这个按钮什么都做不了 + +1282 +01:07:38,058 --> 01:07:41,094 +但我可以很容易地实例化一个 +新的数据扫描对象 + +1283 +01:07:41,128 --> 01:07:44,231 +它可以寻找文本、二维码或条码 + +1284 +01:07:44,264 --> 01:07:46,466 +然后我可以将其导入我的 app + +1285 +01:07:46,500 --> 01:07:49,169 +仅需几行代码 我就可以调出相机 + +1286 +01:07:49,203 --> 01:07:53,373 +指明我想要二维码 然后开始扫描 + +1287 +01:07:53,407 --> 01:07:55,542 +当司机轻点二维码时 + +1288 +01:07:55,576 --> 01:07:58,011 +我想显示出扫描成功 + +1289 +01:07:58,045 --> 01:08:00,147 +我可以在 Xcode 中添加委托处理程序 + +1290 +01:08:03,517 --> 01:08:07,354 +并在轻点时向用户显示扫描成功的提示 + +1291 +01:08:07,387 --> 01:08:10,257 +这样我就可以开始处理订单了 + +1292 +01:08:10,290 --> 01:08:15,562 +现在我运行 app 时 +会调出带有相机视图的视图控制器 + +1293 +01:08:15,596 --> 01:08:16,930 +我可以看到引导信息 + +1294 +01:08:16,964 --> 01:08:20,200 +以及高亮显示二维码的标线视图 + +1295 +01:08:20,234 --> 01:08:23,570 +我轻点二维码时 就可以看到扫描成功了 + +1296 +01:08:23,604 --> 01:08:25,973 +甜甜圈订单已确认 + +1297 +01:08:26,006 --> 01:08:30,444 +就这样简单 我的 #freedonut 已经上路了 + +1298 +01:08:30,477 --> 01:08:31,512 +利用 VisionKit + +1299 +01:08:31,545 --> 01:08:34,448 +全新的实况文本 API +和数据扫描 API + +1300 +01:08:34,481 --> 01:08:38,919 +你可以轻松将这些强大的视觉功能 +带给你的 app + +1301 +01:08:38,952 --> 01:08:41,288 +好 现在交回给 Susan + +1302 +01:08:41,321 --> 01:08:44,725 +对 app 开发来说 这真是个激动人心的时代 + +1303 +01:08:44,758 --> 01:08:49,229 +Xcode Cloud 现在已经准备就绪 +帮你更快地构建更优秀的 app + +1304 +01:08:49,263 --> 01:08:51,265 +Swift 和 SwiftUI + +1305 +01:08:51,298 --> 01:08:57,571 +更便于你讲奇思妙想融入 app 中 +并且适用于 Apple 的各个平台 + +1306 +01:08:57,604 --> 01:09:00,307 +还有很酷的新方法 帮你把你的想法 + +1307 +01:09:00,340 --> 01:09:02,776 +并和系统体验相整合 + +1308 +01:09:02,809 --> 01:09:04,878 +锁定屏幕小组件和实时活动 + +1309 +01:09:04,912 --> 01:09:07,481 +把你的 app 带到锁定屏幕上 + +1310 +01:09:07,514 --> 01:09:10,250 +Messages Collaboration 让你的用户 + +1311 +01:09:10,284 --> 01:09:13,353 +可以无比轻松地联络和协作 + +1312 +01:09:13,387 --> 01:09:17,791 +而 App Intents 可以帮你把 app +和 Siri 整合在一起 + +1313 +01:09:17,824 --> 01:09:19,826 +还有各种全新的 API + +1314 +01:09:19,860 --> 01:09:22,362 +以及对现有 API 的重大更新 + +1315 +01:09:22,396 --> 01:09:27,000 +如 WeatherKit、MapKit +实况文本和 Metal + +1316 +01:09:27,034 --> 01:09:28,869 +而这还不是全部 + +1317 +01:09:28,902 --> 01:09:32,072 +今年的 WWDC 又是一大盛事 + +1318 +01:09:32,105 --> 01:09:34,241 +175 场讲座 + +1319 +01:09:34,274 --> 01:09:39,012 +数百个实验室以及数字聊天室活动 +贯穿整个星期 + +1320 +01:09:39,046 --> 01:09:41,315 +我们迫不及待在这周与大家见面 + +1321 +01:09:41,348 --> 01:09:44,518 +更重要的是 这周的主角是你们 + +1322 +01:09:44,551 --> 01:09:47,421 +我们迫不及待地想看到你们的下一个大作 + +1323 +01:09:47,454 --> 01:09:49,256 +谢谢大家! + +1324 +01:09:49,289 --> 01:09:57,297 +♪ ♪ + +1325 +01:10:06,340 --> 01:10:14,348 +. + diff --git a/zho/2022 Session 103 Apple Design Awards.srt b/zho/2022 Session 103 Apple Design Awards.srt new file mode 100644 index 0000000..911649d --- /dev/null +++ b/zho/2022 Session 103 Apple Design Awards.srt @@ -0,0 +1,1689 @@ +1 +00:00:00,000 --> 00:00:03,504 +(Apple设计大奖) + +2 +00:00:04,972 --> 00:00:09,543 +(2022年Apple设计大奖) + +3 +00:00:09,610 --> 00:00:13,780 +♪♪ + +4 +00:00:13,847 --> 00:00:18,285 +♪♪ + +5 +00:00:18,352 --> 00:00:23,590 +♪♪ + +6 +00:00:23,657 --> 00:00:28,562 +设计对我来说是一种表达自我的途径 + +7 +00:00:28,629 --> 00:00:31,398 +就像写歌或写书一样 + +8 +00:00:31,465 --> 00:00:33,767 +虽然我没学过音乐 + +9 +00:00:33,834 --> 00:00:36,603 +我也写不出华丽的词藻 + +10 +00:00:36,670 --> 00:00:39,406 +但我会编程 + +11 +00:00:39,473 --> 00:00:42,042 +设计就像一个机会 + +12 +00:00:42,109 --> 00:00:46,813 +你可以借机创造出美观且 + +13 +00:00:46,880 --> 00:00:49,650 +实用的东西 + +14 +00:00:49,716 --> 00:00:52,085 +设计在生活中无处不在 + +15 +00:00:52,152 --> 00:00:55,522 +设计会在每个层面上影响人们的生活 + +16 +00:00:55,589 --> 00:00:58,425 +设计 决定了那将是一次绝佳体验 + +17 +00:00:58,492 --> 00:01:01,295 +还是一次噩梦之旅 + +18 +00:01:01,361 --> 00:01:04,731 +没有设计 就不会有惊喜了 + +19 +00:01:04,798 --> 00:01:08,168 +这不仅涉及外观方面 +还在于好不好用 + +20 +00:01:08,235 --> 00:01:12,973 +设计也是最有效的讲述形式之一 + +21 +00:01:13,040 --> 00:01:15,475 +我认为设计经常需要做减法 + +22 +00:01:15,542 --> 00:01:17,611 +化繁为简 + +23 +00:01:17,678 --> 00:01:19,980 +就像一步一脚印地 + +24 +00:01:20,047 --> 00:01:21,048 +爬上高山 + +25 +00:01:21,114 --> 00:01:23,884 +一开始你手里是一张白纸 + +26 +00:01:23,951 --> 00:01:26,420 +然后你把它变成 + +27 +00:01:26,486 --> 00:01:27,454 +一件很酷的东西 + +28 +00:01:27,521 --> 00:01:29,790 +当你完成了好的设计 把它展示给别人 + +29 +00:01:29,857 --> 00:01:32,192 +它会为人们提供便捷 + +30 +00:01:32,259 --> 00:01:34,494 +而这件事曾经做起来非常繁琐 + +31 +00:01:34,561 --> 00:01:36,430 +我觉得这是一件很酷的事情 + +32 +00:01:36,496 --> 00:01:39,666 +我们第一次约会时 + +33 +00:01:39,733 --> 00:01:43,170 +他说他是用户体验设计师 + +34 +00:01:43,237 --> 00:01:46,607 +当时我想 我要是问那是什么职业 + +35 +00:01:46,673 --> 00:01:48,275 +会不会显得笨笨的 + +36 +00:01:48,342 --> 00:01:50,110 +♪♪ + +37 +00:01:50,177 --> 00:01:52,279 +实际设计工作更偏重于功能性 + +38 +00:01:52,346 --> 00:01:53,247 +令人愉悦 + +39 +00:01:53,313 --> 00:01:54,481 +可爱 + +40 +00:01:54,548 --> 00:01:55,816 +-令人感到舒心 +-安逸 + +41 +00:01:55,883 --> 00:01:57,484 +-充满力量 +-令人跃跃欲试 + +42 +00:01:57,551 --> 00:01:59,253 +-超炫 +-实实在在 + +43 +00:01:59,319 --> 00:02:00,220 +简单但充满乐趣 + +44 +00:02:00,287 --> 00:02:00,854 +好玩 + +45 +00:02:00,921 --> 00:02:02,089 +以及美观 + +46 +00:02:02,155 --> 00:02:05,292 +♪♪ + +47 +00:02:05,359 --> 00:02:08,195 +让我想想 我喜欢设计吗 + +48 +00:02:09,696 --> 00:02:11,465 +其实有时候超讨厌它 + +49 +00:02:11,532 --> 00:02:15,402 +不过不会持续很久 + +50 +00:02:15,469 --> 00:02:18,071 +所以总体上 我想我还是喜欢设计的 + +51 +00:02:18,138 --> 00:02:20,707 +某种程度上 我逃不出设计的掌心 + +52 +00:02:20,774 --> 00:02:23,911 +我无法想象生活没有设计会是什么样 + +53 +00:02:23,977 --> 00:02:25,712 +怎么会有人讨厌设计呢 + +54 +00:02:25,779 --> 00:02:27,681 +它像魔法 + +55 +00:02:27,748 --> 00:02:28,982 +除此之外我什么都不会 + +56 +00:02:29,049 --> 00:02:33,787 +我知道我的用户 +能通过我App里的设计 + +57 +00:02:33,854 --> 00:02:34,888 +感受到我的想法 + +58 +00:02:34,955 --> 00:02:38,859 +我认为设计确实为我们的生活方式 + +59 +00:02:38,926 --> 00:02:41,628 +带来了改变 + +60 +00:02:41,695 --> 00:02:45,265 +♪♪ + +61 +00:02:45,332 --> 00:02:50,838 +我的灵感主要来源于 +在大自然中的漫步 + +62 +00:02:50,904 --> 00:02:54,007 +每次我去散步 + +63 +00:02:54,074 --> 00:02:55,909 +都感觉灵思如泉涌 + +64 +00:02:55,976 --> 00:02:57,644 +灵感可能来自任何地方 + +65 +00:02:57,711 --> 00:03:01,181 +不一定非得是博物馆或者画廊 + +66 +00:03:01,248 --> 00:03:03,817 +可以来自大自然 可以来自城市 + +67 +00:03:03,884 --> 00:03:04,785 +当夜色四合 + +68 +00:03:04,852 --> 00:03:06,553 +人们都休息的时候 + +69 +00:03:06,620 --> 00:03:09,456 +整个世界都陷入沉睡 + +70 +00:03:09,523 --> 00:03:14,127 +这让我能更容易地进入状态 + +71 +00:03:14,194 --> 00:03:17,364 +如果能让我远离科技 + +72 +00:03:17,431 --> 00:03:20,100 +离开电脑和手机 + +73 +00:03:20,167 --> 00:03:23,003 +我就可以进行一些深层次的思考 + +74 +00:03:23,070 --> 00:03:27,674 +我想创造一些现实中看不到的东西 + +75 +00:03:27,741 --> 00:03:29,743 +我当时住在曼谷 车水马龙的地方 + +76 +00:03:29,810 --> 00:03:31,011 +交通喧嚣拥挤 + +77 +00:03:31,078 --> 00:03:34,081 +所以开发游戏也是一种 + +78 +00:03:34,147 --> 00:03:36,750 +逃离现实的途径 + +79 +00:03:36,817 --> 00:03:39,553 +设计会面对的最大挑战是 + +80 +00:03:39,620 --> 00:03:43,690 +你做的假设经常是错的 + +81 +00:03:43,757 --> 00:03:46,159 +我会将巫术作为灵感是因为 + +82 +00:03:46,226 --> 00:03:49,096 +英国进行选举时 + +83 +00:03:49,162 --> 00:03:52,099 +有一群人 + +84 +00:03:52,165 --> 00:03:54,835 +决定要对政府下诅咒 + +85 +00:03:54,902 --> 00:03:56,370 +我觉得他们应该是异教徒吧 + +86 +00:03:56,436 --> 00:04:00,807 +♪♪ + +87 +00:04:00,874 --> 00:04:03,143 +总的来说我遇过的最大挫折是什么? + +88 +00:04:03,210 --> 00:04:04,945 +这是个好问题 + +89 +00:04:05,012 --> 00:04:06,647 +最大的挫折 有很多的 + +90 +00:04:06,713 --> 00:04:07,347 +你等等 + +91 +00:04:07,414 --> 00:04:09,950 +是指我个人还是我事业中的败笔? + +92 +00:04:10,017 --> 00:04:11,485 +嗯…… + +93 +00:04:11,552 --> 00:04:13,987 +让我想想…… + +94 +00:04:14,054 --> 00:04:17,090 +要回答这问题很难不得罪人哦 + +95 +00:04:17,157 --> 00:04:18,992 +每一件事都是 + +96 +00:04:19,059 --> 00:04:22,596 +失败是任何创作过程的一部分 + +97 +00:04:22,663 --> 00:04:26,466 +我们花了很多时间努力做整合 +一个月又一个月的不懈坚持 + +98 +00:04:26,533 --> 00:04:28,502 +以期呈递一份优秀的作品 + +99 +00:04:28,569 --> 00:04:31,104 +我们经历的最大挫折是在发行时 + +100 +00:04:31,171 --> 00:04:34,775 +发现游戏里的等级不够 + +101 +00:04:34,842 --> 00:04:37,878 +我们删掉了App的主要功能 + +102 +00:04:37,945 --> 00:04:40,113 +一夜之间 + +103 +00:04:40,180 --> 00:04:42,115 +我们失去了20%的用户 + +104 +00:04:42,182 --> 00:04:44,685 +很有意思的经历吧 + +105 +00:04:44,751 --> 00:04:47,254 +一些用户发来了很不错的反馈 + +106 +00:04:47,321 --> 00:04:50,490 +其实我们都不愿意承认它很糟糕 + +107 +00:04:50,557 --> 00:04:52,993 +我们跟高兴当时做出了修改 + +108 +00:04:53,060 --> 00:04:55,529 +我的格言是 +如果一天里我有了50个想法 + +109 +00:04:55,596 --> 00:04:58,232 +49个一无是处 + +110 +00:04:58,298 --> 00:05:01,101 +1个精妙绝伦 那这一天就非常棒 + +111 +00:05:01,168 --> 00:05:04,037 +应该是久久卡在某一困境里 + +112 +00:05:04,104 --> 00:05:07,608 +找不到出路的窘境吧 + +113 +00:05:07,674 --> 00:05:09,943 +把目光投向管理 经济和法律领域 + +114 +00:05:10,010 --> 00:05:11,979 +似乎会更容易成功 + +115 +00:05:12,045 --> 00:05:16,083 +但是自从2007年iPhone面世后 + +116 +00:05:16,149 --> 00:05:17,851 +我就一门心思扎进这里面了 + +117 +00:05:17,918 --> 00:05:19,753 +回过头来看看 +但我认为我经历的最大挫折 + +118 +00:05:19,820 --> 00:05:21,221 +反而是好事 + +119 +00:05:21,288 --> 00:05:24,091 +因为它助我走到今天的高度 + +120 +00:05:24,157 --> 00:05:26,693 +♪♪ + +121 +00:05:26,760 --> 00:05:28,996 +去年早些时候 我正在开发一款App + +122 +00:05:29,062 --> 00:05:32,733 +帮助有语言障碍的用户通电话 + +123 +00:05:32,799 --> 00:05:34,501 +完成之后 + +124 +00:05:34,568 --> 00:05:36,203 +我又想开发一款类似的 + +125 +00:05:36,270 --> 00:05:38,839 +但功能是反过来的App + +126 +00:05:38,906 --> 00:05:40,107 +帮助听障用户通电话 + +127 +00:05:40,174 --> 00:05:42,409 +让他们可以看到对方讲了什么 + +128 +00:05:42,476 --> 00:05:46,146 +对我来说一切的开始于 +我想要解决自己遇到的问题 + +129 +00:05:46,213 --> 00:05:47,881 +也就是我平时总不爱喝水 + +130 +00:05:47,948 --> 00:05:49,716 +我工作总是一坐几小时不动弹 + +131 +00:05:49,783 --> 00:05:52,819 +直到觉得口渴难忍才想起来没喝水 + +132 +00:05:52,886 --> 00:05:57,157 +让喝水成为你这一天里的快乐时刻 + +133 +00:05:57,224 --> 00:05:59,760 +我的孩子们…… + +134 +00:05:59,826 --> 00:06:02,596 +只要是列在清单上的事他们就会去做 +为了就是稍后可以划掉 + +135 +00:06:02,663 --> 00:06:06,466 +我们希望能帮助你戒掉某个习惯 + +136 +00:06:06,533 --> 00:06:10,137 +并在那一刻感到快乐 + +137 +00:06:10,204 --> 00:06:14,074 +我当时在闲逛 +看到了一个坏掉的霓虹灯牌 + +138 +00:06:14,141 --> 00:06:15,809 +灵感在那一刻迸发出来 + +139 +00:06:15,876 --> 00:06:18,679 +我们想设计世界上最好用的闹钟App + +140 +00:06:18,745 --> 00:06:22,883 +为此我们拜访了很多家具店 + +141 +00:06:22,950 --> 00:06:27,955 +感受各种闹钟拿在手上的感觉 + +142 +00:06:28,021 --> 00:06:30,991 +最初我们是想帮助自己 + +143 +00:06:31,058 --> 00:06:33,193 +当时我们在开会 + +144 +00:06:33,260 --> 00:06:35,829 +但是没有趁手的工具可以 + +145 +00:06:35,896 --> 00:06:37,064 +一边做笔记 + +146 +00:06:37,130 --> 00:06:40,501 +一边跟别人开会、交谈 + +147 +00:06:40,567 --> 00:06:42,870 +于是我们想给自己开发一个App + +148 +00:06:42,936 --> 00:06:46,940 +深入了解过包容性的意义之后 + +149 +00:06:47,007 --> 00:06:49,776 +我们构建产品的方式真的被改变了 + +150 +00:06:49,843 --> 00:06:52,913 +我当时坐在缆车里 遇到了一家人 + +151 +00:06:52,980 --> 00:06:56,016 +他们说想要能够 + +152 +00:06:56,083 --> 00:06:58,819 +把今年和去年的滑雪能力进行对比 + +153 +00:06:58,886 --> 00:07:00,521 +我回家后就着手编写程序 + +154 +00:07:00,587 --> 00:07:02,823 +一周后就在App Store上架了 + +155 +00:07:02,890 --> 00:07:05,459 +专注工作时不要摸手机 + +156 +00:07:05,526 --> 00:07:09,963 +煮面条时不要总打开锅盖 + +157 +00:07:10,030 --> 00:07:13,166 +这就是贯穿Focus Noodles的思想 + +158 +00:07:13,233 --> 00:07:16,003 +让用户可以心无旁骛 + +159 +00:07:16,069 --> 00:07:19,940 +放下手机 集中精力做事 + +160 +00:07:20,007 --> 00:07:21,508 +如果你喜欢某件事 + +161 +00:07:21,575 --> 00:07:23,877 +就总能找到一个方法来精进自己 + +162 +00:07:23,944 --> 00:07:26,847 +我希望让大家爱上学中文 + +163 +00:07:26,914 --> 00:07:29,483 +我希望让其更有趣味性 更好玩 + +164 +00:07:29,550 --> 00:07:31,552 +让大家享受学习的过程 + +165 +00:07:31,618 --> 00:07:32,753 +人们把这当成一个游戏 + +166 +00:07:32,819 --> 00:07:34,188 +我们可以使用我们的技术 + +167 +00:07:34,254 --> 00:07:38,058 +把它构建成追踪你身体的游戏 + +168 +00:07:38,125 --> 00:07:40,694 +让你的手臂跟随身体来运动 + +169 +00:07:40,761 --> 00:07:42,396 +并合上节奏的律动 + +170 +00:07:42,462 --> 00:07:44,264 +音乐节奏类游戏一般都是这样 + +171 +00:07:44,331 --> 00:07:45,966 +这就是我们设计“活力街” + +172 +00:07:46,033 --> 00:07:47,835 +的灵感来源 + +173 +00:07:47,901 --> 00:07:49,169 +这有点像编舞 + +174 +00:07:49,236 --> 00:07:50,838 +就像教你如何跳舞一样 + +175 +00:07:50,904 --> 00:07:53,640 +我们正在进行一项长期项目 + +176 +00:07:53,707 --> 00:07:55,475 +我们知道做一个很快的小项目 + +177 +00:07:55,542 --> 00:07:57,911 +会很有趣 + +178 +00:07:57,978 --> 00:08:00,547 +我们永远不会对此失去动力 + +179 +00:08:00,614 --> 00:08:04,017 +这个游戏是说 你谋杀了你的丈夫 + +180 +00:08:04,084 --> 00:08:08,989 +你的目标是确保别人发觉不了这件事 + +181 +00:08:09,056 --> 00:08:11,658 +Rebel Girls + +182 +00:08:11,725 --> 00:08:17,097 +就像你的崇尚女权主义的阿姨 +她很和善 + +183 +00:08:17,164 --> 00:08:18,999 +且阅历丰富 + +184 +00:08:19,066 --> 00:08:23,670 +她的目标就是向你传授 + +185 +00:08:23,737 --> 00:08:25,005 +珍贵的价值观 + +186 +00:08:25,072 --> 00:08:26,940 +赋能女孩们去成为 + +187 +00:08:27,007 --> 00:08:30,677 +最自信的一代女性 + +188 +00:08:30,744 --> 00:08:34,681 +这个App旨在于你痛失爱人时 + +189 +00:08:34,748 --> 00:08:36,049 +做你的密友 与你慰藉 + +190 +00:08:36,116 --> 00:08:37,217 +智能的备忘录 + +191 +00:08:37,284 --> 00:08:39,419 +会提醒你必须做的事项 + +192 +00:08:39,486 --> 00:08:40,187 +同时 + +193 +00:08:40,254 --> 00:08:41,955 +它提示的仅仅是 +你现在当前必须做的那些 + +194 +00:08:42,022 --> 00:08:45,592 +同时也允许我们为您代办 + +195 +00:08:45,659 --> 00:08:46,660 +我们的Behind the Frame + +196 +00:08:46,727 --> 00:08:49,563 +总体上是一款密室逃生游戏 + +197 +00:08:49,630 --> 00:08:54,701 +像一部吉卜力风格的可以玩的动画 + +198 +00:08:54,768 --> 00:08:58,105 +我们研究过吉卜力风格的配色方案 + +199 +00:08:58,172 --> 00:09:00,340 +以及文艺复兴时期的画作 + +200 +00:09:00,407 --> 00:09:05,479 +Townscaper的玩法就是 +你来修建美丽的房子 + +201 +00:09:05,546 --> 00:09:07,181 +这就是主要内容 + +202 +00:09:07,247 --> 00:09:09,049 +主旨就是让你 + +203 +00:09:09,116 --> 00:09:11,018 +最终能够接触到 + +204 +00:09:11,084 --> 00:09:13,954 +现实中接触不到的美术品 + +205 +00:09:14,021 --> 00:09:16,857 +♪♪ + +206 +00:09:16,924 --> 00:09:19,126 +我觉得为创意人群设计工具的 + +207 +00:09:19,193 --> 00:09:21,695 +最大挑战之一是 + +208 +00:09:21,762 --> 00:09:24,031 +艺术家想创造的作品 +很多时候都是很复杂的作品 + +209 +00:09:24,097 --> 00:09:26,700 +所以挑战在于 +我们要如何在实现强大功能同时 + +210 +00:09:26,767 --> 00:09:29,636 +还让它保持实用且简单 + +211 +00:09:29,703 --> 00:09:33,006 +对于半路出家 没有经验的人 + +212 +00:09:33,073 --> 00:09:34,975 +它要足够易上手 + +213 +00:09:35,042 --> 00:09:38,412 +同时还要兼顾便捷和专业性 + +214 +00:09:38,478 --> 00:09:41,315 +对一个东西做简化其实是很复杂的 + +215 +00:09:41,381 --> 00:09:44,952 +有很多边边角角的细节 + +216 +00:09:45,018 --> 00:09:48,622 +会影响用户体验 + +217 +00:09:48,689 --> 00:09:51,258 +笨重感在所难免 + +218 +00:09:51,325 --> 00:09:53,393 +接下来4年半的开发任务 + +219 +00:09:53,460 --> 00:09:55,996 +就是各种的“瘦身”工作 + +220 +00:09:56,063 --> 00:09:59,333 +思考如何剥离那些会让人分心的东西 + +221 +00:09:59,399 --> 00:10:01,702 +努力帮助用户集中注意力 + +222 +00:10:01,768 --> 00:10:05,105 +这是我们的最终目标 + +223 +00:10:05,172 --> 00:10:06,807 +相当困难 + +224 +00:10:06,874 --> 00:10:08,775 +我们知道 + +225 +00:10:08,842 --> 00:10:11,345 +平面设计起源于案头工作时代 + +226 +00:10:11,411 --> 00:10:15,516 +近10年没有发生过太多革新 + +227 +00:10:15,582 --> 00:10:18,952 +这就类似于设计一幢建筑 + +228 +00:10:19,019 --> 00:10:21,255 +两者都需要做好导航 + +229 +00:10:21,321 --> 00:10:22,856 +网站也好 App也罢 + +230 +00:10:22,923 --> 00:10:24,424 +都有不同的视图 + +231 +00:10:24,491 --> 00:10:25,392 +要有入口 + +232 +00:10:25,459 --> 00:10:26,793 +有些地方要有出口 + +233 +00:10:26,860 --> 00:10:28,295 +要有不同的房间 + +234 +00:10:28,362 --> 00:10:29,997 +相关体验都要很顺畅丝滑 + +235 +00:10:30,063 --> 00:10:33,834 +我的水彩技术很糟糕 + +236 +00:10:33,901 --> 00:10:37,704 +我的编程能力是HTML水平 + +237 +00:10:37,771 --> 00:10:40,807 +我要一路过来说服其他人 + +238 +00:10:40,874 --> 00:10:42,809 +与我一起构建这些东西 + +239 +00:10:42,876 --> 00:10:47,047 +当我们将成品推出时 +市面上没有其他同类的水彩游戏 + +240 +00:10:47,114 --> 00:10:48,448 +甚至没有水彩相关的App + +241 +00:10:48,515 --> 00:10:50,017 +所以我们在所有细节里 + +242 +00:10:50,083 --> 00:10:51,718 +投入大量精力 + +243 +00:10:51,785 --> 00:10:53,220 +让水的流动符合现实 + +244 +00:10:53,287 --> 00:10:56,223 +打造优秀的App用户体验 + +245 +00:10:56,290 --> 00:10:58,392 +超越极限从来不是问题 + +246 +00:10:58,458 --> 00:11:00,627 +整个团队都很喜欢超越自我极限 + +247 +00:11:00,694 --> 00:11:02,629 +他们乐于看到一个角色能走多远 + +248 +00:11:02,696 --> 00:11:05,732 +或者这个场景的故事线能有多丰富 + +249 +00:11:05,799 --> 00:11:07,167 +挑战之处在于 + +250 +00:11:07,234 --> 00:11:08,702 +把界限设定在合理可达的位置 + +251 +00:11:08,769 --> 00:11:11,572 +如果你创造的是 +人们在现实生活中看不到的东西 + +252 +00:11:11,638 --> 00:11:14,741 +让用户们发出惊叹 + +253 +00:11:14,808 --> 00:11:18,478 +这就会让我们感到满足 + +254 +00:11:19,613 --> 00:11:23,483 +对 这就是 +我们选择视错觉为主题的原因 + +255 +00:11:23,550 --> 00:11:26,253 +对大多数人来说 +当你看到视错觉图片 + +256 +00:11:26,320 --> 00:11:27,788 +往往会忍不住发出惊叹 + +257 +00:11:27,855 --> 00:11:30,324 +这是一个很棘手的问题 + +258 +00:11:30,390 --> 00:11:32,593 +我们要确保用户可以在巴士上玩 + +259 +00:11:32,659 --> 00:11:34,728 +但却注意不到自己其实在车上 + +260 +00:11:34,795 --> 00:11:37,531 +这种沉浸感需要许多细枝末节来构成 + +261 +00:11:37,598 --> 00:11:38,999 +而非那些显而易见的大的方面 + +262 +00:11:39,066 --> 00:11:42,603 +像是疾驰的噪音 +排气口的声音之类的 + +263 +00:11:42,669 --> 00:11:45,305 +我们App里有巨大的几何体和景观 + +264 +00:11:45,372 --> 00:11:47,941 +还有很多我们希望能 +快速创建并自定义修改的东西 + +265 +00:11:48,008 --> 00:11:50,444 +我们会用我们设计的工具 + +266 +00:11:50,511 --> 00:11:53,380 +让它自动进行“乐高”化构建 + +267 +00:11:53,447 --> 00:11:57,017 +我们的目标是为触控设备 + +268 +00:11:57,084 --> 00:11:59,186 +设计一套非常集中化的体验 + +269 +00:11:59,253 --> 00:12:00,754 +让玩家可以不假思索地 + +270 +00:12:00,821 --> 00:12:03,123 +与这个世界互动 + +271 +00:12:03,190 --> 00:12:04,992 +这听起来可能很简单 很容易 + +272 +00:12:05,058 --> 00:12:07,561 +但实际上这是最难实现的事情之一 + +273 +00:12:07,628 --> 00:12:12,733 +MARVEL Future Revolution 是一款 +开放性世界的 超级英雄主题的 + +274 +00:12:12,799 --> 00:12:16,069 +动作大型多人在线角色扮演手游 +或简称MMORPG + +275 +00:12:16,136 --> 00:12:18,972 +你和你的伙伴们一起 + +276 +00:12:19,039 --> 00:12:22,910 +联手你最爱的漫威超级英雄 +一起在这里拯救世界 + +277 +00:12:22,976 --> 00:12:24,411 +在这里你可以真正地 + +278 +00:12:24,478 --> 00:12:26,813 +体验超级英雄的感觉 + +279 +00:12:26,880 --> 00:12:29,383 +还可以随身带到任何地方 + +280 +00:12:29,449 --> 00:12:31,785 +我想从最初开始 + +281 +00:12:31,852 --> 00:12:33,587 +我们就很清楚我们是想制作一款游戏 + +282 +00:12:33,654 --> 00:12:37,591 +其中有音乐 也有故事 + +283 +00:12:37,658 --> 00:12:40,561 +你知道的 任何事都可以做成游戏 + +284 +00:12:40,627 --> 00:12:43,964 +游戏里有个角色叫加布里埃尔 +他陷入了昏迷 + +285 +00:12:44,031 --> 00:12:48,001 +你需要通过音乐来解锁记忆 + +286 +00:12:48,068 --> 00:12:51,371 +制作这款游戏是个庞大的工程 + +287 +00:12:51,438 --> 00:12:54,808 +但是这也是个非常棒的游戏 + +288 +00:12:54,875 --> 00:12:56,476 +我想 相机是件令人愉悦的东西 + +289 +00:12:56,543 --> 00:13:00,080 +也许我们可以将类似的愉悦体验 + +290 +00:13:00,147 --> 00:13:01,949 +赋与iPhone摄像头 + +291 +00:13:02,015 --> 00:13:04,451 +我每月每周都会收到大家的邮件 + +292 +00:13:04,518 --> 00:13:06,320 +告诉我说 我很喜欢它 + +293 +00:13:06,386 --> 00:13:07,487 +帮了我很多 + +294 +00:13:07,554 --> 00:13:09,857 +这太酷了 + +295 +00:13:09,923 --> 00:13:12,926 +我们开发的这款App可以说服用户 + +296 +00:13:12,993 --> 00:13:15,329 +放弃开私家车 + +297 +00:13:15,395 --> 00:13:17,164 +且让公共交通工具的乘坐充满了乐趣 + +298 +00:13:17,231 --> 00:13:18,031 +从此 + +299 +00:13:18,098 --> 00:13:20,267 +我们的动力变成了 + +300 +00:13:20,334 --> 00:13:23,170 +通过我们的App +对人们的交通工具选择产生影响 + +301 +00:13:23,237 --> 00:13:26,740 +心理健康是很需要关注的需求之一 + +302 +00:13:26,807 --> 00:13:31,144 +这里非常需要设计者和产品构思者 + +303 +00:13:31,211 --> 00:13:34,815 +有相应的技能组合 +来将大量的关注导向于 + +304 +00:13:34,882 --> 00:13:38,886 +以前被忽视的人群 + +305 +00:13:38,952 --> 00:13:41,989 +其表现方式就是我们所谓的 + +306 +00:13:42,055 --> 00:13:45,993 +“打开大门 释放关心” + +307 +00:13:46,059 --> 00:13:49,096 +App和游戏必须应对社会变迁 + +308 +00:13:49,162 --> 00:13:51,698 +一款有包容性的游戏或App + +309 +00:13:51,765 --> 00:13:53,967 +会让每个人都感觉自在 + +310 +00:13:54,034 --> 00:13:55,402 +每个人都可以…… + +311 +00:13:55,469 --> 00:13:58,305 +既能娱乐 又能够与他人社交 + +312 +00:13:58,372 --> 00:14:01,041 +这种真实使我们能够 + +313 +00:14:01,108 --> 00:14:04,611 +不仅仅象征性地体现多元化 +而是加入真正的多元化 + +314 +00:14:04,678 --> 00:14:07,581 +我认为若我们想看到社会变化 + +315 +00:14:07,648 --> 00:14:10,617 +那就得展示出来 尤其是在娱乐方面 + +316 +00:14:10,684 --> 00:14:13,921 +因为这向人们展示了我们的方向 + +317 +00:14:13,987 --> 00:14:16,056 +我真的开始觉得 + +318 +00:14:16,123 --> 00:14:18,458 +“你看 我现在可以制作一些 +有助于人们的东西 + +319 +00:14:18,525 --> 00:14:21,094 +帮这个世界解决一点问题” + +320 +00:14:21,161 --> 00:14:23,797 +我觉得尤其是过去这两年 + +321 +00:14:23,864 --> 00:14:25,933 +我们看清了前进的方向 + +322 +00:14:25,999 --> 00:14:28,202 +看清了我们生活的哪些方面里 + +323 +00:14:28,268 --> 00:14:29,703 +数字化的分量会越来越重 + +324 +00:14:29,770 --> 00:14:37,811 +而我们作为人类 +要如何塑造日常生活体验 + +325 +00:14:37,878 --> 00:14:40,447 +我可以分享给年轻开发者的小诀窍是 + +326 +00:14:40,514 --> 00:14:43,951 +坚守你最初的想法 + +327 +00:14:44,017 --> 00:14:45,619 +如果你仅仅从喜欢的其他游戏 + +328 +00:14:45,686 --> 00:14:48,121 +汲取灵感 + +329 +00:14:48,188 --> 00:14:49,957 +那你只能创造出另一个游戏 + +330 +00:14:50,023 --> 00:14:54,027 +尝试 失败 再尝试 再失败 +然后继续下一次尝试 + +331 +00:14:54,094 --> 00:14:56,797 +尽你所能去创造 + +332 +00:14:56,864 --> 00:14:58,098 +项目不一定非得很大 + +333 +00:14:58,165 --> 00:15:00,501 +不一定非得惊天动地 + +334 +00:15:00,567 --> 00:15:02,336 +但是你尝试创作的越多 +你关于如何创作的经验就越多 + +335 +00:15:02,402 --> 00:15:06,006 +要明白什么时候该放手 +不要再徒劳地修修补补 + +336 +00:15:06,073 --> 00:15:07,608 +明确搞清楚你的目标是什么 + +337 +00:15:07,674 --> 00:15:09,776 +再来组建队伍着手开始 + +338 +00:15:09,843 --> 00:15:11,011 +不要沮丧 + +339 +00:15:11,078 --> 00:15:13,080 +放弃自己的一些假设 + +340 +00:15:13,146 --> 00:15:14,515 +你想要决定市场要什么 + +341 +00:15:14,581 --> 00:15:15,849 +是行不通的 + +342 +00:15:15,916 --> 00:15:17,851 +还是做一些 + +343 +00:15:17,918 --> 00:15:18,719 +自己有动力坚持做 + +344 +00:15:18,785 --> 00:15:21,088 +自己真的想实现的东西吧 + +345 +00:15:21,154 --> 00:15:24,224 +你可以偷师 但要从最好的人那里偷 + +346 +00:15:24,291 --> 00:15:28,529 +永远要记得加入自己的一缕巧思 + +347 +00:15:28,595 --> 00:15:29,429 +去找灵感吧 + +348 +00:15:29,496 --> 00:15:31,765 +去外面 去周遭寻找灵感 + +349 +00:15:31,832 --> 00:15:33,233 +看看现在有什么技术 + +350 +00:15:33,300 --> 00:15:35,736 +想想如何从全新的出发点 + +351 +00:15:35,802 --> 00:15:40,541 +根据你的偏好和长处来利用这些技术 + +352 +00:15:40,607 --> 00:15:47,047 +Apple设计大奖就像是奥斯卡 + +353 +00:15:47,114 --> 00:15:50,784 +我都不敢相信 我当时热泪盈眶 + +354 +00:15:50,851 --> 00:15:54,454 +我不知道我该跟谁分享这份惊喜 +我觉得 我的天 + +355 +00:15:54,521 --> 00:15:57,925 +这是多么令人惊喜的事情 + +356 +00:15:57,991 --> 00:16:01,428 +可房间里没人能与我一起分享快乐 + +357 +00:16:01,495 --> 00:16:04,898 +我记得当时他都哭了 + +358 +00:16:04,965 --> 00:16:07,501 +这对我也意义重大 + +359 +00:16:07,568 --> 00:16:10,804 +因为是我让他辞职的 + +360 +00:16:10,871 --> 00:16:13,473 +他们都还在睡吗?别这样 + +361 +00:16:13,540 --> 00:16:17,411 +这可是Apple设计大奖哎 + +362 +00:16:17,477 --> 00:16:21,381 +我收到邮件的第一反应是 + +363 +00:16:21,448 --> 00:16:23,550 +“嗯 这可能是垃圾邮件” + +364 +00:16:23,617 --> 00:16:27,087 +我心想“这垃圾邮件还挺好” + +365 +00:16:27,154 --> 00:16:29,957 +然后我跟团队聊到了这个 + +366 +00:16:30,023 --> 00:16:34,494 +然后每个人都惊呼“什么?什么?” + +367 +00:16:34,561 --> 00:16:37,297 +我想对其他决赛选手说什么? + +368 +00:16:37,364 --> 00:16:38,665 +祝你们好运 + +369 +00:16:38,732 --> 00:16:41,001 +无论最后花落谁家 + +370 +00:16:41,068 --> 00:16:43,136 +你们都交出了一份杰作 + +371 +00:16:43,203 --> 00:16:48,542 +现在我们入围了 +Apple设计大奖的决赛 + +372 +00:16:48,609 --> 00:16:52,880 +我感觉现在每一天都立于人生巅峰 + +373 +00:16:52,946 --> 00:16:55,249 +我们做到了 + +374 +00:16:55,315 --> 00:16:57,184 +我第一次听到这消息时 + +375 +00:16:57,251 --> 00:16:58,719 +非常激动 + +376 +00:16:58,785 --> 00:17:02,422 +我希望他们会回顾一下 + +377 +00:17:02,489 --> 00:17:04,858 +自己去年甚至更早的进度和工作 + +378 +00:17:04,925 --> 00:17:06,994 +干得漂亮 祝贺大家 + +379 +00:17:07,060 --> 00:17:08,195 +恭喜大家 + +380 +00:17:08,262 --> 00:17:09,263 +恭喜 + +381 +00:17:09,329 --> 00:17:10,464 +恭喜啦 + +382 +00:17:10,531 --> 00:17:12,266 +能与诸位并列是我的荣幸 + +383 +00:17:12,332 --> 00:17:13,700 +干的漂亮 + +384 +00:17:13,767 --> 00:17:15,402 +让我们继续努力吧 + +385 +00:17:15,469 --> 00:17:20,707 +你们持续的工作和创造以及努力 + +386 +00:17:20,774 --> 00:17:22,409 +会带来不同 + +387 +00:17:22,476 --> 00:17:24,578 +♪♪ + +388 +00:17:24,645 --> 00:17:27,848 +(Apple设计大奖获奖者) + +389 +00:17:27,915 --> 00:17:29,917 +(“兼容并蓄”获奖者) + +390 +00:17:29,983 --> 00:17:32,052 +(游戏 - Wylde Flowers) + +391 +00:17:32,119 --> 00:17:34,888 +(App - Procreate) + +392 +00:17:34,955 --> 00:17:37,057 +(“乐趣横生”获奖者) + +393 +00:17:37,124 --> 00:17:38,825 +(游戏 - Overboard!) + +394 +00:17:38,892 --> 00:17:42,029 +(App - (Not Boring) Habits) + +395 +00:17:42,095 --> 00:17:44,031 +(“优越互动”获奖者) + +396 +00:17:44,097 --> 00:17:45,899 +(游戏 - A Musical Story) + +397 +00:17:45,966 --> 00:17:49,102 +(App - Slopes) + +398 +00:17:49,169 --> 00:17:51,205 +(“社会影响”获奖者) + +399 +00:17:51,271 --> 00:17:52,973 +(游戏 - Gibbon: Beyond the Trees) + +400 +00:17:53,040 --> 00:17:56,176 +(App - Rebel Girls) + +401 +00:17:56,243 --> 00:17:57,911 +(“视觉图像”获奖者) + +402 +00:17:57,978 --> 00:18:00,013 +(游戏 - LEGO® Star Wars™: Castaways) + +403 +00:18:00,080 --> 00:18:03,250 +(App - Halide Mark II - 专业相机) + +404 +00:18:03,317 --> 00:18:05,352 +(“创新思维”获奖者) + +405 +00:18:05,419 --> 00:18:07,120 +(游戏 - MARVEL Future Revolution) + +406 +00:18:07,187 --> 00:18:10,324 +(App - Odio) + +407 +00:18:10,390 --> 00:18:13,427 +(Apple设计大奖获奖者) + +408 +00:18:13,493 --> 00:18:16,897 +♪♪ + +409 +00:18:16,964 --> 00:18:20,767 +♪♪ + +410 +00:18:20,834 --> 00:18:25,405 +♪♪ + +411 +00:18:25,472 --> 00:18:30,043 +♪♪ + +412 +00:18:31,912 --> 00:18:34,014 +♪♪ + +413 +00:18:34,081 --> 00:18:38,919 +♪♪ + diff --git a/zho/2022 Session 110332 What's new in Create ML.srt b/zho/2022 Session 110332 What's new in Create ML.srt new file mode 100644 index 0000000..6113b21 --- /dev/null +++ b/zho/2022 Session 110332 What's new in Create ML.srt @@ -0,0 +1,1304 @@ +1 +00:00:00,167 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,977 +♪ + +3 +00:00:09,977 --> 00:00:13,981 +Namaskar 您好 +欢迎来到 WWDC 22 + +4 +00:00:13,981 --> 00:00:17,651 +我叫 Vrushali Mundhe +是 Create ML 团队的工程师 + +5 +00:00:17,651 --> 00:00:22,456 +很高兴在这里与您分享 +Create ML 的新功能 + +6 +00:00:22,456 --> 00:00:24,525 +Create ML 可以让您 +轻松地用收集到的数据 + +7 +00:00:24,525 --> 00:00:27,628 +训练强大的机器学习模型 + +8 +00:00:27,628 --> 00:00:32,566 +提供独特的体验并优化您的 App + +9 +00:00:32,566 --> 00:00:36,003 +Create ML 作为与 +Xcode 捆绑的 App 发布 + +10 +00:00:36,003 --> 00:00:38,906 +让您无需代码直接在 Mac 上 + +11 +00:00:38,906 --> 00:00:41,808 +创建和训练 Core ML 模型 + +12 +00:00:41,808 --> 00:00:44,978 +Create ML 也可作为 + +13 +00:00:44,978 --> 00:00:47,147 +SDK 中的 Swift 框架 + +14 +00:00:47,147 --> 00:00:51,251 +使用它的 API +您可以直接在您的 App 内 + +15 +00:00:51,251 --> 00:00:54,588 +轻松地自动创建模型 + +16 +00:00:54,588 --> 00:00:57,758 +或通过训练创造动态体验 + +17 +00:00:57,758 --> 00:01:00,427 +要详细了解 +Create ML 的核心功能 + +18 +00:01:00,427 --> 00:01:04,031 +您可以查看这些往期讲座 + +19 +00:01:04,031 --> 00:01:08,135 +在本次讲座中 我们将讨论 +Create ML 中的新增功能 + +20 +00:01:08,135 --> 00:01:10,704 +我们将从 Create ML +App 中的新功能开始 + +21 +00:01:10,704 --> 00:01:12,806 +这些功能可以帮助评估 + +22 +00:01:12,806 --> 00:01:14,942 +您的模型的准确性和实用性 + +23 +00:01:14,942 --> 00:01:18,579 +接着我会介绍 +Create ML 框架 + +24 +00:01:18,579 --> 00:01:20,681 +它的扩展能力 + +25 +00:01:20,681 --> 00:01:23,550 +以及现在为您的 App + +26 +00:01:23,550 --> 00:01:26,119 +高度定制模型的能力 + +27 +00:01:26,119 --> 00:01:28,188 +让我们从回顾一个典型的 + +28 +00:01:28,188 --> 00:01:30,157 +创建模型工流程开始 + +29 +00:01:30,157 --> 00:01:33,160 +给定一个确定的任务 + +30 +00:01:33,160 --> 00:01:35,629 +首先要开始收集和注释数据 + +31 +00:01:35,629 --> 00:01:40,033 +举个例子 想要直观地识别杂货 + +32 +00:01:40,033 --> 00:01:42,002 +对于这个图像分类任务 + +33 +00:01:42,002 --> 00:01:45,839 +您的出发点是收集和标记图像 + +34 +00:01:45,839 --> 00:01:47,941 +在这里 有一些水果和蔬菜 + +35 +00:01:50,410 --> 00:01:53,780 +Create ML +将帮助您根据这些数据训练模型 + +36 +00:01:53,780 --> 00:01:56,283 +模型可在您的 App 中使用 + +37 +00:01:56,283 --> 00:01:58,719 +但是 在使用这个模型之前 + +38 +00:01:58,719 --> 00:02:02,756 +一个重要的步骤是评估它的表现如何 + +39 +00:02:02,756 --> 00:02:05,826 +在这里 +查看该模型在图像上的准确度 + +40 +00:02:05,826 --> 00:02:09,263 +并不是训练集的一部分 + +41 +00:02:09,263 --> 00:02:11,431 +根据评估 + +42 +00:02:11,431 --> 00:02:14,735 +您可以使用其他数据对模型进行迭代 + +43 +00:02:14,735 --> 00:02:17,171 +并修改训练设置 + +44 +00:02:17,171 --> 00:02:19,773 +或者 如果模型表现得足够好 + +45 +00:02:19,773 --> 00:02:22,976 +您可以准备将其集成到 App 中 + +46 +00:02:22,976 --> 00:02:26,947 +我们来进一步关注这个评估步骤 + +47 +00:02:26,947 --> 00:02:29,550 +在进行评估时 我们经常会 + +48 +00:02:29,550 --> 00:02:33,053 +通过在训练中保留的新数据上 + +49 +00:02:33,053 --> 00:02:35,923 +测试您的模型来衡量一组指标 + +50 +00:02:35,923 --> 00:02:39,293 +您可以 +从查看最高级别的准确率指标开始 + +51 +00:02:39,293 --> 00:02:41,695 +或深入了解每类统计数据 + +52 +00:02:41,695 --> 00:02:44,264 +大致了解模型的行为 + +53 +00:02:44,264 --> 00:02:48,769 +以及超出其训练范围的整体能力 + +54 +00:02:48,769 --> 00:02:51,972 +最终 该模型将在您的 App 中 + +55 +00:02:51,972 --> 00:02:54,141 +赋予数据驱动体验 + +56 +00:02:54,141 --> 00:02:55,742 +在评估过程中 + +57 +00:02:55,742 --> 00:03:00,314 +您想确定该模型在输入或 + +58 +00:03:00,314 --> 00:03:03,283 +场景类别方面的主要优势和劣势 + +59 +00:03:03,283 --> 00:03:07,754 +它运作良好或可能达不到预期 + +60 +00:03:07,754 --> 00:03:10,657 +Create ML App +中有一些新功能 + +61 +00:03:10,657 --> 00:03:13,260 +可以在模型创建之旅的这部分帮助您 + +62 +00:03:13,260 --> 00:03:16,296 +让我向您展示一个我正在从事的项目 + +63 +00:03:16,296 --> 00:03:18,699 +在这里 我设置了一个项目 + +64 +00:03:18,699 --> 00:03:20,767 +来创建模型识别杂货 + +65 +00:03:20,767 --> 00:03:23,070 +我开始收集各种水果 + +66 +00:03:23,070 --> 00:03:25,839 +和蔬菜图像作为我的训练数据 + +67 +00:03:25,839 --> 00:03:30,143 +并给它们标上合适的标签 + +68 +00:03:30,143 --> 00:03:32,446 +这是我的不同类别 + +69 +00:03:32,446 --> 00:03:34,281 +和每个类别的图像数量 + +70 +00:03:38,285 --> 00:03:43,557 +我已经对我的图像分类器 +进行了 25 次迭代训练 + +71 +00:03:43,557 --> 00:03:46,260 +接下来 当我点击“评估”选项卡时 + +72 +00:03:46,260 --> 00:03:49,463 +除了我为测试留出的训练数据 + +73 +00:03:49,463 --> 00:03:53,433 +我还可以添加 +新的测试数据 一组图像 + +74 +00:03:58,372 --> 00:04:03,510 +接下来我将单击“评估”开始测试 + +75 +00:04:03,510 --> 00:04:05,579 +完成评估后 + +76 +00:04:05,579 --> 00:04:08,615 +UI 提供了结果的详细信息 + +77 +00:04:08,615 --> 00:04:11,318 +在顶部 有高级别摘要部分 + +78 +00:04:11,318 --> 00:04:14,721 +在这可以快速了解测试的准确性 + +79 +00:04:14,721 --> 00:04:19,293 +在这里 +该测试数据的准确率为 89% + +80 +00:04:19,293 --> 00:04:21,061 +在此“指标”选项卡下方 + +81 +00:04:21,061 --> 00:04:24,798 +这张表为每个类别提供了丰富的指标 + +82 +00:04:24,798 --> 00:04:28,669 +您可以使用这些下拉菜单 +来调整此处显示的内容 + +83 +00:04:28,669 --> 00:04:31,138 +并添加额外的指标 如误报 + +84 +00:04:31,138 --> 00:04:32,606 +和漏报 + +85 +00:04:32,606 --> 00:04:34,675 +让我们来看看其中的一个类别 + +86 +00:04:34,675 --> 00:04:36,276 +“番茄”怎么样? + +87 +00:04:36,276 --> 00:04:40,080 +该模型正确分类了 +32 幅番茄图像中的 29 幅 + +88 +00:04:40,080 --> 00:04:45,586 +它还显示该类的准确率为 91% + +89 +00:04:45,586 --> 00:04:47,154 +这意味着 +该模型说某个东西是番茄时 + +90 +00:04:47,154 --> 00:04:50,624 +有 9% 是不正确的 + +91 +00:04:50,624 --> 00:04:53,227 +虽然这些数字和统计数据非常有用 + +92 +00:04:53,227 --> 00:04:56,096 +但有时 + +93 +00:04:56,096 --> 00:04:58,465 +在数据本身的背景下看它们更重要 + +94 +00:04:58,465 --> 00:05:02,236 +当我点击准确度时 + +95 +00:05:02,236 --> 00:05:05,372 +它会跳转到被错误归类为番茄的图像 + +96 +00:05:05,372 --> 00:05:08,876 +以下是测试数据中的三种情况 + +97 +00:05:08,876 --> 00:05:12,145 +对于每张图像 +App 都会显示其缩略图 + +98 +00:05:12,145 --> 00:05:14,448 +模型预测的类别 + +99 +00:05:14,448 --> 00:05:16,550 +以及它下面的真实标签 + +100 +00:05:16,550 --> 00:05:19,052 +在第一个示例中 +虽然模型将其分类为 + +101 +00:05:19,052 --> 00:05:22,589 +“番茄” 但它被标记为“马铃薯” + +102 +00:05:22,589 --> 00:05:25,058 +在我看来这肯定是番茄 + +103 +00:05:25,058 --> 00:05:27,694 +这似乎 +是一个错误标记测试数据的情况 + +104 +00:05:27,694 --> 00:05:31,632 +事实上 +所有这三个示例似乎都被标记错误 + +105 +00:05:31,632 --> 00:05:33,567 +这应该很容易解决 + +106 +00:05:33,567 --> 00:05:35,135 +我会做一个笔记来再次检查 + +107 +00:05:35,135 --> 00:05:37,738 +并重新审视我的测试集标签 + +108 +00:05:37,738 --> 00:05:40,007 +这显然是我的失误 + +109 +00:05:40,007 --> 00:05:42,943 +但它是错误的唯一来源吗 + +110 +00:05:42,943 --> 00:05:44,845 +我通过研究 +我选择的一个随机类上的指标 + +111 +00:05:44,845 --> 00:05:47,281 +到达这里 + +112 +00:05:47,281 --> 00:05:50,317 +您可能想知道 +“我应该从哪里开始?” + +113 +00:05:50,317 --> 00:05:53,787 +或者 “接下来我应该研究什么?” + +114 +00:05:53,787 --> 00:05:58,225 +顶层摘要部分可以帮助您解决疑惑 + +115 +00:05:58,225 --> 00:05:59,293 +该 App 已选择 + +116 +00:05:59,293 --> 00:06:01,795 +一些最重要的评估细节 + +117 +00:06:01,795 --> 00:06:05,766 +可以从此处开始研究 + +118 +00:06:05,766 --> 00:06:10,604 +让我从头开始 回顾成功案例 + +119 +00:06:10,604 --> 00:06:15,742 +点击这里 这个正确的计数... + +120 +00:06:15,742 --> 00:06:19,413 +在这里 +我们可以快速浏览模型正确分类的 + +121 +00:06:19,413 --> 00:06:23,550 +所有 162 张图片 + +122 +00:06:23,550 --> 00:06:27,187 +接下来 我通过点击不正确 + +123 +00:06:27,187 --> 00:06:31,258 +将其与所有错误分类进行对比 + +124 +00:06:31,258 --> 00:06:33,660 +总共有 21 次错误 + +125 +00:06:35,963 --> 00:06:38,765 +又是那个被标记错误的番茄 + +126 +00:06:38,765 --> 00:06:40,934 +让我检查一下 +是否还有其他类型的错误 + +127 +00:06:40,934 --> 00:06:43,036 +可以突出显示 + +128 +00:06:43,036 --> 00:06:46,139 +这个怎么样? + +129 +00:06:46,139 --> 00:06:50,344 +这张图片被标记为“胡萝卜” + +130 +00:06:50,344 --> 00:06:53,780 +但模型预测为“马铃薯” + +131 +00:06:53,780 --> 00:06:56,483 +在这个小缩略图中很难分辨 + +132 +00:06:56,483 --> 00:07:01,154 +让我们单击此图像 +以获得更清楚的视图 + +133 +00:07:01,154 --> 00:07:03,557 +嗯 这对我来说就像一只脚 + +134 +00:07:03,557 --> 00:07:06,894 +这显然不是 +我认知里又长又瘦的胡萝卜形状 + +135 +00:07:06,894 --> 00:07:09,563 +但很容易被混淆为马铃薯 + +136 +00:07:09,563 --> 00:07:12,199 +也许我应该考虑添加更多的形状变化 + +137 +00:07:12,199 --> 00:07:14,501 +到我的胡萝卜训练数据 + +138 +00:07:14,501 --> 00:07:16,603 +让我也记下这一点 + +139 +00:07:16,603 --> 00:07:20,274 +这一次 我将点击文件名旁边的箭头 + +140 +00:07:20,274 --> 00:07:23,243 +带我跳转到“访达”中的这张图像 + +141 +00:07:25,679 --> 00:07:30,651 +我将右键单击并将其标记为红色 + +142 +00:07:30,651 --> 00:07:33,520 +以此在我的下一轮数据收集中 + +143 +00:07:33,520 --> 00:07:36,456 +提醒我这是要重新查看的东西 + +144 +00:07:36,456 --> 00:07:40,594 +让我从这个扩展的视图中 +继续我的研究 + +145 +00:07:40,594 --> 00:07:44,298 +请注意 +此视图也显示了完整的预测结果 + +146 +00:07:44,298 --> 00:07:46,934 +列出模型对每个类别的预测比例 + +147 +00:07:46,934 --> 00:07:49,670 +使用这些左右箭头 + +148 +00:07:49,670 --> 00:07:53,473 +还可以浏览示例 + +149 +00:07:53,473 --> 00:07:57,244 +我将从这里转到另一个示例 + +150 +00:07:57,244 --> 00:07:58,912 +这是一个有趣的示例 + +151 +00:07:58,912 --> 00:08:02,883 +这个图像中有多种蔬菜 + +152 +00:08:02,883 --> 00:08:07,120 +它说这是茄子 确实是的 + +153 +00:08:07,120 --> 00:08:11,091 +这里有茄子 但也有其他东西 + +154 +00:08:11,091 --> 00:08:13,961 +我需要想想 +这是否是我的 App 中 + +155 +00:08:13,961 --> 00:08:16,830 +需要考虑的一个重要使用案例 + +156 +00:08:16,830 --> 00:08:19,600 +也许 UI 可以引导我的用户 + +157 +00:08:19,600 --> 00:08:22,769 +确保他们一次只指向一种类型的杂货 + +158 +00:08:22,769 --> 00:08:24,972 +或者如果我想支持多种类型 + +159 +00:08:24,972 --> 00:08:28,141 +我可能要考虑使用一个对象检测器 + +160 +00:08:28,141 --> 00:08:29,776 +App 中的另一个模板 + +161 +00:08:29,776 --> 00:08:32,679 +而不是整个图像分类器 + +162 +00:08:32,679 --> 00:08:34,481 +回到概要部分 + +163 +00:08:34,481 --> 00:08:37,885 +让我看看这条最高层级混乱 + +164 +00:08:37,885 --> 00:08:40,621 +在这里它说 +将“辣椒”归类为“豆子” + +165 +00:08:40,621 --> 00:08:44,258 +让我们点击来看看这个案例 + +166 +00:08:44,258 --> 00:08:46,260 +四个标记为辣椒的图像 + +167 +00:08:46,260 --> 00:08:49,730 +被错误地归类为豆类 + +168 +00:08:49,730 --> 00:08:51,598 +这些在我看来像很辣的辣椒 + +169 +00:08:51,598 --> 00:08:55,068 +但我猜它们也像豆子一样绿 +所以才被错误归类 + +170 +00:08:55,068 --> 00:08:58,805 +我想知道这个模型是否在一般情况下 +识别辣椒有问题 + +171 +00:08:58,805 --> 00:09:05,812 +让我将此查询选项从“不正确” +切换到“正确”... + +172 +00:09:05,812 --> 00:09:09,583 +将这些错误与正确分类的辣椒 +进行对比 + +173 +00:09:09,583 --> 00:09:13,020 +它正确分类了 32 张图像 + +174 +00:09:13,020 --> 00:09:17,024 +但是 +我确实注意到其中大部分都是甜椒 + +175 +00:09:17,024 --> 00:09:19,426 +我应该检查我的训练数据以确保 + +176 +00:09:19,426 --> 00:09:24,731 +它有涵盖多种辣椒类型 + +177 +00:09:24,731 --> 00:09:26,934 +这次快速研究很好地提醒了我们 + +178 +00:09:26,934 --> 00:09:29,436 +训练和测试数据的数量、质量和种类 + +179 +00:09:29,436 --> 00:09:34,174 +对于机器学习是多么重要 + +180 +00:09:34,174 --> 00:09:36,543 +在短短的几分钟内 + +181 +00:09:36,543 --> 00:09:38,779 +该 App 帮助我直观地发现了 + +182 +00:09:38,779 --> 00:09:40,848 +一些标签和表述方面的问题 + +183 +00:09:40,848 --> 00:09:43,517 +我需要对我的训练数据进行一些调整 + +184 +00:09:43,517 --> 00:09:46,019 +看看调整后 +它能否解决我们发现的问题 + +185 +00:09:46,019 --> 00:09:49,623 +它还提醒了一些 +我以前没有考虑过的事情: + +186 +00:09:49,623 --> 00:09:52,759 +如果用户在一张图像中 + +187 +00:09:52,759 --> 00:09:54,494 +看到多个蔬菜会发生什么 + +188 +00:09:54,494 --> 00:09:58,732 +我需要再考虑我的 App 设计 + +189 +00:09:58,732 --> 00:10:00,834 +所有这些探索都是可能的 + +190 +00:10:00,834 --> 00:10:04,638 +因为我有一系列的标签数据来评估 + +191 +00:10:04,638 --> 00:10:08,942 +但如果我想快速测试 +未标记的示例该怎么办? + +192 +00:10:08,942 --> 00:10:11,278 +或者考虑是否应该探索 + +193 +00:10:11,278 --> 00:10:15,182 +更多的摄像机角度或照明条件呢? + +194 +00:10:15,182 --> 00:10:18,151 +在“预览”里就可以解决上述问题 + +195 +00:10:18,151 --> 00:10:21,021 +我可以拖拽一些我同事 +刚刚发给我的示例进这里 + +196 +00:10:21,021 --> 00:10:22,856 +看看效果如何 + +197 +00:10:36,603 --> 00:10:38,338 +或者我甚至可以现场测试 + +198 +00:10:38,338 --> 00:10:41,375 +用我的 iPhone +作为“连续互通”相机 + +199 +00:10:43,610 --> 00:10:45,746 +当我将镜头对着这些蔬菜时 + +200 +00:10:45,746 --> 00:10:49,516 +该模型能够正确地 +实时对它们进行分类 + +201 +00:10:49,516 --> 00:10:54,488 +这里 这是一个辣椒和一个番茄 + +202 +00:10:54,488 --> 00:10:56,690 +回顾一下 您现在可以更深入地了解 + +203 +00:10:56,690 --> 00:11:01,061 +一个训练有素的模型 +在任何标记数据集上的行为 + +204 +00:11:01,061 --> 00:11:04,198 +“评估”窗格提供了详细的指标汇总 + +205 +00:11:04,198 --> 00:11:06,400 +及其扩展选项 + +206 +00:11:06,400 --> 00:11:09,503 +新的“探索”选项卡提供了一些选项 + +207 +00:11:09,503 --> 00:11:12,172 +让您可以在新交互式 UI 中筛选 + +208 +00:11:12,172 --> 00:11:16,543 +和可视化测试评估结果以及相关数据 + +209 +00:11:16,543 --> 00:11:18,946 +目前可用于图像分类器 + +210 +00:11:18,946 --> 00:11:24,017 +手部姿势分类器和物体检测模板 + +211 +00:11:24,017 --> 00:11:26,987 +实时预览可实现即时反馈 + +212 +00:11:26,987 --> 00:11:29,456 +它已扩展至图像分类器 + +213 +00:11:29,456 --> 00:11:34,561 +手部动作分类器 +和身体动作分类器模板 + +214 +00:11:34,561 --> 00:11:36,763 +我们还扩展了该功能以允许您 + +215 +00:11:36,763 --> 00:11:39,333 +从任何附加的网络摄像头中选择 + +216 +00:11:39,333 --> 00:11:42,069 +我们还支持 macOS + +217 +00:11:42,069 --> 00:11:45,305 +Ventura 上的“连续互通”相机 + +218 +00:11:45,305 --> 00:11:48,675 +这是对 Create ML +App 新功能的快速回顾总结 + +219 +00:11:48,675 --> 00:11:50,577 +我们接着来讨论 +Create ML 框架中的 + +220 +00:11:50,577 --> 00:11:52,446 +新功能 + +221 +00:11:54,915 --> 00:11:57,518 +Create ML 框架适用于 + +222 +00:11:57,518 --> 00:11:59,820 +macOS、iOS +和 iPadOS + +223 +00:11:59,820 --> 00:12:04,525 +今年 我们正将其部分支持 +扩展到 tvOS 16 + +224 +00:12:04,525 --> 00:12:07,127 +程序化界面不仅让您 + +225 +00:12:07,127 --> 00:12:09,830 +在开发时自动创建模型 + +226 +00:12:09,830 --> 00:12:12,866 +而且还开辟了许多机会 +来构建动态功能 + +227 +00:12:12,866 --> 00:12:17,070 +直接从用户的输入 +或设备上的行为中学习 + +228 +00:12:17,070 --> 00:12:20,073 +提供个性化和自适应的体验 + +229 +00:12:20,073 --> 00:12:24,444 +同时保护用户隐私 + +230 +00:12:24,444 --> 00:12:27,781 +请注意 任务支持因平台而异 + +231 +00:12:27,781 --> 00:12:31,151 +例如 表格分类器和回归器 + +232 +00:12:31,151 --> 00:12:34,588 +在几乎所有平台可用 +但一些对数据和计算要求较大的任务 + +233 +00:12:34,588 --> 00:12:38,325 +如涉及视频的任务 + +234 +00:12:38,325 --> 00:12:41,061 +则需要 macOS + +235 +00:12:41,061 --> 00:12:43,096 +您可能有一个常见的问题是 + +236 +00:12:43,096 --> 00:12:44,998 +“如果我不能把我的想法映射到这些 + +237 +00:12:44,998 --> 00:12:48,802 +Create ML 的 +预定义任务中怎么办?” + +238 +00:12:48,802 --> 00:12:52,239 +为了帮助回答这个问题 +我们要向您介绍 + +239 +00:12:52,239 --> 00:12:54,441 +一位 Create ML 系列的 +新成员: + +240 +00:12:54,441 --> 00:12:56,610 +Create ML 组件 + +241 +00:12:56,610 --> 00:12:59,980 +Create ML 组件展露了 + +242 +00:12:59,980 --> 00:13:02,482 +Create ML 的基本模块 + +243 +00:13:02,482 --> 00:13:05,586 +它允许您将它们组合在一起 + +244 +00:13:05,586 --> 00:13:09,556 +创建为您的用例定制的管道和模型 + +245 +00:13:09,556 --> 00:13:11,458 +强烈建议您查看这些讲座 + +246 +00:13:11,458 --> 00:13:12,926 +以了解更多信息 + +247 +00:13:12,926 --> 00:13:14,895 +在“了解 +Create ML 组件”中 + +248 +00:13:14,895 --> 00:13:16,964 +您将了解构建基块 + +249 +00:13:16,964 --> 00:13:19,600 +以及它们如何组合在一起 + +250 +00:13:19,600 --> 00:13:22,636 +在“使用 Create ML +组件构建高级模型”中 + +251 +00:13:22,636 --> 00:13:26,240 +您将深入了解使用异步时间组件 + +252 +00:13:26,240 --> 00:13:28,609 +和自定义训练 + +253 +00:13:28,609 --> 00:13:31,712 +功能十分丰富 让我演示一个 + +254 +00:13:31,712 --> 00:13:33,680 +我很喜欢的功能: + +255 +00:13:33,680 --> 00:13:35,849 +动作重复计数 + +256 +00:13:35,849 --> 00:13:40,087 +当我休息时 我会去跳舞 + +257 +00:13:40,087 --> 00:13:41,355 +我是受过专业训练的 + +258 +00:13:41,355 --> 00:13:44,691 +印度古典舞卡达克艺术家 + +259 +00:13:44,691 --> 00:13:45,826 +我经常依靠反复练习我的常规动作 + +260 +00:13:45,826 --> 00:13:49,563 +来优化我的舞蹈 + +261 +00:13:49,563 --> 00:13:53,000 +作为一名编舞者或教师 +我希望我的表演者 + +262 +00:13:53,000 --> 00:13:56,236 +能够练习某些舞步并提交给我 + +263 +00:13:56,236 --> 00:13:59,006 +Create ML 中的 +重复计数功能 + +264 +00:13:59,006 --> 00:14:01,475 +就可以帮我实现这个要求 + +265 +00:14:01,475 --> 00:14:04,378 +这是卡达克舞中的一个重要动作 + +266 +00:14:04,378 --> 00:14:06,713 +chakkar 平转 + +267 +00:14:09,249 --> 00:14:11,952 +我想每天练习一定的次数 + +268 +00:14:11,952 --> 00:14:14,588 +以优化我的动作形态和耐力 + +269 +00:14:14,588 --> 00:14:18,625 +我有一个使用 Create ML +构建的 iOS App 可以 + +270 +00:14:18,625 --> 00:14:20,360 +计算我的动作 让我来试一下 + +271 +00:14:27,868 --> 00:14:30,304 +当我开始做 chakkars 时 + +272 +00:14:30,304 --> 00:14:31,972 +与之对应的计数也在增加 + +273 +00:14:31,972 --> 00:14:33,807 +我刚才做了五个 chakkars 动作 + +274 +00:14:33,807 --> 00:14:36,743 +计数也正好是五 + +275 +00:14:36,743 --> 00:14:39,146 +接下来 我来尝试一些不同的小动作 + +276 +00:14:39,146 --> 00:14:41,982 +包括右侧和左侧的动作 + +277 +00:14:41,982 --> 00:14:44,017 +计数器会右侧和左侧动作 +一齐算作一个动作 + +278 +00:14:57,030 --> 00:14:59,566 +在这里 计数显示三个 + +279 +00:14:59,566 --> 00:15:02,903 +让我再试试快速的单侧手臂运动 + +280 +00:15:17,284 --> 00:15:18,685 +这被计为四个 + +281 +00:15:18,685 --> 00:15:20,821 +当与动作分类结合使用时 + +282 +00:15:20,821 --> 00:15:24,558 +这将允许您同时对重复动作 + +283 +00:15:24,558 --> 00:15:26,360 +进行计数和分类 + +284 +00:15:26,360 --> 00:15:30,430 +重复计数 +可作为运行时 API 使用 + +285 +00:15:30,430 --> 00:15:33,800 +它不需要训练数据 + +286 +00:15:33,800 --> 00:15:37,237 +在您的 App 中添加这一功能 +只需几行代码即可 + +287 +00:15:37,237 --> 00:15:40,507 +它的实现 +是基于一个预先训练好的模型 + +288 +00:15:40,507 --> 00:15:42,643 +该模型被设计成与类别无关 + +289 +00:15:42,643 --> 00:15:46,180 +意思是 +虽然它适用于健身或舞蹈动作 + +290 +00:15:46,180 --> 00:15:49,950 +如跳远、深蹲、旋转 +旋转、chakkars 等 + +291 +00:15:49,950 --> 00:15:52,553 +但也适用于 + +292 +00:15:52,553 --> 00:15:56,089 +各种全身性的重复动作 + +293 +00:15:56,089 --> 00:15:57,858 +您可以通过查看示例代码 + +294 +00:15:57,858 --> 00:16:00,827 +和与本次讲座相关的文章 + +295 +00:16:00,827 --> 00:16:04,531 +来了解这个模型 +和潜在用例的更多信息 + +296 +00:16:04,531 --> 00:16:08,335 +以上就是对 Create ML +中新增功能的简要介绍 + +297 +00:16:08,335 --> 00:16:11,104 +Create ML App 中的 +互动评估和实时预览 + +298 +00:16:11,104 --> 00:16:13,574 +可以让您更深入地了解 + +299 +00:16:13,574 --> 00:16:16,476 +您训练的模型 + +300 +00:16:16,476 --> 00:16:20,080 +Create ML 框架 +增加了 tvOS 支持 + +301 +00:16:20,080 --> 00:16:23,116 +重复计数 + +302 +00:16:23,116 --> 00:16:27,020 +并扩展了对丰富的基础组件的访问 + +303 +00:16:27,020 --> 00:16:29,890 +以帮助您建立高度自定义的模型 + +304 +00:16:29,890 --> 00:16:32,059 +满足您的 App 需求 + +305 +00:16:32,059 --> 00:16:33,093 +谢谢 + +306 +00:16:33,093 --> 00:16:35,929 +希望您喜欢这些新功能 + +307 +00:16:35,929 --> 00:16:38,465 +我们迫不及待想看到您如何使用它们 + +308 +00:16:38,465 --> 00:16:42,903 +♪ + diff --git a/zho/2022 Session 110335 Explore Apple Business Essentials.srt b/zho/2022 Session 110335 Explore Apple Business Essentials.srt new file mode 100644 index 0000000..834721c --- /dev/null +++ b/zho/2022 Session 110335 Explore Apple Business Essentials.srt @@ -0,0 +1,1059 @@ +1 +00:00:00,367 --> 00:00:06,373 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:11,678 +大家好 我是 Josh +我是 Apple Business Essentials 团队的 + +3 +00:00:11,712 --> 00:00:13,714 +软件工程师 + +4 +00:00:13,747 --> 00:00:15,983 +作为小型企业 您可能会发现 +随着团队的壮大 + +5 +00:00:16,016 --> 00:00:18,785 +您管理的设备数量也在增加 + +6 +00:00:18,819 --> 00:00:21,421 +随之而来的 IT 需求 +可谓是重重负担 + +7 +00:00:21,455 --> 00:00:24,391 +甚至占据了您处理 +最擅长的工作的时间 + +8 +00:00:24,424 --> 00:00:26,693 +Apple Business Essentials +通过提供 + +9 +00:00:26,727 --> 00:00:29,963 +无缝衔接设备管理 +24x7 小时的支持 + +10 +00:00:29,997 --> 00:00:32,733 +以及云存储的订阅服务 +让这些工作更简便 + +11 +00:00:32,766 --> 00:00:35,302 +从而帮助您的小型企业 +一路管理每个员工的 + +12 +00:00:35,335 --> 00:00:38,639 +iPhone iPad 和 Mac + +13 +00:00:38,672 --> 00:00:41,175 +对您的员工来说可为简单至极 + +14 +00:00:41,208 --> 00:00:43,777 +他们只需要登陆 +托管的 Apple ID + +15 +00:00:43,810 --> 00:00:46,547 +该设备就可享受 +Apple Business Essentials 的服务 + +16 +00:00:48,115 --> 00:00:49,349 +登录后 + +17 +00:00:49,383 --> 00:00:52,052 +设备自动配置为所需的设置 + +18 +00:00:52,085 --> 00:00:56,290 +包括重要安全设置 如 FileVault +和密码政策 + +19 +00:00:56,323 --> 00:00:59,960 +以及他们工作所需的所有 Apps + +20 +00:00:59,993 --> 00:01:02,563 +另外 使用 iCloud Drive 的提供的 + +21 +00:01:02,596 --> 00:01:05,132 +iCloud 存储 协作 +和文件共享功能 + +22 +00:01:05,165 --> 00:01:08,869 +他们甚至可以在 iPhones +和 iPads 中使用 iCloud 备份 + +23 +00:01:08,902 --> 00:01:14,007 +当发生故障时 AppleCare+ for Business Essentials +可提供对应的帮助 + +24 +00:01:14,041 --> 00:01:16,743 +整个企业共享维修费 + +25 +00:01:16,777 --> 00:01:20,380 +且同一套餐下的 +所有设备都能使用 + +26 +00:01:20,414 --> 00:01:21,849 +事实上 +Apple Business Essentials + +27 +00:01:21,882 --> 00:01:23,283 +在您设备生命周期中的 + +28 +00:01:23,317 --> 00:01:25,118 +每一阶段都能为您提供帮助 + +29 +00:01:25,152 --> 00:01:26,854 +在这个讲座中 我们将与大家分享 + +30 +00:01:26,887 --> 00:01:28,255 +这个订阅服务中 + +31 +00:01:28,288 --> 00:01:31,191 +所有您可以利用的内容 + +32 +00:01:31,225 --> 00:01:35,829 +我们首先回顾下第一步 +在 Apple Business Manager 上注册账户 + +33 +00:01:35,863 --> 00:01:39,266 +首先开始一个新的 +Apple Business Essentials 订阅 + +34 +00:01:39,299 --> 00:01:41,401 +添加设置和 Apps + +35 +00:01:41,435 --> 00:01:43,504 +看下员工登记他们的设备时 + +36 +00:01:43,537 --> 00:01:45,339 +是什么样的体验 + +37 +00:01:45,372 --> 00:01:46,974 +我们开始吧 + +38 +00:01:48,809 --> 00:01:51,879 +Apple Business Essentials 存在于 +Apple Business Manager 中 + +39 +00:01:51,912 --> 00:01:55,782 +您可在此管理设备 添加用户 +和购买 Apps + +40 +00:01:55,816 --> 00:01:59,453 +要订阅 Apple Business Essentials +为您的设备管理解决方案 + +41 +00:01:59,486 --> 00:02:02,055 +您首先需要一个 +Apple Business Manager 账户 + +42 +00:02:04,124 --> 00:02:06,760 +在 business.apple.com 上注册 + +43 +00:02:06,793 --> 00:02:08,629 +输入您公司名称 + +44 +00:02:08,662 --> 00:02:10,731 +DUNS 编号和联系信息 + +45 +00:02:12,499 --> 00:02:15,702 +有了账户后 下一步就是添加用户 + +46 +00:02:15,736 --> 00:02:19,006 +您可通过手动输入信息 +添加个人用户 + +47 +00:02:19,039 --> 00:02:23,076 +也可以同步 Microsoft Azure Directory +或 Google Workspace 中的 + +48 +00:02:23,110 --> 00:02:24,411 +已有列表 + +49 +00:02:25,379 --> 00:02:27,381 +您的大部分用户需求都相同 + +50 +00:02:27,414 --> 00:02:29,616 +如销售部门或现场调查员 + +51 +00:02:29,650 --> 00:02:32,519 +所以他们的设置和 Apps 都相同 + +52 +00:02:32,553 --> 00:02:36,223 +这样的话 您可以为刚刚 +创建的用户设置用户组 + +53 +00:02:37,724 --> 00:02:39,927 +用‘smart user groups’ + +54 +00:02:39,960 --> 00:02:43,230 +可根据常用属性自动创建组 +如部门 位置和角色 + +55 +00:02:43,263 --> 00:02:46,400 +从而节省时间 + +56 +00:02:46,433 --> 00:02:49,036 +现在我有 Apple Business Manager +账户了 + +57 +00:02:49,069 --> 00:02:51,672 +设置了用户和组 + +58 +00:02:51,705 --> 00:02:54,308 +那就准备好 +加入 Apple Business Essentials 了 + +59 +00:02:54,341 --> 00:02:57,244 +我们到 Mac 上 +这个是 Apple Business Manager + +60 +00:02:57,277 --> 00:03:03,150 +找到侧边栏的 Subscription +开始免费试用 + +61 +00:03:03,183 --> 00:03:06,820 +我要选择员工方案或是设备方案 + +62 +00:03:06,854 --> 00:03:11,225 +员工方案是指这一方案是 +为我的员工的设备所用 + +63 +00:03:11,258 --> 00:03:15,062 +设备方案还可以包含其它 +未指定具体员工使用的设备 + +64 +00:03:15,095 --> 00:03:17,497 +如会议室设备 信息亭 + +65 +00:03:17,531 --> 00:03:20,300 +借用设备或其它情况 + +66 +00:03:20,334 --> 00:03:25,339 +接下来是每个员工的设备数量 +可以选择仅 1 台或 3 台 + +67 +00:03:25,372 --> 00:03:27,808 +我现在为我的销售团队设置方案 + +68 +00:03:27,841 --> 00:03:31,078 +我知道他们经常都在路上 +有工作用的 MacBook + +69 +00:03:31,111 --> 00:03:33,013 +iPhone 和 iPad + +70 +00:03:33,046 --> 00:03:36,383 +所以我设置了 3 台设备的方案 + +71 +00:03:36,416 --> 00:03:38,452 +接下来 存储 + +72 +00:03:38,485 --> 00:03:42,456 +订阅后 我的员工可以获得 +工作用的 iCloud 账户 + +73 +00:03:42,489 --> 00:03:45,526 +他们可以通过自己的设备 +访问文件和文件夹 + +74 +00:03:45,559 --> 00:03:49,463 +我暂时用了 200 GB +对刚开始来说应该足够了 + +75 +00:03:49,496 --> 00:03:51,665 +但如果未来团队需求改变了 + +76 +00:03:51,698 --> 00:03:53,600 +也可以随时修改 + +77 +00:03:53,634 --> 00:03:57,571 +最后 选择 AppleCare+ +可为 Business Essentials 提供维修 + +78 +00:03:57,604 --> 00:04:01,742 +服务和支持 对经常在现场工作的 +销售员工来说很有用 + +79 +00:04:03,777 --> 00:04:06,980 +接下来 添加用户组和个人用户 + +80 +00:04:07,014 --> 00:04:11,318 +我们搜索销售团队 +将他们加入该方案 + +81 +00:04:12,653 --> 00:04:14,922 +我已经输入了我的付款信息 + +82 +00:04:16,723 --> 00:04:18,992 +现在重新检查下价格 + +83 +00:04:19,026 --> 00:04:20,994 +添加方案 + +84 +00:04:21,028 --> 00:04:23,964 +随着业务的增长 +也会有多种方案可以满足 + +85 +00:04:23,997 --> 00:04:26,366 +我的员工和设备的独特需求 + +86 +00:04:26,400 --> 00:04:30,571 +我可以在任意时间修改 +只需按使用的内容支付即可 + +87 +00:04:30,604 --> 00:04:32,806 +我的 Apple Business Manager 视图 +已更新 + +88 +00:04:32,840 --> 00:04:35,576 +显示我订阅了 +Apple Business Essentials + +89 +00:04:35,609 --> 00:04:38,545 +现在在侧边栏能看到 +Settings (设置) 和 Collections (收集) + +90 +00:04:38,579 --> 00:04:43,116 +Settings 中可提供我自动推送给 +托管设备的配置列表 + +91 +00:04:43,150 --> 00:04:47,287 +Apps 提供了可使用 Essentials App +为我的用户购买的 Apps 列表 + +92 +00:04:47,321 --> 00:04:49,189 +以便他们在自己设备上下载 + +93 +00:04:49,223 --> 00:04:53,894 +Collections 是我为用户或组 +指定的一组 Settings 和 Apps + +94 +00:04:53,927 --> 00:04:56,363 +我们首先看下 settings + +95 +00:04:56,396 --> 00:05:00,267 +Essentials 分类中 把我最可能 +使用到的 settings 都放到了一起 + +96 +00:05:00,300 --> 00:05:03,270 +但我也有不同的方案可选择 +所以我们来逐一看下内容 + +97 +00:05:03,303 --> 00:05:05,506 +然后按需求添加 + +98 +00:05:07,541 --> 00:05:10,377 +security 选项卡集合了 +所有关键的安全设置 + +99 +00:05:10,410 --> 00:05:13,113 +以便配置更便捷 + +100 +00:05:13,146 --> 00:05:15,916 +我的 iOS 设备 +想要一个密码设置 + +101 +00:05:15,949 --> 00:05:17,451 +我稍后来处理 + +102 +00:05:17,484 --> 00:05:20,554 +我给 macOS 设备添加了 +FileVault 设置 + +103 +00:05:20,587 --> 00:05:23,190 +让员工的 Macs 可加密数据 + +104 +00:05:23,223 --> 00:05:26,059 +开启 Application Layer Firewall +避免来自不信任 Apps 的 + +105 +00:05:26,093 --> 00:05:29,530 +网络流量威胁 + +106 +00:05:29,563 --> 00:05:33,567 +开启 Gatekeeper +避免不信任 Apps 同时运行 + +107 +00:05:34,801 --> 00:05:38,405 +在 network 分类下 +我可以为设备配置 AirPrint + +108 +00:05:38,438 --> 00:05:41,308 +以自动连接到打印机 +并使用 Wi-Fi 设置 + +109 +00:05:41,341 --> 00:05:44,511 +来配置信任网络 +这样用户用他们的设备登陆时 + +110 +00:05:44,545 --> 00:05:46,613 +可以自动连接网络 + +111 +00:05:47,881 --> 00:05:50,250 +在 Personalization 下 我可以 + +112 +00:05:50,284 --> 00:05:52,986 +为我使用的设备添加其它设置 +增加自定义体验 + +113 +00:05:53,020 --> 00:05:58,592 +例如 我用会议室设备 +限制 apple TV 仅能使用 airplay + +114 +00:05:58,625 --> 00:06:00,894 +而我的 macOS 设备方面 +登陆窗口设置 + +115 +00:06:00,928 --> 00:06:03,163 +可选择在登陆窗口显示信息 + +116 +00:06:03,197 --> 00:06:06,066 +这个位置显示支持邮箱地址 + +117 +00:06:06,099 --> 00:06:08,502 +或电话是极好的 + +118 +00:06:08,535 --> 00:06:12,506 +我们回到 essentials 类别 +来添加一些设置 + +119 +00:06:13,974 --> 00:06:17,244 +我们创建一个新配置的设置 +命名为 Password Policy + +120 +00:06:23,283 --> 00:06:26,520 +复选框可同时选择 +macOS 和 iOS + +121 +00:06:26,553 --> 00:06:29,556 +“password and security options”的开关 +我们保留开启 + +122 +00:06:29,590 --> 00:06:32,693 +让用户创建强密码 + +123 +00:06:32,726 --> 00:06:35,596 +“allow simple passwords”这里 +选择“no”选项 + +124 +00:06:35,629 --> 00:06:38,398 +让员工在密码中最少设置 + +125 +00:06:38,432 --> 00:06:40,200 +一个特殊字符 + +126 +00:06:40,234 --> 00:06:43,237 +“require alpha numeric password”这里 +选择“yes” + +127 +00:06:43,270 --> 00:06:46,740 +要求密码中最少有一个字母 +和一个数字 + +128 +00:06:46,773 --> 00:06:48,408 +保存该设置 + +129 +00:06:50,344 --> 00:06:53,146 +好了 已经添加到 +我的设置列表了 + +130 +00:06:53,180 --> 00:06:56,517 +接下来 设置 Wi-Fi 密码 +这样员工的设备 + +131 +00:06:56,550 --> 00:06:58,552 +可以自动加入已知 Wi-Fi + +132 +00:06:58,585 --> 00:07:01,555 +我将这一设置 +命名为 BetterBag Secure Wi-Fi + +133 +00:07:03,590 --> 00:07:08,495 +输入我公司的 Wi-Fi 名称 +和密码 + +134 +00:07:11,532 --> 00:07:14,101 +“network visibility”为可见 + +135 +00:07:14,134 --> 00:07:17,304 +“auto join”为“yes” +然后保存 + +136 +00:07:18,539 --> 00:07:21,008 +我们继续到 Apps + +137 +00:07:24,211 --> 00:07:27,014 +在 Apps 页面中 +我可获取付费和免费的 Apps + +138 +00:07:27,047 --> 00:07:30,951 +用户可在他们设备的 +Essentials App 上安装 + +139 +00:07:30,984 --> 00:07:34,321 +我在 Apple App Store 获取了 +几个 Apps 和书籍 + +140 +00:07:34,354 --> 00:07:35,889 +还有一些自定义 Apps + +141 +00:07:35,923 --> 00:07:38,892 +是只给我自己购买的 + +142 +00:07:38,926 --> 00:07:42,596 +我想让我的用户在 iOS 上 +可以安装 Pages App + +143 +00:07:42,629 --> 00:07:45,499 +我们来搜索下载 Pages + +144 +00:07:50,771 --> 00:07:54,308 +用户从 Essentials App 安装 Pages 时 +该 App 是托管的 + +145 +00:07:54,341 --> 00:07:56,643 +也就是说它会自动更新 + +146 +00:07:56,677 --> 00:08:00,214 +用户登出设备后则会卸载 App + +147 +00:08:00,247 --> 00:08:02,950 +我将这个 App +分配到我的办公室 + +148 +00:08:05,152 --> 00:08:10,157 +我需要 4 个许可证 确认费用 +这种情况下为免费 + +149 +00:08:10,190 --> 00:08:12,593 +我们就获得了 App 的许可证 + +150 +00:08:15,162 --> 00:08:18,265 +现在我已经完成好设置 +App 也购买好了 + +151 +00:08:18,298 --> 00:08:21,368 +我们将它们 +整合到 Collection 中 + +152 +00:08:21,401 --> 00:08:25,572 +Collection 可应用于用户和组的 +一套设置和 Apps + +153 +00:08:25,606 --> 00:08:28,242 +可确保员工的设备正确配置 + +154 +00:08:28,275 --> 00:08:30,143 +同时在登陆设备时 + +155 +00:08:30,177 --> 00:08:32,079 +能访问他们所需的 Apps + +156 +00:08:32,112 --> 00:08:36,717 +我为销售团队创建了一个新的 Collection +命名为 Sales + +157 +00:08:38,418 --> 00:08:40,988 +在 Apps 选项卡下 将 Apps +添加到我的 collection 中 + +158 +00:08:41,021 --> 00:08:42,589 +我们添加 Pages + +159 +00:08:46,193 --> 00:08:49,129 +同样的 我在 settings 选项卡下 +将设置添加到我的 collection 中 + +160 +00:08:50,831 --> 00:08:55,235 +我们搜索添加 Wi-Fi + +161 +00:08:55,269 --> 00:08:56,870 +以及密码政策设置 + +162 +00:08:58,372 --> 00:09:02,442 +最后 我在 User Groups 选项卡中 +将销售团队加入 collection + +163 +00:09:05,546 --> 00:09:08,815 +只要搜索 Sales User group +就可以添加了 + +164 +00:09:10,584 --> 00:09:15,422 +保存 我现在可以看到 +新创建的 collection 了 + +165 +00:09:15,989 --> 00:09:20,294 +好了 我已经有了 App 和设置 +现在将它们分配给员工 + +166 +00:09:20,327 --> 00:09:23,864 +现在我要给员工提供一个 +注册设备的方法 + +167 +00:09:23,897 --> 00:09:28,602 +在 User 列表中 +我们找到其中一个员工 + +168 +00:09:28,635 --> 00:09:30,003 +Eliza + +169 +00:09:31,572 --> 00:09:33,941 +为她创建一个 Managed Apple ID + +170 +00:09:35,275 --> 00:09:39,746 +我可以下载一个带有 +用户名和临时密码的文件 + +171 +00:09:39,780 --> 00:09:43,884 +或者给 Eliza 直接发送一封 +带有她的 Managed Apple ID 证书的邮件 + +172 +00:09:47,321 --> 00:09:50,858 +我们看下 Eliza 那边 +收到是什么样的 + +173 +00:09:50,891 --> 00:09:53,794 +她有一台公司 iPad +和个人 iPhone + +174 +00:09:53,827 --> 00:09:57,831 +用我们给她创建的 +Managed Apple ID 加入两台设备 + +175 +00:09:57,865 --> 00:10:00,100 +首先设置公司的 iPad + +176 +00:10:02,035 --> 00:10:04,238 +因为这台 iPad 是特意通过 + +177 +00:10:04,271 --> 00:10:07,374 +Apple 或授权经销商 +为企业购买的 + +178 +00:10:07,407 --> 00:10:11,645 +Eliza 的设备设置好后 +可以注册 Work + +179 +00:10:11,678 --> 00:10:14,948 +根据我发送给她的邮件 +输入用户名和密码 + +180 +00:10:16,250 --> 00:10:17,784 +完成设置后 + +181 +00:10:17,818 --> 00:10:21,154 +设备自动加入办公室 +我设置的 Wi-Fi 网络 + +182 +00:10:21,188 --> 00:10:22,923 +Essentials App 安装完成 + +183 +00:10:24,925 --> 00:10:27,694 +接下来 她可以设置个人 iPhone + +184 +00:10:27,728 --> 00:10:30,631 +这台设备已经用她个人 +Apple ID 注册了 + +185 +00:10:30,664 --> 00:10:33,567 +有她所有个人 App 和数据 + +186 +00:10:33,600 --> 00:10:35,135 +通过 Apple Business Essentials + +187 +00:10:35,169 --> 00:10:38,138 +Eliza 可以独立设置工作账户 + +188 +00:10:38,172 --> 00:10:41,041 +到设置 App 选择 general + +189 +00:10:41,074 --> 00:10:43,710 +再选择 +VPN and Device Management + +190 +00:10:43,744 --> 00:10:46,246 +用工作或学校账户注册 + +191 +00:10:46,280 --> 00:10:49,650 +然后输入用户名和密码 + +192 +00:10:49,683 --> 00:10:52,152 +现在她的 iPhone +可以同时登陆她的个人账户 + +193 +00:10:52,186 --> 00:10:54,721 +和 Apple Business Essentials 账户了 + +194 +00:10:54,755 --> 00:10:57,724 +最好的是 这些密码都是独立的 + +195 +00:10:57,758 --> 00:11:00,294 +意味着她的个人数据 +隐私安全可以保证 + +196 +00:11:00,327 --> 00:11:03,397 +而工作数据也同样 +在安全的管控范围内 + +197 +00:11:05,399 --> 00:11:07,568 +加入后 所有设置都会 + +198 +00:11:07,601 --> 00:11:11,939 +自动加入 Eliza 的设备 +Essentials App 也可进行下载 + +199 +00:11:13,407 --> 00:11:16,076 +她可以用来安装 +我为她分配的 App + +200 +00:11:17,110 --> 00:11:20,047 +在 devices 选项卡下 +她能看到她所有设备 + +201 +00:11:20,080 --> 00:11:21,682 +和 Apple Support 按钮 + +202 +00:11:21,715 --> 00:11:23,951 +如果她其中一台设备故障 + +203 +00:11:23,984 --> 00:11:26,854 +可以在 Essentials App 中 +使用“Visit Apple Support”按钮 + +204 +00:11:26,887 --> 00:11:29,356 +发出维修请求 + +205 +00:11:29,389 --> 00:11:32,492 +批准后 她可以请求 +维修技术员过来维修 + +206 +00:11:32,526 --> 00:11:36,697 +或者她将设备送到 +Apple 授权服务提供商 + +207 +00:11:36,730 --> 00:11:41,502 +我可以在 Service and Support 中看到状态 +可操作批准或拒绝请求 + +208 +00:11:43,804 --> 00:11:46,273 +在 Apple Business Essentials 中 +您的需求改变后 + +209 +00:11:46,306 --> 00:11:49,643 +可以返回 重新访问 +您的 App 和设置 + +210 +00:11:49,676 --> 00:11:53,313 +您所做的改变可自动推送到 +员工的设备 + +211 +00:11:54,114 --> 00:11:58,285 +如果设备丢失或者需要 +重新分配 您可以选择设备 + +212 +00:11:58,318 --> 00:12:02,289 +“登出用户” “锁定设备” +或“删除” + +213 +00:12:02,322 --> 00:12:05,325 +设备会执行对应的动作 + +214 +00:12:05,359 --> 00:12:08,095 +如果员工需要替换 +或升级他们的设备 + +215 +00:12:08,128 --> 00:12:11,198 +只需要用 Managed Apple ID +注册新设备 + +216 +00:12:11,231 --> 00:12:14,201 +就可访问 iCloud 的 App +设置 和工作数据 + +217 +00:12:16,069 --> 00:12:17,771 +我们来总结下 + +218 +00:12:17,804 --> 00:12:20,541 +我们回顾了如何 +安装 Apple Business Manager + +219 +00:12:20,574 --> 00:12:22,676 +订阅 Apple Business Essentials + +220 +00:12:22,709 --> 00:12:25,445 +在过程中做一些关键决策 + +221 +00:12:25,479 --> 00:12:27,314 +我们可以在 collections 中 +添加设置和 App + +222 +00:12:27,347 --> 00:12:29,917 +将其分配给员工的用户组 + +223 +00:12:29,950 --> 00:12:34,488 +同时我们也探索了在员工设备端 +是什么样的体验 + +224 +00:12:34,521 --> 00:12:38,792 +Apple Business Essentials 当前 +可以在美国的小型企业中使用 + +225 +00:12:38,825 --> 00:12:42,763 +让您专注于自己更擅长 +更高效的工作 + +226 +00:12:42,796 --> 00:12:46,066 +管理您员工设备的 +全生命周期易如反掌 + +227 +00:12:46,099 --> 00:12:49,436 +轻松就可以完成安装 管理 +安全和隐私 + +228 +00:12:49,469 --> 00:12:52,339 +存储和备份 支持和维修 + +229 +00:12:52,372 --> 00:12:56,009 +以及更新 +一切均可灵活订阅 + +230 +00:12:56,043 --> 00:12:58,645 +您可访问 +apple.com/business/essentials + +231 +00:12:58,679 --> 00:13:03,250 +以获得更多 +关于 Apple Business Essentials 的信息 + +232 +00:13:03,283 --> 00:13:05,519 +祝大家有一个圆满的 WWDC 旅程 + diff --git a/zho/2022 Session 110336 What's new in Screen Time API.srt b/zho/2022 Session 110336 What's new in Screen Time API.srt new file mode 100644 index 0000000..055dd9b --- /dev/null +++ b/zho/2022 Session 110336 What's new in Screen Time API.srt @@ -0,0 +1,799 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:09,743 --> 00:00:12,546 +MaryAshley Etefia: 大家好 +我是 MaryAshley Etefia + +3 +00:00:12,579 --> 00:00:15,349 +我是 Screen Time 的 +软件工程师 + +4 +00:00:15,382 --> 00:00:18,886 +新冠病毒给我们行业带来了 +很大的压力 + +5 +00:00:18,919 --> 00:00:23,624 +我们需要应对数字健康 +和生产率资源方面急剧增长的需求 + +6 +00:00:23,657 --> 00:00:26,527 +新冠病毒增强了我们社会 +对平衡的需求 + +7 +00:00:26,560 --> 00:00:29,796 +成功将大家的能力用于管理 +个人空间 + +8 +00:00:29,830 --> 00:00:31,565 +以供测试 + +9 +00:00:31,598 --> 00:00:34,935 +去年 我们 +推出了 Screen Time API + +10 +00:00:34,968 --> 00:00:37,538 +让您可以构建新的 App +帮助用户 + +11 +00:00:37,571 --> 00:00:40,607 +管理孩子的设备时间 + +12 +00:00:40,641 --> 00:00:43,410 +我们很高兴地看到 +大家在使用我们的产品时 + +13 +00:00:43,443 --> 00:00:45,579 +都有许多极具创意和成效的方法 + +14 +00:00:45,612 --> 00:00:49,583 +我也很激动看到大家与我们的 +企业文化所说的那样 非同凡响 + +15 +00:00:49,616 --> 00:00:53,487 +我们也非常感激过去一年来 +收到的所有反馈 + +16 +00:00:53,520 --> 00:00:57,558 +在为大家介绍 iOS 16 中 +ScreenTime API 的更新前 + +17 +00:00:57,591 --> 00:01:01,828 +我先回顾下 iOS 15 发布会上的 +一些亮点 + +18 +00:01:01,862 --> 00:01:05,299 +去年的 Screen Time API +推出了三个全新框架 + +19 +00:01:05,332 --> 00:01:09,570 +Family Controls, Managed Settings +和 Device Activity + +20 +00:01:09,603 --> 00:01:12,806 +在 iOS 15 中 这些框架为 +您 App 的家长控制模块 + +21 +00:01:12,840 --> 00:01:14,975 +带来了新的可能 + +22 +00:01:15,008 --> 00:01:18,145 +我们先来快速浏览下 +这三个框架 激活大家的记忆 + +23 +00:01:18,178 --> 00:01:20,447 +Family Controls 从根本上说 +就是一道闸口 + +24 +00:01:20,480 --> 00:01:23,350 +能授权访问 Screen Time API + +25 +00:01:23,383 --> 00:01:25,719 +该框架让您实现避免 + +26 +00:01:25,752 --> 00:01:29,022 +家长控制 App 被移除 +也可通过不透明的token + +27 +00:01:29,056 --> 00:01:33,694 +来识别 App 和网站 +从而保护用户隐私 + +28 +00:01:33,727 --> 00:01:36,997 +有了 ManagedSettings +您的 App 可以采取限制来 + +29 +00:01:37,030 --> 00:01:40,567 +过滤网络流量 屏蔽活动 +这一点与 Screen Time 的功能类似 + +30 +00:01:40,601 --> 00:01:43,837 +但根据您 App 的品牌 +和功能进行自定义 + +31 +00:01:43,871 --> 00:01:47,241 +Device Activity 框架让您可以 +在时间窗口的开始和结束时 + +32 +00:01:47,274 --> 00:01:49,943 +以及在 App 或网站的使用 + +33 +00:01:49,977 --> 00:01:52,145 +超过限值时 执行代码 + +34 +00:01:52,179 --> 00:01:56,950 +这三个框架在 iOS 16 中 +都有激动人心的更新 + +35 +00:01:56,984 --> 00:02:00,754 +这些更新不仅仅让我们的 +API 使用更简单 + +36 +00:02:00,787 --> 00:02:04,858 +也能提高用户的使用体验 + +37 +00:02:04,892 --> 00:02:08,962 +我用 demo App Worklog +来为大家详细解释下 + +38 +00:02:08,996 --> 00:02:12,633 +Worklog 可通过在 +某个使用指标达到前 + +39 +00:02:12,666 --> 00:02:16,737 +限值指定 App 的使用 +从而鼓励新专业人员培养好习惯 + +40 +00:02:16,770 --> 00:02:20,107 +我为大家演示下 +这部 iPhone 的主人 Aniyah + +41 +00:02:20,140 --> 00:02:24,978 +是如何用 iOS 16 的 ScreenTime API +来用这些限制约束自己的 + +42 +00:02:25,012 --> 00:02:27,614 +首先是 Family Controls + +43 +00:02:27,648 --> 00:02:31,485 +如果您还有印象的话 +iOS 15 中 Family Controls 只能 + +44 +00:02:31,518 --> 00:02:35,455 +通过 iCloud 认证 +来授权儿童设备 + +45 +00:02:35,489 --> 00:02:39,693 +我们很高兴地告诉您 在 iOS 16 中 +Family Controls 现在可以 + +46 +00:02:39,726 --> 00:02:43,330 +在各自的设备上授权独立用户了 + +47 +00:02:43,363 --> 00:02:47,167 +这个新的授权方式意味着 +Screen Time API 可以 + +48 +00:02:47,201 --> 00:02:50,070 +用于搭建更多功能的 App +而不仅是家长控制 + +49 +00:02:50,103 --> 00:02:52,873 +和当前的家长控制授权不同 + +50 +00:02:52,906 --> 00:02:57,344 +每个设备的个人授权可以 +任意数量的 App 上使用 + +51 +00:02:57,377 --> 00:03:02,182 +同时 由于个人授权并不是 +为了家长控制这一使用情况搭建的 + +52 +00:03:02,216 --> 00:03:06,854 +无需隐式限制 iCloud 登出 +或删除 App + +53 +00:03:06,887 --> 00:03:09,389 +我们来看看这个新的授权 +如何使用 + +54 +00:03:09,423 --> 00:03:13,160 +您启动 App 时第一步 +就是为 FamilyControls + +55 +00:03:13,193 --> 00:03:14,862 +请求授权 + +56 +00:03:14,895 --> 00:03:17,130 +我用的是共享授权中心 + +57 +00:03:17,164 --> 00:03:20,434 +在 Worklog 首次启动时 +就要发起请求 + +58 +00:03:20,467 --> 00:03:23,937 +这个请求可以更新授权状态 + +59 +00:03:23,971 --> 00:03:26,139 +或弹出错误 + +60 +00:03:26,173 --> 00:03:28,876 +由于 App 之前没有在 +这部 iPhone 上用过 + +61 +00:03:28,909 --> 00:03:32,913 +requestAuthorization 会弹出预警 +询问 Aniyah 的许可 + +62 +00:03:32,946 --> 00:03:36,149 +点击 Allow 可以提示用户 + +63 +00:03:36,183 --> 00:03:40,287 +用 面容 ID 触控 ID +或设备密码授权以继续 + +64 +00:03:40,320 --> 00:03:42,656 +用户成功授权后 + +65 +00:03:42,689 --> 00:03:46,426 +会再次调用 requestAuthorization +但不会提示预警 + +66 +00:03:46,460 --> 00:03:48,529 +而是后台成功运行 + +67 +00:03:48,562 --> 00:03:51,265 +App 获得 Family Controls 的 +授权后 + +68 +00:03:51,298 --> 00:03:54,468 +App 的设置中会增加 +两个开关 + +69 +00:03:54,501 --> 00:03:57,804 +如果 App 有 Screen Time 访问列表 +那就在 Screen Time 下 + +70 +00:03:57,838 --> 00:04:01,675 +另一个在每个 App 的设置中 +标记为 Screen Time Restrictions + +71 +00:04:01,708 --> 00:04:04,845 +家长和个人用户可以 +在 Family Controls 中 + +72 +00:04:04,878 --> 00:04:07,581 +用这几个开关 +解除 App 的授权 + +73 +00:04:07,614 --> 00:04:10,751 +如您所见 使用新的个人授权 + +74 +00:04:10,784 --> 00:04:13,887 +和使用家长控制授权一样简单 + +75 +00:04:13,921 --> 00:04:17,558 +我们对异步使用都做了 +很不错的改进 + +76 +00:04:17,591 --> 00:04:20,527 +现在 我们来看下 +Managed Settings 的更新 + +77 +00:04:20,561 --> 00:04:24,364 +Managed Settings 更新后 +开发者使用更简便 + +78 +00:04:24,398 --> 00:04:27,401 +尤其是使用 +Managed Settings Store 时 + +79 +00:04:27,434 --> 00:04:31,471 +可能有些开发者还不熟悉 +Managed Settings Store 是一个数据储存区 + +80 +00:04:31,505 --> 00:04:34,474 +可以将设置 +应用到当前用户或设备 + +81 +00:04:34,508 --> 00:04:39,580 +在 iOS 15 您每个步骤只能有 +一个 Managed Settings Store + +82 +00:04:39,613 --> 00:04:42,115 +您的 App 和设备活动扩展 + +83 +00:04:42,149 --> 00:04:44,818 +也要有不同的 Managed Settings Stores + +84 +00:04:44,852 --> 00:04:48,822 +如果根据设备活动来改变设置 +就比较困难 + +85 +00:04:48,856 --> 00:04:53,493 +现在 在 iOS 16 中 +每个步骤您可以创建 + +86 +00:04:53,527 --> 00:04:56,964 +高达 50 个Managed Settings Stores +每个都有自己专有的命名 + +87 +00:04:56,997 --> 00:04:59,800 +这些命名储存也可自动在 +您的 App + +88 +00:04:59,833 --> 00:05:02,636 +和所有 App 扩展中共享 + +89 +00:05:02,669 --> 00:05:07,341 +同时 您现在也可以一次性 +移除指定命名储存区的所有设置 + +90 +00:05:07,374 --> 00:05:10,844 +我为大家演示下 Worklog 是 +如何使用命名储存区的 + +91 +00:05:10,878 --> 00:05:14,348 +Worklog 首次启动时 +Aniyah 的设备已经 + +92 +00:05:14,381 --> 00:05:18,852 +成功获得授权 我们创建了 +Gaming Managed Settings Store + +93 +00:05:18,886 --> 00:05:21,255 +该储存区包含我们的游戏限制 + +94 +00:05:21,288 --> 00:05:25,792 +比如在 Worklog 中 +包括屏蔽所有游戏网站 + +95 +00:05:25,826 --> 00:05:29,596 +Worklog 也有一个储存区 +命名为“Social” + +96 +00:05:29,630 --> 00:05:33,734 +可以在 App 首次运行后 +屏蔽所有社交媒体 App 和网站 + +97 +00:05:33,767 --> 00:05:35,402 +然而 使用 Worklog 时 + +98 +00:05:35,435 --> 00:05:38,138 +Aniyah 可以点击 +Allow for Evenings 按钮 + +99 +00:05:38,172 --> 00:05:40,340 +创建一个 +Device Activity Schedule + +100 +00:05:40,374 --> 00:05:44,545 +允许下午 5:00 至 晚上 8:00 期间 +使用社交媒体平台 + +101 +00:05:44,578 --> 00:05:47,948 +到了下午 5:00 +我们的 Device Activity Monitor + +102 +00:05:47,981 --> 00:05:49,883 +就会解除对应命名储存区的限制 + +103 +00:05:49,917 --> 00:05:53,153 +当时间窗口于晚上 8:00 结束后 +会重新在 Aniyah 的设备上 + +104 +00:05:53,187 --> 00:05:56,190 +对社交媒体 App 和网站 +重新应用限制 + +105 +00:05:56,223 --> 00:05:58,225 +开发者可能会感到疑惑 + +106 +00:05:58,258 --> 00:06:00,827 +“我们的 Gaming store +不是限制了所有游戏网站吗” + +107 +00:06:00,861 --> 00:06:03,197 +“如果清除 Social store 中的 +所有设置” + +108 +00:06:03,230 --> 00:06:05,799 +“不会和 Gaming store 的 +设置相冲突吗” + +109 +00:06:05,832 --> 00:06:07,134 +答案是否定的 + +110 +00:06:07,167 --> 00:06:11,104 +通常优先应用最严格的限制 +因此 游戏网站 + +111 +00:06:11,138 --> 00:06:13,774 +在 Aniyah 的设备中 +还是会保留限制 + +112 +00:06:13,807 --> 00:06:16,743 +我们觉得这些新的 +命名储存区很强大 + +113 +00:06:16,777 --> 00:06:20,814 +会让您用 Managed Settings +开发 App 更简便 + +114 +00:06:20,848 --> 00:06:22,449 +但这还没有结束 + +115 +00:06:22,482 --> 00:06:26,386 +我们还为 Device Activity 框架 +添加了非常激动人心的功能 + +116 +00:06:26,420 --> 00:06:30,057 +在 iOS 15 中 +Device Activity 让您的 App + +117 +00:06:30,090 --> 00:06:32,726 +可以响应时间窗口的 +开始和结束 + +118 +00:06:32,759 --> 00:06:35,596 +以及 App 和网站的使用限值 + +119 +00:06:35,629 --> 00:06:40,067 +在 iOS 16 中 Device Activity +有一个新的报告服务 + +120 +00:06:40,100 --> 00:06:45,005 +让您的 App 可以用 SwiftUI +创建完全自定义的使用报告 + +121 +00:06:45,038 --> 00:06:49,076 +使用数据可提供至新的扩展接口 +您可以自定义 + +122 +00:06:49,109 --> 00:06:53,080 +向客户展示哪些数据 +以及如何在屏幕上渲染 + +123 +00:06:53,113 --> 00:06:56,116 +这些设备活动报告让您可以 + +124 +00:06:56,149 --> 00:06:58,285 +完全自定义用户体验 + +125 +00:06:58,318 --> 00:07:02,222 +同时为终端用户提供完整隐私 + +126 +00:07:02,256 --> 00:07:06,059 +在 Worklog 中 您可以看到我们 +建立了 Device Activity Report Context + +127 +00:07:06,093 --> 00:07:08,762 +和 Device Activity Filter + +128 +00:07:08,795 --> 00:07:11,064 +您可以 +将 Device Activity Report Context + +129 +00:07:11,098 --> 00:07:13,500 +当成自定义类型 可提示您的报告 + +130 +00:07:13,534 --> 00:07:17,604 +根据 Device Activity 数据 +绘制哪种视图 + +131 +00:07:17,638 --> 00:07:20,841 +您可以通过指定 +Device Activity Filter 来自定义 + +132 +00:07:20,874 --> 00:07:23,177 +任意报告内容的时间窗口 + +133 +00:07:23,210 --> 00:07:27,047 +然后 我们可以 +在 Device Activity Report Scene 中 + +134 +00:07:27,080 --> 00:07:29,516 +设置设备活动报告内容的定义 + +135 +00:07:29,550 --> 00:07:32,286 +从而提示场景要展示什么内容 + +136 +00:07:32,319 --> 00:07:37,191 +我们的内容确定了 +自定义配置 PieChartView.Configuration + +137 +00:07:37,224 --> 00:07:40,661 +以及最终报告的 SwiftUI 视图 + +138 +00:07:40,694 --> 00:07:45,432 +然后在 makeConfiguration 中 +我们映射到 Aniyah 的 Device Activity Data + +139 +00:07:45,465 --> 00:07:48,969 +以补充饼图视图配置 + +140 +00:07:49,002 --> 00:07:50,938 +这个框架在抓取到 +新的使用数据时 + +141 +00:07:50,971 --> 00:07:56,176 +会唤醒 makeConfiguration +这样您无需自己唤醒 + +142 +00:07:56,210 --> 00:07:59,546 +这里您可以 +看到 PieChartView.Configuration + +143 +00:07:59,580 --> 00:08:01,782 +是如何提供 Aniyah 的 +设备活动数据视图 + +144 +00:08:01,815 --> 00:08:05,219 +作为我们饼图视图的 +视图模型 + +145 +00:08:05,252 --> 00:08:08,455 +最后 我们可以通过将其定义到 +Device Activity Report 扩展的主体中 + +146 +00:08:08,488 --> 00:08:12,259 +渲染自定义 SwiftUI 报告 + +147 +00:08:12,292 --> 00:08:15,429 +您自定义设备活动报告 +有许多神奇的方法 + +148 +00:08:15,462 --> 00:08:19,132 +我们为 Worklog 创建的 +饼图报告只是其中之一 + +149 +00:08:19,166 --> 00:08:24,104 +其中也包括我们对 iOS 16 +Screen Time API 更新的简报 + +150 +00:08:24,137 --> 00:08:27,407 +如您所见 +Screen Time API 可持续 + +151 +00:08:27,441 --> 00:08:30,410 +在安全且能保证隐私的方式下 +与首次启动一样支持 + +152 +00:08:30,444 --> 00:08:34,114 +如核心限制 +和设备活动监控的功能 + +153 +00:08:34,147 --> 00:08:35,315 +我们来回顾下 + +154 +00:08:35,349 --> 00:08:38,819 +独立用户现在可以 +用 Family Controls + +155 +00:08:38,852 --> 00:08:42,623 +授权各设备的多个第三方 App + +156 +00:08:42,656 --> 00:08:46,159 +Managed Settings Stores 现在可以 +本地共享 App + +157 +00:08:46,193 --> 00:08:47,461 +和 App 扩展之间的设置 + +158 +00:08:47,494 --> 00:08:49,563 +因此 您现在可以在 App 中 + +159 +00:08:49,596 --> 00:08:51,999 +管理多个命名储存区 + +160 +00:08:52,032 --> 00:08:57,004 +最后 Device Activity 框架 +推出了全新的隐私保护 UI + +161 +00:08:57,037 --> 00:09:01,074 +可以向用户展示使用数据 +同时也支持自定义 + +162 +00:09:01,108 --> 00:09:03,944 +我们相信这些增强和额外功能 + +163 +00:09:03,977 --> 00:09:07,047 +能让更多用户使用您的 App + +164 +00:09:07,080 --> 00:09:09,516 +感谢大家为我们更新提供的灵感 + +165 +00:09:09,550 --> 00:09:11,385 +也感谢大家未来对数字健康 + +166 +00:09:11,418 --> 00:09:13,921 +和生产性空间所做的贡献 + +167 +00:09:13,954 --> 00:09:16,757 +我们迫不及待看您如何 +以创新 激动人心的方式使用 + +168 +00:09:16,790 --> 00:09:18,325 +全新的 Screen Time API 了 + +169 +00:09:18,358 --> 00:09:22,362 +我们欢迎大家的反馈 +同时也会持续改进这一技术 + +170 +00:09:22,396 --> 00:09:25,566 +让其对大家和我们的用户都适用 + +171 +00:09:25,599 --> 00:09:26,700 +谢谢 + diff --git a/zho/2022 Session 110338 Explore media metadata publishing and playback interactions.srt b/zho/2022 Session 110338 Explore media metadata publishing and playback interactions.srt new file mode 100644 index 0000000..d201784 --- /dev/null +++ b/zho/2022 Session 110338 Explore media metadata publishing and playback interactions.srt @@ -0,0 +1,1301 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:12,646 +Nik: 大家好 我是 Nik +是 Video 团队的工程师 + +3 +00:00:12,679 --> 00:00:16,049 +今天 我很高兴能为大家介绍 +媒体元数据发布 + +4 +00:00:16,083 --> 00:00:17,684 +和播放交互 + +5 +00:00:17,718 --> 00:00:19,887 +这是什么意思呢 + +6 +00:00:19,920 --> 00:00:21,788 +Apple 设备中有很多地方 + +7 +00:00:21,822 --> 00:00:25,192 +是可以显示播放信息 +并控制媒体播放的 + +8 +00:00:25,225 --> 00:00:28,562 +例如 控制中心的正在播放部分 +可以显示当前设备播放的 + +9 +00:00:28,595 --> 00:00:32,165 +专辑 标题和进度条 + +10 +00:00:32,199 --> 00:00:36,737 +您也可以播放 暂停 +甚至是快进或快退 + +11 +00:00:36,770 --> 00:00:40,741 +放大“正在播放”窗口 +可以显示更多信息 如专辑和进度条 + +12 +00:00:40,774 --> 00:00:45,812 +您也可以设置静音 +增大或减小音量 + +13 +00:00:45,846 --> 00:00:48,315 +锁定屏幕也显示了 +同样的信息和控制按钮 + +14 +00:00:48,348 --> 00:00:51,685 +让用户可以更方便地查看 +播放进度 暂停 + +15 +00:00:51,718 --> 00:00:54,755 +甚至不用解锁 就能 AirPlay 到 +另一个设备中 + +16 +00:00:57,424 --> 00:01:00,527 +不管是在什么设备上 +Apple Watch 的“正在播放”App + +17 +00:01:00,561 --> 00:01:01,895 +都能为用户提供相同的体验 + +18 +00:01:01,929 --> 00:01:04,398 +它甚至有内置的 +Apple TV 遥控 + +19 +00:01:05,866 --> 00:01:08,702 +在 Apple tvOS 上使用 AVKit 时 +展示控制按钮的 + +20 +00:01:08,735 --> 00:01:11,905 +覆盖信息会显示 +播放标题和章节信息 + +21 +00:01:11,939 --> 00:01:13,373 +如果您下滑到信息面板 + +22 +00:01:13,407 --> 00:01:16,176 +会显示更详细的信息 +如专辑名称和描述 + +23 +00:01:17,878 --> 00:01:21,114 +按住 Apple TV 遥控上的 +TV 按钮会显示控制中心 + +24 +00:01:21,148 --> 00:01:25,586 +和 iOS 一样 会出现一个 +“正在播放”的窗口 也支持放大 + +25 +00:01:25,619 --> 00:01:28,722 +当 Apple tvOS 后台开始 +播放音频内容时 + +26 +00:01:28,755 --> 00:01:30,657 +按下遥控上的播放按钮 + +27 +00:01:30,691 --> 00:01:33,660 +或者从另一个设备的 +音乐 App 上选择一个曲目 + +28 +00:01:33,694 --> 00:01:38,365 +会显示有正在播放 +信息的通知 + +29 +00:01:38,398 --> 00:01:42,936 +另外 Apple tvOS 上播放音频时 +如果有一段时间未进行操作 + +30 +00:01:42,970 --> 00:01:46,607 +会有全屏覆盖 显示当前播放信息 + +31 +00:01:48,308 --> 00:01:52,112 +最后 在 iOS 上 +Control Other Speakers and TVs 按钮 + +32 +00:01:52,145 --> 00:01:54,815 +可以让您查看您其它所有设备的 +正在播放信息 + +33 +00:01:54,848 --> 00:01:56,950 +您可以控制播放 + +34 +00:01:58,352 --> 00:02:01,989 +随着可支持显示正在播放信息 +且可以控制播放的 + +35 +00:02:02,022 --> 00:02:03,690 +设备和 UI 越来越多 + +36 +00:02:03,724 --> 00:02:05,759 +如何适当发布 +正在播放信息 + +37 +00:02:05,792 --> 00:02:08,896 +并相应遥控指令显得愈发重要 + +38 +00:02:08,929 --> 00:02:10,898 +这次讲座接下来的时间 + +39 +00:02:10,931 --> 00:02:12,900 +我们将阐述如何响应 +遥控指令中的播放交互 + +40 +00:02:12,933 --> 00:02:15,936 +自动元数据发布 + +41 +00:02:15,969 --> 00:02:18,872 +AVKit 显示以及手动发布 + +42 +00:02:18,906 --> 00:02:21,008 +当使用 AVFoundation +来播放媒体内容时 + +43 +00:02:21,041 --> 00:02:22,876 +显示正在播放元数据 + +44 +00:02:22,910 --> 00:02:27,347 +并响应播放交互的最好方法 +就是使用 MPNowPlayingSession 类 + +45 +00:02:28,749 --> 00:02:31,852 +过去该类只可用于 Apple tvOS + +46 +00:02:31,885 --> 00:02:34,621 +但现在也可用于 iOS 16 了 + +47 +00:02:36,523 --> 00:02:38,825 +它可用来显示不同的播放会话 + +48 +00:02:38,859 --> 00:02:40,727 +如果您的 App 包含 +多种活动会话时 + +49 +00:02:40,761 --> 00:02:44,398 +也可提供对 +正在播放状态的控制 + +50 +00:02:44,431 --> 00:02:46,633 +它支持手动元数据发布 + +51 +00:02:46,667 --> 00:02:50,537 +以及 iOS 和 Apple tvOS 16 上 +全新的自动发布 + +52 +00:02:52,206 --> 00:02:55,475 +MPNowPlayingSession 使用 AVKit 时 +不应用在 Apple tvOS 上 + +53 +00:02:55,509 --> 00:02:57,678 +它有自己的自动发布机制 + +54 +00:02:57,711 --> 00:02:59,613 +我们稍后会讲到 + +55 +00:03:00,514 --> 00:03:03,016 +成为“正在播放”App 意味着 +您的 App 会出现在 + +56 +00:03:03,050 --> 00:03:05,219 +控制中心 锁定屏幕等等 + +57 +00:03:05,252 --> 00:03:06,620 +并接收播放控制 + +58 +00:03:06,653 --> 00:03:10,123 +如用户从另一个界面按下暂停 + +59 +00:03:10,157 --> 00:03:12,559 +有了 MPNowPlayingSession +您可以体现在一个 App 中 + +60 +00:03:12,593 --> 00:03:15,229 +展示同时播放的多个播放会话 + +61 +00:03:15,262 --> 00:03:17,064 +然而 使用多重会话时 + +62 +00:03:17,097 --> 00:03:19,032 +您的 App 必须将其中一个 +设置为活动会话 + +63 +00:03:19,066 --> 00:03:22,035 +在用遥控控制您的 App 时 +该会话会显示在整个系统中 + +64 +00:03:22,069 --> 00:03:23,737 +例如 使用画中画时 + +65 +00:03:23,770 --> 00:03:25,772 +可能同时有两个播放会话 + +66 +00:03:25,806 --> 00:03:27,574 +全屏播放部分应是 + +67 +00:03:27,608 --> 00:03:30,244 +活动的正在播放会话 + +68 +00:03:30,277 --> 00:03:34,548 +系统也有特定的标准来判定 +App 是否可以加入正在播放列表 + +69 +00:03:34,581 --> 00:03:38,151 +首先 您要注册一个最少有 +一个遥控指令的处理程序 + +70 +00:03:38,185 --> 00:03:41,655 +如您所见 不能响应 +播放交互的 App + +71 +00:03:41,688 --> 00:03:45,559 +并不适合显示在 +正在播放列表中 + +72 +00:03:45,592 --> 00:03:48,695 +第二 您 App 的 AVAudioSession +必须在 + +73 +00:03:48,729 --> 00:03:52,032 +类别选择中配置有 +non-mixable 类 + +74 +00:03:52,065 --> 00:03:54,668 +Mixable 播放类别和选项 +通常是在播放 + +75 +00:03:54,701 --> 00:03:57,471 +后台通知时使用的 +因此这可以提示系统 + +76 +00:03:57,504 --> 00:04:01,808 +正在播放的内容并不适合 +加入正在播放列表 + +77 +00:04:01,842 --> 00:04:04,811 +以下是几个帮助您理解 +播放会话的例子 + +78 +00:04:04,845 --> 00:04:07,281 +在这个例子中 +只有一个播放内容 + +79 +00:04:07,314 --> 00:04:10,951 +所以可以用单一的 +MPNowPlayingSession 来体现 + +80 +00:04:10,984 --> 00:04:14,188 +如果您的 App 支持 PiP +您也会有两个 MPNowPlayingSessions + +81 +00:04:14,221 --> 00:04:17,824 +一个为主播放器 +另一个是 PiP 播放 + +82 +00:04:17,858 --> 00:04:20,961 +在更复杂的情况下 +单一的 MPNowPlayingSession + +83 +00:04:20,994 --> 00:04:22,362 +有多个播放器 + +84 +00:04:22,396 --> 00:04:25,132 +在这个例子中 有 4 个播放器 +每个占 1/4 的屏幕空间 + +85 +00:04:25,165 --> 00:04:27,801 +显示同一场比赛的不同视角 + +86 +00:04:27,835 --> 00:04:30,337 +添加到相同 +MPNowPlayingSession 中的播放器 + +87 +00:04:30,370 --> 00:04:33,173 +应该具有相同的内容 + +88 +00:04:33,207 --> 00:04:36,476 +这里为每个例子做了说明 + +89 +00:04:36,510 --> 00:04:38,879 +首先 我们只播放单一内容 + +90 +00:04:38,912 --> 00:04:41,715 +因此 在一个播放器 +开启了一个会话 + +91 +00:04:41,748 --> 00:04:44,051 +第二个例子用的是画中画 + +92 +00:04:44,084 --> 00:04:46,520 +所以我们有两个会话 +每个会话一个播放器 + +93 +00:04:46,553 --> 00:04:50,958 +第一个全屏显示 第二个是画中画 + +94 +00:04:50,991 --> 00:04:53,794 +最后一个例子 在一个会话中 +从多个视角 + +95 +00:04:53,827 --> 00:04:56,997 +展示了四个参赛者的情况 + +96 +00:04:57,030 --> 00:04:58,732 +App 有多重会话时 + +97 +00:04:58,765 --> 00:05:02,936 +在必要时 App 需将指定的会话 +定义为活动会话 + +98 +00:05:02,970 --> 00:05:05,606 +例如 如果媒体以画中画的形式 +来播放 + +99 +00:05:05,639 --> 00:05:07,508 +如果用户将其放大到全屏 + +100 +00:05:07,541 --> 00:05:10,010 +之前的全屏会话应该 +不再为活跃会话 + +101 +00:05:10,043 --> 00:05:12,679 +或者说当前为全屏的 +正在播放和 PiP 会话 + +102 +00:05:12,713 --> 00:05:13,947 +应为活跃会话 + +103 +00:05:13,981 --> 00:05:17,184 +这种过渡可以通过 +在 MPNowPlayingSession 上 + +104 +00:05:17,217 --> 00:05:20,787 +调用 becomeActiveIfPossible 来实现 + +105 +00:05:20,821 --> 00:05:23,090 +现在我们已经了解了设置 +MPNowPlayingSession 实例 + +106 +00:05:23,123 --> 00:05:26,260 +以及控制正在播放会话的 +基础知识 + +107 +00:05:26,293 --> 00:05:28,529 +我们来看下从锁定屏幕 +或另一个房间的 HomePod 中 + +108 +00:05:28,562 --> 00:05:31,298 +接收和响应遥控指令 + +109 +00:05:31,331 --> 00:05:33,667 +首先是注册播放和暂停指令的 + +110 +00:05:33,700 --> 00:05:35,402 +基本例子 + +111 +00:05:35,435 --> 00:05:37,771 +这样 用户在另一个设备上 +按下播放或暂停按钮 + +112 +00:05:37,804 --> 00:05:40,674 +或用 Siri 来发布指令时 + +113 +00:05:40,707 --> 00:05:43,410 +您的 App 可以 +收到回调 + +114 +00:05:43,443 --> 00:05:46,713 +我们先将 MPNowPlayingSession +实例化 + +115 +00:05:46,747 --> 00:05:48,081 +由于我们只有一个会话 + +116 +00:05:48,115 --> 00:05:50,918 +就无需唤醒 +‘becomeActiveIfPossible’方法 + +117 +00:05:50,951 --> 00:05:52,386 +当您只有一个会话 + +118 +00:05:52,419 --> 00:05:56,256 +且 App 为“正在播放”App 时 +该会话则为默认会话 + +119 +00:05:56,290 --> 00:06:00,594 +每个 MPNowPlayingSession 实例 +有其自己的 MPRemoteCommandCenter 实例 + +120 +00:06:00,627 --> 00:06:02,563 +可用于声明您的播放会话 + +121 +00:06:02,596 --> 00:06:04,464 +响应的是哪个遥控指令 + +122 +00:06:04,498 --> 00:06:07,167 +接下来 我们为 playCommand +添加处理程序 + +123 +00:06:07,201 --> 00:06:11,738 +用于在播放器中唤醒 +play 方法 返回 success + +124 +00:06:11,772 --> 00:06:14,141 +然后 pauseCommand +也是同样的操作 + +125 +00:06:14,174 --> 00:06:17,010 +您要为 App 支持的每个指令 +都添加处理程序 + +126 +00:06:17,044 --> 00:06:20,280 +这适用于当前播放内容 + +127 +00:06:20,314 --> 00:06:23,350 +另一个例子是快进和快退指令 + +128 +00:06:23,383 --> 00:06:25,886 +这个指令应该用于大部分内容 + +129 +00:06:25,919 --> 00:06:27,287 +但对不能向前跳转的情况不适用 + +130 +00:06:27,321 --> 00:06:30,357 +如流媒体直播 + +131 +00:06:30,390 --> 00:06:32,860 +首先我们要指明首选间隔 + +132 +00:06:32,893 --> 00:06:35,996 +或者跳转的秒数 + +133 +00:06:36,029 --> 00:06:38,365 +在这里 我们用 15 秒 + +134 +00:06:38,398 --> 00:06:40,968 +然后与播放和暂停指令的 +操作一样 + +135 +00:06:41,001 --> 00:06:43,504 +添加一个处理程序 +在用户按下快进按钮 + +136 +00:06:43,537 --> 00:06:47,174 +或让 Siri 快进时唤醒该程序 + +137 +00:06:47,207 --> 00:06:51,078 +在我们的处理程序中 +将会收到 MPSkipIntervalCommandEvent + +138 +00:06:51,111 --> 00:06:54,481 +所以首先我们要将事件 +转换为该类型 + +139 +00:06:54,515 --> 00:06:57,584 +然后通过 MPSkipIntervalCommandEvent +提供的当前时间和间隔 + +140 +00:06:57,618 --> 00:07:00,754 +计算新的运行时间 + +141 +00:07:00,787 --> 00:07:05,058 +找到该位置 返回 success +表明我们跳转到新的位置 + +142 +00:07:05,092 --> 00:07:07,294 +也有可能您的 App 正处于 + +143 +00:07:07,327 --> 00:07:09,096 +指令暂时不可用的情形 + +144 +00:07:09,129 --> 00:07:11,265 +例如在广告时快进的时候 + +145 +00:07:11,298 --> 00:07:14,568 +这样的话 +可禁用 skipForwardCommand + +146 +00:07:14,601 --> 00:07:16,537 +现在我们响应了遥控指令 + +147 +00:07:16,570 --> 00:07:18,972 +可以再处理自动元数据发布 + +148 +00:07:19,006 --> 00:07:22,376 +自动发布让您能更容易 +保证元数据的精准性 + +149 +00:07:22,409 --> 00:07:25,312 +它可自动维持其直接在播放器 +观察到的元数据属性 + +150 +00:07:25,345 --> 00:07:28,882 +如持续时间 当前运行时间 + +151 +00:07:28,916 --> 00:07:31,585 +播放状态 播放进度 + +152 +00:07:31,618 --> 00:07:34,388 +如果内容中有植入广告 +则不应计入 + +153 +00:07:34,421 --> 00:07:36,156 +总持续时间和运行时间 + +154 +00:07:36,190 --> 00:07:39,726 +而应计算纯运行时间并报告 + +155 +00:07:39,760 --> 00:07:43,330 +其它元数据如标题 描述 +和专辑可以 + +156 +00:07:43,363 --> 00:07:47,434 +用 nowPlayingInfo 属性 +直接添加到 AVPlayerItems + +157 +00:07:47,467 --> 00:07:49,503 +在这个例子中 我们用自动发布 + +158 +00:07:49,536 --> 00:07:52,639 +来做大部分工作 +并自己设置标题和专辑 + +159 +00:07:52,673 --> 00:07:55,776 +首先 创建一个新的 +MPMediaItemArtwork 实例 + +160 +00:07:55,809 --> 00:07:57,144 +传递专辑图片 + +161 +00:07:57,177 --> 00:08:00,180 +大部分 App 会运行 +网络请求来抓取这些内容 + +162 +00:08:00,214 --> 00:08:03,150 +然后我们设置内容的视频标题 + +163 +00:08:03,183 --> 00:08:04,985 +然后将专辑和标题 + +164 +00:08:05,018 --> 00:08:06,987 +在当前使用 +MPMediaItemPropertyTitle + +165 +00:08:07,020 --> 00:08:10,457 +和 MPMediaItemPropertyArtwork 的 +播放器上 + +166 +00:08:10,490 --> 00:08:12,893 +设置为 nowPlayingInfo 词典 + +167 +00:08:12,926 --> 00:08:16,396 +正在播放元数据可以包含 + +168 +00:08:16,430 --> 00:08:19,399 +和 MPNowPlayingInfoProperty + +169 +00:08:19,433 --> 00:08:22,102 +最后 我们创建 +MPNowPlayingSession 实例 + +170 +00:08:22,135 --> 00:08:23,270 +传递到播放器 + +171 +00:08:23,303 --> 00:08:26,740 +将 automaticallyPublishNowPlayingInfo +设置为 true + +172 +00:08:26,773 --> 00:08:29,376 +automaticallyPublishNowPlayingInfo +设置为 true 后 + +173 +00:08:29,409 --> 00:08:32,279 +MPNowPlayingSession 实例将会开始 +观察播放器的 + +174 +00:08:32,312 --> 00:08:33,814 +状态变化 如静音 + +175 +00:08:33,847 --> 00:08:37,050 +播放 / 暂停事件 +或当前播放项目的变化 + +176 +00:08:37,084 --> 00:08:40,120 +这是另一个例子 +可以演示有植入广告时 + +177 +00:08:40,153 --> 00:08:42,789 +如果您希望广告时间不计入 +总持续时间或当前运行时间 + +178 +00:08:42,823 --> 00:08:47,327 +我们可以如何在实例中 +使用自动发布 + +179 +00:08:47,361 --> 00:08:50,898 +我们要为每个植入的广告 + +180 +00:08:50,931 --> 00:08:52,766 +创建 MPAdTimeRange 实例 + +181 +00:08:52,799 --> 00:08:55,502 +在这个例子中 +我们有一条 30 秒的广告 + +182 +00:08:55,536 --> 00:08:56,837 +在视频最开始播放 + +183 +00:08:56,870 --> 00:09:01,909 +所以我们创建开始点为 0 +持续时间为 30 秒 + +184 +00:09:01,942 --> 00:09:04,811 +与之前标题和专辑的 +处理方式类似 + +185 +00:09:04,845 --> 00:09:09,082 +我们只要在使用 +MPNowPlayingInfoPropertyAdTimeRanges 的播放项目上 + +186 +00:09:09,116 --> 00:09:14,154 +添加一组 MPAdTimeRange's +到其 nowPlayingInfo 词典 + +187 +00:09:14,188 --> 00:09:17,724 +然后和之前的操作一样 +创建 MPNowPlayingSession + +188 +00:09:17,758 --> 00:09:19,993 +启用自动发布 + +189 +00:09:20,027 --> 00:09:22,729 +接下来是 AVKit 的 +元数据发布 + +190 +00:09:22,763 --> 00:09:26,400 +在 Apple tvOS 上发布 AVKit 的 +正在播放元数据 + +191 +00:09:26,433 --> 00:09:27,968 +与 MPNowPlayingSession +操作类似 + +192 +00:09:28,001 --> 00:09:30,137 +元数据直接添加到 +AVPlayerItem + +193 +00:09:30,170 --> 00:09:33,207 +发布如运行时间 持续时间 +播放状态的数值 + +194 +00:09:33,240 --> 00:09:34,842 +并保持更新 + +195 +00:09:34,875 --> 00:09:37,377 +直接从播放器 +和资产中获取的元数据 + +196 +00:09:37,411 --> 00:09:40,480 +与您 App 在 AVPlayerItem 上 +提供的元数据 + +197 +00:09:40,514 --> 00:09:43,417 +一起输入到播放器 UI 的 +信息面板 + +198 +00:09:43,450 --> 00:09:47,554 +AVKit 也负责注册 +和响应遥控指令 + +199 +00:09:47,588 --> 00:09:50,858 +用 AVKit 是最好 +也是最简单的方法来整合 + +200 +00:09:50,891 --> 00:09:55,562 +我们迄今讨论过的平台 +以及其它如 AirPlay 和画中画的特性 + +201 +00:09:55,596 --> 00:09:59,466 +使用 AVKit 时设置元数据 +可以通过在 AVPlayerItem 上 + +202 +00:09:59,499 --> 00:10:03,637 +使用 externalMetadata 数组来完成 +包括描述内容的 + +203 +00:10:03,670 --> 00:10:05,138 +AVMetadataItem 实例 + +204 +00:10:05,172 --> 00:10:08,342 +每个 AVMetadataItem +您最多可以设置三个数值 + +205 +00:10:08,375 --> 00:10:10,711 +首先 标识符 这是表明 + +206 +00:10:10,744 --> 00:10:14,381 +AVMetadataItem 代表的是 +什么元数据的关键 + +207 +00:10:14,414 --> 00:10:18,285 +例如 当前标题的 +AVMetadataCommonIdentifierTitle + +208 +00:10:18,318 --> 00:10:21,788 +或专辑的 + +209 +00:10:21,822 --> 00:10:23,357 +AVMetadataCommonIdentifierArtwork + +210 +00:10:23,390 --> 00:10:24,992 +第二是数值 + +211 +00:10:25,025 --> 00:10:27,160 +在标题中 这是包含标题的字符串 + +212 +00:10:27,194 --> 00:10:31,198 +在专辑中 这是包含图像数据的 +NSData 实例 + +213 +00:10:31,231 --> 00:10:34,735 +dataType 用于指明 +所提供专辑的格式 + +214 +00:10:34,768 --> 00:10:36,537 +如果包含 JPEG 数据 + +215 +00:10:36,570 --> 00:10:40,274 +将会使用 +kCMMetadatabaseDataType_JPEG + +216 +00:10:40,307 --> 00:10:44,378 +最后 extendedLanguageTag +用于指明字符串 + +217 +00:10:44,411 --> 00:10:47,014 +所用的语言 如标题和描述 + +218 +00:10:47,047 --> 00:10:49,917 +大部分时候 这里应该用 +数值“und” + +219 +00:10:49,950 --> 00:10:52,653 +来确保所有观众都看到 +同样的数值 + +220 +00:10:52,686 --> 00:10:55,923 +如果数值是英语 +您可能会想使用“en-us” + +221 +00:10:55,956 --> 00:10:58,992 +但这样的话会该语言的设备 +设置成其它语言 + +222 +00:10:59,026 --> 00:11:01,261 +如西班牙语 从而不显示元数据 + +223 +00:11:02,262 --> 00:11:05,899 +这里我们有一个 +设置专辑和标题的例子 + +224 +00:11:05,933 --> 00:11:08,402 +首先 从软件包中抓取专辑图像数据 + +225 +00:11:08,435 --> 00:11:11,471 +大部分 App 会通过网络资源 +来抓取该信息 + +226 +00:11:11,505 --> 00:11:15,442 +然后 我们将新的 +可变 AVMetadataItem 实例化 + +227 +00:11:15,475 --> 00:11:18,712 +设置标识符为 +.commonIdentifierArtwork + +228 +00:11:18,745 --> 00:11:23,183 +然后设置数值为 +原始专辑图像数据及 NSData + +229 +00:11:23,217 --> 00:11:24,651 +由于图像数据是 JPEG + +230 +00:11:24,685 --> 00:11:28,021 +我们将 dataType +设置为 kCMMetadataBaseDataType_JPEG + +231 +00:11:28,055 --> 00:11:29,890 +如果您的专辑是 PNG + +232 +00:11:29,923 --> 00:11:33,193 +那就用 kCMMetadataBaseDataType_PNG + +233 +00:11:33,227 --> 00:11:35,128 +因为我们希望 +不管用户设备是什么语言 + +234 +00:11:35,162 --> 00:11:37,097 +这个元数据都是可见的 + +235 +00:11:37,130 --> 00:11:40,734 +所以将 extendedLanguageTag +设置为“und,”或“undefined.” + +236 +00:11:40,767 --> 00:11:44,137 +然后为标题重复同样的步骤 +用 .commonIdentifierTitle + +237 +00:11:44,171 --> 00:11:46,073 +视频标题作为数值 + +238 +00:11:46,106 --> 00:11:49,543 +再用“und” +作为 extendedLanguageTag + +239 +00:11:49,576 --> 00:11:51,545 +我们建立好所有元数据项目后 + +240 +00:11:51,578 --> 00:11:54,114 +将其添加到数组 +设置为 AVPlayerItem 的 + +241 +00:11:54,147 --> 00:11:57,718 +externalMetadata 属性 + +242 +00:11:57,751 --> 00:12:00,320 +现在播放项目上已经添加好了 +专辑和标题 + +243 +00:12:00,354 --> 00:12:05,425 +您可以看下这是如何映射到 +iOS 的控制中心和锁定屏幕上的 + +244 +00:12:05,459 --> 00:12:07,995 +如专辑一样 还有其它元数据类型 +是可以设置的 + +245 +00:12:08,028 --> 00:12:11,532 +如描述 字幕信息 内容评级 + +246 +00:12:11,565 --> 00:12:13,634 +您的 App 可以设置 +尽量多的信息 + +247 +00:12:13,667 --> 00:12:17,604 +尽可能为用户提供丰富的体验 + +248 +00:12:17,638 --> 00:12:20,807 +到目前为止 我们讨论了 +MPNowPlayingSession 的自动发布 + +249 +00:12:20,841 --> 00:12:22,276 +AVKit 的发布 + +250 +00:12:22,309 --> 00:12:24,811 +但 MPNowPlayingSession +及其自动发布功能 + +251 +00:12:24,845 --> 00:12:27,314 +需要传递一个 AVPlayer 实例 + +252 +00:12:27,347 --> 00:12:31,785 +这并不一定适用于所有 App +仍然可以使用手动发布 + +253 +00:12:31,818 --> 00:12:35,055 +手动发布需要您提供 +所有元数据数值 + +254 +00:12:35,088 --> 00:12:37,824 +与自动发布不同 如运行时间 + +255 +00:12:37,858 --> 00:12:40,360 +播放状态的信息无法由系统提供 + +256 +00:12:40,394 --> 00:12:43,764 +这意味着您需要对低等级 +播放状态进行手动细粒度控制 + +257 +00:12:43,797 --> 00:12:48,302 +您的 App 保证在播放状态改变下 +信息随着时间的准确性 + +258 +00:12:48,335 --> 00:12:51,071 +要注意 注册和响应遥控指令 + +259 +00:12:51,104 --> 00:12:52,406 +同样也是需要的 + +260 +00:12:52,439 --> 00:12:54,975 +因为我们没有 +使用 MPNowPlayingSession + +261 +00:12:55,008 --> 00:12:58,645 +那就要使用 +MPRemoteCommandCenter 的共享实例 + +262 +00:12:58,679 --> 00:13:02,082 +以下是更新正在播放Info +词典的基础示例 + +263 +00:13:02,115 --> 00:13:06,019 +首先 创建包含图像的 +MPMediaItemArtwork 实例 + +264 +00:13:06,053 --> 00:13:08,055 +和我们在自动发布时的操作类似 + +265 +00:13:08,088 --> 00:13:12,125 +然后 创建包含 +我们已有元数据的词典 + +266 +00:13:12,159 --> 00:13:17,064 +在这里 我们设置标题 专辑 +以及播放持续时间 + +267 +00:13:17,097 --> 00:13:19,399 +运行时间 播放状态的数值 + +268 +00:13:19,433 --> 00:13:21,768 +然后将其设置到 +MPNowPlayingInfoCenter + +269 +00:13:21,802 --> 00:13:23,670 +默认实例上 + +270 +00:13:23,704 --> 00:13:27,074 +在播放期间有任意变化 +如播放或暂停 + +271 +00:13:27,107 --> 00:13:29,076 +用户滑动快进或快退 +或者开始播放新项目时 + +272 +00:13:29,109 --> 00:13:32,779 +这一元数据都应相应更新 + +273 +00:13:32,813 --> 00:13:34,948 +您不需要定期更新运行时间 + +274 +00:13:34,982 --> 00:13:37,484 +系统会根据自上一次更新以来 + +275 +00:13:37,518 --> 00:13:41,054 +过去了多少时间 从而推算 +正确的运行时间 + +276 +00:13:41,088 --> 00:13:43,857 +现在您已经熟悉了 +发布正在播放元数据 + +277 +00:13:43,891 --> 00:13:47,494 +及响应其它设备和界面遥控指令的 +所有不同方法 + +278 +00:13:47,528 --> 00:13:50,130 +那就可以集成这些方法 +从而最大化用户体验了 + +279 +00:13:50,163 --> 00:13:51,632 +这是前所未有的便捷 + +280 +00:13:51,665 --> 00:13:53,834 +当前的集成同样也能用上 + +281 +00:13:53,867 --> 00:13:57,070 +转换到自动发布 从而避免 +未来的性能倒退 + +282 +00:13:57,104 --> 00:13:59,506 +最小化您要维持的代码数量 + +283 +00:13:59,540 --> 00:14:03,410 +您可访问 developer.apple.com 上的 +MediaPlayer 以获取更多信息 + +284 +00:14:03,443 --> 00:14:04,811 +感谢大家的观看 + diff --git a/zho/2022 Session 110344 Get to know Developer Mode.srt b/zho/2022 Session 110344 Get to know Developer Mode.srt new file mode 100644 index 0000000..1546ecc --- /dev/null +++ b/zho/2022 Session 110344 Get to know Developer Mode.srt @@ -0,0 +1,539 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,376 +♪ + +3 +00:00:09,376 --> 00:00:11,545 +大家好 我的名字叫 Pavlo + +4 +00:00:11,545 --> 00:00:12,913 +我从事安全技术工作 + +5 +00:00:12,913 --> 00:00:15,682 +安全技术有助于 +保证您和您的用户的安全 + +6 +00:00:15,682 --> 00:00:17,684 +今天我要告诉您一些即将发生的变化 + +7 +00:00:17,684 --> 00:00:19,920 +这些变化可能会影响您开发 测试 + +8 +00:00:19,920 --> 00:00:22,756 +和部署 App 的方式 + +9 +00:00:22,756 --> 00:00:25,292 +首先 我想告诉您何谓开发者模式 + +10 +00:00:25,292 --> 00:00:27,661 +创建开发者模式的原因 + +11 +00:00:27,661 --> 00:00:29,363 +其发挥的安全作用 + +12 +00:00:29,363 --> 00:00:32,766 +其影响的工作流程 + +13 +00:00:32,766 --> 00:00:34,835 +然后 我们将讨论打开开发者模式的 + +14 +00:00:34,835 --> 00:00:37,337 +方式和时间 + +15 +00:00:37,337 --> 00:00:40,107 +在本讲座的结束阶段 我会介绍 + +16 +00:00:40,107 --> 00:00:42,442 +我们为支持自动化流程而构建的工具 + +17 +00:00:42,442 --> 00:00:44,144 +当您操作许多设备时 + +18 +00:00:44,144 --> 00:00:47,214 +例如在测试实验室环境中 +可以使用这些工具 + +19 +00:00:47,214 --> 00:00:49,783 +好 那么什么是开发者模式? + +20 +00:00:49,783 --> 00:00:52,886 +它是 iOS 16 和 watchOS 9 中的 +一种新模式 + +21 +00:00:52,886 --> 00:00:55,956 +可实现一般的开发者工作流程 + +22 +00:00:55,956 --> 00:00:58,125 +开发者模式在默认情况下是禁用的 + +23 +00:00:58,125 --> 00:01:00,460 +如果要将设备设置为开发者模式 + +24 +00:01:00,460 --> 00:01:01,862 +需要您明确注册 + +25 +00:01:01,862 --> 00:01:05,732 +您的注册在设备重启和系统更新后 +仍然有效 + +26 +00:01:05,732 --> 00:01:07,434 +当然 我们还构建了一些工具 + +27 +00:01:07,434 --> 00:01:09,369 +让您可以根据需要自动设置 + +28 +00:01:09,369 --> 00:01:11,171 +开发者模式 + +29 +00:01:11,171 --> 00:01:12,806 +您可能会忍不住想问 + +30 +00:01:12,806 --> 00:01:15,909 +“我们为什么要引入开发者模式?” + +31 +00:01:15,909 --> 00:01:18,011 +原因是强大的开发者功能 + +32 +00:01:18,011 --> 00:01:20,280 +在有针对性的攻击中被滥用 + +33 +00:01:20,280 --> 00:01:21,882 +同时 绝大多数用户 + +34 +00:01:21,882 --> 00:01:23,817 +不需要此类功能 + +35 +00:01:23,817 --> 00:01:26,353 +因此默认情况下不应该启用它们 + +36 +00:01:26,353 --> 00:01:28,655 +这样 我们可以保留 +您所依赖的开发能力 + +37 +00:01:28,655 --> 00:01:31,425 +并通过缓解措施提高用户的安全性 + +38 +00:01:31,425 --> 00:01:34,895 +否则这些缓解措施会对您造成妨碍 + +39 +00:01:34,895 --> 00:01:36,063 +话虽如此 + +40 +00:01:36,063 --> 00:01:39,132 +大多数常见的分发流程 +都不需要开发者模式 + +41 +00:01:39,132 --> 00:01:41,635 +例如 通过 TestFlight 部署 App + +42 +00:01:41,635 --> 00:01:43,570 +或使用企业内部分发流程 + +43 +00:01:43,570 --> 00:01:46,607 +不需要开发者模式 + +44 +00:01:46,607 --> 00:01:48,775 +当然 通过 App Store + +45 +00:01:48,775 --> 00:01:52,145 +分发 App 也不需要开发者模式 + +46 +00:01:52,145 --> 00:01:54,281 +只有当您作为开发者 + +47 +00:01:54,281 --> 00:01:57,885 +在设备上开发 App 时才需要它 + +48 +00:01:57,885 --> 00:01:59,920 +好 我相信您现在迫切想要知道 + +49 +00:01:59,920 --> 00:02:01,688 +如何开始使用 + +50 +00:02:01,688 --> 00:02:03,223 +开发者模式了 + +51 +00:02:03,223 --> 00:02:05,659 +那么让我们看看您何时需要 + +52 +00:02:05,659 --> 00:02:07,794 +以及如何打开开发者模式 + +53 +00:02:07,794 --> 00:02:10,597 +以下情况下应该打开开发者模式: + +54 +00:02:10,597 --> 00:02:12,866 +需要运行和安装 +Development 签名的 App + +55 +00:02:12,866 --> 00:02:16,069 +包括使用 Personal Team +签名的 App + +56 +00:02:16,069 --> 00:02:18,438 +需要调试和检测 App + +57 +00:02:18,438 --> 00:02:23,043 +或是想要在设备上实现测试自动化 + +58 +00:02:23,043 --> 00:02:24,878 +打开开发者模式很简单 + +59 +00:02:24,878 --> 00:02:27,381 +但首先您需要将设备连接到 Xcode + +60 +00:02:27,381 --> 00:02:30,617 +以显示开发者模式菜单项 + +61 +00:02:30,617 --> 00:02:32,119 +您下载的 Beta 版 + +62 +00:02:32,119 --> 00:02:36,390 +将暂时使该菜单项始终可见 + +63 +00:02:36,390 --> 00:02:38,992 +在没有连接到 Xcode 的情况下 +安装 Development 签名的 App + +64 +00:02:38,992 --> 00:02:40,327 +例如通过 Apple Configurator 安装 + +65 +00:02:40,327 --> 00:02:43,397 +也会使该菜单项可见 + +66 +00:02:43,397 --> 00:02:45,732 +完成后 您可以在“设置”的 +“隐私和安全”下 + +67 +00:02:45,732 --> 00:02:49,803 +找到“开发者模式”控件 + +68 +00:02:49,803 --> 00:02:52,105 +对于自动化 您可以使用 +macOS Ventura 上 + +69 +00:02:52,105 --> 00:02:54,408 +默认提供的新 devmodectl + +70 +00:02:54,408 --> 00:02:56,944 +我稍后会对自动化做详细介绍 + +71 +00:02:56,944 --> 00:02:58,445 +好 让我们来看看 + +72 +00:02:58,445 --> 00:03:00,280 +如何打开开发者模式 + +73 +00:03:00,280 --> 00:03:02,049 +在我面前有一部 iPhone 13 Pro + +74 +00:03:02,049 --> 00:03:03,984 +我刚刚拿起它来运行我的代码 + +75 +00:03:03,984 --> 00:03:05,652 +首先 我要把它连接到 + +76 +00:03:05,652 --> 00:03:08,555 +已经运行 Xcode 的 Mac + +77 +00:03:08,555 --> 00:03:11,024 +如您所见 Xcode 识别出 + +78 +00:03:11,024 --> 00:03:13,126 +这个设备没有启用开发者模式 + +79 +00:03:13,126 --> 00:03:17,564 +它将阻止我运行这个 App + +80 +00:03:17,564 --> 00:03:19,433 +但现在我已经连接了这部手机 + +81 +00:03:19,433 --> 00:03:25,506 +我可以进入“设置”的 +“隐私和安全” + +82 +00:03:25,506 --> 00:03:28,008 +再进入“开发者模式” + +83 +00:03:30,010 --> 00:03:30,911 +打开开发者模式 + +84 +00:03:30,911 --> 00:03:32,613 +需要重新启动设备 + +85 +00:03:32,613 --> 00:03:35,215 +那么让我们继续吧 + +86 +00:03:37,451 --> 00:03:38,986 +设备重启后 + +87 +00:03:38,986 --> 00:03:42,222 +系统会再次提示您确认您的决定 + +88 +00:03:42,222 --> 00:03:46,894 +轻点“打开”后 您就可以开始了 + +89 +00:03:46,894 --> 00:03:52,466 +现在 Xcode 看到 +设备启用了开发者模式 + +90 +00:03:52,466 --> 00:03:55,169 +我可以运行我的 App 了 + +91 +00:03:59,006 --> 00:04:00,774 +虽然此流程在您使用 + +92 +00:04:00,774 --> 00:04:01,842 +一台设备时有效 + +93 +00:04:01,842 --> 00:04:03,210 +但如果您正在操作多台设备 + +94 +00:04:03,210 --> 00:04:05,145 +这个过程可能会很耗时 + +95 +00:04:05,145 --> 00:04:06,380 +出于这个原因 我们构建了 + +96 +00:04:06,380 --> 00:04:09,383 +帮助您自动化这个过程的工具 + +97 +00:04:09,383 --> 00:04:11,451 +自动化流程有一个限制 + +98 +00:04:11,451 --> 00:04:12,886 +只有没有密码的设备 + +99 +00:04:12,886 --> 00:04:15,789 +才能自动启用开发者模式 + +100 +00:04:15,789 --> 00:04:17,424 +这是因为当您重新启动 iPhone 时 + +101 +00:04:17,424 --> 00:04:18,892 +您需要先解锁您的设备 + +102 +00:04:18,892 --> 00:04:21,762 +然后才能与之进行交互 + +103 +00:04:21,762 --> 00:04:23,063 +为了支持自动化 + +104 +00:04:23,063 --> 00:04:25,632 +macOS Ventura 附带了 devmodectl + +105 +00:04:25,632 --> 00:04:27,634 +您可以使用它在已连接的单个设备上 + +106 +00:04:27,634 --> 00:04:29,670 +启用开发者模式 + +107 +00:04:29,670 --> 00:04:31,805 +或者在流模式下自动 + +108 +00:04:31,805 --> 00:04:34,708 +为您插入的所有设备打开开发者模式 + +109 +00:04:36,977 --> 00:04:39,880 +这里有两台设备连接到我的 Mac + +110 +00:04:43,050 --> 00:04:44,351 +它们没有密码 + +111 +00:04:44,351 --> 00:04:46,854 +我不想在这些设备上 +手动设置开发者模式 + +112 +00:04:46,854 --> 00:04:50,991 +因此 我将使用流模式子命令 +运行 devmodectl + +113 +00:04:50,991 --> 00:04:53,093 +这将自动重启连接的设备 + +114 +00:04:53,093 --> 00:04:56,964 +并设置开发者模式 + +115 +00:04:56,964 --> 00:04:58,465 +设置开发者模式后 + +116 +00:04:58,465 --> 00:05:01,368 +您将在设备上收到通知 + +117 +00:05:05,372 --> 00:05:08,041 +现在这些设备一切就绪 + +118 +00:05:08,041 --> 00:05:10,477 +好 这就是我今天要讲的全部内容 + +119 +00:05:10,477 --> 00:05:13,013 +总结一下 +在 iOS 16 和 watchOS 9 中 + +120 +00:05:13,013 --> 00:05:14,481 +您必须启用开发者模式 + +121 +00:05:14,481 --> 00:05:16,083 +才能进行一般的开发活动 + +122 +00:05:16,083 --> 00:05:19,419 +如部署和调试 App + +123 +00:05:19,419 --> 00:05:21,321 +如果您需要自动设置开发者模式 + +124 +00:05:21,321 --> 00:05:25,392 +您可以使用 macOS Ventura 中 +附带的 devmodectl + +125 +00:05:25,392 --> 00:05:27,361 +如果您想深入了解 + +126 +00:05:27,361 --> 00:05:29,696 +可能影响 macOS 分发工作流程的 +安全变更 + +127 +00:05:29,696 --> 00:05:33,033 +请查看“Mac App 公证 +的新功能”讲座 + +128 +00:05:33,033 --> 00:05:34,735 +我希望您度过美好的一天 + +129 +00:05:34,735 --> 00:05:35,903 +祝您编程愉快! + +130 +00:05:35,903 --> 00:05:40,174 +♪ + diff --git a/zho/2022 Session 110347 Explore more content with MusicKit.srt b/zho/2022 Session 110347 Explore more content with MusicKit.srt new file mode 100644 index 0000000..ce0c740 --- /dev/null +++ b/zho/2022 Session 110347 Explore more content with MusicKit.srt @@ -0,0 +1,2022 @@ +1 +00:00:00,334 --> 00:00:07,341 +♪ ♪ + +2 +00:00:10,177 --> 00:00:13,180 +David Ho: 大家好 欢迎来到 WWDC + +3 +00:00:13,213 --> 00:00:15,415 +我是 David +今天我想向您介绍的是 + +4 +00:00:15,449 --> 00:00:18,685 +如何用 MusicKit 探索更多内容 + +5 +00:00:18,719 --> 00:00:21,288 +MusicKit 框架于 2021 年推出 + +6 +00:00:21,321 --> 00:00:25,659 +提供了一组 API 用于在 Swift 中 +访问和播放本机音乐 + +7 +00:00:25,692 --> 00:00:28,996 +此框架使您的 App 能够 +轻松地与 Apple Music 整合 + +8 +00:00:29,029 --> 00:00:32,299 +并提供对整个 Apple Music +目录的访问 + +9 +00:00:32,332 --> 00:00:34,968 +今天 我要介绍的是 +我们对 MusicKit 所做的 + +10 +00:00:35,002 --> 00:00:36,937 +一些主要改进 + +11 +00:00:36,970 --> 00:00:40,641 +我将从一些附加内容开始 +通过新的音乐项目类型 + +12 +00:00:40,674 --> 00:00:45,012 +新的请求和新的元数据 +从 Apple Music 目录中获得更多信息 + +13 +00:00:46,046 --> 00:00:49,283 +之后 我将讨论如何获取个性化内容 + +14 +00:00:49,316 --> 00:00:53,187 +以便为每个用户提供定制的体验 + +15 +00:00:53,220 --> 00:00:56,223 +接下来 我将介绍 +Apple Music 目录以外的内容 + +16 +00:00:56,256 --> 00:00:59,092 +今年 通过加入用户曲库中的音乐 + +17 +00:00:59,126 --> 00:01:02,596 +您可以将 App 提升到 +一个全新的水平 + +18 +00:01:02,629 --> 00:01:06,133 +最后 我将讨论如何主动与曲库交互 + +19 +00:01:06,166 --> 00:01:09,036 +例如向曲库或播放列表中添加项目 + +20 +00:01:09,069 --> 00:01:12,072 +以及创建和编辑播放列表 + +21 +00:01:12,105 --> 00:01:14,842 +让我们深入研究添加的目录内容 + +22 +00:01:14,875 --> 00:01:18,579 +最初发布的 MusicKit +引入了一个新的音乐模型层 + +23 +00:01:18,612 --> 00:01:22,616 +包括歌曲 专辑 +和播放列表等核心类型 + +24 +00:01:22,649 --> 00:01:25,252 +今年 我们增加了两种新类型 + +25 +00:01:25,285 --> 00:01:28,722 +让 MusicKit 更容易发现新音乐 + +26 +00:01:28,755 --> 00:01:30,824 +Curator 和 Radio Show + +27 +00:01:32,092 --> 00:01:34,561 +除此之外 MusicKit 现在还可以让您 + +28 +00:01:34,595 --> 00:01:37,831 +构建出色的 UI 来搜索目录 + +29 +00:01:37,865 --> 00:01:41,134 +访问排行榜以获取 +最受欢迎的歌曲 专辑等 + +30 +00:01:41,168 --> 00:01:44,204 +并获取新的属性 + +31 +00:01:44,238 --> 00:01:48,809 +例如更高质量的音频元数据 +如支持 Dolby Atmos 的 Spatial Audio + +32 +00:01:49,610 --> 00:01:53,213 +让我们从 curator 和广播节目开始 +这是发现音乐的 + +33 +00:01:53,247 --> 00:01:54,882 +极好资源 + +34 +00:01:54,915 --> 00:01:58,385 +在这里 我们来看一个 +Curator 的例子 Nike + +35 +00:01:58,418 --> 00:02:02,756 +其他 curator 的例子还有 +Shazam 和 Dr. Dre 的 Beats + +36 +00:02:02,789 --> 00:02:07,127 +在这里 我们可以很容易找到 +这位 curator 生成的所有播放列表 + +37 +00:02:07,160 --> 00:02:11,231 +此功能允许人们快速访问 +他们喜欢的播放列表 + +38 +00:02:11,265 --> 00:02:14,434 +查找新歌或重新访问旧的个人收藏 + +39 +00:02:14,468 --> 00:02:17,304 +现在 让我们深入了解 +更多的技术细节 + +40 +00:02:18,238 --> 00:02:20,641 +Curators 拥有多种属性 + +41 +00:02:20,674 --> 00:02:24,244 +这个新的 Curator 类型的 +一些主要属性包括名称 + +42 +00:02:24,278 --> 00:02:28,348 +URL 插图和种类 + +43 +00:02:28,382 --> 00:02:32,719 +种类属性是一个 enum +可以是“编辑”或“外部” + +44 +00:02:32,753 --> 00:02:37,291 +指示给定的 curator 是 +Apple curator 还是第三方 curator + +45 +00:02:38,258 --> 00:02:40,761 +curator 也有一个播放列表关系 + +46 +00:02:40,794 --> 00:02:42,896 +展示 curator 制作的播放列表 + +47 +00:02:42,930 --> 00:02:46,133 +真正服务于我们刚才看到的 +音乐发现概念 + +48 +00:02:47,835 --> 00:02:50,304 +接下来 我们来看看广播节目类型 + +49 +00:02:50,337 --> 00:02:52,940 +像 Zane Lowe 的 New Music Daily + +50 +00:02:52,973 --> 00:02:56,343 +和 Brooke Reese 的 Pop Hits Radio +这样的广播节目 + +51 +00:02:56,376 --> 00:02:59,046 +是通过经验丰富的专业人士 +发现新音乐的另一种方式 + +52 +00:02:59,079 --> 00:03:00,647 +与 Curator 类型非常相似 + +53 +00:03:00,681 --> 00:03:03,317 +广播节目也有播放列表关系 + +54 +00:03:03,350 --> 00:03:06,320 +以查找广播节目的音乐功能 + +55 +00:03:06,353 --> 00:03:09,623 +正如这两种新类型 +与播放列表的关系一样 + +56 +00:03:09,656 --> 00:03:13,260 +我们也公开了 Playlist 类型上的 +两种新关系 + +57 +00:03:13,293 --> 00:03:17,698 +即反向逻辑的“Curator” +和“RadioShow” 给定一个播放列表 + +58 +00:03:17,731 --> 00:03:21,702 +我们可以很容易地获得 +生成所述播放列表的实体的结构 + +59 +00:03:23,203 --> 00:03:26,840 +MusicKit 允许在目录中 +搜索多种类型的内容 + +60 +00:03:26,874 --> 00:03:31,645 +我们添加了对新项目类型的支持 +比如 curator 和广播节目 + +61 +00:03:31,678 --> 00:03:34,481 +列表还在继续增长 因此 + +62 +00:03:34,515 --> 00:03:37,651 +构建良好的 UI +变得越来越具有挑战性 + +63 +00:03:37,684 --> 00:03:40,621 +所以今年我们通过最匹配结果和建议 + +64 +00:03:40,654 --> 00:03:43,857 +让您的搜索变得更容易 + +65 +00:03:43,891 --> 00:03:47,694 +让我们来看看这些增强 +给 UI 带来的效用 + +66 +00:03:47,728 --> 00:03:51,164 +当键入搜索内容时 +您可能会得到强大的 + +67 +00:03:51,198 --> 00:03:53,834 +与音乐相关的 +以及自动完成的相关支持 + +68 +00:03:53,867 --> 00:03:56,170 +这就是建议发挥作用的地方 + +69 +00:03:56,203 --> 00:03:59,239 +提供人们可能试图达到的条件 + +70 +00:03:59,273 --> 00:04:02,309 +您甚至可以更进一步显示最匹配结果 + +71 +00:04:02,342 --> 00:04:06,380 +以便快速访问人们正在搜索的内容 + +72 +00:04:06,413 --> 00:04:09,650 +为了获得最好的结果 +您可能并不关心项目的类型 + +73 +00:04:09,683 --> 00:04:12,653 +而是想要专注于相关性 + +74 +00:04:12,686 --> 00:04:15,355 +这就是最匹配结果的力量 + +75 +00:04:15,389 --> 00:04:18,659 +现在 让我们从 Top Results 开始 + +76 +00:04:18,692 --> 00:04:20,227 +看一下实施起来会是什么样子 + +77 +00:04:20,260 --> 00:04:23,864 +这里是我们创建 +目录搜索请求的现有方法 + +78 +00:04:23,897 --> 00:04:25,499 +需要一个搜索词 + +79 +00:04:25,532 --> 00:04:28,001 +和您想要表示的项目类型 + +80 +00:04:28,035 --> 00:04:31,805 +响应包括按请求的类型分类的集合 + +81 +00:04:31,839 --> 00:04:35,175 +这意味着有多个 +特定于类型的结果列表 + +82 +00:04:35,209 --> 00:04:38,078 +尽管这很好 但我们还是想公开一个 + +83 +00:04:38,111 --> 00:04:41,081 +与类型无关的最相关的结果列表 + +84 +00:04:41,114 --> 00:04:45,652 +请求这些信息就像 +添加一行代码一样简单 + +85 +00:04:45,686 --> 00:04:49,790 +这里 我们将请求的 +includeTopResults 属性设置为 true + +86 +00:04:49,823 --> 00:04:53,060 +并在响应中填充一个新属性 + +87 +00:04:53,093 --> 00:04:55,796 +这个新属性被命名为 topResults + +88 +00:04:55,829 --> 00:04:58,866 +它包含任何请求类型的项目 + +89 +00:04:58,899 --> 00:05:02,202 +下面是 print statement 的输出 + +90 +00:05:02,236 --> 00:05:06,073 +我们可以看到 返回的最匹配结果 +是一个合集中的 + +91 +00:05:06,106 --> 00:05:11,011 +歌曲 艺术家和专辑的混合 +并根据相关性排序 + +92 +00:05:11,044 --> 00:05:14,047 +现在 我将向您展示 +如何用 Suggestions + +93 +00:05:14,081 --> 00:05:16,683 +帮助人们更快地到达 +他们的搜索目的地 + +94 +00:05:16,717 --> 00:05:20,687 +只需创建一个带有字符串项的 +建议请求 + +95 +00:05:20,721 --> 00:05:25,192 +调用响应后 您将得到建议响应 + +96 +00:05:25,225 --> 00:05:27,961 +响应中包含了一系列 Suggestions + +97 +00:05:27,995 --> 00:05:32,232 +每个建议都包括一个 +适合您的 UI 的显示词 + +98 +00:05:32,266 --> 00:05:34,067 +以及一个搜索词 + +99 +00:05:34,101 --> 00:05:37,538 +当人们选择一个建议时 +您可以通过使用搜索词 + +100 +00:05:37,571 --> 00:05:40,240 +执行搜索请求来获取相应的结果 + +101 +00:05:41,508 --> 00:05:46,280 +目录排行榜是了解 +最新最流行歌曲的好方法 + +102 +00:05:46,313 --> 00:05:50,584 +MusicKit 提供各种类型的图表 +来查看流行趋势 + +103 +00:05:50,617 --> 00:05:53,053 +所提供的图表类型是排行榜 + +104 +00:05:53,086 --> 00:05:57,824 +例如热门歌曲或热门专辑 +它们对应于最常播放的音乐 + +105 +00:05:57,858 --> 00:06:01,528 +城市排行榜和每日前 100 名 + +106 +00:06:01,562 --> 00:06:06,633 +您还可以指定所请求的排行榜 +按特定的类型进行筛选 + +107 +00:06:06,667 --> 00:06:09,870 +通过代码检索这些排行榜非常简单 + +108 +00:06:09,903 --> 00:06:12,539 +目录排行榜请求遵循目录搜索请求中 + +109 +00:06:12,573 --> 00:06:15,709 +已经使用的既定模式 + +110 +00:06:15,742 --> 00:06:18,879 +首先 初始化排行榜请求 + +111 +00:06:18,912 --> 00:06:22,182 +然后 您可以指定 +您喜欢的排行榜类型 + +112 +00:06:22,216 --> 00:06:25,252 +默认情况下 +这将获取播放次数最多的内容 + +113 +00:06:25,285 --> 00:06:30,157 +但也可以获得 +每日全球排行榜和城市排行榜 + +114 +00:06:30,190 --> 00:06:33,560 +最后 您只需指定 +您希望排行榜包含的类型 + +115 +00:06:33,594 --> 00:06:35,896 +就是这样了 + +116 +00:06:35,929 --> 00:06:38,699 +当我们访问响应中的第一个 +播放列表排行榜时 + +117 +00:06:38,732 --> 00:06:43,270 +我们会得到 MusicCatalogChart +它代表每天的全球排行榜 + +118 +00:06:43,303 --> 00:06:48,775 +其播放列表包括 “TOP 100:Global” +和 “Top 100: USA” + +119 +00:06:48,809 --> 00:06:52,279 +如果您过去一直用 +MusicDataRequest 获取目录排行榜 + +120 +00:06:52,312 --> 00:06:55,482 +那么现在您不需要这样做了 +因为 MusicKit 将为您完成这项工作 + +121 +00:06:55,516 --> 00:06:58,752 +它在项目集合中内置了分页支持 + +122 +00:06:58,785 --> 00:07:00,320 +在 2021 年 + +123 +00:07:00,354 --> 00:07:02,789 +我们推出了具有真正多维声音 + +124 +00:07:02,823 --> 00:07:05,959 +和清晰度的突破性音频体验 + +125 +00:07:05,993 --> 00:07:09,396 +支持 Dolby Atmos 的 Spatial Audio + +126 +00:07:09,429 --> 00:07:13,166 +这种身临其境的体验 +已经可用于数千首歌曲 + +127 +00:07:13,200 --> 00:07:15,702 +现在您可以访问这些数据 + +128 +00:07:15,736 --> 00:07:20,674 +MusicKit 通过 Audio Variants +公开歌曲或专辑的可用音频资源 + +129 +00:07:20,707 --> 00:07:25,646 +因此现在 +您可以将此信息转发给其他人 + +130 +00:07:25,679 --> 00:07:28,315 +Audio Variants 的示例包括 +前面提到的 + +131 +00:07:28,348 --> 00:07:33,387 +支持 Dolby Atmos 和 Lossless Audio的 +Spatial Audio 等 + +132 +00:07:34,755 --> 00:07:38,492 +除了 Audio Variants 之外 我们还 +公开了一个新的 boolean 属性 + +133 +00:07:38,525 --> 00:07:43,297 +即 Apple Digital Master +它是受支持的最高质量的 master + +134 +00:07:43,330 --> 00:07:46,099 +由于这些元数据是在项目级别公开的 + +135 +00:07:46,133 --> 00:07:48,368 +Audio Variants 非常适合细节视图 + +136 +00:07:48,402 --> 00:07:51,471 +允许您实现这样的 UI + +137 +00:07:51,505 --> 00:07:54,341 +我们这里有一张专辑的详细视图 + +138 +00:07:54,374 --> 00:07:56,743 +在这里 我们可以看到 +基于前面提到的 + +139 +00:07:56,777 --> 00:07:59,580 +Audio Variants 属性的相应徽章 + +140 +00:07:59,613 --> 00:08:02,950 +让用户知道他们将获得 +怎样的音频质量 + +141 +00:08:02,983 --> 00:08:05,819 +在这种情况下 空间⾳频和无损音频 + +142 +00:08:05,853 --> 00:08:08,088 +可用于该特定专辑 + +143 +00:08:08,121 --> 00:08:11,325 +现在让我们看看 +如何编写代码来实现这一点 + +144 +00:08:11,358 --> 00:08:14,928 +加载 Audio Variants +就像加载任何其他扩展属性一样 + +145 +00:08:14,962 --> 00:08:18,732 +使用加载 +audioVariants 扩展属性的方法 + +146 +00:08:18,765 --> 00:08:22,803 +获取现有的专辑或歌曲 +在本例中是专辑 + +147 +00:08:22,836 --> 00:08:27,441 +现在 detailedAlbum +已经填充了 audioVariants 属性 + +148 +00:08:27,474 --> 00:08:29,510 +这里我们可以看到 +Audio Variants 属性 + +149 +00:08:29,543 --> 00:08:32,913 +它是一个数组 +其元素是 AudioVariant + +150 +00:08:32,946 --> 00:08:36,884 +使用这些值 您可以在 UI 中指定 +该特定元素的 + +151 +00:08:36,917 --> 00:08:40,153 +可用音频资源 +就像我们前面看到的那样 + +152 +00:08:40,187 --> 00:08:42,256 +现在 效果很好 但您可能不仅仅希望 + +153 +00:08:42,289 --> 00:08:45,959 +在顶层或细节视图上 +显示这些音频徽章 + +154 +00:08:45,993 --> 00:08:48,562 +这就是为什么我们还要更进一步 + +155 +00:08:48,595 --> 00:08:52,099 +为音乐播放器提供动态音频版本 + +156 +00:08:52,132 --> 00:08:55,469 +访问活动的 audioVariant 允许对 + +157 +00:08:55,502 --> 00:08:58,772 +当前播放项的音频质量 +进行可视化指示 + +158 +00:08:58,805 --> 00:09:01,542 +例如此视图中的 Dolby Atmos + +159 +00:09:01,575 --> 00:09:04,511 +MusicKit 播放器 API +会根据用户设置 + +160 +00:09:04,545 --> 00:09:08,382 +和网络条件自动选择正确的音频质量 + +161 +00:09:09,216 --> 00:09:11,518 +要从播放器访问活动特征 + +162 +00:09:11,552 --> 00:09:15,122 +首先 我们访问观察对象中 + +163 +00:09:15,155 --> 00:09:17,157 +ApplicationMusicPlayer 的播放状态 + +164 +00:09:17,191 --> 00:09:21,728 +然后 我们可以直接从播放状态 +访问活动的 audioVariant + +165 +00:09:21,762 --> 00:09:24,031 +现在 我们只需检查 +audioVariant 属性 + +166 +00:09:24,064 --> 00:09:27,734 +看看它是否是 dolbyAtmos +如果是 则添加额外的 UI + +167 +00:09:27,768 --> 00:09:30,204 +因为播放状态是观察到的对象 + +168 +00:09:30,237 --> 00:09:32,272 +所以只要当前播放的项目发生更改 + +169 +00:09:32,306 --> 00:09:34,274 +此视图就会自动更新 + +170 +00:09:34,308 --> 00:09:37,311 +从而确保您的视图始终是最新的 + +171 +00:09:37,344 --> 00:09:39,680 +现在我们已经了解了一些目录添加 + +172 +00:09:39,713 --> 00:09:42,282 +让我们深入了解个性化内容 + +173 +00:09:42,316 --> 00:09:45,285 +个性化内容是特定于订阅者的数据 + +174 +00:09:45,319 --> 00:09:49,423 +为 App 中的每个用户 +提供独特的定制体验 + +175 +00:09:49,456 --> 00:09:52,526 +通常 个性化内容需要 +特殊的身份验证 + +176 +00:09:52,559 --> 00:09:55,395 +和用户令牌 但在 MusicKit 框架中 + +177 +00:09:55,429 --> 00:09:59,132 +我们已将其全部自动化 +因此您无需处理任何麻烦 + +178 +00:09:59,166 --> 00:10:01,502 +我们为开发人员提供的个性化内容是 + +179 +00:10:01,535 --> 00:10:03,770 +访问最近播放的项目 + +180 +00:10:03,804 --> 00:10:06,907 +和个人推荐 + +181 +00:10:06,940 --> 00:10:09,443 +最近播放的内容 + +182 +00:10:09,476 --> 00:10:12,279 +是个人音乐消费体验的宝贵数据 + +183 +00:10:12,312 --> 00:10:16,917 +它可以使您快速方便地访问 +他们喜欢的音乐项目 + +184 +00:10:16,950 --> 00:10:20,354 +当听新音乐时 它允许人们回头 + +185 +00:10:20,387 --> 00:10:22,489 +去查阅他们的听歌历史 + +186 +00:10:22,523 --> 00:10:25,526 +要获取最近播放的容器 +如专辑 播放列表 + +187 +00:10:25,559 --> 00:10:29,730 +和电台 您可以创建 +最近播放的容器请求 + +188 +00:10:29,763 --> 00:10:32,432 +请注意 如果您要播放 +播放列表或专辑中的歌曲 + +189 +00:10:32,466 --> 00:10:34,635 +就需要检索容器类型 + +190 +00:10:34,668 --> 00:10:38,138 +在响应中 +您会发现最近播放的音乐项目 + +191 +00:10:38,172 --> 00:10:43,443 +您可以轻松地访问标题 +副标题和插图 + +192 +00:10:43,477 --> 00:10:46,947 +您还可以获取最近播放的 +更具体类型的项目 + +193 +00:10:46,980 --> 00:10:48,882 +如歌曲或电台 + +194 +00:10:48,916 --> 00:10:52,653 +这里 我们创建一个最近播放的请求 + +195 +00:10:52,686 --> 00:10:56,490 +通过由尖括号指示的 +泛型参数指定歌曲类型 + +196 +00:10:56,523 --> 00:10:59,693 +我们的响应现在只包含 +我们播放的歌曲 + +197 +00:10:59,726 --> 00:11:02,596 +现在 谈谈个人推荐 + +198 +00:11:02,629 --> 00:11:07,067 +个人推荐可以让您的 App 体验 +更加亲密和吸引人 + +199 +00:11:07,100 --> 00:11:11,905 +因为它们是基于用户的曲库 +和听歌历史产生的 + +200 +00:11:11,939 --> 00:11:14,575 +推荐会按照主题整齐排列 + +201 +00:11:14,608 --> 00:11:20,147 +按照流派 艺术家 收藏 +如“为您而做”等进行分组 + +202 +00:11:20,180 --> 00:11:22,683 +要获取个人推荐 + +203 +00:11:22,716 --> 00:11:25,552 +只需创建个人推荐请求即可 + +204 +00:11:25,586 --> 00:11:28,388 +响应是一系列推荐 + +205 +00:11:28,422 --> 00:11:32,092 +当我们记录第一个推荐时 +我们可以看到这个特定的元素 + +206 +00:11:32,125 --> 00:11:34,595 +代表“为您而做”的推荐 + +207 +00:11:34,628 --> 00:11:38,632 +推荐包含 ID 标题和 nextRefreshDate + +208 +00:11:38,665 --> 00:11:42,135 +nextRefreshDate 表示刷新此推荐 + +209 +00:11:42,169 --> 00:11:45,372 +以获得最新建议的日期和时间 + +210 +00:11:45,405 --> 00:11:49,109 +播放列表属性包含 +“为我而做”的所有播放列表 + +211 +00:11:49,142 --> 00:11:52,446 +让我们看看另一个推荐的例子 + +212 +00:11:52,479 --> 00:11:56,250 +在这里 我们将打印 +推荐响应的第二个元素 + +213 +00:11:56,283 --> 00:11:59,820 +我听了一大堆另类音乐 +这个推荐包含了 + +214 +00:11:59,853 --> 00:12:04,391 +不同类型的混合 +在这个例子中为专辑和播放列表 + +215 +00:12:04,424 --> 00:12:06,994 +它们被分组在一个单独的项目集合中 + +216 +00:12:07,027 --> 00:12:11,131 +这些项目是按照相关性排序的 +类似于目录搜索的最匹配结果 + +217 +00:12:11,164 --> 00:12:14,868 +现在 让我们更进一步谈谈如何通过 + +218 +00:12:14,902 --> 00:12:17,371 +将用户曲库中的内容整合到 App 中 + +219 +00:12:17,404 --> 00:12:21,175 +来创造更多与音乐相关的体验 + +220 +00:12:21,208 --> 00:12:25,312 +今年 MusicKit 允许 App +通过两种请求 + +221 +00:12:25,345 --> 00:12:28,749 +从曲库中提取项目 曲库请求 + +222 +00:12:28,782 --> 00:12:31,485 +和曲库分段请求 + +223 +00:12:31,518 --> 00:12:34,588 +搜索用户曲库中的内容 + +224 +00:12:34,621 --> 00:12:37,524 +并专门从曲库中 + +225 +00:12:37,558 --> 00:12:39,927 +加载扩展属性和关系 + +226 +00:12:39,960 --> 00:12:42,296 +在我们看到技术细节之前 + +227 +00:12:42,329 --> 00:12:45,566 +让我们看看如何使用曲库内容 +来增强 App + +228 +00:12:45,599 --> 00:12:48,435 +我一直在开发一款名为 +Music Marathon 的健身 App + +229 +00:12:48,468 --> 00:12:50,704 +它将跟踪您的户外跑步情况 + +230 +00:12:50,737 --> 00:12:52,906 +通过在项目中加入 MusicKit + +231 +00:12:52,940 --> 00:12:55,509 +人们可以直接通过该 App 播放音乐 + +232 +00:12:55,542 --> 00:12:59,546 +而无需在 Apple Music App +和这个 App 之间切换 + +233 +00:12:59,580 --> 00:13:03,016 +我们开始一次新的训练 +寻找音乐内容 + +234 +00:13:04,818 --> 00:13:07,154 +我们在这里看到一些 +从个人推荐请求中 + +235 +00:13:07,187 --> 00:13:09,122 +检索到的推荐播放列表 + +236 +00:13:09,156 --> 00:13:12,860 +以便人们快速访问我们认为 +他们会喜欢的播放列表 + +237 +00:13:12,893 --> 00:13:17,531 +转到“曲库”选项卡 +我们可以看到它是一个空视图 + +238 +00:13:17,564 --> 00:13:20,267 +如果能看到我所有的 +个人播放列表就太好了 + +239 +00:13:20,300 --> 00:13:21,835 +所以让我们来写这个特性吧 + +240 +00:13:21,869 --> 00:13:25,439 +我已经设置了一些 UI 来处理 +这个视图的基本内容 + +241 +00:13:25,472 --> 00:13:29,109 +现在我想从曲库中加载播放列表 + +242 +00:13:29,142 --> 00:13:30,777 +首先 我会向曲库申请 + +243 +00:13:33,647 --> 00:13:35,749 +在泛型参数中指定播放列表 + +244 +00:13:35,782 --> 00:13:38,785 +以表明我们需要用户曲库中的 +播放列表 + +245 +00:13:42,256 --> 00:13:44,958 +我把它存储在一个局部变量里 +将其命名为“请求” + +246 +00:13:47,928 --> 00:13:51,098 +接下来 我将接受这个请求 +并调用响应函数 + +247 +00:13:53,867 --> 00:13:56,403 +此方法为异步抛出方法 + +248 +00:13:56,436 --> 00:13:58,572 +让我们添加尝试和等待的关键字 + +249 +00:13:58,605 --> 00:14:01,441 +并再次将其存储在响应变量中 + +250 +00:14:04,311 --> 00:14:07,614 +然后 我将更新状态对象 +以接收此响应 + +251 +00:14:11,752 --> 00:14:14,555 +现在要做的就是更新列表 + +252 +00:14:14,588 --> 00:14:17,457 +这样我们就可以在 UI 中 +看到播放列表了 + +253 +00:14:17,491 --> 00:14:21,228 +我将使用 ForEach 迭代响应中的项 + +254 +00:14:25,432 --> 00:14:28,669 +并检索 MusicItemCollection 中的 +每个播放列表 + +255 +00:14:30,404 --> 00:14:31,638 +现在我们已经有了播放列表 + +256 +00:14:31,672 --> 00:14:33,941 +我将把它们传递到 +我已经制作的 PlaylistCell 中 + +257 +00:14:35,642 --> 00:14:37,644 +现在如果我们重新运行 + +258 +00:14:44,017 --> 00:14:46,753 +然后导航回到 App + +259 +00:14:46,787 --> 00:14:50,057 +我们可以在曲库里看到 +我所有的个人播放列表 + +260 +00:14:50,090 --> 00:14:52,826 +现在 我可以选择听个人推荐 + +261 +00:14:52,860 --> 00:14:57,097 +Apple Music 目录中的内容 +以及我自己的个人曲库 + +262 +00:14:57,130 --> 00:15:00,467 +现在我们已经了解了 +访问曲库内容有多么容易 + +263 +00:15:00,501 --> 00:15:02,569 +让我们看看曲库请求还能做些什么 + +264 +00:15:02,603 --> 00:15:05,239 +音乐曲库请求是一个强大的 API + +265 +00:15:05,272 --> 00:15:07,741 +可以从用户的曲库中获取项目 + +266 +00:15:07,774 --> 00:15:11,845 +在 iOS 上 与其他从音乐目录中 +获取内容的请求不同 + +267 +00:15:11,879 --> 00:15:15,682 +MusicLibraryRequest 实际上 +不会从网络加载数据 + +268 +00:15:15,716 --> 00:15:19,152 +相反 它将从存储在设备上的 + +269 +00:15:19,186 --> 00:15:21,622 +用户曲库副本中加载项目 + +270 +00:15:21,655 --> 00:15:24,591 +这个请求的基本内容只要求您指定 + +271 +00:15:24,625 --> 00:15:27,027 +想要的音乐项目类型 + +272 +00:15:27,060 --> 00:15:29,429 +此项目类型通过 +MusicLibraryRequest 的 + +273 +00:15:29,463 --> 00:15:32,332 +泛型参数传递 + +274 +00:15:32,366 --> 00:15:36,003 +您可以对请求应用各种 +过滤器和排序选项 + +275 +00:15:36,036 --> 00:15:39,873 +以便对调用进行微调 +使其与您的需求相匹配 + +276 +00:15:39,907 --> 00:15:43,710 +此请求还能够获取已经下载的内容 + +277 +00:15:43,744 --> 00:15:46,947 +支持完全脱机体验 + +278 +00:15:46,980 --> 00:15:50,450 +让我们从简单的基本请求开始 +就像我们在 + +279 +00:15:50,484 --> 00:15:55,322 +Music Marathon App 中写的那样 +但这次我们请求的是曲库中的专辑 + +280 +00:15:55,355 --> 00:15:58,625 +专辑类型通过泛型参数来指定 + +281 +00:15:58,659 --> 00:16:01,695 +要执行请求 请调用响应函数 + +282 +00:16:01,728 --> 00:16:04,898 +看看输出 我们有一个 +MusicLibraryResponse + +283 +00:16:04,932 --> 00:16:07,334 +其中的项目是用户音乐曲库中 + +284 +00:16:07,367 --> 00:16:11,104 +找到的所有专辑的 MusicItemCollection + +285 +00:16:11,138 --> 00:16:14,541 +在这里 我们注意到 +这些专辑与您从我们的 + +286 +00:16:14,575 --> 00:16:19,346 +各种目录请求中得到的专辑结构相同 +并且具有相同的功能 + +287 +00:16:19,379 --> 00:16:22,649 +而在本例中 +我们将获取曲库中的每个专辑 + +288 +00:16:22,683 --> 00:16:27,221 +我们知道在某些情况下 +您只需要专辑的一个特定子集 + +289 +00:16:27,254 --> 00:16:31,458 +这就是为什么 MusicLibraryRequest +还可以让您更具体地 + +290 +00:16:31,491 --> 00:16:34,595 +说明要从曲库中提取哪些项目 + +291 +00:16:34,628 --> 00:16:38,665 +我们以之前写的同样的请求为例 +并添加一个过滤器 + +292 +00:16:38,699 --> 00:16:42,369 +这里 我们希望加载 +isCompilation 属性为 true 的 + +293 +00:16:42,402 --> 00:16:43,971 +所有专辑 + +294 +00:16:44,004 --> 00:16:47,941 +当您调用过滤器方法时 +Xcode 的自动完成功能 + +295 +00:16:47,975 --> 00:16:52,212 +只会为您请求的项目类型 +提供特定的关键路径 + +296 +00:16:52,246 --> 00:16:56,283 +现在 响应中只有编译过的专辑 + +297 +00:16:56,316 --> 00:16:59,653 +但这并不是 MusicLibraryRequest +所能提供的全部功能 + +298 +00:16:59,686 --> 00:17:01,655 +您可以链接多个过滤器 + +299 +00:17:01,688 --> 00:17:04,958 +为您提供更精确的请求 + +300 +00:17:04,992 --> 00:17:08,862 +如果我们想要 +某一特定流派的所有汇编呢 + +301 +00:17:08,896 --> 00:17:11,331 +我们可以向请求添加另一个过滤器 + +302 +00:17:11,365 --> 00:17:15,002 +例如 这里有一个名为 +“Dance”的流派实例 + +303 +00:17:15,035 --> 00:17:18,305 +您可以根据流派的关系进行过滤 + +304 +00:17:18,338 --> 00:17:22,309 +以将结果限制为仅显示 +包含此特定流派的编辑 + +305 +00:17:22,342 --> 00:17:25,746 +现在我们的响应只包含舞蹈汇编 + +306 +00:17:25,779 --> 00:17:29,283 +如果只包括已经下载的舞蹈汇编如何 + +307 +00:17:29,316 --> 00:17:32,252 +为此 只需将请求中的 +includeOnlyDownloadedContent + +308 +00:17:32,286 --> 00:17:33,787 +设置为 true + +309 +00:17:33,820 --> 00:17:34,955 +就是这样了 + +310 +00:17:34,988 --> 00:17:37,891 +响应是相同的 MusicLibraryResponse + +311 +00:17:37,925 --> 00:17:41,662 +但项目现在只包含下载的元素 + +312 +00:17:41,695 --> 00:17:45,165 +正如您所看到的 +音乐曲库请求功能非常强大 + +313 +00:17:45,199 --> 00:17:50,204 +并解锁了定制 MusicDataRequest +无法实现的新功能 + +314 +00:17:50,237 --> 00:17:54,842 +但 MusicKit 提供了更多 +从用户曲库中获取数据的选项 + +315 +00:17:54,875 --> 00:17:57,611 +来看看 Library Sectioned Request + +316 +00:17:57,644 --> 00:18:02,082 +分段请求能够获取按段分组的项目 + +317 +00:18:02,115 --> 00:18:06,987 +因此 分段请求接受 +两个不同的泛型参数 + +318 +00:18:07,020 --> 00:18:11,758 +第一个表示段类型 +第二个表示项类型 + +319 +00:18:11,792 --> 00:18:14,661 +曲库分段请求支持 +与常规曲库请求相同的功能 + +320 +00:18:14,695 --> 00:18:18,098 +例如您可以应用于段或项的 + +321 +00:18:18,131 --> 00:18:23,470 +各种过滤和排序方法 + +322 +00:18:23,504 --> 00:18:26,874 +以下是如何使用曲库分段请求 + +323 +00:18:26,907 --> 00:18:29,743 +来获取所有按其流派分段的专辑 + +324 +00:18:29,776 --> 00:18:33,647 +分段响应包含一个名为 +“段”的属性 其中每个元素 + +325 +00:18:33,680 --> 00:18:38,318 +对应于请求的第一个泛型参数 +在本例中为 Genre + +326 +00:18:38,352 --> 00:18:42,456 +每个流派不仅公开了自己的属性 +而且还包含一个 + +327 +00:18:42,489 --> 00:18:46,660 +专辑集合 可通过项属性访问 + +328 +00:18:46,693 --> 00:18:50,030 +这些项目对应于第二个泛型参数 + +329 +00:18:50,063 --> 00:18:53,367 +在这里突出显示 +专辑的类型是 Alternative + +330 +00:18:53,400 --> 00:18:56,937 +正如前面提到的 过滤和排序功能 + +331 +00:18:56,970 --> 00:18:59,706 +也可以用于这个分段请求 + +332 +00:18:59,740 --> 00:19:02,643 +假设我们想要相同的专辑 +按流派进行分类 + +333 +00:19:02,676 --> 00:19:05,979 +但这些专辑是按艺术家的名字排序的 + +334 +00:19:06,013 --> 00:19:07,681 +我们添加一个排序过滤器 + +335 +00:19:07,714 --> 00:19:11,585 +通过在专辑上指定 +artistName keyPath 并说明 + +336 +00:19:11,618 --> 00:19:15,055 +我们希望这些是升序的 +对响应进行排序 + +337 +00:19:15,088 --> 00:19:18,592 +请注意 该方法是排序项 +因为我们指定了 + +338 +00:19:18,625 --> 00:19:21,662 +要应用于项目而不是段的排序 + +339 +00:19:21,695 --> 00:19:23,564 +如果我们想要指定段 + +340 +00:19:23,597 --> 00:19:27,668 +可以使用一组 +filterSections 和 sortSection 方法 + +341 +00:19:27,701 --> 00:19:29,670 +让我们来看看新的响应结果 + +342 +00:19:32,139 --> 00:19:35,776 +我们现在可以看到我们的专辑 +是按艺术家名字的字母顺序排列的 + +343 +00:19:35,809 --> 00:19:37,811 +而不是按标题 + +344 +00:19:37,845 --> 00:19:42,516 +曲库请求和曲库分段请求都非常强大 + +345 +00:19:42,549 --> 00:19:45,485 +但是您可能还想通过 +添加用户曲库中的 + +346 +00:19:45,519 --> 00:19:48,655 +搜索结果来补充您的音乐搜索 UI + +347 +00:19:48,689 --> 00:19:52,593 +我们添加了一个新的结构化请求 +它的操作与目录搜索几乎相同 + +348 +00:19:52,626 --> 00:19:54,962 +但它不是从目录中加载结果 + +349 +00:19:54,995 --> 00:19:59,666 +而是在用户的曲库中找到相关的项目 + +350 +00:19:59,700 --> 00:20:02,669 +与对应的目录一样 曲库搜索请求 + +351 +00:20:02,703 --> 00:20:06,773 +只需要一个搜索词和一个类型数组 + +352 +00:20:06,807 --> 00:20:10,244 +现在我们已经了解了 +从用户曲库中检索项目的不同方法 + +353 +00:20:10,277 --> 00:20:13,814 +那么加载扩展属性和关系怎么样 + +354 +00:20:13,847 --> 00:20:17,784 +您可能知道 MusicKit 的初始版本 +引入了 with 方法 + +355 +00:20:17,818 --> 00:20:22,189 +以一种简单的方式从 +Apple Music API 加载这些属性 + +356 +00:20:22,222 --> 00:20:24,658 +今年 我们增加了 Current with 方法 + +357 +00:20:24,691 --> 00:20:28,195 +还引入了一个首选源参数 + +358 +00:20:28,228 --> 00:20:32,299 +对于 Apple Music 目录 +和用户曲库中均可用的 + +359 +00:20:32,332 --> 00:20:36,170 +扩展属性和关系 +此首选源指示从何处 + +360 +00:20:36,203 --> 00:20:38,438 +加载数据 + +361 +00:20:38,472 --> 00:20:41,942 +对于只存在于目录或曲库中的属性 + +362 +00:20:41,975 --> 00:20:44,711 +无论首选源是什么 它们都将被提取 + +363 +00:20:44,745 --> 00:20:47,581 +以确保不会忽略任何内容 + +364 +00:20:47,614 --> 00:20:49,950 +此外 无论初始项目来自何处 + +365 +00:20:49,983 --> 00:20:52,419 +无论是目录请求 曲库请求 + +366 +00:20:52,452 --> 00:20:56,390 +还是其他地方 都可以使用此功能 + +367 +00:20:56,423 --> 00:20:57,958 +它都很管用 + +368 +00:20:58,959 --> 00:21:02,963 +这里我们了解了已知的 +接收音乐项关系的方法 + +369 +00:21:02,996 --> 00:21:06,700 +我们正在加载一张专辑的曲目 +当我们显示输出时 + +370 +00:21:06,733 --> 00:21:09,269 +可以看到该专辑的所有曲目 + +371 +00:21:09,303 --> 00:21:13,574 +但是 通过新添加的 +preferredSource 属性 + +372 +00:21:13,607 --> 00:21:15,242 +我们可以指定希望从曲库中 + +373 +00:21:15,275 --> 00:21:17,578 +获取这种关系 + +374 +00:21:17,611 --> 00:21:22,349 +现在 我们的输出只包含 +在曲库中找到的专辑的曲目 + +375 +00:21:22,382 --> 00:21:25,886 +现在 您可以通过各种方式 +从用户的曲库中获取项目 + +376 +00:21:25,919 --> 00:21:28,655 +但只有允许用户通过 MusicKit + +377 +00:21:28,689 --> 00:21:31,358 +直接与曲库交互才有意义 + +378 +00:21:31,391 --> 00:21:34,228 +让我们回到我的示例 App +Music Marathon + +379 +00:21:34,261 --> 00:21:37,164 +看看这个曲库提供的一些功能 + +380 +00:21:37,197 --> 00:21:39,333 +在我训练的时候 我想浏览一下 + +381 +00:21:39,366 --> 00:21:40,834 +我的个人推荐 + +382 +00:21:43,270 --> 00:21:45,839 +当我浏览这些曲目时 +发现这些歌曲中 + +383 +00:21:45,873 --> 00:21:47,975 +有一首非常适合我的训练播放列表 + +384 +00:21:48,008 --> 00:21:51,311 +如果按住其中一个单元格 +就会弹出一个快捷菜单 + +385 +00:21:51,345 --> 00:21:53,881 +允许我将这首歌添加到播放列表中 + +386 +00:21:53,914 --> 00:21:57,851 +当我们按下它时 +我所有的播放列表再次弹出 + +387 +00:21:57,885 --> 00:22:01,555 +我们来编写代码 将选定的曲目 +添加到我选择的播放列表中 + +388 +00:22:01,588 --> 00:22:05,025 +我已经将所选项目通过管道 +传输到 AddToPlaylistCell 单元 + +389 +00:22:05,058 --> 00:22:09,229 +所以我们所要做的就是 +通过共享实例访问 MusicLibrary + +390 +00:22:13,534 --> 00:22:16,703 +我们将调用“add”方法 + +391 +00:22:16,737 --> 00:22:18,972 +指定我们选择的曲目 + +392 +00:22:19,006 --> 00:22:21,275 +和要添加到哪个播放列表 + +393 +00:22:23,343 --> 00:22:25,812 +这个方法也是一个异步抛出函数 + +394 +00:22:25,846 --> 00:22:28,815 +所以我们再次添加 +尝试和等待的关键字 + +395 +00:22:31,084 --> 00:22:33,053 +最后 我们通过将 + +396 +00:22:33,086 --> 00:22:36,490 +isShowingPlaylistPicker 绑定变量 +设置为 false 来关闭选取器 + +397 +00:22:38,225 --> 00:22:40,827 +现在 如果我们重新运行 + +398 +00:22:40,861 --> 00:22:44,598 +并向播放列表中添加一首曲目 +并选择其中一个播放列表 + +399 +00:22:44,631 --> 00:22:47,901 +我们应该会看到添加了此项目 + +400 +00:22:47,935 --> 00:22:50,704 +导航回 App 中的曲库选项卡 + +401 +00:22:50,737 --> 00:22:53,607 +我们可以看到歌曲现在已添加到 +我们的训练播放列表中 + +402 +00:22:53,640 --> 00:22:56,443 +向播放列表中添加项目就是这么简单 + +403 +00:22:56,476 --> 00:22:59,913 +让我们看看这个曲库提供的 +其他一些功能 + +404 +00:22:59,947 --> 00:23:03,317 +与曲库交互的各种其他方式包括 + +405 +00:23:03,350 --> 00:23:06,420 +向曲库添加内容 创建播放列表 + +406 +00:23:06,453 --> 00:23:10,524 +以及编辑播放列表的元数据 +和曲目列表 + +407 +00:23:10,557 --> 00:23:14,728 +向用户的音乐库添加内容 +可以让人们在 Apple Music App 的 + +408 +00:23:14,761 --> 00:23:18,532 +曲库选项卡中找到 +特定的歌曲或专辑 + +409 +00:23:18,565 --> 00:23:21,134 +以及在设置中打开 Sync Library 时 + +410 +00:23:21,168 --> 00:23:24,338 +在所有设备之间进行同步 + +411 +00:23:24,371 --> 00:23:27,474 +在您的 App 中直接 +提供此功能可以避免人们 + +412 +00:23:27,508 --> 00:23:30,878 +在 Apple Music App +和您的 App 之间切换 + +413 +00:23:30,911 --> 00:23:34,515 +这样他们就可以 +继续关注您提供的内容 + +414 +00:23:34,548 --> 00:23:36,917 +此外 通过将添加 + +415 +00:23:36,950 --> 00:23:39,586 +和新引入的曲库请求集成在一起 + +416 +00:23:39,620 --> 00:23:42,322 +您的 App 可以立即 +从这些结果中受益 + +417 +00:23:42,356 --> 00:23:46,026 +让用户轻松访问他们喜欢的内容 + +418 +00:23:46,059 --> 00:23:47,928 +即使有了这种强大的服务 + +419 +00:23:47,961 --> 00:23:51,331 +您可能还是想创造特殊的音乐体验 + +420 +00:23:51,365 --> 00:23:56,236 +因此今年 我们将播放列表的 +创建和编辑引入 MusicKit + +421 +00:23:56,270 --> 00:23:59,806 +现在 您可以代表用户创建播放列表 + +422 +00:23:59,840 --> 00:24:03,277 +我们还可以将歌曲 +甚至整个专辑等项目 + +423 +00:24:03,310 --> 00:24:07,447 +添加到用户曲库中的 +任何符合条件的播放列表中 + +424 +00:24:07,481 --> 00:24:11,151 +创建播放列表非常适合 +将人们喜欢的内容分组 + +425 +00:24:11,185 --> 00:24:14,188 +或者根据情绪设置 App + +426 +00:24:14,221 --> 00:24:16,557 +通过向现有的播放列表添加内容 + +427 +00:24:16,590 --> 00:24:19,860 +您可以使用 MusicKit 提供的 +各种音乐发现工具 + +428 +00:24:19,893 --> 00:24:22,629 +来直接影响用户 + +429 +00:24:22,663 --> 00:24:24,898 +您现在还可以编辑已创建的播放列表 + +430 +00:24:24,932 --> 00:24:28,402 +可以编辑曲目列表和元数据 +以确保 + +431 +00:24:28,435 --> 00:24:30,504 +一切都符合您的需要 + +432 +00:24:30,537 --> 00:24:33,507 +这些就是您可以在 App 中 + +433 +00:24:33,540 --> 00:24:35,776 +与用户曲库交互的方式 + +434 +00:24:35,809 --> 00:24:39,713 +总而言之 MusicKit 今年 +进行了一些重大升级 + +435 +00:24:39,746 --> 00:24:43,750 +轻松将我们针对新类型属性的 +目录增强功能 + +436 +00:24:43,784 --> 00:24:47,988 +和搜索增强功能整合到现有 App 中 +以获得更好的体验 + +437 +00:24:49,256 --> 00:24:51,458 +集成曲库内容和功能 + +438 +00:24:51,491 --> 00:24:53,260 +以解锁全新的功能 + +439 +00:24:53,293 --> 00:24:55,596 +并让用户控制自己的体验 + +440 +00:24:57,130 --> 00:25:00,367 +使用 MusicKit 可以增强 +多种不同类型的 App + +441 +00:25:00,400 --> 00:25:03,637 +健身 App 游戏 社交媒体 App +地图 App 等 + +442 +00:25:03,670 --> 00:25:07,975 +都可以从播放或分享音乐中受益 + +443 +00:25:08,008 --> 00:25:12,012 +欲了解更多信息 +请查看更多相关讲座 + +444 +00:25:12,045 --> 00:25:14,681 +深入研究 Swift +了解该语言的新增功能 + +445 +00:25:14,715 --> 00:25:19,620 +以充分利用 MusicKit +和其他 Apple 框架 + +446 +00:25:19,653 --> 00:25:23,257 +查看2021年的 MusicKit 讲座 +学习如何设置 App + +447 +00:25:23,290 --> 00:25:28,662 +来使用框架 启动回放 +并提供订阅优惠 + +448 +00:25:28,695 --> 00:25:32,432 +如果您有兴趣在 Android 或 web 上 +与 Apple Music 集成 + +449 +00:25:32,466 --> 00:25:36,370 +我们还有一个讲座 +讨论了如何直接使用 Apple Music API + +450 +00:25:37,538 --> 00:25:40,207 +希望您喜欢我们的讲座 +并通过我们的开发者论坛 + +451 +00:25:40,240 --> 00:25:42,442 +保持更新和参与 + +452 +00:25:42,476 --> 00:25:46,847 +感谢观看 +请享受您的 WWDC 2022 之旅吧 + diff --git a/zho/2022 Session 110348 Build your first app in Swift Playgrounds.srt b/zho/2022 Session 110348 Build your first app in Swift Playgrounds.srt new file mode 100644 index 0000000..0bc7c26 --- /dev/null +++ b/zho/2022 Session 110348 Build your first app in Swift Playgrounds.srt @@ -0,0 +1,1030 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:13,447 +欢迎来到“在 Swift Playgrounds 中 +构建您的首个 App” + +3 +00:00:13,480 --> 00:00:17,684 +我是 Swift Playgrounds 团队的工程师 +Collett Charlton + +4 +00:00:17,718 --> 00:00:19,019 +我是 Connor Wakamo + +5 +00:00:19,052 --> 00:00:21,588 +Swift Playgrounds 团队的 +另一位工程师 + +6 +00:00:21,622 --> 00:00:26,159 +Swift Playgrounds +是学习 Swift 编码的绝佳工具 + +7 +00:00:26,193 --> 00:00:31,498 +现在您可以更进一步 +可以通过它构建 App! + +8 +00:00:31,532 --> 00:00:36,170 +今天 我们将介绍在 Swift Playgrounds 中 +如何从一个空白模版 + +9 +00:00:36,203 --> 00:00:38,472 +构建一个 App + +10 +00:00:38,505 --> 00:00:42,809 +然后我们将展示 +如何使用预览和控制台进行调试 + +11 +00:00:42,843 --> 00:00:46,446 +最后 我们会将 App +提交给 TestFlight + +12 +00:00:48,282 --> 00:00:52,719 +我们的团队非常喜欢泡茶和喝茶 + +13 +00:00:52,753 --> 00:00:56,857 +我们非常喜欢这个活动 +以至于我们想为此制作一个 App + +14 +00:00:56,890 --> 00:01:01,094 +Connor 和我将构建一个 App +来帮助我们在下午茶时间 + +15 +00:01:01,128 --> 00:01:06,033 +提供给我们一份茶清单 +用来帮助我们选择每天喝什么 + +16 +00:01:06,066 --> 00:01:09,970 +Swift Playgrounds +在 Mac 和 iPad 上工作得很好 + +17 +00:01:10,003 --> 00:01:11,738 +因为我今天带着 Mac 电脑 + +18 +00:01:11,772 --> 00:01:15,008 +所以我要开始在这里构建这个 App + +19 +00:01:17,044 --> 00:01:20,614 +无论您是编程新手 +还是经验丰富的开发者 + +20 +00:01:20,647 --> 00:01:25,018 +Swift Playgrounds +都会为您提供开始编程的 + +21 +00:01:25,052 --> 00:01:26,753 +各种模版和教学内容 + +22 +00:01:26,787 --> 00:01:31,391 +对于开发我们的选茶 App +我们要首先单击空白 App 模板 + +23 +00:01:31,425 --> 00:01:33,827 +它在屏幕的左下角 + +24 +00:01:37,431 --> 00:01:40,801 +现在我们有了模板 让我们双击打开 + +25 +00:01:42,636 --> 00:01:48,442 +好了 右侧的实时交互式预览里 +显示了“Hello World”文本 + +26 +00:01:50,777 --> 00:01:55,549 +在我们开始写代码前 要使用 App 设置 +对程序进行一些功能的自定义 + +27 +00:01:55,582 --> 00:01:58,485 +为此 我需要单击边栏左上角的 + +28 +00:01:58,519 --> 00:02:00,988 +App Settings (App 设置) 按钮 + +29 +00:02:02,356 --> 00:02:06,660 +在这里 您可以自定义各种项目属性 +例如 App 名称 + +30 +00:02:06,693 --> 00:02:08,695 +和主题颜色 + +31 +00:02:08,729 --> 00:02:12,399 +您还可以添加自定义 +或占位符程序图标 + +32 +00:02:12,432 --> 00:02:17,437 +软件功能或用途的 +描述字符串和 Bundle ID + +33 +00:02:17,471 --> 00:02:20,274 +我会将 App 的名称 +更改为“Tea Time” + +34 +00:02:23,477 --> 00:02:25,679 +然后将主题颜色设置为棕色 + +35 +00:02:27,047 --> 00:02:30,217 +然后把程序图标换成 +咖啡杯的占位符图标 + +36 +00:02:32,252 --> 00:02:35,756 +好的 现在重要的部分已经设置完毕 + +37 +00:02:35,789 --> 00:02:39,393 +让我们通过选择模板文本 +开始编写一些代码 + +38 +00:02:39,426 --> 00:02:43,163 +并将其替换为 +我们在库中的第一个视图 + +39 +00:02:44,131 --> 00:02:50,237 +可以通过单击项目工具栏 +中的加号按钮访问库 + +40 +00:02:50,270 --> 00:02:53,807 +它包含易于使用的 +代码片段 如:视图 + +41 +00:02:53,841 --> 00:02:59,379 +修饰符、SF 符号和颜色 + +42 +00:02:59,413 --> 00:03:03,016 +我们将使用列表视图 +来显示我们的茶列表 + +43 +00:03:03,050 --> 00:03:07,921 +所以我将在搜索中键入 list (列表) +并单击将其插入代码段 + +44 +00:03:11,258 --> 00:03:14,895 +现在我们有了列表视图 +下面向其中添加一些茶的项目 + +45 +00:03:16,363 --> 00:03:19,132 +我将开始输入文本… + +46 +00:03:19,166 --> 00:03:20,734 +并使用回车键 + +47 +00:03:20,767 --> 00:03:23,670 +从内联代码完成面板 + +48 +00:03:23,704 --> 00:03:26,240 +接受并插入建议的完整代码 + +49 +00:03:30,711 --> 00:03:35,048 +好的 现在我们的列表视图里 +有了一个茶项目 + +50 +00:03:35,082 --> 00:03:36,884 +让我们再添加一些 + +51 +00:03:42,289 --> 00:03:46,460 +等等 我好像不小心 +加了两次“茉莉绿茶” + +52 +00:03:46,493 --> 00:03:51,431 +为了避免我们输入重复 我们应该 +将它们存储为 orderedSet + +53 +00:03:51,465 --> 00:03:56,069 +幸运的是 Apple 的 swift-collection 包 +提供了这一功能 + +54 +00:03:56,103 --> 00:03:59,306 +所以 让我们将 swift-collection 包 +添加到我们的项目中 + +55 +00:04:00,574 --> 00:04:04,578 +为此 让我们打开“文件”菜单 +并选择 Add Package (添加软件包) + +56 +00:04:07,681 --> 00:04:11,985 +我将首先输入 swift-collections 包 +的 URL 地址 + +57 +00:04:12,019 --> 00:04:12,853 +然后按回车键 + +58 +00:04:17,357 --> 00:04:20,294 +获取包后 我们需要查看包的版本 + +59 +00:04:20,327 --> 00:04:23,664 +以及其他可以添加到 +我们项目中的功能 + +60 +00:04:23,697 --> 00:04:28,335 +对于这个 App 我们将只选择 Collections (合集) +然后单击 Add to Project (添加至项目) + +61 +00:04:31,772 --> 00:04:36,577 +现在我们在 Packages 下的侧边栏中将 +swift-collections 添加到我们的项目中 + +62 +00:04:36,610 --> 00:04:41,381 +让我们创建一个 String 类型的 +OrderedSet 用来存储我们的茶列表 + +63 +00:04:47,421 --> 00:04:50,824 +等等 好像我们的程序有点问题 + +64 +00:04:50,858 --> 00:04:53,393 +让我们通过点击问题图标来看看 + +65 +00:04:54,928 --> 00:04:57,497 +“在范围内找不到类型有序集” + +66 +00:04:57,531 --> 00:05:00,701 +哦 我明白是什么问题了 + +67 +00:05:00,734 --> 00:05:03,937 +我忘记在我们的项目中导入 +Collections 模块 + +68 +00:05:03,971 --> 00:05:06,373 +现在让我们导入它 +问题应该能得到解决 + +69 +00:05:13,046 --> 00:05:15,582 +现在我们已经解决了这个问题 + +70 +00:05:15,616 --> 00:05:19,419 +下面让我们更新列表视图 +以使用我们刚刚创建的集合 + +71 +00:05:19,453 --> 00:05:22,656 +为此 我们需要 +使用 ForEach 视图 + +72 +00:05:43,577 --> 00:05:45,712 +好的 这里就有内容了 + +73 +00:05:45,746 --> 00:05:49,449 +我们的列表正在从 +茶集合中展示各种茶的信息 + +74 +00:05:49,483 --> 00:05:51,919 +在我做这个项目时 + +75 +00:05:51,952 --> 00:05:55,789 +我对要添加的功能 +产生了越来越多的想法 + +76 +00:05:55,822 --> 00:06:00,127 +如果我们的 App 可以听到 +茶壶的叫声那就太酷了 + +77 +00:06:00,160 --> 00:06:02,896 +可以让我们知道什么时候倒茶 + +78 +00:06:02,930 --> 00:06:05,165 +我现在还不打算添加这个功能 + +79 +00:06:05,199 --> 00:06:07,835 +但让我们先来看看 将采取哪些做法 + +80 +00:06:07,868 --> 00:06:12,105 +才能向用户解释清楚为什么 +我们的 App 需要使用麦克风 + +81 +00:06:13,173 --> 00:06:17,344 +要添加它 +让我们回到我们的 App 设置 + +82 +00:06:17,377 --> 00:06:19,346 +并单击 Capability (功能) + +83 +00:06:20,714 --> 00:06:23,650 +使用右上角的加号按钮 + +84 +00:06:23,684 --> 00:06:27,020 +我们将看到 +可以添加到项目中的功能列表 + +85 +00:06:27,054 --> 00:06:30,490 +让我们找到“麦克风” +并点击“Add”将其添加 + +86 +00:06:31,358 --> 00:06:35,963 +对于目标描述字符串 +我们将编写:“Tea Time 使用麦克风 + +87 +00:06:35,996 --> 00:06:38,265 +监听茶壶的声音” + +88 +00:06:38,298 --> 00:06:41,702 +然后单击“Add” +关闭 App 设置 + +89 +00:06:44,738 --> 00:06:49,476 +好的 我们今天做了很多 +并且我非常高兴为您分享这个项目 + +90 +00:06:49,510 --> 00:06:52,212 +以及我与 Connor +在这个项目之中那些很酷的想法 + +91 +00:06:53,780 --> 00:06:57,818 +我会与 Connor 在我们共享的 +iCloud 文件夹中共享这个项目 + +92 +00:06:57,851 --> 00:07:01,955 +但首先 我们要给它起一个比 +My App 更好听的文件名称 + +93 +00:07:08,795 --> 00:07:12,566 +现在 我需要将文件拖拽到 +iCloud 共享文件夹中 + +94 +00:07:15,335 --> 00:07:20,007 +我已完成我的工作内容 现在我将 +交给 Connor 来完成这个 App + +95 +00:07:20,040 --> 00:07:23,844 +谢谢 Collett 我会在 +iPad 上完成优化这个项目 + +96 +00:07:23,877 --> 00:07:26,980 +由于我们是通过 iCloud 共享文件夹 +来共享我们的项目文件 + +97 +00:07:27,014 --> 00:07:29,583 +因此项目文件没有出现在 +Swift Playgrounds 的项目的主列表中 + +98 +00:07:29,616 --> 00:07:32,119 +但如果 +我点击 Locations (位置) + +99 +00:07:32,152 --> 00:07:34,888 +我就可以从 +iCloud 访问项目文件 + +100 +00:07:34,922 --> 00:07:37,758 +或者甚至可以从 +第三方文件提供商获取 + +101 +00:07:37,791 --> 00:07:39,760 +现在我已经处于 +我们的共享文件夹中 + +102 +00:07:39,793 --> 00:07:42,829 +所以我会点击 +Tea Time 文件来打开项目 + +103 +00:07:42,863 --> 00:07:47,067 +我所做的任何程序更改 +都会自动更新这个共享项目 + +104 +00:07:47,100 --> 00:07:49,803 +看起来 Collett +是个很好的工程师 + +105 +00:07:49,837 --> 00:07:53,473 +把只添加了一些额外功能 +的项目文件上传到 iCloud + +106 +00:07:53,507 --> 00:07:57,578 +她在这里实现了一个 TabView 控件 +所以我们的项目不只有一个茶列表 + +107 +00:07:57,611 --> 00:07:59,847 +同时它还是一个助手类程序 + +108 +00:07:59,880 --> 00:08:01,782 +如果我点击 Assistant (助手) 选项卡 + +109 +00:08:01,815 --> 00:08:04,952 +可以看到它非常简单 但可以工作 + +110 +00:08:04,985 --> 00:08:08,555 +我可以做一个推荐功能 +并且提供一些可能要喝的茶的建议 + +111 +00:08:09,957 --> 00:08:12,726 +看来今天我应该喝茉莉清茶 + +112 +00:08:13,694 --> 00:08:17,064 +现在我知道 Collett +正在制作一种有趣的选茶新方法 + +113 +00:08:17,097 --> 00:08:18,966 +为它添加一些有趣的风格 + +114 +00:08:18,999 --> 00:08:21,134 +让我们打开侧边栏来找找看 + +115 +00:08:23,403 --> 00:08:26,874 +看起来 TeaWheelView +像是我们正在找的 所以让我们打开它 + +116 +00:08:28,408 --> 00:08:31,945 +我们看到 +这里有一个收集数据集的视图 + +117 +00:08:31,979 --> 00:08:34,982 +让我们添加一个视图预览 +以便我们可以 + +118 +00:08:35,015 --> 00:08:37,584 +在 TeaWheelView +添加到主程序之前 先看看效果 + +119 +00:08:37,618 --> 00:08:39,520 +滑到文件的底部 + +120 +00:08:42,856 --> 00:08:45,325 +然后输入“PreviewProvider” + +121 +00:08:47,060 --> 00:08:50,531 +在这里我将通过按回车键 +来应用代码完成建议 + +122 +00:08:50,564 --> 00:08:54,234 +然后将其命名为 +TeaWheelView_Previews + +123 +00:08:56,436 --> 00:08:59,506 +在右侧预览区域的底部 +此时出现页面切换箭头 + +124 +00:08:59,540 --> 00:09:03,544 +这表示 Swift Playgrounds +可以识别我的程序 + +125 +00:09:03,577 --> 00:09:07,681 +如果我点击 +App 预览下方的右箭头… + +126 +00:09:07,714 --> 00:09:11,618 +这样就可以只使用我的视图预览 +而不是使用 App 的预览 + +127 +00:09:11,652 --> 00:09:13,620 +现在这里只显示了 +“Hello, world!” + +128 +00:09:13,654 --> 00:09:16,657 +那么现在让我们添加一些代码 +来创建 TeaWheelView + +129 +00:09:16,690 --> 00:09:20,694 +首先 我将添加一个 +包含一些条目的数组 作为静态属性 + +130 +00:09:20,727 --> 00:09:23,030 +以便于我的预览可以使用它们 + +131 +00:09:29,436 --> 00:09:31,972 +我会将光标放在两个方括号之间 + +132 +00:09:32,005 --> 00:09:35,976 +然后通过拖动右括号添加占位符 + +133 +00:09:40,447 --> 00:09:44,551 +接下来我将用 +条目内容描述字符串替换这些占位符 + +134 +00:09:52,626 --> 00:09:56,029 +现在我们已经有了一些条目 +让我们把它添加至 TeaWheelView + +135 +00:09:56,063 --> 00:09:57,865 +我会选择 Hello, world! 示例 + +136 +00:09:57,898 --> 00:10:01,001 +然后将其替换为显示刚创建的条目的 +TeaWheelView 实例 + +137 +00:10:10,811 --> 00:10:12,813 +我还需要 +添加一点 padding 空间 + +138 +00:10:16,049 --> 00:10:19,019 +太好了 现在我们的视图预览里 +显示了一个轮盘 + +139 +00:10:19,052 --> 00:10:20,888 +多漂亮的轮盘 + +140 +00:10:20,921 --> 00:10:26,527 +我可以旋转它 它会根据 +停止的位置 来选择不同的条目 + +141 +00:10:26,560 --> 00:10:30,631 +让我们回到助手选项卡 +并添加这个轮盘 + +142 +00:10:30,664 --> 00:10:34,768 +我将使用侧边栏打开名为 +AssistantTab Swift 文件 + +143 +00:10:34,801 --> 00:10:38,238 +我将删除 Button 控件 +并将其替换为 TeaWheelView + +144 +00:10:48,749 --> 00:10:51,451 +TeaWheelView 可以通过 +使用可选的操作闭包 + +145 +00:10:51,485 --> 00:10:53,720 +当轮盘停止旋转时调用 + +146 +00:10:55,622 --> 00:11:00,494 +我会用它把上一次选择的茶 +设置为 “选定的茶” + +147 +00:11:00,527 --> 00:11:05,399 +然后将 showPickAlert +设置为 true 以便 SwiftUI 显示告警信息 + +148 +00:11:08,869 --> 00:11:12,339 +好的太棒了 我们已把轮盘编辑好了 +那么现在让我们来试试吧 + +149 +00:11:12,372 --> 00:11:17,411 +我会旋转它… +然后它建议我喝字节乌龙茶 + +150 +00:11:17,444 --> 00:11:19,546 +我再刷一遍… + +151 +00:11:22,015 --> 00:11:24,251 +还是字节乌龙茶 + +152 +00:11:24,284 --> 00:11:25,919 +再一次 + +153 +00:11:28,856 --> 00:11:31,391 +唔 似乎有些不对劲 + +154 +00:11:31,425 --> 00:11:33,627 +即使它落在轮盘上的不同位置 + +155 +00:11:33,660 --> 00:11:36,830 +程序还总是推荐字节乌龙 + +156 +00:11:36,864 --> 00:11:40,634 +虽然那是一种很好的茶 +但我还是想要一些多样性的选择 + +157 +00:11:40,667 --> 00:11:43,370 +让我们切换回轮盘视图 +并试着查查到底怎么回事 + +158 +00:11:45,405 --> 00:11:47,341 +从这里看不出哪里出了问题 + +159 +00:11:47,374 --> 00:11:50,410 +因为轮盘确实旋转了 +并降落在不同的位置 + +160 +00:11:50,444 --> 00:11:52,880 +让我们在视图预览中 +添加一个打印语句 + +161 +00:11:52,913 --> 00:11:55,048 +以便于检查预览是否也出了问题 + +162 +00:12:02,656 --> 00:12:04,458 +现在 当我转动轮盘时… + +163 +00:12:05,993 --> 00:12:09,463 +在源编辑器的左下方会 +弹出一条控制台消息 + +164 +00:12:09,496 --> 00:12:11,765 +条目一… + +165 +00:12:11,798 --> 00:12:15,035 +条目一…条目一 + +166 +00:12:15,068 --> 00:12:18,338 +啊哈 每次旋转都会给我们条目一 + +167 +00:12:18,372 --> 00:12:21,175 +这表明某些功能 +并没有正确的关联起来 + +168 +00:12:21,208 --> 00:12:23,877 +因为它每次都给我第一个条目 + +169 +00:12:23,911 --> 00:12:28,215 +我将首先使用项目范围内 +的查找进行搜索 + +170 +00:12:28,248 --> 00:12:30,484 +我将点击位于屏幕左侧的 +侧边栏顶部 + +171 +00:12:30,517 --> 00:12:33,120 +的搜索框 + +172 +00:12:33,153 --> 00:12:36,557 +然后键入“first” +并按回车键 + +173 +00:12:38,458 --> 00:12:41,428 +这个结果看起来像是我正在找的 +所以我会点击它 + +174 +00:12:42,896 --> 00:12:45,933 +啊 看来 Collett 在这里 +留下了一些调试代码 + +175 +00:12:45,966 --> 00:12:50,103 +这使轮盘每次都返回第一个条目 +而不是正确的结果 + +176 +00:12:50,137 --> 00:12:52,940 +让我们快速修改它 然后再旋转一次 + +177 +00:13:00,047 --> 00:13:01,715 +条目二 … + +178 +00:13:01,748 --> 00:13:03,217 +条目四 + +179 +00:13:03,250 --> 00:13:05,652 +太好了! +看起来它已经可以正常工作了 + +180 +00:13:05,686 --> 00:13:07,788 +如果我们通过点击预览下方的左箭头 + +181 +00:13:07,821 --> 00:13:10,524 +切换回我们的 App 预览 + +182 +00:13:10,557 --> 00:13:13,260 +我们就可以在真实的 +App 中测试一下功能 + +183 +00:13:13,293 --> 00:13:18,198 +转动轮盘 然后它推荐给我英式早餐茶 + +184 +00:13:18,232 --> 00:13:20,701 +所以现在我们有了一个助手功能 + +185 +00:13:20,734 --> 00:13:24,571 +太厉害了!为了确认 App +在各种屏幕尺寸下都能正常工作 + +186 +00:13:24,605 --> 00:13:28,008 +我可以通过按下 +屏幕左上角的 Run (运行) 按钮 + +187 +00:13:28,041 --> 00:13:29,943 +让它在这个设备的 +真实窗口中运行程序 + +188 +00:13:33,413 --> 00:13:35,616 +好的 看起来 所有功能都在这里了 + +189 +00:13:35,649 --> 00:13:38,685 +我有我的茶单功能 + +190 +00:13:38,719 --> 00:13:41,255 +和包含一个轮盘的助手功能 + +191 +00:13:41,288 --> 00:13:43,524 +我可以通过点击 +状态栏右侧的小 Swift 图标 + +192 +00:13:43,557 --> 00:13:46,260 +返回 Swift +Playgrounds 项目 + +193 +00:13:46,293 --> 00:13:50,130 +然后在弹出的视窗中 +选择 Show Project (显示项目) 按钮 + +194 +00:13:52,299 --> 00:13:56,103 +我已准备好 我与朋友和家人 +一起测试这个 App + +195 +00:13:56,136 --> 00:13:58,405 +Swift Playgrounds +让测试变得容易 + +196 +00:13:58,438 --> 00:14:00,340 +因为您可以从 Swift Playgrounds + +197 +00:14:00,374 --> 00:14:02,009 +把项目直接提交到 TestFlight + +198 +00:14:02,042 --> 00:14:07,481 +如果我打开 App Settings +并滚动到底部 + +199 +00:14:07,514 --> 00:14:10,250 +您会看到有一个 +“Upload to App Store Connect”的按钮 + +200 +00:14:10,284 --> 00:14:14,121 +如果我点击这个按钮 Swift Playgrounds +会完成创建 App 记录 + +201 +00:14:14,154 --> 00:14:17,658 +以及将 App 上传到 +App Store Connect 的所有麻烦工作 + +202 +00:14:17,691 --> 00:14:21,495 +这样我就可以将它发布到 +TestFlight 并最终发布到 App Store + +203 +00:14:27,935 --> 00:14:31,405 +现在我的 App 已上传 +我可以前往 App Store Connect + +204 +00:14:31,438 --> 00:14:33,740 +并将其提交给 Beta App Review + +205 +00:14:33,774 --> 00:14:36,844 +稍等片刻后 +我们可以转到 TestFlight + +206 +00:14:36,877 --> 00:14:39,980 +并从那里安装它 +甚至可以安装在 iPhone 上 + +207 +00:14:42,549 --> 00:14:45,118 +我将点击 Install (安装) +来安装 Tea Time + +208 +00:14:46,486 --> 00:14:50,290 +现在它已安装 +我点击 Open (打开) 按钮将其打开 + +209 +00:14:50,324 --> 00:14:52,826 +我会点击测试按钮 + +210 +00:14:52,860 --> 00:14:55,596 +这里会显示 +关于如何提供反馈的说明 + +211 +00:14:57,030 --> 00:15:00,534 +好了 我们的 App +正在 iPhone 上运行 + +212 +00:15:00,567 --> 00:15:02,603 +我今天应该喝什么茶? + +213 +00:15:04,771 --> 00:15:07,374 +看起来我要参加 +Matt P 的茶话会了 + +214 +00:15:07,407 --> 00:15:10,944 +今天 Collett 和我向您展示了 +如何使用 Swift Playgrounds + +215 +00:15:10,978 --> 00:15:13,480 +在 Mac 和 iPad 上构建 App + +216 +00:15:13,514 --> 00:15:17,217 +我们演示了如何使用库和代码 +完成插入新的代码 + +217 +00:15:17,251 --> 00:15:20,487 +我们通过 iCloud 共享文件夹 +分享了我们的项目 + +218 +00:15:20,521 --> 00:15:24,758 +我们使用视图预览和控制台 +来调试我们的代码问题 + +219 +00:15:24,791 --> 00:15:28,328 +我们甚至直接从 iPad 向 +TestFlight 提交了一个 App + +220 +00:15:28,362 --> 00:15:30,697 +希望您在此过程中学到了一些内容 + +221 +00:15:30,731 --> 00:15:33,667 +我们迫不及待地想看看 +您使用 Swift Playgrounds 构建的内容 + +222 +00:15:33,700 --> 00:15:37,938 +感谢您的收看 +希望您享受 WWDC 的其他讲座 + diff --git a/zho/2022 Session 110354 What's new in Swift.srt b/zho/2022 Session 110354 What's new in Swift.srt new file mode 100644 index 0000000..615c25a --- /dev/null +++ b/zho/2022 Session 110354 What's new in Swift.srt @@ -0,0 +1,3531 @@ +1 +00:00:00,000 --> 00:00:03,003 +♪ 柔和乐器演奏的嘻哈音乐 ♪ + +2 +00:00:03,003 --> 00:00:09,810 +♪ + +3 +00:00:09,810 --> 00:00:11,545 +Angela Laar:大家好 我是 Angela + +4 +00:00:11,545 --> 00:00:13,413 +Becca Royal-Gordon:我是 Becca + +5 +00:00:13,413 --> 00:00:15,415 +Angela:欢迎关注 Swift 的新功能! + +6 +00:00:15,415 --> 00:00:17,317 +今天我们很高兴能给您介绍一下 + +7 +00:00:17,317 --> 00:00:21,154 +Swift 5.7 中所有优秀的新功能 + +8 +00:00:21,154 --> 00:00:22,956 +我们今天要讲的许多事情都体现了 + +9 +00:00:22,956 --> 00:00:28,195 +Swift 的目标 即让 +您的开发工作生活更轻松 + +10 +00:00:28,195 --> 00:00:29,429 +我们将研究新工具 + +11 +00:00:29,429 --> 00:00:31,732 +以帮助您自定义工作流程 + +12 +00:00:31,732 --> 00:00:35,569 +并介绍一些令人惊叹的根本性改进 + +13 +00:00:35,569 --> 00:00:38,772 +然后我们将讨论 +最新的 Swift 并发模型 + +14 +00:00:38,772 --> 00:00:43,243 +以及通往 Swift 6 的道路 +包括全线程安全 + +15 +00:00:43,243 --> 00:00:44,912 +Becca:最后我会介绍 + +16 +00:00:44,912 --> 00:00:47,447 +一些使 Swift +更易于读写的语言改进 + +17 +00:00:47,447 --> 00:00:50,784 +包括更简洁、更简单的泛型 + +18 +00:00:50,784 --> 00:00:54,688 +和强大的新字符串处理工具 + +19 +00:00:54,688 --> 00:00:57,424 +Angela:但首先 让我们先谈谈 + +20 +00:00:57,424 --> 00:01:01,228 +让 Swift 如此特别的原因之一 + +21 +00:01:01,228 --> 00:01:02,763 +那就是所有开发者 + +22 +00:01:02,763 --> 00:01:05,499 +Swift 之所以能如此迅速的扩张 + +23 +00:01:05,499 --> 00:01:08,268 +要归功于开发者的付出和贡献 + +24 +00:01:08,268 --> 00:01:11,038 +社区参与是 Swift 的核心 + +25 +00:01:11,038 --> 00:01:14,174 +我们于去年发布了 + +26 +00:01:14,174 --> 00:01:16,210 +docC 文档生成工具 + +27 +00:01:16,210 --> 00:01:19,446 +并于今年面向社区 +提供更多 Swift 计划 + +28 +00:01:19,446 --> 00:01:23,150 +并且开源了 Swift.org 网站 + +29 +00:01:23,150 --> 00:01:24,651 +要开源运作起来最好 + +30 +00:01:24,651 --> 00:01:28,889 +需要有活跃的社区来引领 + +31 +00:01:28,889 --> 00:01:31,592 +我们一直在服务器端上的 Swift +和 Swift 多样性项目中 + +32 +00:01:31,592 --> 00:01:34,528 +以工作组的方式来管理 + +33 +00:01:34,528 --> 00:01:36,196 +并为对特定领域感兴趣的 + +34 +00:01:36,196 --> 00:01:38,732 +社区成员提供支持 + +35 +00:01:38,732 --> 00:01:40,400 +效果一直很显著 + +36 +00:01:40,400 --> 00:01:42,336 +所以我们启动了两个新的工作组 + +37 +00:01:42,336 --> 00:01:44,171 +一个用于在 Swift 网站的迭代 + +38 +00:01:44,171 --> 00:01:46,340 +并使其更像是一种社区资源 + +39 +00:01:46,340 --> 00:01:49,409 +另一个用于 C++ 互用性 + +40 +00:01:49,409 --> 00:01:54,581 +以设计改变在 C++ 和 Swift +之间的模型 + +41 +00:01:54,581 --> 00:01:57,551 +当我们冒险进入新领域时 + +42 +00:01:57,551 --> 00:02:00,020 +我们都需要来自社区内的成员的支持 + +43 +00:02:00,020 --> 00:02:02,856 +作为其中的一部分 +Swift 多样性工作组 + +44 +00:02:02,856 --> 00:02:05,792 +去年推出了 Swift 导师计划 + +45 +00:02:05,792 --> 00:02:07,427 +该计划为那些不知道如何开始 + +46 +00:02:07,427 --> 00:02:09,563 +或想加深 +其在特定领域的专业知识的人 + +47 +00:02:09,563 --> 00:02:11,398 +提供了为所有工作组领域 + +48 +00:02:11,398 --> 00:02:15,869 +做出贡献的途径 + +49 +00:02:15,869 --> 00:02:18,805 +去年的计划取得了巨大的成功 + +50 +00:02:18,805 --> 00:02:21,708 +有很多感兴趣的学员慕名而来 + +51 +00:02:21,708 --> 00:02:25,913 +因此我们创建了 +41 个一对一指导小组 + +52 +00:02:25,913 --> 00:02:29,082 +鉴于其取得了巨大成功 + +53 +00:02:29,082 --> 00:02:30,617 +此计划将在第二年继续开展 + +54 +00:02:30,617 --> 00:02:32,419 +我们希望所有感兴趣的人都能 + +55 +00:02:32,419 --> 00:02:35,656 +加入此计划 但要做到这一点 + +56 +00:02:35,656 --> 00:02:38,792 +我们需要大家 即正在听课的 +优秀且且经验丰富的开发人员 + +57 +00:02:38,792 --> 00:02:40,827 +愿意分享广博知识 + +58 +00:02:40,827 --> 00:02:42,763 +并建立新联系的人员 + +59 +00:02:42,763 --> 00:02:45,599 +因为导师计划不仅仅涉及代码 + +60 +00:02:45,599 --> 00:02:49,002 +还涉及在社区内建立关系 + +61 +00:02:49,002 --> 00:02:52,005 +一点点指导就可以产生持久的影响 + +62 +00:02:52,005 --> 00:02:54,641 +我有真凭实据 + +63 +00:02:54,641 --> 00:02:58,045 +去年 Amrit 参加了导师计划 + +64 +00:02:58,045 --> 00:03:00,848 +并专注于编译器和语言设计 + +65 +00:03:00,848 --> 00:03:02,749 +开始时 Amrit 只是感到好奇 + +66 +00:03:02,749 --> 00:03:06,019 +最终却真得做出了贡献 + +67 +00:03:06,019 --> 00:03:09,056 +进入一个新领域并不容易 + +68 +00:03:09,056 --> 00:03:12,092 +即便如此 她还是找到了成功之路 + +69 +00:03:12,092 --> 00:03:14,828 +并感到受到了鼓舞 +想要做出更多贡献 + +70 +00:03:14,828 --> 00:03:16,230 +像许多其他人一样 + +71 +00:03:16,230 --> 00:03:19,499 +这次经历为 Amrit 打开了一扇门 + +72 +00:03:19,499 --> 00:03:22,202 +除了编译器和语言设计 + +73 +00:03:22,202 --> 00:03:26,340 +去年还有很多重点领域 + +74 +00:03:26,340 --> 00:03:28,008 +从技术写作和测试 + +75 +00:03:28,008 --> 00:03:30,744 +到为 Swift 软件包做贡献 + +76 +00:03:30,744 --> 00:03:33,080 +今年 我们增加了更多领域 + +77 +00:03:33,080 --> 00:03:36,116 +新主题将层出不穷 + +78 +00:03:36,116 --> 00:03:39,253 +如果您在此列表中 +没有看到您感兴趣的内容 + +79 +00:03:39,253 --> 00:03:42,256 +您仍然可以在申请表格中提出 + +80 +00:03:42,256 --> 00:03:45,425 +另一点是 今年的计划将为初学者 + +81 +00:03:45,425 --> 00:03:48,262 +提供全年导师服务 + +82 +00:03:48,262 --> 00:03:50,731 +以帮助能力不足 + +83 +00:03:50,731 --> 00:03:54,735 +但十分想参与的人 + +84 +00:03:54,735 --> 00:03:56,503 +如果您想申请 + +85 +00:03:56,503 --> 00:03:58,238 +或者只是想了解更多内容 + +86 +00:03:58,238 --> 00:04:00,474 +请查看最新的 Swift 博客文章 + +87 +00:04:00,474 --> 00:04:02,809 +在那里 您可以找到重点学员的 + +88 +00:04:02,809 --> 00:04:05,512 +详细描述链接 + +89 +00:04:05,512 --> 00:04:08,048 +导师计划只是 Swift 多样性 + +90 +00:04:08,048 --> 00:04:10,717 +中的其中一项举措 + +91 +00:04:10,717 --> 00:04:12,553 +要了解有关导师计划的更多信息 + +92 +00:04:12,553 --> 00:04:14,755 +以及关于 Swift 多样性的工作 + +93 +00:04:14,755 --> 00:04:17,691 +您可以访问 Swift.org/diversity + +94 +00:04:17,691 --> 00:04:20,494 +为了进一步打开大门 +我们想尽量让您 + +95 +00:04:20,494 --> 00:04:24,965 +可以轻松地使用 Swift 和现有资源! + +96 +00:04:24,965 --> 00:04:27,868 +我们简化了适用于 Linux 平台的 + +97 +00:04:27,868 --> 00:04:29,269 +Swift 工具链分发流程 + +98 +00:04:29,269 --> 00:04:32,072 +方式是添加 +对 Linux 包格式的支持 + +99 +00:04:32,072 --> 00:04:33,941 +现在您可以 +使用新原生工具链安装器 + +100 +00:04:33,941 --> 00:04:37,110 +直接从 Swift.org 下载 + +101 +00:04:37,110 --> 00:04:40,380 +Amazon Linux 2 和 CentOS 7 的 RPM + +102 +00:04:40,380 --> 00:04:42,115 +这些工具链是实验性的 + +103 +00:04:42,115 --> 00:04:45,419 +所以请一定在 Swift.org 论坛上分享反馈 + +104 +00:04:45,419 --> 00:04:48,155 +Swift 主要用于构建 App + +105 +00:04:48,155 --> 00:04:52,626 +然而 Swift 的愿景 +一直是成为可扩展的工具 + +106 +00:04:52,626 --> 00:04:54,661 +力求适用于从高级脚本 + +107 +00:04:54,661 --> 00:04:57,531 +到裸机环境的所有情况 + +108 +00:04:57,531 --> 00:04:58,932 +为了鼓励将 Swift 用于 + +109 +00:04:58,932 --> 00:05:01,235 +以前从未使用过的地方 + +110 +00:05:01,235 --> 00:05:04,171 +Swift 今年经历了一些重大变化 + +111 +00:05:04,171 --> 00:05:05,706 +使标准库更小 + +112 +00:05:05,706 --> 00:05:08,442 +以适用于独立的 +静态链接的二进制文件 + +113 +00:05:08,442 --> 00:05:09,943 +我们放弃了依赖 + +114 +00:05:09,943 --> 00:05:12,446 +外部 Unicode 支持库 + +115 +00:05:12,446 --> 00:05:17,384 +而是用更快的原生实现来替代 + +116 +00:05:17,384 --> 00:05:20,187 +在事件驱动型服务器 +解决方案上运行时 + +117 +00:05:20,187 --> 00:05:22,756 +更小、更快的二进制文件好处颇多 + +118 +00:05:22,756 --> 00:05:24,925 +默认情况下 您会 +在 Linux 上获得静态链接 + +119 +00:05:24,925 --> 00:05:28,595 +以更好地 +支持服务器的容器化部署 + +120 +00:05:28,595 --> 00:05:30,531 +这种尺寸减小使 Swift 适合 + +121 +00:05:30,531 --> 00:05:32,432 +于受限的环境 + +122 +00:05:32,432 --> 00:05:33,634 +这让我们可以在 Apple 的 + +123 +00:05:33,634 --> 00:05:36,270 +Secure Enclave Processor 中使用它 + +124 +00:05:36,270 --> 00:05:38,739 +Swift 适用于从 App 到服务器 + +125 +00:05:38,739 --> 00:05:41,675 +一直到受限处理器的各种场合 + +126 +00:05:41,675 --> 00:05:46,713 +将它们联系在一起的是软件包生态系统 + +127 +00:05:46,713 --> 00:05:48,782 +今年 Swift 软件包的新功能 + +128 +00:05:48,782 --> 00:05:50,584 +会让您的生活更美好 + +129 +00:05:50,584 --> 00:05:55,656 +首先 Swift Package Manager 引入了 TOFU + +130 +00:05:55,656 --> 00:05:58,592 +这不是指那个美味的小吃 + +131 +00:05:58,592 --> 00:06:01,929 +TOFU 是首字母缩写词 +代表首次使用时的信任 + +132 +00:06:01,929 --> 00:06:04,231 +这是一种新的安全协议 + +133 +00:06:04,231 --> 00:06:06,066 +会在首次下载软件时 + +134 +00:06:06,066 --> 00:06:08,468 +记录一个包的指纹 + +135 +00:06:08,468 --> 00:06:11,038 +后续下载将验证此指纹 + +136 +00:06:11,038 --> 00:06:14,675 +如果指纹不同则报错 + +137 +00:06:14,675 --> 00:06:17,377 +这只是内置于软件包生态系统核心的 + +138 +00:06:17,377 --> 00:06:20,147 +信任和安全性的一个例子 + +139 +00:06:20,147 --> 00:06:23,383 +可帮助您自信地使用它 + +140 +00:06:23,383 --> 00:06:26,353 +对于 Swift 开发人员来说 + +141 +00:06:26,353 --> 00:06:28,288 +指令插件是改进工作流程的好方法 + +142 +00:06:28,288 --> 00:06:30,657 +它们是提供更多可扩展的 + +143 +00:06:30,657 --> 00:06:32,926 +且安全的构建工具的第一步 + +144 +00:06:32,926 --> 00:06:35,963 +指令插件可用于文档生成 + +145 +00:06:35,963 --> 00:06:38,632 +源代码重新格式化等 + +146 +00:06:38,632 --> 00:06:41,068 +使用 Swift +您就不必在 Shell 脚本中 + +147 +00:06:41,068 --> 00:06:44,438 +编写自动化内容 +并维护单独的工作流程 + +148 +00:06:44,438 --> 00:06:46,907 +想想开源格式化程序和静态检查工具 + +149 +00:06:46,907 --> 00:06:50,644 +现在所有这些开源工具 +都可以在 Xcode + +150 +00:06:50,644 --> 00:06:53,947 +和 Swift Package Manager 中找到 + +151 +00:06:53,947 --> 00:06:57,050 +指令插件是开源工具和 + +152 +00:06:57,050 --> 00:06:58,819 +Swift Package Manager 之间的粘合剂 + +153 +00:06:58,819 --> 00:07:01,054 +Swift 项目接纳 +开源社区的开发者工具 + +154 +00:07:01,054 --> 00:07:03,957 +与您的自动化 + +155 +00:07:03,957 --> 00:07:06,693 +工作流程无缝整合 + +156 +00:07:06,693 --> 00:07:09,296 +docC 是将文档集成到 + +157 +00:07:09,296 --> 00:07:10,697 +您的源代码中的优秀工具 + +158 +00:07:10,697 --> 00:07:14,735 +在 Objective-C 和 C 支持的帮助下 + +159 +00:07:14,735 --> 00:07:16,537 +今年它更加完善了 让我们看看 + +160 +00:07:16,537 --> 00:07:19,072 +使用 docC 创建插件都需要什么 + +161 +00:07:19,072 --> 00:07:20,908 +插件只是简单的 Swift 代码 + +162 +00:07:20,908 --> 00:07:23,110 +您可以通过创建符合指令插入 + +163 +00:07:23,110 --> 00:07:25,479 +协议的结构体来定义插件 + +164 +00:07:25,479 --> 00:07:28,015 +然后您只需添加一个函数来告诉 + +165 +00:07:28,015 --> 00:07:30,250 +您的插件您要调用哪个工具即可 + +166 +00:07:30,250 --> 00:07:34,454 +这个函数就是我们要调用 docC 的地方 + +167 +00:07:34,454 --> 00:07:37,291 +一旦您定义了您的插件 它就可以通过 + +168 +00:07:37,291 --> 00:07:39,026 +Swift PM 命令行界面 + +169 +00:07:39,026 --> 00:07:40,928 +和 Xcode 作为菜单项使用了 + +170 +00:07:40,928 --> 00:07:44,364 +现在我们可以告诉 Swift PM 生成文档 + +171 +00:07:44,364 --> 00:07:48,569 +它知道要将此操作传递给 docC 可执行文件 + +172 +00:07:48,569 --> 00:07:50,337 +还不止于此 + +173 +00:07:50,337 --> 00:07:54,241 +还有第二个称为构建工具插件的插件 + +174 +00:07:54,241 --> 00:07:56,376 +这些插件是允许您 + +175 +00:07:56,376 --> 00:07:59,246 +在构建过程中添加额外的步骤的包 + +176 +00:07:59,246 --> 00:08:01,381 +实现构建工具插件时 + +177 +00:08:01,381 --> 00:08:02,983 +将为构建系统创建一个指令 + +178 +00:08:02,983 --> 00:08:05,085 +以在沙盒中执行 + +179 +00:08:05,085 --> 00:08:06,787 +它们不同于指令插件 + +180 +00:08:06,787 --> 00:08:09,089 +您可以随时直接执行 + +181 +00:08:09,089 --> 00:08:11,225 +并且可以被授予显式权限 + +182 +00:08:11,225 --> 00:08:13,994 +以更改包中的文件 + +183 +00:08:13,994 --> 00:08:16,997 +构建工具插件可用于源代码生成 + +184 +00:08:16,997 --> 00:08:20,234 +或特殊类型文件的自定义处理 + +185 +00:08:20,234 --> 00:08:23,570 +在使用构建工具插件时 +包布局是这样的 + +186 +00:08:23,570 --> 00:08:25,839 +在这个例子中 plugin.Swift + +187 +00:08:25,839 --> 00:08:27,608 +是实施包插件目标的 + +188 +00:08:27,608 --> 00:08:29,142 +Swift 脚本 + +189 +00:08:29,142 --> 00:08:33,480 +该插件被视为 Swift 可执行文件 + +190 +00:08:33,480 --> 00:08:35,482 +并且编写插件的方法与编写 + +191 +00:08:35,482 --> 00:08:38,852 +Swift 可执行文件的方法是相同的 + +192 +00:08:38,852 --> 00:08:40,654 +要实现插件 +您可以定义一组构建指令 + +193 +00:08:40,654 --> 00:08:43,457 +它们告诉构建系统 + +194 +00:08:43,457 --> 00:08:46,560 +要运行什么可执行指令 + +195 +00:08:46,560 --> 00:08:48,295 +以及预期有什么输出 + +196 +00:08:48,295 --> 00:08:50,631 +包插件通过您的软件包提供 + +197 +00:08:50,631 --> 00:08:53,367 +可扩展的安全解决方案 + +198 +00:08:53,367 --> 00:08:55,702 +要详细了解插件的工作原理 + +199 +00:08:55,702 --> 00:08:58,705 +以及如何实现自己的插件 + +200 +00:08:58,705 --> 00:09:00,207 +请观看“认识 Swift 包插件” + +201 +00:09:00,207 --> 00:09:03,410 +和“创建 Swift 包插件”这两门课程 + +202 +00:09:03,410 --> 00:09:05,546 +随着您使用的软件包越来越多 + +203 +00:09:05,546 --> 00:09:08,682 +您可能遇到过模块冲突 + +204 +00:09:08,682 --> 00:09:10,284 +那是两个单独的包 + +205 +00:09:10,284 --> 00:09:12,786 +用同样的名称定义一个模块 + +206 +00:09:12,786 --> 00:09:14,321 +为了解决这种问题 + +207 +00:09:14,321 --> 00:09:19,226 +Swift 5.7 引入了模块消歧 + +208 +00:09:19,226 --> 00:09:22,896 +模块消歧是一种功能 + +209 +00:09:22,896 --> 00:09:26,900 +它允许您从 +定义模块包的外部重命名模块 + +210 +00:09:26,900 --> 00:09:28,902 +在我们的 Stunning App 中 + +211 +00:09:28,902 --> 00:09:31,905 +我们引入了 +两个都定义了 Logging 模块的包 + +212 +00:09:31,905 --> 00:09:33,140 +因此发生了冲突 + +213 +00:09:33,140 --> 00:09:35,909 +要为我们的 Stunning App 解决此问题 + +214 +00:09:35,909 --> 00:09:38,545 +您只需要在包清单的依赖关系部分 + +215 +00:09:38,545 --> 00:09:42,950 +添加 moduleAliases 关键字即可 + +216 +00:09:42,950 --> 00:09:44,718 +这样您就可以用两个不同的名字 + +217 +00:09:44,718 --> 00:09:46,520 +区分之前拥有 + +218 +00:09:46,520 --> 00:09:49,456 +相同名称的模块了 + +219 +00:09:49,456 --> 00:09:53,560 +Swift 5.7 带来了 +一些惊人的性能改进 + +220 +00:09:53,560 --> 00:09:56,129 +让我们先看看构建时间 + +221 +00:09:56,129 --> 00:09:58,699 +去年 我们告诉大家我们如何重写了 + +222 +00:09:58,699 --> 00:10:00,634 +Swift Driver 它被用于协调 + +223 +00:10:00,634 --> 00:10:04,104 +在 Swift 中 Swift 源代码的编译工作 + +224 +00:10:04,104 --> 00:10:05,372 +去年的重构 + +225 +00:10:05,372 --> 00:10:07,140 +解锁了一些非常重要的变化 + +226 +00:10:07,140 --> 00:10:09,443 +让构建速度大幅提升 + +227 +00:10:09,443 --> 00:10:11,612 +现在可将驱动程序直接在 + +228 +00:10:11,612 --> 00:10:13,747 +Xcode 构建系统中作为框架调用 + +229 +00:10:13,747 --> 00:10:16,316 +而不是作为单独的可执行文件 + +230 +00:10:16,316 --> 00:10:18,452 +这让它可以更紧密地与构建系统 + +231 +00:10:18,452 --> 00:10:22,623 +一起协调构建让诸如并行化之类的 +方式成为可能 + +232 +00:10:22,623 --> 00:10:25,125 +如果您喜欢听到关于快速构建的内容 + +233 +00:10:25,125 --> 00:10:26,894 +您可以在观看 + +234 +00:10:26,894 --> 00:10:31,031 +“深入探索 Xcode 构建中的并行” + +235 +00:10:31,031 --> 00:10:33,133 +为了向您展示构建速度有多快 + +236 +00:10:33,133 --> 00:10:36,003 +让我们看一些示例 +以了解构建我们经常使用的 + +237 +00:10:36,003 --> 00:10:39,306 +用 Swift 编写的工具需要多长时间 + +238 +00:10:39,306 --> 00:10:41,842 +在 10 核 iMac 上 改进程度 + +239 +00:10:41,842 --> 00:10:46,580 +从 5% 一直到 25% 不等 + +240 +00:10:46,580 --> 00:10:49,883 +接下来 +类型检查的速度也有所改进 + +241 +00:10:49,883 --> 00:10:52,586 +今年 我们改进了类型检查器的性能 + +242 +00:10:52,586 --> 00:10:56,156 +方式是重新实现泛型系统的关键部分 + +243 +00:10:56,156 --> 00:10:58,192 +即根据协议和 where 子句 + +244 +00:10:58,192 --> 00:11:00,727 +计算函数签名的部分 + +245 +00:11:00,727 --> 00:11:03,530 +在旧的实现中 随着引入越来越多的协议 + +246 +00:11:03,530 --> 00:11:07,167 +时间和内存使用会指数级增加 + +247 +00:11:07,167 --> 00:11:10,871 +例如在这里 我们有一组复杂的协议 + +248 +00:11:10,871 --> 00:11:13,340 +它们定义了一个坐标系 + +249 +00:11:13,340 --> 00:11:16,577 +以及许多关联类型的范型要求 + +250 +00:11:16,577 --> 00:11:20,714 +以前需要 17 秒来检查此代码 + +251 +00:11:20,714 --> 00:11:24,218 +但现在 +Swift 5.7 中 此例能够 + +252 +00:11:24,218 --> 00:11:28,889 +显着加快类型检查 耗时不足一秒钟 + +253 +00:11:28,889 --> 00:11:32,826 +我们还有一些 +同样令人印象深刻的运行时间改进 + +254 +00:11:32,826 --> 00:11:36,630 +在 Swift 5.7 之前 +我们看到 iOS 上的 App 启动时 + +255 +00:11:36,630 --> 00:11:39,633 +的协议检查最多需要四秒钟 + +256 +00:11:39,633 --> 00:11:42,970 +每次我们启动 App 时 +都需要计算协议 + +257 +00:11:42,970 --> 00:11:44,771 +这导致添加的协议越多 + +258 +00:11:44,771 --> 00:11:46,740 +启动时间更长 + +259 +00:11:46,740 --> 00:11:48,709 +现在协议被存入了高速缓冲存储器 + +260 +00:11:48,709 --> 00:11:50,644 +根据 App 的编写方式 + +261 +00:11:50,644 --> 00:11:52,679 +以及使用了多少协议 + +262 +00:11:52,679 --> 00:11:55,716 +这可能意味着 +在 iOS 16 上运行时 + +263 +00:11:55,716 --> 00:11:58,051 +某些 App 的启动时间减少了一半 + +264 +00:11:58,051 --> 00:12:01,221 +“优化 App 大小和运行时性能”课程 + +265 +00:12:01,221 --> 00:12:03,357 +将深入探讨如何在您自己的 App 中 + +266 +00:12:03,357 --> 00:12:07,160 +利用这些改进 + +267 +00:12:07,160 --> 00:12:09,630 +现在是时候讲讲大家 + +268 +00:12:09,630 --> 00:12:12,332 +感兴趣的内容了 + +269 +00:12:12,332 --> 00:12:15,903 +去年我们推出了新的并发模型 + +270 +00:12:15,903 --> 00:12:19,439 +结合 Actor 和 async/await + +271 +00:12:19,439 --> 00:12:23,410 +这对您的 App 并发架构 + +272 +00:12:23,410 --> 00:12:25,078 +产生了变革性的影响 + +273 +00:12:25,078 --> 00:12:29,516 +async/await 和 Actor 比回调 + +274 +00:12:29,516 --> 00:12:31,718 +和手动队列管理更安全、更容易 + +275 +00:12:31,718 --> 00:12:34,221 +今年我们进一步充实了模型 + +276 +00:12:34,221 --> 00:12:37,424 +将数据竞争安全放在首位 + +277 +00:12:37,424 --> 00:12:39,560 +因为并发对于改进 App 代码库 + +278 +00:12:39,560 --> 00:12:41,929 +而言是如此重要和不可或缺 + +279 +00:12:41,929 --> 00:12:44,431 +我们将这些改变向后部署 + +280 +00:12:44,431 --> 00:12:48,202 +到 iOS 13 和 macOS Catalina + +281 +00:12:48,202 --> 00:12:50,504 +为了部署到较旧的操作系统 + +282 +00:12:50,504 --> 00:12:54,208 +您的 App 为较久的 OS 捆绑了 + +283 +00:12:54,208 --> 00:12:55,976 +Swift 5.5 并发系统运行时间副本 + +284 +00:12:55,976 --> 00:12:58,178 +这类似于在 ABI 稳定之前 + +285 +00:12:58,178 --> 00:13:01,915 +将 Swift 向后部署到操作系统中 + +286 +00:13:01,915 --> 00:13:05,152 +接下来我们将这个模型 +推向了新的方向 + +287 +00:13:05,152 --> 00:13:06,587 +我们引入了语言功能 + +288 +00:13:06,587 --> 00:13:08,522 +和配套软件包 + +289 +00:13:08,522 --> 00:13:12,759 +首先让我们谈谈避免数据竞争 + +290 +00:13:12,759 --> 00:13:14,027 +在我开始讲解之前 + +291 +00:13:14,027 --> 00:13:15,729 +我可能应该退一步 + +292 +00:13:15,729 --> 00:13:18,498 +谈谈 Swift 的重要功能之一是 + +293 +00:13:18,498 --> 00:13:20,868 +默认的内存安全 + +294 +00:13:20,868 --> 00:13:23,871 +Swift 用户不能做 +产生无法预测行为的事情 + +295 +00:13:23,871 --> 00:13:25,072 +就像在正在修改一个数值时 + +296 +00:13:25,072 --> 00:13:27,574 +读取数值 + +297 +00:13:27,574 --> 00:13:31,278 +在此例中 我们删除了数组中 + +298 +00:13:31,278 --> 00:13:33,447 +与同一数组计数匹配的所有数字 + +299 +00:13:33,447 --> 00:13:36,183 +最初 数组的计数是 3 + +300 +00:13:36,183 --> 00:13:38,986 +所以我们将从数组中删除 3 + +301 +00:13:38,986 --> 00:13:41,955 +但是这样操作之后 计数将变成 2 + +302 +00:13:41,955 --> 00:13:44,525 +我们是否从数组中删除 3 和 2 + +303 +00:13:44,525 --> 00:13:46,527 +还是只删除 3 呢? + +304 +00:13:46,527 --> 00:13:48,328 +答案是都不是 + +305 +00:13:48,328 --> 00:13:50,163 +Swift 会阻止您这样做 + +306 +00:13:50,163 --> 00:13:52,866 +因为在修改数组时 + +307 +00:13:52,866 --> 00:13:55,435 +访问数组的计数是不安全的 + +308 +00:13:55,435 --> 00:13:58,839 +我们的目标是 +为线程安全做类似的处理 + +309 +00:13:58,839 --> 00:14:00,073 +我们设想一种语言 +它可以在默认情况下 + +310 +00:14:00,073 --> 00:14:03,377 +消除低级别的数据竞争 + +311 +00:14:03,377 --> 00:14:06,380 +换句话说 我们要防止可能会导致 + +312 +00:14:06,380 --> 00:14:09,216 +不可预测的行为的并发错误 + +313 +00:14:09,216 --> 00:14:10,951 +另一个例子如下 + +314 +00:14:10,951 --> 00:14:14,621 +我们使用同样数字的数组 +创建了一个后台任务 + +315 +00:14:14,621 --> 00:14:17,224 +将 0 附加到数组中 + +316 +00:14:17,224 --> 00:14:20,561 +然后我们删除数组的最后一个元素 + +317 +00:14:20,561 --> 00:14:23,063 +但是等等 +是在附加 0 之前还是之后 + +318 +00:14:23,063 --> 00:14:26,567 +删除最后一个元素呢? + +319 +00:14:26,567 --> 00:14:29,670 +答案还是都不是 + +320 +00:14:29,670 --> 00:14:32,406 +Swift 会阻止您这样做 + +321 +00:14:32,406 --> 00:14:34,308 +因为未通过类似 Actor 等同步访问 + +322 +00:14:34,308 --> 00:14:38,679 +在后台任务的修改数组是不安全的 + +323 +00:14:38,679 --> 00:14:42,749 +Actor 是消除数据竞争的第一步 + +324 +00:14:42,749 --> 00:14:45,185 +今年我们完善了并发模型 + +325 +00:14:45,185 --> 00:14:49,122 +离最终目标更进了一步 + +326 +00:14:49,122 --> 00:14:52,326 +您可以把每个 Actor +想象成一个独立的小岛 + +327 +00:14:52,326 --> 00:14:56,096 +与并发海洋中的其他一切隔离开来 + +328 +00:14:56,096 --> 00:14:58,799 +但是当不同的线程想要查询 + +329 +00:14:58,799 --> 00:15:03,003 +每个独立 Actor 存储的 +信息时会发生什么呢? + +330 +00:15:03,003 --> 00:15:06,073 +我们将在“使用 Swift +并发消除数据竞争” + +331 +00:15:06,073 --> 00:15:10,644 +课程中进一步探讨这一点 + +332 +00:15:10,644 --> 00:15:14,014 +从默认内存安全到线程安全 + +333 +00:15:14,014 --> 00:15:16,850 +这是 Swift 6 的目标 + +334 +00:15:16,850 --> 00:15:19,052 +为此 我们首先用新语言功能 + +335 +00:15:19,052 --> 00:15:21,522 +改进了去年的并发模型 + +336 +00:15:21,522 --> 00:15:23,123 +我刚才提到了 + +337 +00:15:23,123 --> 00:15:24,992 +第二件事我还没有提到 + +338 +00:15:24,992 --> 00:15:26,693 +就是新的安全检查可选项 + +339 +00:15:26,693 --> 00:15:30,163 +它可识别潜在的数据竞争 + +340 +00:15:30,163 --> 00:15:32,866 +您可以通过在构建设置中启用它 + +341 +00:15:32,866 --> 00:15:36,203 +尝试更严格的并发检查 + +342 +00:15:36,203 --> 00:15:38,372 +我们再来看看 Actor + +343 +00:15:38,372 --> 00:15:41,642 +我们可以采用 +这个 Actor 隔离的概念 + +344 +00:15:41,642 --> 00:15:44,545 +并进一步推广到分布式 Actor + +345 +00:15:44,545 --> 00:15:47,314 +分布式 Actor +将这些岛屿放在不同的机器上 + +346 +00:15:47,314 --> 00:15:49,249 +它们之间有网络相连 + +347 +00:15:49,249 --> 00:15:52,186 +这种新语言功能使开发 + +348 +00:15:52,186 --> 00:15:54,354 +分布式系统变得更加简单 + +349 +00:15:54,354 --> 00:15:56,590 +假设您要创建一个游戏 App + +350 +00:15:56,590 --> 00:15:59,426 +您现在可以 +轻松地用 Swift 编写后端 + +351 +00:15:59,426 --> 00:16:02,396 +在这里 分布式 Actor +就像是一个 Actor + +352 +00:16:02,396 --> 00:16:04,831 +但它可能在另一台机器上 + +353 +00:16:04,831 --> 00:16:07,501 +在此示例中 +我们将看到计算机玩家 + +354 +00:16:07,501 --> 00:16:11,271 +通过它维护用户玩游戏期间的游戏状态 + +355 +00:16:11,271 --> 00:16:14,174 +也可以将 distributed 关键字添加到函数中 + +356 +00:16:14,174 --> 00:16:15,843 +我们预计需要为远程机器 + +357 +00:16:15,843 --> 00:16:19,580 +上的 Actor 上调用该函数 + +358 +00:16:19,580 --> 00:16:22,449 +让我们添加另一个 +名为 endOfRound 的函数 + +359 +00:16:22,449 --> 00:16:26,386 +它通过遍历玩家对象 +在玩家上调用 makeMove + +360 +00:16:26,386 --> 00:16:28,922 +其中一些玩家 +可能是本地的或远程的 + +361 +00:16:28,922 --> 00:16:30,023 +但我们不必管 + +362 +00:16:30,023 --> 00:16:33,026 +是哪个玩家 + +363 +00:16:33,026 --> 00:16:35,429 +它与常规 Actor 调用的唯一区别是 + +364 +00:16:35,429 --> 00:16:38,198 +因为网络错误 + +365 +00:16:38,198 --> 00:16:40,234 +分布式 Actor 调用可能会失败 + +366 +00:16:40,234 --> 00:16:41,969 +如果发生网络故障 + +367 +00:16:41,969 --> 00:16:44,438 +Actor 方法会抛出一个错误 + +368 +00:16:44,438 --> 00:16:46,273 +所以 您需要在 Swift 中添加 + +369 +00:16:46,273 --> 00:16:49,109 +所需的 try 关键字 + +370 +00:16:49,109 --> 00:16:52,412 +以及常规的 await 关键字 + +371 +00:16:52,412 --> 00:16:54,414 +基于这些核心语言原语 + +372 +00:16:54,414 --> 00:16:57,417 +我们还构建了一个 +开源分布式 Actor 包 + +373 +00:16:57,417 --> 00:16:59,753 +它专注于通过 Swift 构建服务器端 + +374 +00:16:59,753 --> 00:17:02,589 +集群分布式系统 + +375 +00:17:02,589 --> 00:17:05,225 +该软件包包括一个 +使用 SwiftNIO 并实现了 + +376 +00:17:05,225 --> 00:17:09,196 +SWIM 共识协议的集成网络层 + +377 +00:17:09,196 --> 00:17:11,598 +以管理整个集群的状态 + +378 +00:17:11,598 --> 00:17:13,634 +“认识 Swift 中的 +分布式 Actor” 课程 + +379 +00:17:13,634 --> 00:17:15,569 +将详细介绍如何构建 + +380 +00:17:15,569 --> 00:17:19,473 +具有这些新功能的分布式系统 + +381 +00:17:19,473 --> 00:17:23,076 +我们还推出了一套新的开源算法 + +382 +00:17:23,076 --> 00:17:27,114 +为处理 AsyncSequence 时的常见操作 + +383 +00:17:27,114 --> 00:17:29,516 +提供简单的开箱即用解决方案 + +384 +00:17:29,516 --> 00:17:32,152 +它与 Swift 5.5 一起发布 + +385 +00:17:32,152 --> 00:17:34,154 +将这些 API 作为一个软件包发布 + +386 +00:17:34,154 --> 00:17:37,558 +为开发人员提供了跨平台 + +387 +00:17:37,558 --> 00:17:40,761 +和跨操作系统版本部署的灵活性 + +388 +00:17:40,761 --> 00:17:44,631 +有几种方法可以组合多个异步序列 + +389 +00:17:44,631 --> 00:17:47,367 +并将值分组到各个集合中 + +390 +00:17:47,367 --> 00:17:49,036 +这些只是此包中 + +391 +00:17:49,036 --> 00:17:51,071 +包含的一些算法 + +392 +00:17:51,071 --> 00:17:53,941 +查看 “认识 Swift 异步算法“ 讲座 + +393 +00:17:53,941 --> 00:17:58,111 +了解如何使用这个强大的新 API + +394 +00:17:58,111 --> 00:18:00,647 +但并发系统还包含一个方面 + +395 +00:18:00,647 --> 00:18:02,516 +就是性能 + +396 +00:18:02,516 --> 00:18:04,818 +今年我们对 Actor 进行了优化 + +397 +00:18:04,818 --> 00:18:08,655 +Actor 现在首先执行 +优先级最高的工作 + +398 +00:18:08,655 --> 00:18:10,457 +并通过与操作系统调度程序 + +399 +00:18:10,457 --> 00:18:12,292 +继续进行深度整合 + +400 +00:18:12,292 --> 00:18:15,429 +该模型内置了预防优先级反转功能 + +401 +00:18:15,429 --> 00:18:20,300 +所以不太重要的工作 +不会阻止优先级更高的工作 + +402 +00:18:20,300 --> 00:18:23,070 +过去我们很难想象 + +403 +00:18:23,070 --> 00:18:26,073 +App 中并发系统对性能的影响 + +404 +00:18:26,073 --> 00:18:31,411 +但是现在我们有了一个很棒的新工具 + +405 +00:18:31,411 --> 00:18:34,081 +Instruments 中 +新的 Swift Concurrency 视图 + +406 +00:18:34,081 --> 00:18:36,717 +可以帮助您调查性能问题 + +407 +00:18:36,717 --> 00:18:39,553 +Swift Tasks 和 Swift Actors 工具 + +408 +00:18:39,553 --> 00:18:42,689 +提供一整套工具来帮助您呈现 + +409 +00:18:42,689 --> 00:18:46,159 +并优化并发代码 + +410 +00:18:46,159 --> 00:18:49,096 +在顶部 Swift Tasks Instrument + +411 +00:18:49,096 --> 00:18:52,132 +提供实用统计信息 + +412 +00:18:52,132 --> 00:18:54,835 +包括同时运行的任务数量 + +413 +00:18:54,835 --> 00:18:58,005 +在那个时间点之前创建的任务总数 + +414 +00:18:58,005 --> 00:18:59,873 +在此窗口的下半部分 + +415 +00:18:59,873 --> 00:19:03,777 +您可以看到所谓的 Task Forest + +416 +00:19:03,777 --> 00:19:06,213 +它提供了图形化表示 + +417 +00:19:06,213 --> 00:19:07,981 +展示了结构化并发代码中的 + +418 +00:19:07,981 --> 00:19:11,552 +任务之间的父子关系 + +419 +00:19:11,552 --> 00:19:13,520 +这只是 Swift Actor Instrument + +420 +00:19:13,520 --> 00:19:16,990 +的详细视图之一 + +421 +00:19:16,990 --> 00:19:19,493 +要了解如何使用这个令人兴奋的新工具 + +422 +00:19:19,493 --> 00:19:20,961 +请查看 + +423 +00:19:20,961 --> 00:19:24,198 +“Swift 并发系统可视化和优化”讲座 + +424 +00:19:24,198 --> 00:19:26,867 +并且不要忘记尝试这些新软件包 + +425 +00:19:26,867 --> 00:19:29,703 +请大胆地在论坛上告诉我们使用情况 + +426 +00:19:29,703 --> 00:19:32,005 +现在我们请 Becca 来谈谈 + +427 +00:19:32,005 --> 00:19:36,143 +对 Swift 语言可用性的诸多改进 + +428 +00:19:36,143 --> 00:19:38,412 +Becca:语言是工具 + +429 +00:19:38,412 --> 00:19:40,547 +关于工具有一些有意思的事情 + +430 +00:19:40,547 --> 00:19:42,850 +工具真得可以影响您建造的东西 + +431 +00:19:42,850 --> 00:19:44,952 +当您只有一把锤子时 + +432 +00:19:44,952 --> 00:19:48,121 +您会用钉子而不是螺丝来建造东西 + +433 +00:19:48,121 --> 00:19:50,858 +即使您有全套工具 + +434 +00:19:50,858 --> 00:19:52,659 +如果您的锤子 +有一个又大又防滑的把手 + +435 +00:19:52,659 --> 00:19:55,662 +而您的螺丝刀是塑料的 很难握住 + +436 +00:19:55,662 --> 00:19:58,098 +您可能仍然倾向于用钉子建造 + +437 +00:19:58,098 --> 00:20:00,000 +语言也是如此 + +438 +00:20:00,000 --> 00:20:02,503 +如果 Swift 有一个工具 +能很好地表达事物 + +439 +00:20:02,503 --> 00:20:05,205 +人们就会更频繁地使用它 + +440 +00:20:05,205 --> 00:20:07,541 +Swift 用于表达您希望代码做什么 + +441 +00:20:07,541 --> 00:20:11,512 +的工具在许多方面都有所改进 + +442 +00:20:11,512 --> 00:20:13,580 +其中一些更改是 + +443 +00:20:13,580 --> 00:20:15,415 +让您常做的事更加便利 + +444 +00:20:15,415 --> 00:20:18,785 +例如 在等号两边添加相同名称的 + +445 +00:20:18,785 --> 00:20:22,155 +if let 是非常常见的 + +446 +00:20:22,155 --> 00:20:24,091 +毕竟 对于展开的值 + +447 +00:20:24,091 --> 00:20:25,592 +可能没有比给可选值取的名字 + +448 +00:20:25,592 --> 00:20:28,562 +更好的名字了 + +449 +00:20:28,562 --> 00:20:30,097 +但是当名字真的很长的时候 + +450 +00:20:30,097 --> 00:20:33,100 +这种重复就会变得麻烦 + +451 +00:20:33,100 --> 00:20:35,736 +您可能会想缩写这个名字 + +452 +00:20:35,736 --> 00:20:39,106 +但是随后您的代码变得模棱两可 + +453 +00:20:39,106 --> 00:20:41,375 +如果您稍后重命名可选变量 + +454 +00:20:41,375 --> 00:20:45,245 +缩写可能不会被同步 + +455 +00:20:45,245 --> 00:20:47,781 +Swift 5.7 为这种模式引入了一种 + +456 +00:20:47,781 --> 00:20:49,650 +全新的简便方法 + +457 +00:20:49,650 --> 00:20:51,018 +如果您展开一个可选值 + +458 +00:20:51,018 --> 00:20:53,520 +并希望展开的值具有相同的名称 + +459 +00:20:53,520 --> 00:20:55,789 +只需删除右边的代码即可 + +460 +00:20:55,789 --> 00:20:58,492 +Swift 会假设名称是一样的 + +461 +00:20:58,492 --> 00:21:00,761 +当然 这种方式同样适用于 guard + +462 +00:21:00,761 --> 00:21:04,031 +甚至 while + +463 +00:21:04,031 --> 00:21:06,834 +我们还查看了当您做了细微更改 + +464 +00:21:06,834 --> 00:21:09,203 +某个功能突然停止工作的地方 + +465 +00:21:09,203 --> 00:21:11,371 +例如 Swift 总是能够根据 + +466 +00:21:11,371 --> 00:21:13,941 +单语句闭包内编写的代码推导出 + +467 +00:21:13,941 --> 00:21:16,543 +一个调用将返回什么类型 + +468 +00:21:16,543 --> 00:21:19,513 +在这个 compactMap 调用中 +闭包返回 parseLine + +469 +00:21:19,513 --> 00:21:22,449 +并且 parseLine 函数 +返回了一个 MailmapEntry + +470 +00:21:22,449 --> 00:21:25,352 +Swift 可以推导出 entries 应该是 + +471 +00:21:25,352 --> 00:21:30,190 +一个 MailmapEntry 的数组 + +472 +00:21:30,190 --> 00:21:32,159 +这现在适用于具有多个语句 + +473 +00:21:32,159 --> 00:21:35,362 +或控制流功能的更复杂的闭包 + +474 +00:21:35,362 --> 00:21:37,598 +所以您可以使用 do-catch 或 if…else + +475 +00:21:37,598 --> 00:21:39,800 +或只是添加一个 print 调用 + +476 +00:21:39,800 --> 00:21:43,303 +而无需手动指定闭包的结果类型 + +477 +00:21:43,303 --> 00:21:45,973 +我们关注的另一件事是那些并未 + +478 +00:21:45,973 --> 00:21:49,576 +真正标示任何实际危险的危险标志 + +479 +00:21:49,576 --> 00:21:52,913 +Swift 非常注重类型和内存安全 + +480 +00:21:52,913 --> 00:21:54,448 +为了不让您犯错 + +481 +00:21:54,448 --> 00:21:56,016 +它绝对不会在不同指针类型的指针之间自动转换 + +482 +00:21:56,016 --> 00:21:58,318 +也不会在原始指针和 + +483 +00:21:58,318 --> 00:22:01,321 +类型化指针之间自动转换 + +484 +00:22:01,321 --> 00:22:02,923 +这与 C 非常不同 + +485 +00:22:02,923 --> 00:22:05,259 +C 允许某些转换 + +486 +00:22:05,259 --> 00:22:07,995 +例如 您可以更改带符号类型的指针 + +487 +00:22:07,995 --> 00:22:11,732 +或将任何指针转换为 char* +以将其作为字节访问 + +488 +00:22:11,732 --> 00:22:15,402 +这不违反任何 C 指针规则 + +489 +00:22:15,402 --> 00:22:17,771 +但有时这些指针行为的差异会 + +490 +00:22:17,771 --> 00:22:22,042 +在 C API 导入 Swift 时会出现问题 + +491 +00:22:22,042 --> 00:22:24,178 +最初的开发者在设计 +API 时可能有轻微的不匹配 + +492 +00:22:24,178 --> 00:22:26,079 +这些不匹配在 C 语言中 +可以通过自动转换来处理 + +493 +00:22:26,079 --> 00:22:30,784 +但在 Swift 中却是错误 + +494 +00:22:30,784 --> 00:22:33,120 +在 Swift 中 +将一种类型的指针 + +495 +00:22:33,120 --> 00:22:35,989 +当作不同类型来访问是非常危险的 + +496 +00:22:35,989 --> 00:22:39,393 +所以您必须明确地描述您在做什么 + +497 +00:22:39,393 --> 00:22:41,161 +但如果我们向 C 传递指针 +这一切都毫无意义 + +498 +00:22:41,161 --> 00:22:43,830 +因为在 C 中 + +499 +00:22:43,830 --> 00:22:47,501 +指针不匹配是完全合法的 + +500 +00:22:47,501 --> 00:22:50,170 +所以在这种情况下 +我们把一件非常简单的事情 + +501 +00:22:50,170 --> 00:22:52,639 +当作危险的事情来对待 + +502 +00:22:52,639 --> 00:22:55,976 +这很重要 +因为 Swift 既重视类型安全 + +503 +00:22:55,976 --> 00:23:00,047 +它还重视对 C 系列代码的轻松访问 + +504 +00:23:00,047 --> 00:23:01,815 +这就是为什么 C +和 Objective-C 的互操作 + +505 +00:23:01,815 --> 00:23:05,085 +如此丰富和无缝 +为什么 Swift 项目 + +506 +00:23:05,085 --> 00:23:08,255 +组建了 Angela +在前面提到的 C++ 工作组 + +507 +00:23:08,255 --> 00:23:11,592 +开始构建为 C++ 提供同样强大的互用性 + +508 +00:23:11,592 --> 00:23:13,460 +我们不想让使用这样的 C 函数 + +509 +00:23:13,460 --> 00:23:16,763 +变得非常痛苦 +这种痛苦是可以避免的 + +510 +00:23:16,763 --> 00:23:18,565 +所以 Swift 制定了一套单独的规则 + +511 +00:23:18,565 --> 00:23:21,435 +用于调用导入的函数和方法 + +512 +00:23:21,435 --> 00:23:24,171 +它允许在 C 中合法的指针转换 + +513 +00:23:24,171 --> 00:23:26,974 +即使它们通常在 Swift 中是不合法的 + +514 +00:23:26,974 --> 00:23:31,512 +这样您的 Swift 代码 +就可以无缝地使用这些 API + +515 +00:23:31,512 --> 00:23:33,747 +到目前为止 我们已经讨论了对 + +516 +00:23:33,747 --> 00:23:35,415 +您已经拥有的工具的一些小的改进 + +517 +00:23:35,415 --> 00:23:38,151 +今年 Swift 中还新增了一个全新工具 + +518 +00:23:38,151 --> 00:23:41,588 +用于从字符串中提取信息 + +519 +00:23:41,588 --> 00:23:43,390 +这里有一个函数 可以从一个字符串中 + +520 +00:23:43,390 --> 00:23:45,092 +解析出一些信息 + +521 +00:23:45,092 --> 00:23:46,593 +这种任务对于 Swift 来说 + +522 +00:23:46,593 --> 00:23:48,795 +一直有点难 + +523 +00:23:48,795 --> 00:23:51,798 +您得反复搜索、分割和切片 + +524 +00:23:51,798 --> 00:23:54,768 +直到您得到您想要的 + +525 +00:23:54,768 --> 00:23:56,570 +当人们注意到这一点时 + +526 +00:23:56,570 --> 00:23:58,705 +他们往往会关注一些小事 + +527 +00:23:58,705 --> 00:24:00,741 +比如操纵字符串索引有多冗长 + +528 +00:24:00,741 --> 00:24:03,877 +但我认为这有点忽略了大局 + +529 +00:24:03,877 --> 00:24:06,747 +因为即使我们改变了这个语法 + +530 +00:24:06,747 --> 00:24:09,183 +它也不能帮助您 +回答您提出的基本问题 + +531 +00:24:09,183 --> 00:24:12,386 +当您查看此代码时 + +532 +00:24:12,386 --> 00:24:15,389 +传入它的行变量究竟是什么样子的? + +533 +00:24:15,389 --> 00:24:18,458 +它想拆开什么样的字符串? + +534 +00:24:18,458 --> 00:24:20,661 +如果您凝视它足够长的时间 +您可能会意识到 + +535 +00:24:20,661 --> 00:24:23,530 +它正在解析 mailmap 的简化版本 + +536 +00:24:23,530 --> 00:24:25,732 +即您放入 git 存储库的 + +537 +00:24:25,732 --> 00:24:29,069 +以更正之前提交的 +开发人员姓名的文件 + +538 +00:24:29,069 --> 00:24:31,839 +但是通过搜索和切片来提取这些信息 + +539 +00:24:31,839 --> 00:24:35,843 +太复杂了 很难弄清楚 + +540 +00:24:35,843 --> 00:24:38,345 +您执着于如何分割字符串 + +541 +00:24:38,345 --> 00:24:42,316 +以至于忘记了那个字符串是什么 + +542 +00:24:42,316 --> 00:24:45,953 +问题不在于这两种表达方式 + +543 +00:24:45,953 --> 00:24:48,355 +问题是整个事情 + +544 +00:24:48,355 --> 00:24:49,890 +我们需要打破这一切 + +545 +00:24:49,890 --> 00:24:52,092 +并用更好的东西代替它 + +546 +00:24:52,092 --> 00:24:54,494 +我们需要一种不同的方法 + +547 +00:24:54,494 --> 00:24:56,964 +在这种方法中 您的代码可以描述出 + +548 +00:24:56,964 --> 00:24:58,832 +您想要匹配的字符串 + +549 +00:24:58,832 --> 00:25:01,602 +语言会说明如何去做 + +550 +00:25:01,602 --> 00:25:05,772 +是一种声明性方法 +而不是强制性方法 + +551 +00:25:05,772 --> 00:25:10,811 +在 Swift 5.7 中 您现在可以 +通过编写正则表达式来做到这一点 + +552 +00:25:10,811 --> 00:25:14,214 +正则表达式是 +一种描述字符串中模式的方法 + +553 +00:25:14,214 --> 00:25:16,717 +50 多年来 语言和工具 + +554 +00:25:16,717 --> 00:25:18,619 +允许开发人员编以紧凑 + +555 +00:25:18,619 --> 00:25:21,588 +且信息丰富的语法写正则表达式 + +556 +00:25:21,588 --> 00:25:24,491 +开发者中的一些人 +已在 Xcode 查找栏中使用过它们 + +557 +00:25:24,491 --> 00:25:26,426 +在 grep 等指令行工具中 + +558 +00:25:26,426 --> 00:25:29,096 +在 Foundation 的 +NSRegularExpression 类 + +559 +00:25:29,096 --> 00:25:31,465 +或其他编程语言中 + +560 +00:25:31,465 --> 00:25:34,501 +Swift 的正则表达式字面量 +现在支持该语法 + +561 +00:25:34,501 --> 00:25:37,971 +它的工作原理 +就像在任何其他开发工具中一样 + +562 +00:25:37,971 --> 00:25:40,174 +但是开发者中的一些人以前没用过正则表达式 + +563 +00:25:40,174 --> 00:25:42,843 +您可能会问:“那是真正的代码吗? + +564 +00:25:42,843 --> 00:25:46,280 +还是一只猫从键盘上乱踩出来的?” + +565 +00:25:46,280 --> 00:25:47,948 +我不会责备您 + +566 +00:25:47,948 --> 00:25:50,450 +正则表达式字面量 +是用符号和助记符编写的 + +567 +00:25:50,450 --> 00:25:53,720 +您必须记住才能阅读它们 + +568 +00:25:53,720 --> 00:25:55,189 +对于懂这种语言的人来说 + +569 +00:25:55,189 --> 00:25:56,823 +即使是 +这个正则表达式中最粗糙的部分 + +570 +00:25:56,823 --> 00:25:59,259 +比如和开发者名字匹配的部分 + +571 +00:25:59,259 --> 00:26:02,763 +只是几个简单匹配规则的组合 + +572 +00:26:02,763 --> 00:26:06,767 +但要把很多行为 +塞进 11 个字符里是很难的 + +573 +00:26:06,767 --> 00:26:10,204 +正则表达式字面量非常紧凑 +即使是经验丰富的开发人员 + +574 +00:26:10,204 --> 00:26:13,407 +有时需要一些时间 +来理解一个复杂的表达式 + +575 +00:26:13,407 --> 00:26:15,809 +但是如果您能写出 +同样的匹配规则 + +576 +00:26:15,809 --> 00:26:18,946 +只是用词汇而不是符号? + +577 +00:26:18,946 --> 00:26:21,915 +这似乎更容易理解 + +578 +00:26:21,915 --> 00:26:23,150 +其实放在一起 + +579 +00:26:23,150 --> 00:26:26,887 +您会得到一些看起来 +很像 SwiftUI 的东西 + +580 +00:26:26,887 --> 00:26:30,290 +这将是很好的 +替代正则表达式的文字 不是吗? + +581 +00:26:30,290 --> 00:26:33,460 +所以 Swift 支持它是一件好事! + +582 +00:26:33,460 --> 00:26:35,329 +RegexBuilder 库提供了一个全新的 + +583 +00:26:35,329 --> 00:26:39,066 +SwiftUI 风格的正则表达式语言 + +584 +00:26:39,066 --> 00:26:42,236 +更易于使用 +并且比传统语法更具可读性 + +585 +00:26:42,236 --> 00:26:44,671 +它可以做 +与正则表达式文字相同的事情 + +586 +00:26:44,671 --> 00:26:47,341 +但它用您能理解或查阅的语言 + +587 +00:26:47,341 --> 00:26:50,177 +描述了它的行为 + +588 +00:26:50,177 --> 00:26:52,279 +而不是用您必须记住的符号和缩写 + +589 +00:26:52,279 --> 00:26:54,414 +正则表达式构建器非常适合初学者 + +590 +00:26:54,414 --> 00:26:57,150 +但它的功能不仅仅适合初学者 + +591 +00:26:57,150 --> 00:26:59,253 +它具有强大的功能 + +592 +00:26:59,253 --> 00:27:01,622 +远远超过了正则表达式字面量 + +593 +00:27:01,622 --> 00:27:03,457 +首先您可以把正则表达式 + +594 +00:27:03,457 --> 00:27:05,993 +变成一个可重用的正则表达式组件 + +595 +00:27:05,993 --> 00:27:08,495 +就像您可以把 SwiftUI 视图层次 + +596 +00:27:08,495 --> 00:27:10,597 +变成一个视图一样 + +597 +00:27:10,597 --> 00:27:12,833 +您可以使用构建器语法创建的 + +598 +00:27:12,833 --> 00:27:14,768 +其他正则表达式中的这些组件 + +599 +00:27:14,768 --> 00:27:17,404 +您甚至可以让它们递归 + +600 +00:27:17,404 --> 00:27:19,740 +正则表达式构建器还支持将 + +601 +00:27:19,740 --> 00:27:22,142 +一些 Swift 类型 +直接放入正则表达式中 + +602 +00:27:22,142 --> 00:27:24,111 +例如 字符串文字只匹配 + +603 +00:27:24,111 --> 00:27:28,549 +里面的确切文本 不需要特殊的转义 + +604 +00:27:28,549 --> 00:27:30,217 +您还可以使用在正则表达式生成器 + +605 +00:27:30,217 --> 00:27:32,352 +中的正则表达式字面量 + +606 +00:27:32,352 --> 00:27:34,388 +所以您可以 +在正则表达式构建器清晰度 + +607 +00:27:34,388 --> 00:27:38,559 +和正则表达式字面量的 +简洁性之间取得平衡 + +608 +00:27:38,559 --> 00:27:41,662 +其他类型 比如这个 +Foundation 日期格式风格 + +609 +00:27:41,662 --> 00:27:44,531 +可以将自定义解析逻辑 +与正则表达式构建器集成 + +610 +00:27:44,531 --> 00:27:48,702 +甚至在捕获数据之前 +将其转换为更丰富的类型 + +611 +00:27:48,702 --> 00:27:50,838 +最后 无论您使用哪种语法 + +612 +00:27:50,838 --> 00:27:54,141 +正则表达式支持很多有用的匹配方法 + +613 +00:27:54,141 --> 00:27:58,212 +以及易于使用的强类型捕获 + +614 +00:27:58,212 --> 00:28:00,113 +对于那些惴惴不安的 + +615 +00:28:00,113 --> 00:28:02,382 +痴迷于正则表达式的人来说 + +616 +00:28:02,382 --> 00:28:05,219 +Swift Regex +使用全新的开源匹配引擎 + +617 +00:28:05,219 --> 00:28:06,353 +具有可与最先进的正则表达式实现 + +618 +00:28:06,353 --> 00:28:09,623 +相匹配的功能集 + +619 +00:28:09,623 --> 00:28:13,193 +字面量语法与 Unicode 正则表达式标准兼容 + +620 +00:28:13,193 --> 00:28:16,263 +它具有不同寻常的 Unicode 正确性级别 + +621 +00:28:16,263 --> 00:28:19,166 +例如 点默认匹配整个字符 + +622 +00:28:19,166 --> 00:28:22,970 +不是 Unicode.Scalar 或 UTF-8 字节 + +623 +00:28:22,970 --> 00:28:25,172 +要使用 Swift Regex 您的 App 需要在 + +624 +00:28:25,172 --> 00:28:28,008 +在内置 Swift Regex 引擎的 OS 上运行 + +625 +00:28:28,008 --> 00:28:32,212 +比如 macOS 13 或 iOS 16 + +626 +00:28:32,212 --> 00:28:34,515 +Swift Regex 是一门完整的语言 + +627 +00:28:34,515 --> 00:28:36,416 +嗯 真的是两种语言 + +628 +00:28:36,416 --> 00:28:38,819 +所以还有很多内容要讲 + +629 +00:28:38,819 --> 00:28:40,787 +“Swift 正则表达式简介” + +630 +00:28:40,787 --> 00:28:43,156 +“深入了解 Swift 正则表达式” + +631 +00:28:43,156 --> 00:28:46,793 +将为您提供 +更多关于其用途的详细信息 + +632 +00:28:46,793 --> 00:28:48,028 +最后 我们在一个地方 + +633 +00:28:48,028 --> 00:28:50,464 +对现有的工具进行了全面的检查 + +634 +00:28:50,464 --> 00:28:53,200 +并进行了大量的修改来改进它们 + +635 +00:28:53,200 --> 00:28:56,270 +那就是在泛型和协议中 + +636 +00:28:56,270 --> 00:28:58,105 +为了向您展示这些工具是如何改进的 + +637 +00:28:58,105 --> 00:29:00,474 +我需要举一个协议示例 + +638 +00:29:00,474 --> 00:29:02,209 +假设您正在 +编写一个 git 客户端 + +639 +00:29:02,209 --> 00:29:05,846 +而且您必须 +以两种不同的方式表示邮件映射 + +640 +00:29:05,846 --> 00:29:08,949 +当您显示提交时 +您使用字典类型 + +641 +00:29:08,949 --> 00:29:11,585 +快速查找名称 + +642 +00:29:11,585 --> 00:29:13,954 +但是当您让用户编辑邮件映射时 + +643 +00:29:13,954 --> 00:29:16,156 +您使用数组类型 + +644 +00:29:16,156 --> 00:29:18,859 +按照其原来的顺序来保留条目 + +645 +00:29:18,859 --> 00:29:20,627 +您有一个叫做 Mailmap 的协议 + +646 +00:29:20,627 --> 00:29:22,329 +它们都符合这个协议 + +647 +00:29:22,329 --> 00:29:26,700 +因此您的邮件映射解析器 +可将条目添加到任一类型 + +648 +00:29:26,700 --> 00:29:28,502 +但是解析器可以通过两种方式 + +649 +00:29:28,502 --> 00:29:30,704 +使用 Mailmap 协议 + +650 +00:29:30,704 --> 00:29:31,939 +我写了两个不同的版本 + +651 +00:29:31,939 --> 00:29:34,575 +addEntries 函数来加以说明 + +652 +00:29:34,575 --> 00:29:36,176 +但实际上有点难解释 + +653 +00:29:36,176 --> 00:29:37,477 +它们的不同之处 + +654 +00:29:37,477 --> 00:29:41,615 +因为 Swift 对两种不同的事物 +使用相同的语法 + +655 +00:29:41,615 --> 00:29:45,352 +看起来 “Mailmap” 这个词 +在这里意味着一件事 + +656 +00:29:45,352 --> 00:29:47,754 +但它在这里的意思略有不同 + +657 +00:29:50,290 --> 00:29:53,060 +当您命名协议是用在在继承列表 + +658 +00:29:53,060 --> 00:29:56,463 +泛型参数列表 泛型一致性约束 + +659 +00:29:56,463 --> 00:29:58,198 +或不透明的结果类型中时 + +660 +00:29:58,198 --> 00:30:01,902 +它的意思是一个符合这个协议的实例 + +661 +00:30:01,902 --> 00:30:04,371 +但在变量类型 泛型变元 + +662 +00:30:04,371 --> 00:30:06,373 +泛型同类型约束 + +663 +00:30:06,373 --> 00:30:08,709 +或函数参数或结果类型中 + +664 +00:30:08,709 --> 00:30:10,978 +它实际上的意思是 + +665 +00:30:10,978 --> 00:30:14,615 +“一个包含符合此协议的实例的容器” + +666 +00:30:14,615 --> 00:30:16,416 +这种区别很重要 因为容器 + +667 +00:30:16,416 --> 00:30:20,254 +通常使用更多空间 +需要更多时间来操作 + +668 +00:30:20,254 --> 00:30:22,022 +并不具备里面的 + +669 +00:30:22,022 --> 00:30:24,391 +实例的所有能力 + +670 +00:30:24,391 --> 00:30:25,993 +但是您使用容器的地方 + +671 +00:30:25,993 --> 00:30:28,362 +和不使用容器的地方看起来很像 + +672 +00:30:28,362 --> 00:30:31,164 +所以很难弄清楚您是否正在使用容器 + +673 +00:30:31,164 --> 00:30:34,801 +Swift 5.7 修复了这个疏忽 + +674 +00:30:34,801 --> 00:30:36,370 +当您使用包含一个 + +675 +00:30:36,370 --> 00:30:38,238 +符合类型的容器之一时 + +676 +00:30:38,238 --> 00:30:41,975 +Swift 希望您能写入 any 关键字 + +677 +00:30:41,975 --> 00:30:45,879 +这在 Swift 5.7 之前 +有效的代码中不是强制性的 + +678 +00:30:45,879 --> 00:30:47,948 +但我们鼓励您这样做 + +679 +00:30:47,948 --> 00:30:50,717 +您会在生成的界面 +和错误消息中看到它 + +680 +00:30:50,717 --> 00:30:53,620 +即使您没有明确写出来 + +681 +00:30:53,620 --> 00:30:55,622 +所以在右侧的列中写入所有 + +682 +00:30:55,622 --> 00:30:58,825 +这些内容的首选方式 +是带有 any 关键字 + +683 +00:30:58,825 --> 00:31:00,761 +这样您就能知道 + +684 +00:31:00,761 --> 00:31:03,564 +您是不是在使用其中一个容器 + +685 +00:31:03,564 --> 00:31:05,332 +在此例中 any 关键字标记了参数之一 + +686 +00:31:05,332 --> 00:31:07,835 +更容易解释 + +687 +00:31:07,835 --> 00:31:10,337 +这两个函数的区别 + +688 +00:31:10,337 --> 00:31:14,074 +addEntries1 将 Mailmap 作为泛型类型 + +689 +00:31:14,074 --> 00:31:17,277 +addEntries2 将其视为 any 类型 + +690 +00:31:17,277 --> 00:31:18,879 +并且当您遇到 any 类型的限制之一时 + +691 +00:31:18,879 --> 00:31:20,380 +错误消息也更容易 + +692 +00:31:20,380 --> 00:31:23,450 +解释发生了什么 + +693 +00:31:23,450 --> 00:31:26,453 +例如这个 mergeMailmaps 函数视图将 + +694 +00:31:26,453 --> 00:31:30,390 +一个 any Mailmap 传递 +给泛型 Mailmap 参数 + +695 +00:31:30,390 --> 00:31:31,592 +这曾经产生错误 + +696 +00:31:31,592 --> 00:31:34,494 +说 Mailmap 与它自己不符 + +697 +00:31:34,494 --> 00:31:37,764 +这似乎有点自相矛盾 + +698 +00:31:37,764 --> 00:31:40,000 +但是现在我们有了 any 类型的概念 + +699 +00:31:40,000 --> 00:31:42,803 +我们就可以 +更清楚地解释正在发生的事情 + +700 +00:31:42,803 --> 00:31:44,872 +问题是 any Mailmap + +701 +00:31:44,872 --> 00:31:47,107 +是包含 Maimap 的容器 + +702 +00:31:47,107 --> 00:31:49,943 +不符合 Mailmap 协议 + +703 +00:31:49,943 --> 00:31:51,745 +但容器是您试图传递的东西 + +704 +00:31:51,745 --> 00:31:55,015 +并且它不适合泛型参数 + +705 +00:31:55,015 --> 00:31:57,551 +如果要在此处传递容器内的实例 + +706 +00:31:57,551 --> 00:32:00,654 +您必须以某种方式打开容器 + +707 +00:32:00,654 --> 00:32:04,491 +取出里面的 Mailmap 然后传递它 + +708 +00:32:04,491 --> 00:32:08,462 +但实际上 在这种简单的情况下 + +709 +00:32:08,462 --> 00:32:10,631 +Swift 会为您做这件事 + +710 +00:32:10,631 --> 00:32:13,467 +打开容器 取出里面的实例 + +711 +00:32:13,467 --> 00:32:16,103 +并将其传递给泛型参数 + +712 +00:32:16,103 --> 00:32:17,704 +所以您不会再经常 + +713 +00:32:17,704 --> 00:32:19,640 +看到这个错误信息了 + +714 +00:32:19,640 --> 00:32:21,275 +还有一个更令人兴奋的 + +715 +00:32:21,275 --> 00:32:23,877 +对 any 类型的改进 + +716 +00:32:23,877 --> 00:32:26,880 +以前协议不能用作 any 类型 + +717 +00:32:26,880 --> 00:32:30,784 +如果它使用 Self 类型或具有关联类型 + +718 +00:32:30,784 --> 00:32:32,920 +甚至只是符合一个协议 + +719 +00:32:32,920 --> 00:32:34,888 +比如 Equatable + +720 +00:32:34,888 --> 00:32:38,492 +但在 Swift 5.7 中 + +721 +00:32:38,492 --> 00:32:39,793 +这个错误 + +722 +00:32:39,793 --> 00:32:42,496 +消失了 + +723 +00:32:42,496 --> 00:32:44,298 +很多开发者都在为此苦苦挣扎 + +724 +00:32:44,298 --> 00:32:47,501 +所以我们很高兴能从源头上修复它 + +725 +00:32:47,501 --> 00:32:50,370 +现在对于像 Mailmap +这样的协议来说 这足够令人兴奋 + +726 +00:32:50,370 --> 00:32:52,573 +但还不止于此 + +727 +00:32:52,573 --> 00:32:55,642 +因为即使是 +非常复杂的协议 比如 Collection + +728 +00:32:55,642 --> 00:32:58,278 +也可以用作 any 类型 + +729 +00:32:58,278 --> 00:33:00,247 +您甚至可以指定元素类型 + +730 +00:33:00,247 --> 00:33:04,251 +这要归功于 +一个名为“主关联类型”的新功能 + +731 +00:33:04,251 --> 00:33:05,419 +很多关联类型 + +732 +00:33:05,419 --> 00:33:08,722 +基本上只是实现细节 + +733 +00:33:08,722 --> 00:33:11,058 +您通常不会关心集合为其索引 + +734 +00:33:11,058 --> 00:33:13,927 +迭代器或子序列使用哪种类型 + +735 +00:33:13,927 --> 00:33:16,897 +您只需要使用它支持的类型 + +736 +00:33:16,897 --> 00:33:20,067 +但它的 Element 就不同了 + +737 +00:33:20,067 --> 00:33:21,935 +您可能并不一定关心 + +738 +00:33:21,935 --> 00:33:23,804 +集合究竟使用哪种元素类型 + +739 +00:33:23,804 --> 00:33:25,772 +但您可能要用元素做点什么 + +740 +00:33:25,772 --> 00:33:29,877 +所以您需要约束它们或返回它们等等 + +741 +00:33:29,877 --> 00:33:32,012 +当您有像 Element 这样 +几乎每个协议的用户 + +742 +00:33:32,012 --> 00:33:35,249 +都会关心的关联类型时 + +743 +00:33:35,249 --> 00:33:37,017 +您可以将其名称放在协议名称之后 + +744 +00:33:37,017 --> 00:33:41,255 +用尖括号括上 +以使其成为主关联类型 + +745 +00:33:41,255 --> 00:33:43,724 +这样您就可以用尖括号语法 + +746 +00:33:43,724 --> 00:33:46,660 +来限制协议的的主关联类型 + +747 +00:33:46,660 --> 00:33:49,596 +在可以在写协议名称的 +任何地方都添加尖括号 + +748 +00:33:49,596 --> 00:33:52,165 +包括在任何 Collection 中 + +749 +00:33:52,165 --> 00:33:54,902 +现在 开发者中的一些人 +可能正在看这种类型 + +750 +00:33:54,902 --> 00:33:57,271 +并想“等一下 + +751 +00:33:57,271 --> 00:33:59,640 +是不是已经有一个 +叫做 AnyCollection 的东西 + +752 +00:33:59,640 --> 00:34:03,844 +一起运行并且 Any 是大写的了?” + +753 +00:34:03,844 --> 00:34:06,380 +您是对的 是有的! + +754 +00:34:06,380 --> 00:34:09,650 +旧的 AnyCollection +是一个去类型包装器 + +755 +00:34:09,650 --> 00:34:12,085 +它是一个作用 +与 any 类型相同的 + +756 +00:34:12,085 --> 00:34:13,887 +手写的结构 + +757 +00:34:13,887 --> 00:34:15,889 +不同之处在于 +AnyCollection 结构体 + +758 +00:34:15,889 --> 00:34:18,992 +只是一行又一行最无聊的模板代码 + +759 +00:34:18,992 --> 00:34:22,629 +您在生活中见过的 + +760 +00:34:22,629 --> 00:34:24,131 +而 any 类型是一种内置的语言功能 + +761 +00:34:24,131 --> 00:34:26,066 +基本上做同样的事情 + +762 +00:34:26,066 --> 00:34:27,601 +是免费的! + +763 +00:34:27,601 --> 00:34:29,436 +现在 为了向后兼容 + +764 +00:34:29,436 --> 00:34:31,338 +AnyCollection 结构体将继续存在 +因为它有 + +765 +00:34:31,338 --> 00:34:34,875 +一些 any 类型无法完全匹配的功能 + +766 +00:34:34,875 --> 00:34:36,777 +但如果您的代码中 +有自己的去类型包装器 + +767 +00:34:36,777 --> 00:34:40,047 +您可能想看看 +是否可以使用内置的 any 类型 + +768 +00:34:40,047 --> 00:34:44,284 +而不是通过容器类或闭包重新实现它们 + +769 +00:34:44,284 --> 00:34:47,921 +或甚至只是用类型别名替换它们 + +770 +00:34:47,921 --> 00:34:51,458 +所以 Swift 极大地 +改进了 any 类型 + +771 +00:34:51,458 --> 00:34:52,993 +它引入了 any 关键字 + +772 +00:34:52,993 --> 00:34:55,596 +这样您就可以看到您在哪里使用它们 + +773 +00:34:55,596 --> 00:34:58,866 +它允许您将它们传递给泛型变元 + +774 +00:34:58,866 --> 00:35:01,101 +它取消了使许多协议不能 + +775 +00:35:01,101 --> 00:35:03,504 +与之一起使用的限制 + +776 +00:35:03,504 --> 00:35:04,605 +它甚至可以让您约束 + +777 +00:35:04,605 --> 00:35:08,442 +any 类型的主关联类型 + +778 +00:35:08,442 --> 00:35:10,511 +但即使有了所有这些改进 + +779 +00:35:10,511 --> 00:35:13,480 +any 类型仍然有限制 + +780 +00:35:13,480 --> 00:35:16,517 +例如 即使您现在 +可以使用 any Mailmap + +781 +00:35:16,517 --> 00:35:18,852 +当 Mailmap 符合 Equatable 时 + +782 +00:35:18,852 --> 00:35:21,622 +您仍然不能对它们使用等于运算符 + +783 +00:35:21,622 --> 00:35:24,258 +因为等于运算符需要两个 Mailmap + +784 +00:35:24,258 --> 00:35:27,461 +具有相同的具体类型 + +785 +00:35:27,461 --> 00:35:30,030 +但当您使用两个 any Mailmap 时 +并不能保证这一点 + +786 +00:35:30,030 --> 00:35:32,599 +所以即使 Swift 对 any 类型做了很多改进 + +787 +00:35:32,599 --> 00:35:34,735 +它们在能力和性能方面 + +788 +00:35:34,735 --> 00:35:37,971 +仍然有不可忽视的限制 + +789 +00:35:37,971 --> 00:35:41,008 +这就是为什么很多时候 +您不应该使用它们 + +790 +00:35:41,008 --> 00:35:43,377 +而应该改用泛型 + +791 +00:35:43,377 --> 00:35:46,013 +那么让我们回到 +addEntries 的两个版本 + +792 +00:35:46,013 --> 00:35:48,015 +并运用这种智慧 + +793 +00:35:48,015 --> 00:35:50,651 +两个版本的功能完全相同 + +794 +00:35:50,651 --> 00:35:53,287 +但最上面的那个使用泛型类型 + +795 +00:35:53,287 --> 00:35:56,757 +底部的使用 any 类型 + +796 +00:35:56,757 --> 00:35:59,159 +泛型版本可能会更有效 + +797 +00:35:59,159 --> 00:36:02,829 +本领更大 所以您应该使用泛型版本 + +798 +00:36:02,829 --> 00:36:05,599 +但您可能很想使用 any 类型 + +799 +00:36:05,599 --> 00:36:08,735 +因为它们更容易读写 + +800 +00:36:08,735 --> 00:36:10,003 +要编写泛型版本 + +801 +00:36:10,003 --> 00:36:12,439 +您需要声明两个泛型类型名称 + +802 +00:36:12,439 --> 00:36:14,641 +约束它们 + +803 +00:36:14,641 --> 00:36:18,745 +最后使用这些泛型类型名称 +作为参数类型 + +804 +00:36:18,745 --> 00:36:21,481 +与写 “any Collection” +和 “any Mailmap” 相比 + +805 +00:36:21,481 --> 00:36:23,417 +这简直令人筋疲力尽 + +806 +00:36:23,417 --> 00:36:27,387 +因此尽管有缺点 +您还是很想使用 any 类型 + +807 +00:36:27,387 --> 00:36:30,190 +但这和我之前说的一样 + +808 +00:36:30,190 --> 00:36:32,192 +用锤子代替螺丝刀 + +809 +00:36:32,192 --> 00:36:34,728 +因为锤子有一个又大又防滑的把手 + +810 +00:36:34,728 --> 00:36:37,264 +您不应该做出这样的选择 + +811 +00:36:37,264 --> 00:36:40,100 +所以 Swift 让泛型变得更容易使用 + +812 +00:36:40,100 --> 00:36:42,169 +和 any 类型一样 + +813 +00:36:42,169 --> 00:36:44,938 +如果泛型参数只用在一个地方 + +814 +00:36:44,938 --> 00:36:48,442 +您现在可以 +用关键字 some 作为速记写法 + +815 +00:36:48,442 --> 00:36:50,844 +它甚至支持主要的关联类型 + +816 +00:36:50,844 --> 00:36:53,180 +所以您可以用更容易理解的代码 + +817 +00:36:53,180 --> 00:36:55,849 +接受所有邮件映射条目集合 + +818 +00:36:55,849 --> 00:36:57,217 +在您的工具箱里 + +819 +00:36:57,217 --> 00:37:00,354 +没有理由再避免使用泛型了 + +820 +00:37:00,354 --> 00:37:02,890 +如果您可以在泛型和 any 类型之间进行选择 + +821 +00:37:02,890 --> 00:37:05,192 +泛型将同样易于使用 + +822 +00:37:05,192 --> 00:37:07,995 +只写 “some” 而不是 “any” 即可 + +823 +00:37:07,995 --> 00:37:11,198 +所以您不妨使用 +最好的工具来完成这项工作 + +824 +00:37:11,198 --> 00:37:13,166 +我只是讲解了协议和泛型 + +825 +00:37:13,166 --> 00:37:15,068 +变更的一些皮毛 + +826 +00:37:15,068 --> 00:37:17,171 +为了深入了解 + +827 +00:37:17,171 --> 00:37:19,106 +并介绍所有 Swift 泛型功能 + +828 +00:37:19,106 --> 00:37:21,341 +今年我们还有两场讲座 + +829 +00:37:21,341 --> 00:37:23,010 +即“拥抱 Swift 泛型” + +830 +00:37:23,010 --> 00:37:25,345 +和“在 Swift 中设计协议接口” + +831 +00:37:28,182 --> 00:37:29,550 +现在 Angela 和我差不多介绍了 + +832 +00:37:29,550 --> 00:37:31,785 +二十多个 Swift 更改 + +833 +00:37:31,785 --> 00:37:35,255 +我们在这次课程中 +还有很多没讲到的内容 + +834 +00:37:35,255 --> 00:37:38,692 +这些变化中的每一个都 + +835 +00:37:38,692 --> 00:37:41,562 +经过了确定标准、提议、审查 + +836 +00:37:41,562 --> 00:37:43,430 +并在 Swift 论坛的 +Evolution 板上被公开接受 + +837 +00:37:43,430 --> 00:37:45,899 +所有这些都是 +在 Apple 以外的社区成员 + +838 +00:37:45,899 --> 00:37:48,836 +的帮助下成形和得以实现的 + +839 +00:37:48,836 --> 00:37:52,706 +如果您是这些人中的一员 +感谢各位开发者 + +840 +00:37:52,706 --> 00:37:55,075 +让 Swift 5.7 成为一个伟大的版本 + +841 +00:37:55,075 --> 00:37:57,211 +如果您想帮助决定接下来的事情 + +842 +00:37:57,211 --> 00:38:02,216 +访问 Swift.org/contributing +以了解如何参与 + +843 +00:38:02,216 --> 00:38:03,350 +感谢您付出的时间 + +844 +00:38:03,350 --> 00:38:04,952 +Angela:编码快乐 + +845 +00:38:06,987 --> 00:38:08,755 +[大笑] + +846 +00:38:08,755 --> 00:38:12,826 +♪ + diff --git a/zho/2022 Session 110355 Meet Swift Async Algorithms.srt b/zho/2022 Session 110355 Meet Swift Async Algorithms.srt new file mode 100644 index 0000000..bab2251 --- /dev/null +++ b/zho/2022 Session 110355 Meet Swift Async Algorithms.srt @@ -0,0 +1,1019 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,710 --> 00:00:11,612 +Philippe Hausler: +您好 我叫 Philippe + +3 +00:00:11,645 --> 00:00:15,148 +Swift 拥有越来越多的 +开源软件包 + +4 +00:00:15,182 --> 00:00:18,352 +我很高兴向您介绍 +最新添加的内容之一 + +5 +00:00:18,385 --> 00:00:20,354 +Swift Async Algorithms + +6 +00:00:20,387 --> 00:00:23,090 +这个包和其他包一起 + +7 +00:00:23,123 --> 00:00:26,493 +例如 Swift Collections +和 Swift Algorithms + +8 +00:00:26,527 --> 00:00:29,997 +Swift Async Algorithms 包含一组算法 + +9 +00:00:30,030 --> 00:00:35,435 +专门通过 AsyncSequence 按时序 +处理数值 + +10 +00:00:35,469 --> 00:00:37,171 +但在我们进入内容之前 + +11 +00:00:37,204 --> 00:00:40,207 +让我们花点时间 +回顾一下 AsyncSequence + +12 +00:00:40,240 --> 00:00:43,644 +AsyncSequence 是一种协议 +可以让您描述 + +13 +00:00:43,677 --> 00:00:45,612 +通过异步过程产生的值 + +14 +00:00:45,646 --> 00:00:50,817 +基本上 它与 Sequence 类似 +但有两个关键区别 + +15 +00:00:50,851 --> 00:00:54,288 +其迭代器的 +next 函数是异步的 + +16 +00:00:54,321 --> 00:00:58,325 +因为它可以使用 +Swift 并发功能传递值 + +17 +00:00:58,358 --> 00:01:03,297 +它还允许您使用 Swift 的抛出异常 +以便于处理任何潜在的故障 + +18 +00:01:03,330 --> 00:01:06,233 +并且您可以像 +Sequence 一样 + +19 +00:01:06,266 --> 00:01:09,002 +使用 for-await-in 语法 +迭代它 + +20 +00:01:09,036 --> 00:01:11,905 +总之 如果您知道 +如何使用 Sequence + +21 +00:01:11,939 --> 00:01:15,409 +那么您就已经知道了 +如何使用 AsyncSequence + +22 +00:01:15,442 --> 00:01:19,847 +现在 当引入 AsyncSequence +我们在异步版本中添加了 + +23 +00:01:19,880 --> 00:01:23,984 +几乎所有可以用于 Sequence 的工具 + +24 +00:01:24,017 --> 00:01:29,990 +例如 map、filter +reduce 等算法 + +25 +00:01:30,023 --> 00:01:33,861 +Swift Async Algorithms +通过合并更高级的算法 + +26 +00:01:33,894 --> 00:01:37,664 +以及与时钟的互操作 +向您提供一些真正强大的功能 + +27 +00:01:37,698 --> 00:01:41,535 +让那些功能效果更上一层楼 + +28 +00:01:41,568 --> 00:01:45,305 +这是一个开源的 +AsyncSequence 算法包 + +29 +00:01:45,339 --> 00:01:48,008 +可以增强 Swift 并发的功能 + +30 +00:01:48,041 --> 00:01:51,011 +去年我们推出了 +Swift Algorithms 包 + +31 +00:01:51,044 --> 00:01:53,680 +为了演示这些算法的用途 + +32 +00:01:53,714 --> 00:01:55,115 +我们制作了一个消息 App + +33 +00:01:55,148 --> 00:01:58,485 +这是一个很好的例子 +您可以用这个包 + +34 +00:01:58,519 --> 00:02:00,454 +做一些丰富和强大的东西 + +35 +00:02:00,487 --> 00:02:03,457 +我们认为这是很好机会 + +36 +00:02:03,490 --> 00:02:07,661 +通过迁移 App 使用 Swift 并发 + +37 +00:02:07,694 --> 00:02:10,998 +为了强调一些异步算法的使用 + +38 +00:02:11,031 --> 00:02:13,834 +我将带您了解我们使用的一些功能 + +39 +00:02:13,867 --> 00:02:16,036 +以及它们是如何工作的 + +40 +00:02:16,069 --> 00:02:18,972 +首先 我们有一系列 + +41 +00:02:19,006 --> 00:02:21,675 +处理多输入 +AsyncSequence 的算法 + +42 +00:02:21,708 --> 00:02:27,581 +这些算法侧重于以不同的方式将 +多个 AsyncSequence 组合在一起 + +43 +00:02:27,614 --> 00:02:30,083 +但它们都有一个共同特点 + +44 +00:02:30,117 --> 00:02:35,822 +它们接受多个 AsyncSequence 输入 +并产生一个 AsyncSequence 输出 + +45 +00:02:36,857 --> 00:02:40,260 +您可能已经非常熟悉 Zip + +46 +00:02:40,294 --> 00:02:44,064 +Zip 算法接受多个 +输入并对其进行迭代 + +47 +00:02:44,097 --> 00:02:48,101 +以便通过每个基础内容 +生成一个结果元组 + +48 +00:02:48,135 --> 00:02:52,539 +Zip 的每个输入 +都是构造 Zip 的基础内容 + +49 +00:02:52,573 --> 00:02:56,276 +在标准库中 +异步 Zip 算法的工作原理 + +50 +00:02:56,310 --> 00:02:57,744 +与 Zip 算法一样 + +51 +00:02:57,778 --> 00:03:00,347 +但它并发迭代每个基础内容 + +52 +00:03:00,380 --> 00:03:04,785 +如果在迭代其中的 +任何一个出现失败则重新抛出报错 + +53 +00:03:04,818 --> 00:03:07,187 +现在 完成并发迭代 + +54 +00:03:07,221 --> 00:03:10,424 +并支持重抛出错误会相当复杂 + +55 +00:03:10,457 --> 00:03:13,460 +但是 Swift Async Algorithms 包 +在我们的消息 App 中 + +56 +00:03:13,493 --> 00:03:15,629 +为我们解决了所有这些问题 + +57 +00:03:15,662 --> 00:03:17,297 +我们之前有很多代码 + +58 +00:03:17,331 --> 00:03:19,900 +用来协同异步工作 + +59 +00:03:19,933 --> 00:03:22,469 +比如生成视频录制预览和视频转码 + +60 +00:03:22,503 --> 00:03:26,673 +以及生成各种尺寸的视频 +用来实现高效存储和传输 + +61 +00:03:26,707 --> 00:03:31,211 +通过使用 Zip +我们可以确保转码视频 + +62 +00:03:31,245 --> 00:03:33,213 +在发送到服务器时得到预览 + +63 +00:03:33,247 --> 00:03:36,416 +由于 Zip 是并发的 +所以转码和预览 + +64 +00:03:36,450 --> 00:03:39,152 +都不会对彼此的工作造成延迟 + +65 +00:03:39,186 --> 00:03:40,988 +但更进一步想一下 + +66 +00:03:41,021 --> 00:03:43,924 +Zip 本身对任何一边 +都没有明显的偏向 + +67 +00:03:43,957 --> 00:03:48,095 +所以可以先出视频 也可以出预览 + +68 +00:03:48,128 --> 00:03:51,098 +不管它在哪一边 它都会 + +69 +00:03:51,131 --> 00:03:54,968 +等待另一方发送完成一个完整的元组 + +70 +00:03:55,002 --> 00:03:58,505 +我们可以等待视频和预览的资源配对 +以便它们可以一起上传 + +71 +00:03:58,539 --> 00:04:04,044 +因为 Zip 会同时等待 +双方构造的元组的值 + +72 +00:04:04,077 --> 00:04:07,714 +我们得出的结论是 对传入消息 + +73 +00:04:07,748 --> 00:04:10,717 +作为 AsyncSequence +建模会很有意义 + +74 +00:04:10,751 --> 00:04:14,421 +所以我们决定使用 AsyncStream +来处理这些消息 + +75 +00:04:14,454 --> 00:04:17,157 +因为它保留了顺序并 +将我们的回调转换为 + +76 +00:04:17,191 --> 00:04:20,093 +消息的 AsyncSequence 实例 + +77 +00:04:20,127 --> 00:04:23,130 +我们需要解决的功能要求之一是 + +78 +00:04:23,163 --> 00:04:25,532 +我们希望支持多个帐户 + +79 +00:04:25,566 --> 00:04:30,304 +所以每个帐户都会 +构建一个用于传入消息的 AsyncStream + +80 +00:04:30,337 --> 00:04:31,939 +但在实现时 + +81 +00:04:31,972 --> 00:04:36,844 +我们需要将它们作为一个单一的 +AsyncSequence 一起进行处理 + +82 +00:04:36,877 --> 00:04:41,715 +这意味着我们需要一种算法 +来将这些 AsyncSequences 合并在一起 + +83 +00:04:41,748 --> 00:04:47,421 +多亏 Swift Async Algorithms 包 +有一个算法可以做到这一点 + +84 +00:04:47,454 --> 00:04:49,957 +它的名字为 “Merge” + +85 +00:04:49,990 --> 00:04:54,194 +在并发迭代多个 +AsyncSequences 方面 + +86 +00:04:54,228 --> 00:04:58,565 +它的工作方式与 Zip 类似 +但它不创建成对的元组 + +87 +00:04:58,599 --> 00:05:01,735 +它要求共享相同的元素类型 + +88 +00:05:01,768 --> 00:05:04,137 +并将基础 AsyncSequences 合并为 + +89 +00:05:04,171 --> 00:05:08,141 +这些元素的一个单独的 +AsyncSequence + +90 +00:05:08,175 --> 00:05:12,346 +Merge 的工作方式是在迭代时 + +91 +00:05:12,379 --> 00:05:13,914 +采用任何一边产生的第一个元素 + +92 +00:05:13,947 --> 00:05:18,318 +它不断迭代 +直到没有更多的值可以产生 + +93 +00:05:18,352 --> 00:05:23,357 +具体就是当所有基本 AsyncSequence +从其迭代器返回 nil 时 + +94 +00:05:23,390 --> 00:05:27,861 +如果有任何基础错误产生 +则会取消其他迭代器的工作 + +95 +00:05:27,895 --> 00:05:33,400 +这让我们可以获取 +多个消息的 AsyncSequence 并合并它们 + +96 +00:05:33,433 --> 00:05:38,338 +这些组合算法 +在产生值时同时进行工作 + +97 +00:05:38,372 --> 00:05:43,076 +但有时 +与时间本身实际互动是有用的 + +98 +00:05:43,110 --> 00:05:47,481 +Swift Async Algorithms 包 +引入了一系列算法 + +99 +00:05:47,514 --> 00:05:51,919 +通过利用 Swift 中新的 +Clock API 来处理时间 + +100 +00:05:51,952 --> 00:05:55,455 +时间本身可以是 +一个非常复杂的主题 + +101 +00:05:55,489 --> 00:05:58,959 +Swift (5.7) 中新增了 +一组 API + +102 +00:05:58,992 --> 00:06:01,495 +以确保其安全性和一致性 + +103 +00:06:01,528 --> 00:06:04,565 +Clock (时钟) 、Instant (即时) +和 Duration (持续时间) + +104 +00:06:06,433 --> 00:06:09,236 +Clock (时钟) +协议定义了两个基元 + +105 +00:06:09,269 --> 00:06:11,605 +一种在给定时长后唤醒的方式 + +106 +00:06:11,638 --> 00:06:13,740 +和一种产生现在概念的方式 + +107 +00:06:13,774 --> 00:06:15,876 +它含有几个内置时钟 + +108 +00:06:15,909 --> 00:06:17,811 +其中比较常用的两个是 + +109 +00:06:17,845 --> 00:06:20,280 +ContinuousClock +和 SuspendingClock + +110 +00:06:20,314 --> 00:06:24,885 +您可以使用 ContinuousClock +像秒表一样测量时间 + +111 +00:06:24,918 --> 00:06:28,655 +无论被测事物的状态如何 +时间都在那里进行 + +112 +00:06:28,689 --> 00:06:32,593 +另一方面 SuspendingClock +正如它的名字一样 + +113 +00:06:32,626 --> 00:06:35,462 +当机器进入睡眠状态时它会挂起 + +114 +00:06:35,495 --> 00:06:40,400 +我们在 App 中 +使用了新的 Clock API + +115 +00:06:40,434 --> 00:06:45,672 +从现有的回调事件迁移到时钟睡眠功能 +用来处理截止日期后解除警报 + +116 +00:06:45,706 --> 00:06:49,943 +我们能够通过添加 +持续时间值来创建截止日期 + +117 +00:06:49,977 --> 00:06:55,249 +这个值需要特别表明 +我们想要的延迟秒数 + +118 +00:06:55,282 --> 00:06:58,785 +Clock (时钟) +也有一些方便的方法 + +119 +00:06:58,819 --> 00:07:00,454 +来测量工作执行的持续时间 + +120 +00:07:00,487 --> 00:07:03,891 +这里我们有之前 +提到的两个常见的时钟 + +121 +00:07:03,924 --> 00:07:06,493 +SuspendingClock 和 +ContinuousClock + +122 +00:07:07,494 --> 00:07:09,363 +下面展示出的计时器是 + +123 +00:07:09,396 --> 00:07:11,031 +用来解释实测工作的 + +124 +00:07:11,064 --> 00:07:12,699 +潜在工作时间的 + +125 +00:07:12,733 --> 00:07:16,170 +这两个时钟之间的主要区别 + +126 +00:07:16,203 --> 00:07:19,373 +来自于它在机器休眠时的行为 + +127 +00:07:20,440 --> 00:07:24,244 +对于此类长时间运行的工作 +工作可以暂停 + +128 +00:07:24,278 --> 00:07:25,812 +就像我们在合上盖子一样 + +129 +00:07:25,846 --> 00:07:30,083 +但是 当我们恢复设备运行时 + +130 +00:07:30,117 --> 00:07:32,286 +可以看到 ContinuousClock +仍在记录时间 + +131 +00:07:32,319 --> 00:07:33,887 +即使在机器休眠的时候 + +132 +00:07:33,921 --> 00:07:36,390 +但 SuspendingClock 并没有 + +133 +00:07:36,423 --> 00:07:39,426 +通常 这种差异对于 +通过暂停执行时间 + +134 +00:07:39,459 --> 00:07:42,829 +以确保动画之类的工作 + +135 +00:07:42,863 --> 00:07:45,999 +如预期方式完成很关键 + +136 +00:07:46,033 --> 00:07:49,536 +如果您需要与机器进行 +在时间方面的交互 + +137 +00:07:49,570 --> 00:07:52,873 +比如像动画一样 请使用 +SuspendingClock + +138 +00:07:53,907 --> 00:07:57,110 +判定和计量 +与设备前的人有关的任务 + +139 +00:07:57,144 --> 00:07:59,813 +使用 ContinuousClock +则更加合适 + +140 +00:07:59,847 --> 00:08:03,116 +因此 如果您需要做 +一个绝对持续时间 + +141 +00:08:03,150 --> 00:08:07,788 +工作是相对于人类有关的话 就请用 +ContinuousClock + +142 +00:08:07,821 --> 00:08:12,292 +Swift Async Algorithms 包 +使用这些新的 Clock、Instant + +143 +00:08:12,326 --> 00:08:16,263 +和 Duration 类型 +来构建通用算法 + +144 +00:08:16,296 --> 00:08:21,001 +用于许多与时间相关的事件处理方法 + +145 +00:08:21,034 --> 00:08:24,404 +在我们的消息 App 中 +我们发现这些功能确实有助于 + +146 +00:08:24,438 --> 00:08:27,508 +提供对事件的精确控制 + +147 +00:08:27,541 --> 00:08:32,412 +它让我们可以限制交互 +并有效的缓冲消息 + +148 +00:08:33,347 --> 00:08:36,483 +也许我们利用时间的最突出的领域 + +149 +00:08:36,517 --> 00:08:38,352 +是搜索消息 + +150 +00:08:38,385 --> 00:08:42,289 +我们创建了一个 +管理结果通道的控制器 + +151 +00:08:42,322 --> 00:08:47,661 +通道会整理好搜索任务 +的结果并返回给我们的 UI + +152 +00:08:47,694 --> 00:08:51,598 +搜索任务本身需要有一些 + +153 +00:08:51,632 --> 00:08:53,333 +在时间方面的特征 + +154 +00:08:53,367 --> 00:08:58,105 +我们希望确保在服务器上 +对搜索消息进行频率限制 + +155 +00:08:59,740 --> 00:09:03,177 +Debounce 算法会在迭代过程中 +发出下一个值之前 + +156 +00:09:03,210 --> 00:09:06,547 +等待一个静止时间 + +157 +00:09:06,580 --> 00:09:10,784 +这意味着虽然事件可以很快到来 +但我们希望确保 + +158 +00:09:10,817 --> 00:09:14,588 +在处理下一个值之前 +有一个静默期 + +159 +00:09:14,621 --> 00:09:18,025 +当用户搜索时 +对搜索框里的文本进行快速更改 + +160 +00:09:18,058 --> 00:09:19,793 +我们不希望搜索控制器 + +161 +00:09:19,826 --> 00:09:22,796 +对每次搜索内容的修改都发送请求 + +162 +00:09:22,829 --> 00:09:26,133 +而是 我们要确保 +经过一个静默期 + +163 +00:09:26,166 --> 00:09:29,670 +直到我们确定打字的动作 +很可能已经完成时 + +164 +00:09:29,703 --> 00:09:33,740 +默认情况下 Debounce 算法 +将使用 ContinuousClock + +165 +00:09:33,774 --> 00:09:37,077 +在这种情况下 +我们可以对输入进行去抖动处理 + +166 +00:09:37,110 --> 00:09:40,581 +使它等待指定的 +期间不发生任何事的时间段 + +167 +00:09:40,614 --> 00:09:43,951 +Clock (时钟) 和 Debounce (持续时间) +不仅用于去抖动 + +168 +00:09:43,984 --> 00:09:46,420 +它们也用于其他算法 + +169 +00:09:46,453 --> 00:09:49,122 +我们发现真正有用的一个方面 + +170 +00:09:49,156 --> 00:09:52,626 +是向服务器发送批量消息 + +171 +00:09:52,659 --> 00:09:54,795 +在 Swift 算法包中 + +172 +00:09:54,828 --> 00:09:57,998 +有一组算法来对值进行分块 + +173 +00:09:58,031 --> 00:10:01,034 +Swift Async Algorithms 包 +提供了这些功能 + +174 +00:10:01,068 --> 00:10:03,003 +而且还添加了一组 + +175 +00:10:03,036 --> 00:10:06,406 +与时钟和持续时间互操作的版本 + +176 +00:10:06,440 --> 00:10:10,244 +分块算法系列允许按计数 + +177 +00:10:10,277 --> 00:10:12,713 +按时间或按内容控制分块 + +178 +00:10:12,746 --> 00:10:16,517 +如果其中任何一个发生错误 +则重新抛出该报错 + +179 +00:10:16,550 --> 00:10:19,853 +所以我们的代码 +在遇到故障时是安全的 + +180 +00:10:20,821 --> 00:10:24,691 +我们使用 +“chunked(by:)” API 来确保 + +181 +00:10:24,725 --> 00:10:28,529 +消息块在一定的持续时间 +内被序列化并发送出去 + +182 +00:10:28,562 --> 00:10:33,667 +这样 我们的服务器就可以 +得到客户端发送的有效数据包 + +183 +00:10:33,700 --> 00:10:37,037 +我们能够使用这个 API +以每 500 毫秒的间隔 + +184 +00:10:37,070 --> 00:10:39,506 +来构建批量消息 + +185 +00:10:39,540 --> 00:10:43,777 +那样的话 如果有人 +真的很兴奋并且打字很快 + +186 +00:10:43,810 --> 00:10:47,014 +那么发送到服务器的请求 +就会被分组 + +187 +00:10:47,047 --> 00:10:49,783 +在使用集合和序列时 + +188 +00:10:49,816 --> 00:10:54,621 +延迟处理元素 通常是有用且高效的 + +189 +00:10:54,655 --> 00:10:58,559 +在 Swift 标准库中 +AsyncSequence 与 + +190 +00:10:58,592 --> 00:11:00,794 +惰性算法的工作方式非常相似 + +191 +00:11:00,827 --> 00:11:04,831 +但就像那些惰性算法一样 +很多时候您需要 + +192 +00:11:04,865 --> 00:11:08,202 +回到集合的世界 + +193 +00:11:08,235 --> 00:11:12,005 +Swift Async Algorithms 包 +提供了一组初始化器 + +194 +00:11:12,039 --> 00:11:15,342 +用于使用 AsyncSequence +构建集合 + +195 +00:11:15,375 --> 00:11:19,246 +这些让您可以用已知限定的 +AsyncSequence 异步序列 + +196 +00:11:19,279 --> 00:11:23,183 +构建字典、集合或数组 + +197 +00:11:23,217 --> 00:11:26,820 +集合初始化器让我们 +将转换直接整合在消息初始化 + +198 +00:11:26,854 --> 00:11:31,825 +使我们仍然可以用数组作为的数据类型 + +199 +00:11:31,859 --> 00:11:34,962 +这真的很有用 因为我们有很多功能 + +200 +00:11:34,995 --> 00:11:38,398 +真的可以通过一些更新 +来使用 Swift 并发 + +201 +00:11:38,432 --> 00:11:41,268 +通过保留我们现有的数据结构 + +202 +00:11:41,301 --> 00:11:44,304 +我们可以逐步迁移部分 App + +203 +00:11:44,338 --> 00:11:46,974 +从有意义的地方开始 + +204 +00:11:47,007 --> 00:11:49,910 +到目前为止 我们只讨论了一小部分 + +205 +00:11:49,943 --> 00:11:52,579 +关于 Swift Async Algorithms 包的亮点 + +206 +00:11:52,613 --> 00:11:54,047 +除了我们今天介绍的 + +207 +00:11:54,081 --> 00:11:55,849 +还有很多其他内容 + +208 +00:11:55,883 --> 00:12:01,855 +我们的算法范围从 +组合多个异步序列 + +209 +00:12:01,889 --> 00:12:05,425 +按时间限制速率 + +210 +00:12:05,459 --> 00:12:08,061 +将事项分块 + +211 +00:12:08,095 --> 00:12:10,764 +但这些只是我们最终 + +212 +00:12:10,797 --> 00:12:13,233 +在我们的 App 中 +广泛使用的亮点功能 + +213 +00:12:13,267 --> 00:12:16,436 +这个软件包不仅只有这些 + +214 +00:12:16,470 --> 00:12:19,139 +它的范围包括 缓冲 + +215 +00:12:19,173 --> 00:12:23,610 +归约、合并 + +216 +00:12:23,644 --> 00:12:27,848 +间歇性注入值等等 + +217 +00:12:27,881 --> 00:12:31,818 +Swift Async Algorithms 包 +采用了一组算法 + +218 +00:12:31,852 --> 00:12:35,889 +来处理随时间推移的工作 +并将其扩展到一系列 + +219 +00:12:35,923 --> 00:12:39,526 +可以在您的 App 中 +提供帮助的高级功能 + +220 +00:12:39,560 --> 00:12:40,928 +试试看 + +221 +00:12:40,961 --> 00:12:44,198 +我们真的很希望看看 +您用这些构建了什么 + +222 +00:12:44,231 --> 00:12:46,400 +这种兴奋也是共享的 + +223 +00:12:46,433 --> 00:12:50,437 +该软件包面向您开放式开发 + +224 +00:12:50,470 --> 00:12:53,173 +感谢您的收看 +并享受课程的其余部分 + +225 +00:12:53,207 --> 00:12:58,345 +[欢快的音乐] + diff --git a/zho/2022 Session 110384 Support multiple users in tvOS apps.srt b/zho/2022 Session 110384 Support multiple users in tvOS apps.srt new file mode 100644 index 0000000..71cca0a --- /dev/null +++ b/zho/2022 Session 110384 Support multiple users in tvOS apps.srt @@ -0,0 +1,1046 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,309 --> 00:00:11,345 +Felipe:嗨 我是 Felipe + +3 +00:00:11,378 --> 00:00:14,081 +我是 tvOS 团队 +的软件工程师 + +4 +00:00:14,114 --> 00:00:18,652 +今天我很高兴与大家分享我们在 +tvOS 16 中所做的改进 + +5 +00:00:18,685 --> 00:00:22,623 +可以让您更轻松地 +在 App 中支持多用户 + +6 +00:00:22,656 --> 00:00:26,460 +Apple TV 是为所有人使用 +而设计的 + +7 +00:00:26,493 --> 00:00:31,899 +自 tvOS 13 以来 我们一直 +在改进 Apple TV 上的多用户功能 + +8 +00:00:31,932 --> 00:00:35,802 +在 tvOS 16 中 +我们提供了一些新功能 可以 + +9 +00:00:35,836 --> 00:00:38,872 +让在所有 App 中 +支持多用户变得更容易 + +10 +00:00:38,906 --> 00:00:43,243 +我将首先简单介绍 +Apple TV 上的多用户功能 + +11 +00:00:43,277 --> 00:00:48,582 +向您展示在每个人都使用的设备上 +个性化 App 是多么容易 + +12 +00:00:48,615 --> 00:00:53,187 +然后我将演示为流媒体 App 的 +每个用户 + +13 +00:00:53,220 --> 00:00:56,490 +存储用户资料选择有多么简单 + +14 +00:00:56,523 --> 00:01:00,827 +最后是为您的 App +提供最适合方法的一些建议 + +15 +00:01:00,861 --> 00:01:05,799 +在 tvOS 16 中 我们让整个 +家庭都能更轻松地使用 Apple TV + +16 +00:01:06,600 --> 00:01:09,903 +当您按住 Siri Remote +上的电视按钮时 + +17 +00:01:09,937 --> 00:01:12,339 +“控制中心”就会出现 + +18 +00:01:12,372 --> 00:01:16,844 +顶部是此 Apple TV 上的 +用户列表 + +19 +00:01:16,877 --> 00:01:18,812 +tvOS 16 中 +有一项新功能 + +20 +00:01:18,846 --> 00:01:21,648 +让用户列表包含还没有被添加的 + +21 +00:01:21,682 --> 00:01:23,450 +iCloud 家庭成员 + +22 +00:01:23,483 --> 00:01:27,654 +让整个家庭都可以 +比以往更轻松地使用 Apple TV + +23 +00:01:29,122 --> 00:01:32,526 +在这里 Anne 还 +没有出现在 Apple TV 上 + +24 +00:01:32,559 --> 00:01:35,863 +加号图标会给出建议的用户 + +25 +00:01:35,896 --> 00:01:40,033 +要让 Anne 加入 +我们只需选择建议用户 + +26 +00:01:41,835 --> 00:01:48,542 +Anne 需要做的就是把 iPhone +带到 Apple TV 所在房间 + +27 +00:01:48,575 --> 00:01:52,646 +并在 iPhone 上确认连接 + +28 +00:01:52,679 --> 00:01:54,348 +仅此而已 + +29 +00:01:54,381 --> 00:01:58,485 +Anne 现在可以访问 +在 Apple TV 上的数据 + +30 +00:01:58,519 --> 00:02:02,756 +现在让我们回到 +Anne 的 iPhone + +31 +00:02:02,789 --> 00:02:06,059 +我们来看看 Anne +最喜欢的视频流媒体 App + +32 +00:02:06,093 --> 00:02:08,695 +这个 App 由整个家庭使用 + +33 +00:02:08,729 --> 00:02:12,165 +每个成员都有自己的个人资料 + +34 +00:02:12,199 --> 00:02:15,802 +当 App 首次启动时 +它会显示个人资料选择器 + +35 +00:02:15,836 --> 00:02:18,539 +Anne 选择了她的个人资料 + +36 +00:02:18,572 --> 00:02:21,475 +这个 App 在个人设备上运行时 + +37 +00:02:21,508 --> 00:02:25,979 +可以简单地将首选个人资料存储在 +NSUserDefaults 中 + +38 +00:02:26,013 --> 00:02:30,350 +甚至放入 CloudKit +以使其同步到所有设备 + +39 +00:02:31,919 --> 00:02:34,888 +每个家庭成员的 iPhone + +40 +00:02:34,922 --> 00:02:38,058 +都会记住该成员的首选个人资料 + +41 +00:02:38,091 --> 00:02:42,896 +当 App 打开时 +无需一直询问要使用哪版个人资料 + +42 +00:02:42,930 --> 00:02:45,999 +Apple TV 是全家人 +共享的设备 + +43 +00:02:46,033 --> 00:02:50,404 +我们认为 让每个使用 +Apple TV 的人都能访问 + +44 +00:02:50,437 --> 00:02:54,007 +自己的内容和数据非常重要 + +45 +00:02:54,575 --> 00:03:01,315 +在 tvOS 14 中 我们引入了 +App 以当前用户身份运行的能力 + +46 +00:03:01,348 --> 00:03:05,219 +使用单个复选框添加 +“以当前用户身份运行”资格 + +47 +00:03:05,252 --> 00:03:07,454 +完全不需要代码更改 + +48 +00:03:07,487 --> 00:03:12,292 +App 就可以访问每个用户的数据 +就像在 iPhone 上一样 + +49 +00:03:16,964 --> 00:03:22,102 +调用这些 API 的 iOS 代码 +可在 Apple TV 上按原样运行 + +50 +00:03:22,135 --> 00:03:27,174 +就像每个人都在使用 +属于自己的 Apple TV + +51 +00:03:27,207 --> 00:03:30,844 +当 App 启动时 +tvOS 会处理好一切 + +52 +00:03:30,878 --> 00:03:34,982 +隐私和安全问题全部由系统处理 + +53 +00:03:35,015 --> 00:03:38,752 +“以当前用户身份运行” +资格非常适合游戏 + +54 +00:03:38,785 --> 00:03:43,557 +以及任何与个人进程有关的 App + +55 +00:03:43,590 --> 00:03:47,794 +但是 带有个人资料的 +媒体 App 则需要更多 + +56 +00:03:47,828 --> 00:03:52,232 +到目前为止 在我的例子中 +跳过了一个重要部分:登录 + +57 +00:03:52,266 --> 00:03:58,872 +我们认为登录需要 +尽可能简单且不那么频繁 + +58 +00:03:58,906 --> 00:04:03,944 +在 tvOS 15 中 我们 +引入了一项允许人们使用 iPhone + +59 +00:04:03,977 --> 00:04:09,550 +或 iPad 无缝登录 +tvOS App 的功能 + +60 +00:04:09,583 --> 00:04:12,019 +这是一种绝佳的登录体验 + +61 +00:04:12,052 --> 00:04:14,154 +各个设备协同工作 + +62 +00:04:14,188 --> 00:04:18,492 +提供登录 Apple TV +最便捷的方式 + +63 +00:04:18,525 --> 00:04:21,495 +Apple TV 上 +不直接提​​供的功能 + +64 +00:04:21,528 --> 00:04:25,933 +就像您在 iCloud Keychain 中的 +密码一样 只需轻点一下即可 + +65 +00:04:25,966 --> 00:04:29,069 +想要了解如何打造出色的登录体验 + +66 +00:04:29,102 --> 00:04:34,741 +请观看 WWDC 2021 的 +“简化 tvOS App 的登录”讲座 + +67 +00:04:36,109 --> 00:04:39,546 +今年我们将引入 tvOS 上 + +68 +00:04:39,580 --> 00:04:42,049 +对 OAuth 和密钥的支持 + +69 +00:04:42,082 --> 00:04:45,152 +密钥是一种出色的 +全新身份验证技术 + +70 +00:04:45,185 --> 00:04:48,722 +用于替换您的 App 和 +网站中的密码 + +71 +00:04:48,755 --> 00:04:53,894 +如要了解有关密钥的更多信息 +请观看“认识密钥”视频 + +72 +00:04:53,927 --> 00:04:57,431 +但简单和方便并不是全部 + +73 +00:04:57,464 --> 00:05:01,568 +让登录仅仅发生一次也很重要 + +74 +00:05:01,602 --> 00:05:05,506 +为了使用“以当前用户身份运行” +实现这种最佳用户体验 + +75 +00:05:05,539 --> 00:05:09,910 +我们在 tvOS 16 中 +引入了一个简单的新 API + +76 +00:05:09,943 --> 00:05:12,913 +它是 Keychain Services +中的一个新常量 + +77 +00:05:12,946 --> 00:05:17,484 +允许 App 访问独立于 +用户的“钥匙串” + +78 +00:05:17,518 --> 00:05:23,423 +Apple TV 上的所有用户始终 +可以访问使用此新密钥存储的项目 + +79 +00:05:23,457 --> 00:05:26,293 +让我们来看一个例子 + +80 +00:05:26,326 --> 00:05:30,163 +这是一种在“钥匙串”中 +保存项目的方法 + +81 +00:05:30,197 --> 00:05:33,367 +带有用户名和密码 + +82 +00:05:33,400 --> 00:05:36,403 +要将项目保存到 +独立于用户的“钥匙串” + +83 +00:05:36,436 --> 00:05:40,440 +您所要做的就是向传递给函数 +SecItemAdd 的属性字典 + +84 +00:05:40,474 --> 00:05:43,810 +添加一个新键 + +85 +00:05:43,844 --> 00:05:49,850 +我们只需将 true 作为 +键 kSecUseUserIndependentKeychain 的值传递 + +86 +00:05:51,084 --> 00:05:53,353 +独立于用户的“钥匙串”设置好后 + +87 +00:05:53,387 --> 00:05:58,458 +您读取和写入的项目 +将对所有用户可见 + +88 +00:05:58,492 --> 00:06:01,528 +新的 Keychain API + +89 +00:06:01,562 --> 00:06:03,664 +和“以当前用户身份运行”资格的 +结合 + +90 +00:06:03,697 --> 00:06:08,335 +让您的 App 享有 iPhone +和 Apple TV 的精华 + +91 +00:06:08,368 --> 00:06:12,272 +在共享设备上进行简单的 +各用户数据分离 + +92 +00:06:12,306 --> 00:06:16,677 +同时保持 Apple TV +上的单点登录体验 + +93 +00:06:16,710 --> 00:06:21,615 +在 tvOS 16 中 +我们已弃用手动将个人资料映射到 + +94 +00:06:21,648 --> 00:06:24,618 +TVUserManager +中系统用户的方法 + +95 +00:06:24,651 --> 00:06:29,189 +您不再需要维护 +用户到个人资料的映射 + +96 +00:06:29,223 --> 00:06:31,325 +系统会为您处理 + +97 +00:06:31,358 --> 00:06:36,763 +您在 iOS 上使用的相同 API +也可以在 Apple TV 上原样使用 + +98 +00:06:36,797 --> 00:06:39,800 +这变得容易了许多 + +99 +00:06:39,833 --> 00:06:42,436 +让我通过演示来介绍实际使用情况 + +100 +00:06:42,469 --> 00:06:47,274 +我将引导您完成一个示例 App +它代表含个人资料的媒体 App + +101 +00:06:47,307 --> 00:06:50,978 +这是我的视频流媒体 App + +102 +00:06:51,011 --> 00:06:55,315 +目前它没有使用我谈到的任何功能 + +103 +00:06:55,349 --> 00:07:00,821 +它不以当前用户身份运行 +也没有使用新的 Keychain API + +104 +00:07:00,854 --> 00:07:04,124 +我会继续登录并向您展示 + +105 +00:07:06,860 --> 00:07:10,531 +登录后 我看到了一个 +用户个人资料列表 + +106 +00:07:10,564 --> 00:07:14,001 +当前用户是 Mei +所以我选择她的个人资料 + +107 +00:07:16,270 --> 00:07:20,807 +选择个人资料会显示 +Mei 可能想看的个性化内容 + +108 +00:07:22,176 --> 00:07:26,680 +晚些时候 Anne +坐在沙发上看电视 + +109 +00:07:26,713 --> 00:07:29,082 +通过长按 Siri Remote 上的 + +110 +00:07:29,116 --> 00:07:32,486 +电视按钮打开“控制中心” + +111 +00:07:32,519 --> 00:07:37,457 +控制中心顶部是用户列表 + +112 +00:07:37,491 --> 00:07:40,627 +绿色复选标记表示当前用户 + +113 +00:07:40,661 --> 00:07:43,897 +我现在要切换到 Anne +并打开 App + +114 +00:07:45,566 --> 00:07:49,269 +正如预想的那样 +App 再次显示个人资料选择器 + +115 +00:07:49,303 --> 00:07:51,905 +所以 Anne 可以选择 +自己的个人资料 + +116 +00:07:54,174 --> 00:07:57,945 +但请注意切换回 Mei 时 +会发生什么 + +117 +00:08:02,349 --> 00:08:04,651 +App 仍然停留在 Anne 的 +个人资料中 + +118 +00:08:04,685 --> 00:08:08,856 +它不记得 Mei 以前选择过 +她首选的个人资料 + +119 +00:08:08,889 --> 00:08:11,525 +借助 tvOS 16 +中的新功能 + +120 +00:08:11,558 --> 00:08:14,228 +用户体验可以大幅改善 + +121 +00:08:14,261 --> 00:08:19,166 +我希望使用该 App 的人 +不必再次选择正在观看的人 + +122 +00:08:19,199 --> 00:08:22,769 +让我们转到 Xcode +我会向您展示这有多么容易 + +123 +00:08:22,803 --> 00:08:27,074 +让我的 App 以 +当前用户身份执行非常简单 + +124 +00:08:27,107 --> 00:08:31,612 +我要做的就是为我 App 的 +目标添加一项性能 + +125 +00:08:31,645 --> 00:08:33,614 +在我 App 的目标中 + +126 +00:08:33,647 --> 00:08:37,451 +我将转到 +Signing and Capabilities 选项卡 + +127 +00:08:37,484 --> 00:08:40,254 +就在标签下 在左上角 + +128 +00:08:40,287 --> 00:08:43,757 +我将点按“添加性能”按钮 + +129 +00:08:43,790 --> 00:08:46,393 +它将打开性能列表 + +130 +00:08:46,426 --> 00:08:49,363 +我感兴趣的是“用户管理”性能 + +131 +00:08:49,396 --> 00:08:52,165 +所以我将输入“用户”来进行筛选 + +132 +00:08:53,700 --> 00:08:57,437 +现在我只需连按 +要添加到我的 App 的性能 + +133 +00:08:58,805 --> 00:09:02,509 +在这里“以当前用户身份运行” +复选框 + +134 +00:09:02,543 --> 00:09:05,512 +已经默认选中 + +135 +00:09:05,546 --> 00:09:07,981 +这正是我所需要的 + +136 +00:09:08,015 --> 00:09:11,251 +使用此资格 我的 App 的 +进程将始终 + +137 +00:09:11,285 --> 00:09:13,620 +以当前选择的用户启动 + +138 +00:09:13,654 --> 00:09:17,991 +系统将确保每个 +用户的数据是有区别的 + +139 +00:09:18,025 --> 00:09:20,961 +所有数据包括“钥匙串” + +140 +00:09:20,994 --> 00:09:24,298 +但是对于我的 App 而言 +为每个用户配备独立的“钥匙串” + +141 +00:09:24,331 --> 00:09:26,900 +会产生意想不到的副作用 + +142 +00:09:26,934 --> 00:09:30,804 +这将要求每个用户单独登录 + +143 +00:09:30,838 --> 00:09:36,610 +在 tvOS 16 中 +我们可以在当前用户身份运行时 + +144 +00:09:36,643 --> 00:09:39,446 +保持所有用户使用一个帐户的体验 + +145 +00:09:39,479 --> 00:09:44,885 +使用新的 Keychain API +来访问独立于用户的“钥匙串”即可 + +146 +00:09:44,918 --> 00:09:47,855 +我现在去 +KeychainController 类 + +147 +00:09:47,888 --> 00:09:51,158 +并用它来读写“钥匙串” + +148 +00:09:52,993 --> 00:09:57,231 +这里的属性 baseQuery 有访问 + +149 +00:09:57,264 --> 00:10:00,701 +我 App 的认证信息时需要的键 + +150 +00:10:00,734 --> 00:10:04,004 +要更新它以便使用 +独立于用户的新“钥匙串” + +151 +00:10:04,037 --> 00:10:07,808 +我所要做的就是 +在字典中添加一个新元素 + +152 +00:10:07,841 --> 00:10:11,411 +我将添加新的 +kSecUseUserIndependentKeychain + +153 +00:10:11,445 --> 00:10:13,247 +并将其设置为 true + +154 +00:10:15,649 --> 00:10:19,553 +我只需要更改这些内容 +来以使 App 与所有用户 + +155 +00:10:19,586 --> 00:10:20,621 +共享认证信息 + +156 +00:10:20,654 --> 00:10:22,256 +没有其他的了 + +157 +00:10:22,289 --> 00:10:24,224 +不过 需要注意的一个重点是 + +158 +00:10:24,258 --> 00:10:27,361 +其他所有数据仍然 +是基于各个用户区别的 + +159 +00:10:27,394 --> 00:10:29,930 +就像我将要用来记住每个用户 + +160 +00:10:29,963 --> 00:10:32,966 +个人资料选择的 UserDefaults + +161 +00:10:34,434 --> 00:10:37,237 +现在我要打开 ProfileData 类 + +162 +00:10:37,271 --> 00:10:41,642 +此文件在我的 iOS 和 +tvOS 项目之间共享 + +163 +00:10:41,675 --> 00:10:46,180 +事实上 我 App 的 iOS 版本 +已经在 UserDefaults 中 + +164 +00:10:46,213 --> 00:10:48,282 +存储了用户资料选择 + +165 +00:10:48,315 --> 00:10:50,484 +但仅限在 iOS 上运行时 + +166 +00:10:50,517 --> 00:10:54,555 +那是因为 iPhone 是 +个人设备 + +167 +00:10:54,588 --> 00:10:57,524 +但现在我的 App +以当前用户身份运行 + +168 +00:10:57,558 --> 00:11:00,260 +让 Apple TV 可以 +像个人设备一样 + +169 +00:11:00,294 --> 00:11:05,799 +我可以移除打勾的 iOS 选项 并让 +代码在 Apple TV 上以相同的方式工作 + +170 +00:11:05,832 --> 00:11:12,005 +系统将确保为每个用户 +使用正确的 UserDefaults + +171 +00:11:12,039 --> 00:11:15,542 +当我运行新版本的 App 时 +它以当前用户身份启动 + +172 +00:11:15,576 --> 00:11:16,710 +也就是 Mei + +173 +00:11:16,743 --> 00:11:20,113 +Mei 登录并选择她的个人资料 + +174 +00:11:20,147 --> 00:11:24,251 +以当前用户身份运行 App 时 +它运行的方式就像 Apple TV + +175 +00:11:24,284 --> 00:11:26,486 +在那一刻是一台个人设备 + +176 +00:11:26,520 --> 00:11:28,121 +Mei 的设备 + +177 +00:11:28,155 --> 00:11:32,526 +Mei 的个人资料选择 +存储在她的 UserDefaults 中 + +178 +00:11:32,559 --> 00:11:34,561 +当 Anne 观看的时候 + +179 +00:11:34,595 --> 00:11:38,232 +可以使用“控制中心” +切换到自己的用户 + +180 +00:11:38,265 --> 00:11:41,568 +系统会搭建一个用户切换 UI + +181 +00:11:41,602 --> 00:11:43,904 +它留出了时间 + +182 +00:11:43,937 --> 00:11:48,442 +让您在重新启动之前完成最后的任务 + +183 +00:11:48,475 --> 00:11:51,979 +tvOS 现在 +以 Anne 的身份重新启动 App + +184 +00:11:52,012 --> 00:11:54,615 +现在 Apple TV 是 Anne 的设备 + +185 +00:11:54,648 --> 00:11:58,318 +登录提示跳过了 +因为认证信息已存储在 + +186 +00:11:58,352 --> 00:12:02,523 +独立于用户的“钥匙串”中 +所有用户都可以访问 + +187 +00:12:02,556 --> 00:12:06,994 +但是 Anne 的 UserDefaults 中 +还没有存储个人资料选择 + +188 +00:12:07,027 --> 00:12:09,062 +所以个人资料选择器出现了 + +189 +00:12:09,096 --> 00:12:14,968 +选中 Anne 的个人资料 +将选择保存到 UserDefaults 中 + +190 +00:12:15,002 --> 00:12:19,706 +好了 现在 Mei 和 +Anne 都选择了个人资料 + +191 +00:12:19,740 --> 00:12:21,141 +切换用户时 + +192 +00:12:21,175 --> 00:12:24,511 +App 将不再显示任何插页式提示 + +193 +00:12:24,545 --> 00:12:27,881 +它将始终直接转到内容 + +194 +00:12:27,915 --> 00:12:31,451 +自动为每个人选择正确的个人资料 + +195 +00:12:31,485 --> 00:12:32,819 +每次都是如此 + +196 +00:12:32,853 --> 00:12:36,790 +这就是在 tvOS 16 中 +我们如何让记住每个用户的 + +197 +00:12:36,823 --> 00:12:39,393 +个人资料变得更加容易 + +198 +00:12:39,426 --> 00:12:43,664 +使用一个简单的新 API 来 +访问独立于用户的“钥匙串” + +199 +00:12:43,697 --> 00:12:47,968 +由系统分别处理每个用户的数据 + +200 +00:12:48,001 --> 00:12:51,605 +现在您已经了解了如何 +记住每个用户的个人资料选择 + +201 +00:12:51,638 --> 00:12:55,075 +而无需每个人单独登录 + +202 +00:12:55,108 --> 00:12:58,345 +让我们回顾一下 App +在 Apple TV 上的运作方式 + +203 +00:12:58,378 --> 00:13:01,782 +没有以当前用户身份运行 +资格的 App + +204 +00:13:01,815 --> 00:13:04,952 +使用“默认用户”的资源 + +205 +00:13:04,985 --> 00:13:09,623 +您可以将其视作 +Apple TV 自己的资源 + +206 +00:13:09,656 --> 00:13:14,061 +切换用户对 App 的进程 +没有影响 + +207 +00:13:14,094 --> 00:13:18,332 +如果您想要进行个性化 +以下是我的建议 + +208 +00:13:18,365 --> 00:13:21,201 +这张表格显示了由您在 + +209 +00:13:21,235 --> 00:13:25,839 +tvOS App 上 +使用的功能决定的可用性能 + +210 +00:13:25,873 --> 00:13:29,142 +如果您的 App +是媒体 App 或与之相似的 + +211 +00:13:29,176 --> 00:13:32,212 +通过个人资料显示 +个性化内容的 App + +212 +00:13:32,246 --> 00:13:36,717 +在使用 Apple TV 的 +所有人之间共享一个帐户 + +213 +00:13:36,750 --> 00:13:39,553 +您可以采用“以当前 +用户身份运行”的资格 + +214 +00:13:39,586 --> 00:13:44,224 +并使用独立于用户的 +新 Keychain API + +215 +00:13:44,258 --> 00:13:48,395 +如果像游戏那样 +在您的 App 中个人进程非常重要 + +216 +00:13:48,428 --> 00:13:52,266 +您只需要采用 +“以当前用户身份运行”的资格 + +217 +00:13:52,299 --> 00:13:55,169 +tvOS 将处理其他事务 + +218 +00:13:55,202 --> 00:13:56,937 +对于所有其他 App + +219 +00:13:56,970 --> 00:13:59,973 +也就是向所有用户 +呈现相同内容的 App + +220 +00:14:00,007 --> 00:14:02,242 +例如食谱 App + +221 +00:14:02,276 --> 00:14:04,111 +您就不必进行任何操作 + +222 +00:14:04,144 --> 00:14:08,515 +只需在 Xcode 中创建 +一个新的 tvOS App 项目 + +223 +00:14:08,549 --> 00:14:11,218 +想要了解有关 +“以当前用户身份运行”的更多信息 + +224 +00:14:11,251 --> 00:14:14,922 +请观看 +我们在 WWDC 2020 的讲座 + +225 +00:14:14,955 --> 00:14:21,161 +我们相信顺畅地直接前往内容 +是 tvOS App 的最佳体验 + +226 +00:14:21,195 --> 00:14:23,830 +我希望所有这些功能都可以帮助您 + +227 +00:14:23,864 --> 00:14:26,600 +在 App 中实现出色的大屏幕体验 + +228 +00:14:26,633 --> 00:14:29,269 +感谢观看 希望您享受本次大会 + diff --git a/zho/2022 Session 110401 Create Swift Package plugins.srt b/zho/2022 Session 110401 Create Swift Package plugins.srt new file mode 100644 index 0000000..f6ad5bb --- /dev/null +++ b/zho/2022 Session 110401 Create Swift Package plugins.srt @@ -0,0 +1,1498 @@ +1 +00:00:00,767 --> 00:00:06,773 +[迷幻音乐] + +2 +00:00:09,309 --> 00:00:11,078 +Boris:嗨 我是 Boris + +3 +00:00:11,111 --> 00:00:13,714 +欢迎来到“创建 +Swift 软件包插件”讲座 + +4 +00:00:14,848 --> 00:00:18,252 +我们在 Xcode 11 中 +引入了对 Swift 软件包的支持 + +5 +00:00:18,285 --> 00:00:21,588 +提供一种以源代码形式 +直接发布软件库的方法 + +6 +00:00:22,523 --> 00:00:26,527 +在 Xcode 14 中 +我们希望将这种架构和分享组件的 + +7 +00:00:26,560 --> 00:00:28,729 +出色方式带入开发工作流中 + +8 +00:00:28,762 --> 00:00:31,765 +例如通过 +Swift 软件包插件生成源代码 + +9 +00:00:31,798 --> 00:00:33,834 +或自动发布任务 + +10 +00:00:34,701 --> 00:00:36,870 +首先 我将简单概述今天的讲座内容 + +11 +00:00:36,904 --> 00:00:38,839 +在了解插件的基础信息后 + +12 +00:00:38,872 --> 00:00:42,242 +我们将演示如何创建第一个 +自定义命令插件 + +13 +00:00:42,276 --> 00:00:45,612 +接下来 我们将了解 +更多关于创建插件的细节 + +14 +00:00:45,646 --> 00:00:49,416 +随后继续演示如何创建构建中 + +15 +00:00:49,449 --> 00:00:50,751 +和构建前命令插件 + +16 +00:00:51,818 --> 00:00:56,356 +软件包插件是一种使用 +PackagePlugin API 的 + +17 +00:00:56,390 --> 00:00:58,725 +类似于 +软件包清单的 Swift 代码 + +18 +00:00:58,759 --> 00:01:01,028 +插件可以通过定义明确的扩展点 + +19 +00:01:01,061 --> 00:01:04,598 +扩展 Xcode 或 +Swift 软件包管理器的功能 + +20 +00:01:06,567 --> 00:01:09,002 +软件包插件是如何运行的呢? + +21 +00:01:09,036 --> 00:01:12,539 +Xcode 将编译和运行您的插件 + +22 +00:01:12,573 --> 00:01:15,709 +能够使用相关可用可执行文件 + +23 +00:01:15,742 --> 00:01:18,178 +和输入文件的信息来创建命令 + +24 +00:01:18,212 --> 00:01:19,913 +它将这些命令返回 Xcode + +25 +00:01:19,947 --> 00:01:22,182 +根据需要执行命令 + +26 +00:01:24,718 --> 00:01:27,254 +软件包插件可以 +帮助完成构建前或构建中 + +27 +00:01:27,287 --> 00:01:29,556 +运行的自定义构建任务 + +28 +00:01:29,590 --> 00:01:32,226 +比如可以生成源代码或资源文件 + +29 +00:01:33,493 --> 00:01:37,030 +它们也可以新增自定义命令 +到 SwiftPM 的命令行界面 + +30 +00:01:37,064 --> 00:01:39,666 +或将菜单项添加到 Xcode + +31 +00:01:39,700 --> 00:01:43,103 +如想了解更多关于插件的基础信息 +我推荐您先观看 + +32 +00:01:43,136 --> 00:01:44,938 +“认识 Swift 软件包插件”讲座 + +33 +00:01:44,972 --> 00:01:47,841 +如果您此前对软件包没有任何了解 + +34 +00:01:47,875 --> 00:01:51,645 +可以观看 WWDC19 的 +“创建 Swift 软件包”讲座 + +35 +00:01:53,547 --> 00:01:57,084 +我们来看看如何创建 +第一个自定义命令插件 + +36 +00:01:58,886 --> 00:02:01,388 +我正在 Swift 开放源码中 + +37 +00:02:01,421 --> 00:02:02,723 +参与核心支持工具软件包的工作 + +38 +00:02:02,756 --> 00:02:04,224 +我想要新增一个 + +39 +00:02:04,258 --> 00:02:06,793 +列出项目所有贡献者的文本文件 + +40 +00:02:06,827 --> 00:02:10,731 +我还想根据需要从软件包的 +Git 历史中重新生成它 + +41 +00:02:12,065 --> 00:02:13,967 +从前 我可能会 +写一个 shell 脚本 + +42 +00:02:14,001 --> 00:02:15,536 +或 makefile + +43 +00:02:15,569 --> 00:02:17,804 +但现在我要创建一个自定义命令插件 + +44 +00:02:17,838 --> 00:02:20,807 +让我不需要离开 Xcode +就能重新生成文件 + +45 +00:02:22,943 --> 00:02:26,813 +首先 我们必须为插件创建目录架构 + +46 +00:02:26,847 --> 00:02:31,018 +打开软件包的上下文菜单 + +47 +00:02:31,051 --> 00:02:33,887 +选择“新文件夹” + +48 +00:02:33,921 --> 00:02:38,792 +来创建名为 “Plugins” 的顶层文件夹 + +49 +00:02:38,825 --> 00:02:41,862 +与现有的源码与测试文件夹类似 + +50 +00:02:43,697 --> 00:02:48,535 +接下来 我们要为插件目标创建 + +51 +00:02:48,569 --> 00:02:51,505 +另一个嵌套文件夹 +命名为 “GenerateContributors” + +52 +00:02:57,110 --> 00:03:00,747 +在这个文件夹里创建一个新文件 +命名为 “plugin.swift” + +53 +00:03:12,426 --> 00:03:15,629 +接下来 我们要对 +软件包清单进行一些更改 + +54 +00:03:15,662 --> 00:03:18,298 +来声明我们的新目标 + +55 +00:03:18,332 --> 00:03:22,336 +但首先 我们必须将 +软件包工具版本升到 5.6 + +56 +00:03:22,369 --> 00:03:25,205 +因为插件从这一版本开始才可用 + +57 +00:03:33,046 --> 00:03:35,516 +接下来就可以插入插件目标了 + +58 +00:03:44,791 --> 00:03:47,761 +我们来看一看新的清单 API + +59 +00:03:49,496 --> 00:03:50,931 +我们将创建一个对应于 + +60 +00:03:50,964 --> 00:03:53,567 +“Plugins” 文件夹中 +某一文件夹的插件目标 + +61 +00:03:53,600 --> 00:03:55,402 +与源码模块的目标类似 + +62 +00:03:56,904 --> 00:03:59,940 +它得到一个既与命名文件夹有关 + +63 +00:03:59,973 --> 00:04:02,209 +又是 Xcode 中菜单项的名称 + +64 +00:04:03,477 --> 00:04:05,145 +我们需要指定功能 + +65 +00:04:05,179 --> 00:04:07,648 +也就是我们想用什么类型的扩展点 + +66 +00:04:07,681 --> 00:04:10,417 +在这个案例中 +我们是在创建自定义命令 + +67 +00:04:12,119 --> 00:04:15,522 +intent 可以为 +SwiftPM 命令行定义一个动词 + +68 +00:04:15,556 --> 00:04:19,459 +以及描述该插件的作用 + +69 +00:04:19,493 --> 00:04:22,729 +最后 我们可以声明 +该插件需要的权限 + +70 +00:04:24,264 --> 00:04:27,467 +在这个案例中 我们要将 +新文件写到软件包的根目录 + +71 +00:04:27,501 --> 00:04:30,304 +所以需要写入该目录的权限 + +72 +00:04:30,337 --> 00:04:33,106 +reason 字符串会显示给插件使用者 + +73 +00:04:33,140 --> 00:04:35,909 +让他们知道是否已获得权限 + +74 +00:04:35,943 --> 00:04:39,179 +和 OS 自身权限的管理方式类似 + +75 +00:04:39,213 --> 00:04:43,650 +声明了插件之后 +让我们返回进行实施 + +76 +00:04:45,686 --> 00:04:49,890 +插件会运行调用 Git 获取提交历史 + +77 +00:04:49,923 --> 00:04:52,793 +它会从外部 Git 命令的 +标准输出中读取历史 + +78 +00:04:52,826 --> 00:04:55,229 +并解析结果 + +79 +00:04:55,262 --> 00:04:57,998 +最后将其写出为文本文件 + +80 +00:04:59,399 --> 00:05:04,571 +我们需要打开之前创建的插件源文件 + +81 +00:05:04,605 --> 00:05:06,173 +导入 PackagePlugin + +82 +00:05:09,109 --> 00:05:10,377 +这是一个内置模块 + +83 +00:05:10,410 --> 00:05:13,614 +和 PackageDescription 很像 + +84 +00:05:13,647 --> 00:05:15,816 +可以获取实施插件 +需要用到的 API + +85 +00:05:17,751 --> 00:05:24,491 +我们来定义一个结构体 +GenerateContributors + +86 +00:05:24,525 --> 00:05:26,360 +使其符合 CommandPlugin + +87 +00:05:32,165 --> 00:05:35,369 +接受这里的修订 + +88 +00:05:35,402 --> 00:05:39,506 +来获取实施协议所缺的代码片段 + +89 +00:05:39,540 --> 00:05:42,042 +我们还需要将 +结构体标记为 @main + +90 +00:05:42,075 --> 00:05:44,945 +因为它将是插件 +可执行文件的 main 函数 + +91 +00:05:46,180 --> 00:05:49,016 +performCommand +是我们命令的进入点 + +92 +00:05:49,049 --> 00:05:50,984 +我们会收到两个参数 + +93 +00:05:51,018 --> 00:05:54,788 +一个是 context 它让我们 +能够获取经过解析的软件包图 + +94 +00:05:54,821 --> 00:05:58,292 +和其他关于执行的上下文信息 + +95 +00:05:58,325 --> 00:06:00,427 +包括参数 + +96 +00:06:00,460 --> 00:06:03,597 +由于是用户发起了自定义命令 + +97 +00:06:03,630 --> 00:06:06,567 +用户可以用参数形式提供输入信息 + +98 +00:06:06,600 --> 00:06:08,735 +我们来创建一个简单命令 + +99 +00:06:08,769 --> 00:06:10,571 +在这个时候不向用户 + +100 +00:06:10,604 --> 00:06:12,039 +提供任何选择 + +101 +00:06:20,113 --> 00:06:21,582 +因为我们要运行调用 Git + +102 +00:06:21,615 --> 00:06:24,251 +获取关于提交历史的信息 + +103 +00:06:24,284 --> 00:06:25,586 +就要导入 Foundation + +104 +00:06:25,619 --> 00:06:28,255 +因为我们需要用到 Process API + +105 +00:06:35,329 --> 00:06:39,333 +接下来 我们将定义一个进程实例 +并通过一些格式化参数 + +106 +00:06:39,366 --> 00:06:41,401 +使它执行 git log + +107 +00:06:45,239 --> 00:06:48,509 +我们需要创建管道来捕获进程输出值 + +108 +00:06:48,542 --> 00:06:51,144 +然后就可以运行并等待它退出 + +109 +00:06:55,015 --> 00:06:56,617 +这个过程完成后 + +110 +00:06:56,650 --> 00:06:58,819 +我们从管道中读取所有数据 + +111 +00:06:58,852 --> 00:07:01,822 +并将它转化为字符串 +其中包含所有版本记录输出值 + +112 +00:07:05,926 --> 00:07:07,828 +我们可以对字符串进行操作 + +113 +00:07:07,861 --> 00:07:10,697 +将输出数据修整为无重复值的列表 + +114 +00:07:10,731 --> 00:07:12,232 +最后 我们就可以将它写成文件 + +115 +00:07:12,266 --> 00:07:14,168 +命名为 “CONTRIBUTORS.txt” + +116 +00:07:14,201 --> 00:07:16,503 +因为自定义命令是在 + +117 +00:07:16,537 --> 00:07:18,105 +软件包的根目录中执行的 + +118 +00:07:18,138 --> 00:07:19,506 +我们也将文件存储在那里 + +119 +00:07:22,276 --> 00:07:24,778 +现在 如果我们先保存 +然后在项目导航器中 + +120 +00:07:24,811 --> 00:07:29,049 +右键点击软件包 + +121 +00:07:29,082 --> 00:07:32,085 +上下文菜单中就会出现 +一条对应我们命令的项目 + +122 +00:07:32,119 --> 00:07:33,520 +来执行它吧! + +123 +00:07:37,391 --> 00:07:40,427 +在接下来的对话框中 +我们可以选择应为 + +124 +00:07:40,460 --> 00:07:43,997 +插件输入项的软件包或目标 +以及任何参数 + +125 +00:07:44,031 --> 00:07:47,234 +但由于我们的插件并不回应这些选项 +我们可以点按“运行” + +126 +00:07:51,538 --> 00:07:55,609 +接下来 我们会被要求授权 +因为之前在清单中定义的就是这样 + +127 +00:07:55,642 --> 00:07:59,379 +由于插件是我们刚才自己写的 +可以直接运行 + +128 +00:07:59,413 --> 00:08:03,116 +但请确保您只向 +信任的插件进行额外授权 + +129 +00:08:08,288 --> 00:08:11,992 +运行后 CONTRIBUTORS.txt +文件出现在项目导航器中 + +130 +00:08:14,828 --> 00:08:18,198 +在使用第一个插件 +扩展了 Xcode 之后 + +131 +00:08:18,232 --> 00:08:20,334 +让我们更深入地探讨插件的运作方式 + +132 +00:08:20,367 --> 00:08:22,736 +以及创建插件时的注意事项 + +133 +00:08:26,240 --> 00:08:28,342 +软件包插件在沙盒中运行 + +134 +00:08:28,375 --> 00:08:31,912 +和软件包清单本身的解释运行类似 + +135 +00:08:31,945 --> 00:08:34,915 +网络连接 以及写入 +除插件自身运行目录之外的 + +136 +00:08:34,948 --> 00:08:38,218 +非临时位置都将被禁止 + +137 +00:08:38,252 --> 00:08:41,722 +像之前演示的那样 自定义命令可以 + +138 +00:08:41,755 --> 00:08:44,525 +选择性声明是否写入软件包根目录 + +139 +00:08:45,459 --> 00:08:47,895 +如果您要包装已有的第三方工具 + +140 +00:08:47,928 --> 00:08:51,098 +必须考虑如何将其限制在沙盒模式中 + +141 +00:08:51,131 --> 00:08:54,234 +比如说 可以通过配置 +生成文件的写入位置来实现 + +142 +00:08:55,669 --> 00:08:58,338 +我在介绍中谈到了不同类型的插件 + +143 +00:08:58,372 --> 00:09:00,607 +一个问题是由自定义命令 +还是构建工具来解决更好 + +144 +00:09:00,641 --> 00:09:02,476 +这一点应该已经清楚了 + +145 +00:09:02,509 --> 00:09:05,546 +但我们还是来看一看 +构建工具插件的结构 + +146 +00:09:07,014 --> 00:09:09,283 +这些插件允许您可以通过 +描述一次构建中可运行 + +147 +00:09:09,316 --> 00:09:13,086 +哪些可执行文件 +并指定其输入和输出内容 + +148 +00:09:13,120 --> 00:09:15,155 +来扩展构建系统 + +149 +00:09:15,189 --> 00:09:18,725 +这可以帮助您在 +构建期间合适的时机规划任务 + +150 +00:09:19,726 --> 00:09:21,562 +如果您在 Xcode 项目中 +创建过 run script phase + +151 +00:09:21,595 --> 00:09:23,263 +就应该对这部分涉及的 + +152 +00:09:23,297 --> 00:09:24,498 +基础内容很熟悉了 + +153 +00:09:26,400 --> 00:09:29,469 +构建工具插件分为两种不同类型 + +154 +00:09:29,503 --> 00:09:33,273 +区分要点在于您的 +工具是否定义了的输出集 + +155 +00:09:34,541 --> 00:09:37,411 +如果有 您就应该创建构建中命令 + +156 +00:09:37,444 --> 00:09:39,980 +如果输出与输入相比已经过时 + +157 +00:09:40,013 --> 00:09:43,684 +它将由构建系统自动重新运行 + +158 +00:09:43,717 --> 00:09:47,154 +如果您没有明确的输出集 +可以创建构建前命令 + +159 +00:09:47,187 --> 00:09:49,556 +它将在每次构建开始时运行 + +160 +00:09:49,590 --> 00:09:51,625 +正因为如此 您应当 +避免在构建前命令中 + +161 +00:09:51,658 --> 00:09:53,794 +进行代价高昂的工作 + +162 +00:09:53,827 --> 00:09:56,630 +或想一个适合您用例的 + +163 +00:09:56,663 --> 00:09:58,532 +自定义策略来缓存结果 + +164 +00:10:02,336 --> 00:10:04,972 +在第二项演示中 +我打算创建一个新软件库 + +165 +00:10:05,005 --> 00:10:08,942 +其中包含了我想在 +手头不同的工具中共享的图标 + +166 +00:10:11,044 --> 00:10:13,447 +首先通过模板创建新的软件包 + +167 +00:10:13,480 --> 00:10:15,115 +命名为 “IconLibrary” + +168 +00:10:15,148 --> 00:10:19,987 +我现在要把一些已有的图标资产 +拖到我软件库的目标中 + +169 +00:10:20,020 --> 00:10:24,591 +让我们再给软件库加上 +基础 SwiftUI 视图和预览 + +170 +00:10:24,625 --> 00:10:28,328 +首先 我们要将必需的 +最低部署目标添加到清单 + +171 +00:10:33,800 --> 00:10:37,171 +接下来 我们来添加基础视图和预览 + +172 +00:10:37,204 --> 00:10:40,407 +在这里我们可以使用之前拖入的资产 + +173 +00:10:44,978 --> 00:10:46,380 +我觉得 比较理想的做法 + +174 +00:10:46,413 --> 00:10:48,815 +是用一种类型安全的方式 +来引用这些图片 + +175 +00:10:48,849 --> 00:10:52,252 +而不是非得在这里处理字符串 + +176 +00:10:52,286 --> 00:10:55,289 +这似乎是构建中 +命令插件的绝佳使用案例 + +177 +00:10:55,322 --> 00:10:56,924 +因为这一插件考虑资产目录 + +178 +00:10:56,957 --> 00:10:59,560 +并以此为基础生成 Swift 代码 + +179 +00:10:59,593 --> 00:11:01,995 +让我们在 Finder 中 +看一看资产目录 + +180 +00:11:02,029 --> 00:11:05,432 +来了解我们应该 +如何提取插件需要的信息 + +181 +00:11:06,466 --> 00:11:11,338 +每张图片都有自己的图集目录 +包含资产名称 + +182 +00:11:15,709 --> 00:11:18,946 +还有一个用于描述 +基础内容的 JSON 文件 + +183 +00:11:21,815 --> 00:11:24,284 +构建中命令 +与自定义命令的运行方式有所不同 + +184 +00:11:24,318 --> 00:11:27,120 +它们除了提供用于 +运行的可执行文件描述 + +185 +00:11:27,154 --> 00:11:28,589 +还有提供输入和输出 + +186 +00:11:30,157 --> 00:11:32,559 +可执行文件可以由系统或 + +187 +00:11:32,593 --> 00:11:36,463 +第三方软件包提供 +您也可以专门为插件定制可执行文件 + +188 +00:11:36,496 --> 00:11:38,298 +我们选择第三种途径 + +189 +00:11:40,300 --> 00:11:42,569 +插件在构建过程开始时运行 + +190 +00:11:42,603 --> 00:11:45,239 +以参与构件图的计算 + +191 +00:11:46,807 --> 00:11:50,577 +以此为基础 可执行文件 +作为构建执行的一部分进行排期 + +192 +00:11:52,279 --> 00:11:54,915 +现在回到我们构建的可执行文件 + +193 +00:11:54,948 --> 00:11:59,453 +我们要资产目录中的每张图 +都有一个编译期常量 + +194 +00:11:59,486 --> 00:12:03,123 +这样一来就不需要 +记住每张图片的正确字符串 + +195 +00:12:03,156 --> 00:12:05,392 +而是可以让它们 +作为 Swift 符号自动完成 + +196 +00:12:07,294 --> 00:12:09,229 +我们将循环遍历资产目录的内容 + +197 +00:12:09,263 --> 00:12:12,366 +来找到所有的图集 + +198 +00:12:12,399 --> 00:12:15,469 +我们将解析每个图集的元数据来确定 + +199 +00:12:15,502 --> 00:12:17,137 +它是否真的包含图片 + +200 +00:12:17,171 --> 00:12:19,740 +以及是否应当为其生成代码 + +201 +00:12:21,408 --> 00:12:24,278 +然后我们就可以 +生成代码并写入到一个文件 + +202 +00:12:24,311 --> 00:12:27,381 +由于我们声明这些文件 +为插件的输出内容 + +203 +00:12:27,414 --> 00:12:30,417 +它们将自动并入插件 + +204 +00:12:30,450 --> 00:12:31,919 +所应用的目标的构建之中 + +205 +00:12:33,887 --> 00:12:35,789 +我们需要想办法处理参数 + +206 +00:12:35,822 --> 00:12:39,126 +因为这是插件和 +可执行文件沟通的方式 + +207 +00:12:40,827 --> 00:12:46,200 +第一个参数是指向我们 +正在处理的资产目录的路径 + +208 +00:12:46,233 --> 00:12:49,903 +第二个是插件为 +生成的代码提供的路径 + +209 +00:12:51,605 --> 00:12:55,976 +接下来 我们需要模型对象来 +对 contents.json 文件进行解码 + +210 +00:12:57,010 --> 00:13:00,948 +可以使用 Decodable 来充分 +利用 Swift 内置的 JSON 解码功能 + +211 +00:13:02,416 --> 00:13:06,720 +我们唯一感兴趣的信息是图像列表 + +212 +00:13:06,753 --> 00:13:09,990 +和它们的文件名 但这是可选的 +因为可能不是每一种 + +213 +00:13:10,023 --> 00:13:13,493 +像素密度都有对应的图像 + +214 +00:13:13,527 --> 00:13:15,762 +这里我们以一种极其 +简化的方式来生成代码 + +215 +00:13:15,796 --> 00:13:17,898 +只需要建立一个字符串 + +216 +00:13:17,931 --> 00:13:20,234 +我们首先导入需要的框架 + +217 +00:13:20,267 --> 00:13:21,735 +Foundation 和 SwiftUI + +218 +00:13:23,637 --> 00:13:25,506 +我们要循环遍历资产目录的 + +219 +00:13:25,539 --> 00:13:26,773 +全部内容 + +220 +00:13:26,807 --> 00:13:29,543 +来找到所有的图集 + +221 +00:13:29,576 --> 00:13:32,546 +下一步是解析 JSON + +222 +00:13:32,579 --> 00:13:35,916 +文件名使用了输入参数 + +223 +00:13:35,949 --> 00:13:39,353 +我们使用 Foundation 的 +JSONDecoder API 进行解码 + +224 +00:13:41,121 --> 00:13:43,357 +我们感兴趣的主要信息是 + +225 +00:13:43,390 --> 00:13:47,728 +是否存在针对 +给定图集进行定义的图像 + +226 +00:13:47,761 --> 00:13:50,631 +我们可以通过检查是否至少有一个 + +227 +00:13:50,664 --> 00:13:53,967 +图像拥有非空的文件名来确认 + +228 +00:13:54,001 --> 00:13:55,903 +如果给定图集中有图像 + +229 +00:13:55,936 --> 00:13:57,838 +我们就需要生成 SwiftUI 图像 + +230 +00:13:57,871 --> 00:14:00,307 +从软件包中载入该图像 + +231 +00:14:02,109 --> 00:14:05,579 +实现的方式是通过每个图片 +的 basename 创建字符串 + +232 +00:14:05,612 --> 00:14:07,748 +从模块包中载入相应的图片 + +233 +00:14:07,781 --> 00:14:10,184 +此模块包就是构建系统 +为每个带资源的软件包 + +234 +00:14:10,217 --> 00:14:12,186 +创建的资源包 + +235 +00:14:13,620 --> 00:14:17,824 +我们可以通过将生成的代码 +写入文件 为可执行文件的工作收尾 + +236 +00:14:17,858 --> 00:14:19,426 +以参数所指定的方式 + +237 +00:14:21,528 --> 00:14:24,231 +我们回到 Xcode 中 +创建可执行文件 + +238 +00:14:30,904 --> 00:14:33,473 +将它命名为 “AssetConstantsExec” + +239 +00:14:40,447 --> 00:14:41,782 +并添加主文件 + +240 +00:14:51,358 --> 00:14:53,961 +现在我们要在软件包清单中声明它 + +241 +00:15:00,067 --> 00:15:03,070 +我们可以将刚才讨论的 +代码添加到它的主文件中 + +242 +00:15:09,243 --> 00:15:11,945 +现在有了可以生成代码的可执行文件 + +243 +00:15:11,979 --> 00:15:14,681 +我们可以通过插件将它带入构建系统 + +244 +00:15:41,408 --> 00:15:43,076 +我们从软件库目标中添加必需的目标 + +245 +00:15:43,110 --> 00:15:46,380 +以及插件的使用方法 + +246 +00:16:09,436 --> 00:16:13,473 +像之前一样 我们导入 +PackagePlugin 软件库 + +247 +00:16:13,507 --> 00:16:14,808 +并创建结构体 + +248 +00:16:14,842 --> 00:16:17,578 +这一次要使它符合 +BuildTool 插件协议 + +249 +00:16:37,564 --> 00:16:41,068 +入口点看上去很类似 +但这里我们得到的是一个目标 + +250 +00:16:41,101 --> 00:16:42,903 +而非用户参数 + +251 +00:16:42,936 --> 00:16:45,739 +这就是插件应用的目标 + +252 +00:16:45,772 --> 00:16:49,643 +每个使用给定插件的目标 +都会对入口点调用一次 + +253 +00:16:55,649 --> 00:16:59,353 +这个插件会尤其关注源模块目标 + +254 +00:16:59,386 --> 00:17:02,256 +指那些实际携带源文件的目标 + +255 +00:17:02,289 --> 00:17:05,492 +区别于与其他目标 +比如说二进制目标 + +256 +00:17:05,526 --> 00:17:07,561 +为了创建构建命令的数组 + +257 +00:17:07,594 --> 00:17:11,164 +我们需要循环遍历 +目标中所有 xcasset 包 + +258 +00:17:11,198 --> 00:17:13,534 +我们要为之后要显示在构建日志中的 + +259 +00:17:13,567 --> 00:17:15,469 +显示名称提取字符串 + +260 +00:17:15,502 --> 00:17:18,705 +并建立合适的输入和输出路径 + +261 +00:17:19,473 --> 00:17:23,544 +我们也可以使用插件 API +来查找可执行文件 + +262 +00:17:23,577 --> 00:17:25,579 +然后将构建命令合在一起 + +263 +00:17:27,047 --> 00:17:29,950 +这样 我们就准备好 +再次构建这个项目了 + +264 +00:17:29,983 --> 00:17:32,719 +我们可以通过构建日志 +查看新的构建步骤 + +265 +00:17:32,753 --> 00:17:33,754 +看看发生了什么 + +266 +00:17:40,727 --> 00:17:44,598 +插件在构建开始时编译和运行 + +267 +00:17:44,631 --> 00:17:47,601 +从那里 它将生成的所有 +命令都添加到构建图中 + +268 +00:17:52,472 --> 00:17:55,342 +再来看看目标 +我们的新构建命令已经运行了 + +269 +00:17:59,279 --> 00:18:02,015 +最后 生成的源文件作为 + +270 +00:18:02,049 --> 00:18:04,451 +Swift 编译文件的一部分出现 + +271 +00:18:05,919 --> 00:18:12,359 +现在回到预览 + +272 +00:18:12,392 --> 00:18:16,430 +在这里我们可以用新常量 +来替代字符串类型的图像创建 + +273 +00:18:20,000 --> 00:18:23,203 +其他图像名称也自动补完了 + +274 +00:18:28,141 --> 00:18:30,344 +很好 我们几乎没用什么代码 + +275 +00:18:30,377 --> 00:18:32,479 +只使用熟悉的 Swift API + +276 +00:18:32,513 --> 00:18:36,683 +没有离开 Xcode 就改善了工作流 + +277 +00:18:39,386 --> 00:18:42,289 +到这里 我们已经探讨了如何将插件 + +278 +00:18:42,322 --> 00:18:45,125 +作为我们 +已有软件库的一部分为自己所用 + +279 +00:18:45,158 --> 00:18:47,461 +但插件的另一项强大的属性是 + +280 +00:18:47,494 --> 00:18:49,696 +我们可以像软件库那样 + +281 +00:18:49,730 --> 00:18:51,198 +直接共享它们 + +282 +00:18:53,033 --> 00:18:54,968 +在下一个演示中 我将展示如何 + +283 +00:18:55,002 --> 00:18:56,336 +使用随 Xcode 发布的 +genstrings 工具 + +284 +00:18:56,370 --> 00:18:58,705 +自动化某些构建前的处理工作 + +285 +00:18:59,473 --> 00:19:02,042 +这一工具可以从您的代码中 +提取本地化字符串 + +286 +00:19:02,075 --> 00:19:05,078 +进入本地化目录 供未来使用 + +287 +00:19:05,112 --> 00:19:07,014 +由于这个插件看起来很有用 + +288 +00:19:07,047 --> 00:19:09,249 +我想让它成为独立的软件包 + +289 +00:19:09,283 --> 00:19:11,251 +以便进行单独分享 + +290 +00:19:12,886 --> 00:19:14,054 +如果您想了解更多 + +291 +00:19:14,087 --> 00:19:16,523 +软件包中的资源和本地化的相关信息 + +292 +00:19:16,557 --> 00:19:20,661 +我推荐您观看 +WWDC20 中关于此话题的讲座 + +293 +00:19:20,694 --> 00:19:23,263 +如果想了解更多本地化的总体信息 + +294 +00:19:23,297 --> 00:19:26,633 +请查看 WWDC21 的 +“本地化您的 SwiftUI App” 讲座 + +295 +00:19:28,936 --> 00:19:32,272 +针对这个插件 我们首先 +对用于本地化的输出目录 + +296 +00:19:32,306 --> 00:19:34,942 +进行计算 + +297 +00:19:34,975 --> 00:19:36,343 +我们需要计算输入文件 + +298 +00:19:36,376 --> 00:19:41,215 +它们全都是给定目标中的 +Swift 或 Objective-C 源文件 + +299 +00:19:41,248 --> 00:19:42,783 +之后我们要创建构建前命令 + +300 +00:19:42,816 --> 00:19:46,220 +来执行 Xcode 提供的 +genstrings 工具 + +301 +00:19:46,253 --> 00:19:49,323 +请注意 构建前和构建中命令的 +最大区别在于 + +302 +00:19:49,356 --> 00:19:52,059 +我们没有对明确定义的 +输出集进行声明 + +303 +00:19:52,092 --> 00:19:54,528 +也就是说这些命令 +将在每一项构建上运行 + +304 +00:19:56,063 --> 00:19:58,532 +工具会从用户的源代码中 + +305 +00:19:58,565 --> 00:20:00,834 +提取所有本地化字符串 + +306 +00:20:00,868 --> 00:20:04,371 +然后将所有字符串都 +写入本地化目录 + +307 +00:20:04,404 --> 00:20:07,407 +此目录可以作为用户项目实际的 + +308 +00:20:07,441 --> 00:20:08,408 +本地化工作的基础进行使用 + +309 +00:20:11,078 --> 00:20:13,847 +开始之前 我已经创建好了整体架构 + +310 +00:20:13,881 --> 00:20:16,383 +现在 在软件包清单中 + +311 +00:20:16,416 --> 00:20:21,255 +我们像之前一样添加插件目标 + +312 +00:20:21,288 --> 00:20:23,724 +但我们还需要添加插件产品 + +313 +00:20:29,296 --> 00:20:32,299 +与软件库产品类似 这是一种将插件 + +314 +00:20:32,332 --> 00:20:35,536 +作为软件包让客户可用 +而不仅仅是自己使用 + +315 +00:20:38,572 --> 00:20:42,276 +我们可以写下之前讨论过的代码 + +316 +00:20:50,384 --> 00:20:51,818 +现在我们已经构建好了插件 + +317 +00:20:51,852 --> 00:20:55,155 +需要将其作为单独 +示例软件包进行测试 + +318 +00:21:00,694 --> 00:21:03,297 +为此 让我们从模板 +创建一个新软件包 + +319 +00:21:04,731 --> 00:21:08,268 +我们将添加一个为软件包提供 +本地化字符串的 API + +320 +00:21:14,608 --> 00:21:17,578 +再在生成的测试中添加其用法 + +321 +00:21:35,729 --> 00:21:40,701 +正如预想的那样 测试成功了 +我们的 API 返回了字符串 “World” + +322 +00:21:40,734 --> 00:21:44,271 +让我们为插件包添加 +一个基于路径的依赖项 + +323 +00:21:51,745 --> 00:21:54,348 +再向软件库目标添加插件的用法 + +324 +00:22:03,757 --> 00:22:05,492 +现在我们可以再运行一次 + +325 +00:22:10,864 --> 00:22:17,804 +如果我们看一看构建日志 + +326 +00:22:17,838 --> 00:22:23,410 +就会发现插件在构建一开始就执行了 + +327 +00:22:23,443 --> 00:22:26,547 +生成的文件添加到了我们的目标中 + +328 +00:22:26,580 --> 00:22:30,017 +因此我们将资源包构建好 + +329 +00:22:30,050 --> 00:22:34,288 +并生成了一个资源存取器 + +330 +00:22:34,321 --> 00:22:38,859 +好像资源从一开始 +就是我们目标的一部分 + +331 +00:22:38,892 --> 00:22:42,462 +现在让我们改写代码 +来实际使用资源包 + +332 +00:22:53,073 --> 00:22:55,075 +最后 如果我们修改代码 + +333 +00:23:10,757 --> 00:23:12,993 +并看一下生成的资源包 + +334 +00:23:26,974 --> 00:23:29,343 +可以看到修改反映在这里 + +335 +00:23:30,811 --> 00:23:32,946 +现在我们有了插件的测试环境 + +336 +00:23:32,980 --> 00:23:34,314 +就可以完善测试套件 + +337 +00:23:34,348 --> 00:23:36,583 +并最终将插件包与他人共享 + +338 +00:23:37,184 --> 00:23:42,456 +回顾一下 插件可以用于 +对开发者工具进行自动化和共享 + +339 +00:23:42,489 --> 00:23:46,293 +自定义命令提供了一种 +对普通任务进行自动化的方法 + +340 +00:23:46,326 --> 00:23:47,561 +构建工具则可以用于 + +341 +00:23:47,594 --> 00:23:51,465 +在构建过程中生成文件 + +342 +00:23:51,498 --> 00:23:53,400 +感谢您的聆听! + +343 +00:23:53,433 --> 00:23:56,236 +[迷幻音乐] + diff --git a/zho/2022 Session 110404 Implement proactive in-app purchase restore.srt b/zho/2022 Session 110404 Implement proactive in-app purchase restore.srt new file mode 100644 index 0000000..38a5880 --- /dev/null +++ b/zho/2022 Session 110404 Implement proactive in-app purchase restore.srt @@ -0,0 +1,1664 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,309 --> 00:00:11,245 +David:开发者好 +我是 David Wendland + +3 +00:00:11,278 --> 00:00:14,414 +App Store 的商务技术倡导者 + +4 +00:00:14,448 --> 00:00:18,452 +今天 我将向您介绍该如何通过 +主动识别用户购买记录 + +5 +00:00:18,485 --> 00:00:21,555 +包括新记录、当前记录、历史记录 +来让您的 App 为顾客提供一流体验 + +6 +00:00:21,588 --> 00:00:25,859 +且期间不需要顾客的任何操作 + +7 +00:00:25,893 --> 00:00:30,330 +我将介绍如何使用 StoreKit 2 +和初版 StoreKit + +8 +00:00:30,364 --> 00:00:33,100 +方便您为所有顾客优化 + +9 +00:00:33,133 --> 00:00:36,003 +App 的启用体验 + +10 +00:00:36,036 --> 00:00:39,907 +先说说主动 App 内购买项目恢复的定义吧 + +11 +00:00:39,940 --> 00:00:42,309 +这指的是当顾客启动您的 App 时 + +12 +00:00:42,342 --> 00:00:45,946 +您可以通过使用设备上现成的数据 + +13 +00:00:45,979 --> 00:00:48,582 +主动检查交易记录 + +14 +00:00:48,615 --> 00:00:53,420 +来确定这是新顾客还是现有顾客 + +15 +00:00:53,453 --> 00:00:56,557 +期间不需要顾客进行操作 + +16 +00:00:56,590 --> 00:01:01,328 +甚至都不需要 +点击“恢复购买”或输入密码 + +17 +00:01:01,361 --> 00:01:04,164 +由此 您能够根据 +顾客的购买历史和状态 + +18 +00:01:04,198 --> 00:01:07,801 +为其定制 App 体验 + +19 +00:01:07,835 --> 00:01:12,039 +您的 App 可以为现有顾客 +解锁产品或服务 + +20 +00:01:12,072 --> 00:01:16,743 +也可以向新顾客推销最新产品 + +21 +00:01:16,777 --> 00:01:18,345 +而对于那些曾经订阅的顾客 + +22 +00:01:18,378 --> 00:01:21,815 +您可以为其提供订阅优惠 +来吸引顾客回归 + +23 +00:01:21,849 --> 00:01:24,418 +这就是主动恢复的意义所在 + +24 +00:01:24,451 --> 00:01:27,221 +通过 StoreKit 自动为新顾客 +现有顾客和既往顾客 + +25 +00:01:27,254 --> 00:01:33,360 +在所有设备上自动优化 App 体验 + +26 +00:01:33,393 --> 00:01:35,462 +我们来看看这个例子 + +27 +00:01:35,495 --> 00:01:38,232 +这个 App 名为“海洋日志” +以它为例 + +28 +00:01:38,265 --> 00:01:40,667 +在常见的销售体验中 + +29 +00:01:40,701 --> 00:01:44,304 +顾客有几个行为召唤选项可供选择 + +30 +00:01:44,338 --> 00:01:47,107 +我可以试着进行 App 内购买 + +31 +00:01:47,140 --> 00:01:50,777 +并使用面容 ID 等 +生物识别技术进行身份验证 + +32 +00:01:50,811 --> 00:01:52,412 +我也可以创建 App 帐户 + +33 +00:01:52,446 --> 00:01:56,250 +通过密钥串输入密码来登录帐号 + +34 +00:01:56,283 --> 00:01:58,652 +如果我是个活跃订阅者 + +35 +00:01:58,685 --> 00:02:01,388 +还可以使用“恢复购买”功能 + +36 +00:02:01,421 --> 00:02:03,757 +当活跃订阅者使用新设备时 + +37 +00:02:03,790 --> 00:02:07,427 +并不一定知道该选哪个选项 + +38 +00:02:07,461 --> 00:02:10,297 +但有了触手可及的数据 + +39 +00:02:10,330 --> 00:02:12,199 +加上我们的主动 App 内购买项目恢复最优解 + +40 +00:02:12,232 --> 00:02:15,469 +您的 App 可以简化这一流程 + +41 +00:02:16,036 --> 00:02:21,475 +也就是说 如果我在新设备上 +启动了 App 且我是个活跃订阅者 + +42 +00:02:21,508 --> 00:02:26,013 +启动后 无需我进行任何操作 +该 App 会自动 + +43 +00:02:26,046 --> 00:02:28,649 +主动恢复我的服务内容 + +44 +00:02:28,682 --> 00:02:31,318 +因此 请看这里 App 识别出了 +我的专业会员订阅 + +45 +00:02:31,351 --> 00:02:34,488 +于是加载了我最喜欢的海滩 +附上了冲浪条件 + +46 +00:02:34,521 --> 00:02:36,990 +并启用了实时摄像功能 + +47 +00:02:37,024 --> 00:02:41,061 +这种体验能够 +让您的 App 与众不同 + +48 +00:02:41,094 --> 00:02:45,899 +我将介绍如何在 iOS 15 及更高版本 +上使用 StoreKit 2 实现这种效果 + +49 +00:02:45,933 --> 00:02:49,636 +此外 针对 +支持旧版本 iOS 的 App + +50 +00:02:49,670 --> 00:02:51,905 +我也将介绍如何使用旧版 +StoreKit 和 verifyReceipt 端点 + +51 +00:02:51,939 --> 00:02:55,542 +来创造同样出色的体验 + +52 +00:02:55,576 --> 00:02:58,178 +背景介绍到此结束 我们进入正题 + +53 +00:02:58,212 --> 00:03:02,149 +在本期视频 我将首先详细描述 +App 所用的核心顾客产品状态 + +54 +00:03:02,182 --> 00:03:06,019 +基于该状态 您的 App +能够使用 StoreKit + +55 +00:03:06,053 --> 00:03:10,257 +基于顾客的 App 内购买记录生成个性化体验 + +56 +00:03:10,290 --> 00:03:14,194 +随后我将回顾使用 StoreKit 2 +实现该效果的步骤 + +57 +00:03:14,228 --> 00:03:19,132 +我会用 StoreKit 演示 App +来完成示例代码 + +58 +00:03:19,166 --> 00:03:21,335 +先来看看每种 App 内购买项目类型 +的核心顾客产品状态 + +59 +00:03:23,370 --> 00:03:27,975 +并查看一些个性化入职体验示例 + +60 +00:03:28,008 --> 00:03:30,711 +首先 适用的主动恢复的 +App 内购类型包括 + +61 +00:03:30,744 --> 00:03:35,148 +非消耗品 非续订类订阅 + +62 +00:03:35,182 --> 00:03:37,217 +和自动续期订阅 + +63 +00:03:37,251 --> 00:03:40,454 +此类服务都记录在顾客的交易历史中 + +64 +00:03:40,487 --> 00:03:43,056 +StoreKit 始终可以调用 + +65 +00:03:43,090 --> 00:03:46,994 +因此 您的 App 可以识别 +每个顾客帐户中 + +66 +00:03:47,027 --> 00:03:51,298 +对每个产品或订阅组的购买状态 + +67 +00:03:51,331 --> 00:03:54,001 +当查看顾客产品状态时 + +68 +00:03:54,034 --> 00:03:57,104 +我将使用“订阅项”一词来指代 + +69 +00:03:57,137 --> 00:04:01,608 +非续订和自动续订订阅 + +70 +00:04:01,642 --> 00:04:05,078 +以下是您的 App 可以针对其 +进行个性化的三个核心状态 + +71 +00:04:05,112 --> 00:04:08,549 +让我们深入观察一下新顾客 + +72 +00:04:08,582 --> 00:04:11,785 +该状态表示的是某个已登录 +App Store 的 Apple ID 中 + +73 +00:04:11,818 --> 00:04:16,456 +没有任何当前或过去的 App 内购买记录 + +74 +00:04:16,490 --> 00:04:21,328 +此状态通常也就是 +App 的默认销售体验状态 + +75 +00:04:21,361 --> 00:04:25,599 +我们的“海洋日志”正在推销 +可免费试用一个月的 + +76 +00:04:25,632 --> 00:04:28,268 +月度和年度订阅 + +77 +00:04:28,302 --> 00:04:33,307 +接下来是第二个核心状态 +已购顾客和活跃订阅者 + +78 +00:04:33,340 --> 00:04:36,210 +在这种状态下 +顾客有一个活跃的交易 + +79 +00:04:36,243 --> 00:04:39,046 +且您的 App 有义务授予顾客 + +80 +00:04:39,079 --> 00:04:41,548 +访问已购产品或服务的权限 + +81 +00:04:41,582 --> 00:04:44,852 +请看这里 “海洋日志”立即 +给顾客推送了 + +82 +00:04:44,885 --> 00:04:48,722 +顾客偏好的海滩 +以及高质量海滩实时镜头 + +83 +00:04:48,755 --> 00:04:53,560 +由于服务已主动恢复 +购买按钮消失了 + +84 +00:04:53,594 --> 00:04:56,263 +对于每个已购产品或有效订阅 + +85 +00:04:56,296 --> 00:05:00,501 +其交易都具有 +静态且唯一的原始交易 ID + +86 +00:05:00,534 --> 00:05:04,505 +始终绑定顾客的 +Apple ID 和 App Store + +87 +00:05:04,538 --> 00:05:07,274 +为了维护顾客的交易状态 + +88 +00:05:07,307 --> 00:05:12,012 +您需要将原始交易 ID +与您系统的帐户关联 + +89 +00:05:12,045 --> 00:05:14,147 +它可以是匿名帐户 + +90 +00:05:14,181 --> 00:05:17,017 +或用户通过您的系统创建的帐户 + +91 +00:05:17,050 --> 00:05:20,053 +原始交易 ID 对于 +充分利用 App Store + +92 +00:05:20,087 --> 00:05:23,290 +服务器通知的强大功能非常重要 + +93 +00:05:23,323 --> 00:05:27,194 +能够使您的服务器始终 +保持最新的交易状态 + +94 +00:05:27,227 --> 00:05:30,397 +需要强调的情况是 当顾客的订阅 + +95 +00:05:30,430 --> 00:05:32,199 +未能自动续订 + +96 +00:05:32,232 --> 00:05:35,836 +就进入了所谓的计费重试状态 + +97 +00:05:35,869 --> 00:05:39,740 +在该情况下 我们将努力在至多 +60 天内恢复订阅 + +98 +00:05:39,773 --> 00:05:43,544 +如果您在 App Store Connect 中 +选择了计费宽限期功能 + +99 +00:05:43,577 --> 00:05:46,046 +进入计费重试状态 +但处于宽限期内的订阅者 + +100 +00:05:46,079 --> 00:05:48,949 +可以在我们努力恢复订阅的同时 + +101 +00:05:48,982 --> 00:05:52,119 +继续访问订阅服务 + +102 +00:05:52,152 --> 00:05:54,688 +虽然订阅者仍可以访问您的服务 + +103 +00:05:54,721 --> 00:05:57,291 +请务必为其展示简单的行为召唤 + +104 +00:05:57,324 --> 00:05:59,459 +来解决订阅者的付款问题 + +105 +00:05:59,493 --> 00:06:02,596 +如果您想详细了解 +计费重试和计费宽限期 + +106 +00:06:02,629 --> 00:06:04,598 +请查看我们有关于 +减少非自愿订户损失的 + +107 +00:06:04,631 --> 00:06:08,569 +讲座和资源 + +108 +00:06:08,602 --> 00:06:13,574 +最后一个核心状态是 +不活跃购买或不活跃订阅者 + +109 +00:06:13,607 --> 00:06:17,678 +此状态代表顾客曾进行过 App 内购买 + +110 +00:06:17,711 --> 00:06:20,747 +但由于到期或被撤销 + +111 +00:06:20,781 --> 00:06:23,984 +不再有产品或服务使用权限的顾客 + +112 +00:06:24,017 --> 00:06:28,188 +这些交易始终存在 +并包含原始交易 ID + +113 +00:06:28,222 --> 00:06:32,893 +您因此能够跨设备和平台维护状态 + +114 +00:06:32,926 --> 00:06:37,130 +对于订阅 其非活跃状态 +是由到期日期确定的 + +115 +00:06:37,164 --> 00:06:38,966 +对于所有 App 内购买项目类型 + +116 +00:06:38,999 --> 00:06:42,135 +如果存在撤销日期 +就可能会处于非活跃状态 + +117 +00:06:42,169 --> 00:06:44,638 +会出现该状态的情况包括 +交易已退款时 + +118 +00:06:44,671 --> 00:06:48,575 +或者通过家庭共享授予的 +访问权限已被撤销时 + +119 +00:06:48,609 --> 00:06:52,746 +对于由于到期或被撤销 +产生的非活动订阅者 + +120 +00:06:52,779 --> 00:06:56,250 +您可以考虑提供订阅优惠 +来让顾客回归 + +121 +00:06:56,283 --> 00:06:58,519 +对于处于计费重试状态的顾客 + +122 +00:06:58,552 --> 00:07:01,221 +别忘记向他们展示同样的行为召唤 + +123 +00:07:01,255 --> 00:07:03,891 +来解决顾客的付款细节问题 + +124 +00:07:03,924 --> 00:07:08,562 +回顾一下 以下是 +在主动恢复 App 内购买状态 + +125 +00:07:08,595 --> 00:07:11,465 +并为顾客量身定制 App 体验时 + +126 +00:07:11,498 --> 00:07:15,068 +App 将使用的三个 +核心顾客产品状态 + +127 +00:07:15,102 --> 00:07:19,473 +接下来看看“海洋日志”是 +怎样应用这些体验的吧 + +128 +00:07:21,475 --> 00:07:26,146 +新顾客将看到最新产品和试销优惠 + +129 +00:07:26,180 --> 00:07:29,616 +而活跃顾客会觉得 +App 运行一如往常 + +130 +00:07:29,650 --> 00:07:33,187 +因为 App 在该类顾客的 +所有设备上 + +131 +00:07:33,220 --> 00:07:35,289 +简化了对产品和服务的访问流程 + +132 +00:07:35,322 --> 00:07:37,257 +对于非活跃订阅者 + +133 +00:07:37,291 --> 00:07:39,826 +您可以用优惠代码或促销优惠 + +134 +00:07:39,860 --> 00:07:42,763 +向其展示最新的回归优惠 + +135 +00:07:43,363 --> 00:07:46,967 +到此我们已经介绍了 +三个核心顾客产品状态 + +136 +00:07:47,000 --> 00:07:50,971 +也说明了为什么根据状态提供服务 +能够为顾客带来良好体验 + +137 +00:07:51,004 --> 00:07:54,775 +但是当然 我们还有更进一步的空间 + +138 +00:07:54,808 --> 00:07:57,611 +您的 App 可以扩展或 +改进顾客体验 + +139 +00:07:57,644 --> 00:08:00,414 +来适合您的产品供应 商业模式 + +140 +00:08:00,447 --> 00:08:02,883 +策略和优先事项 + +141 +00:08:02,916 --> 00:08:04,885 +但您在 App 中实施主动恢复时 + +142 +00:08:04,918 --> 00:08:08,655 +还有几件事需要考虑 + +143 +00:08:09,756 --> 00:08:12,726 +如果您支持多个产品或订阅组 + +144 +00:08:12,759 --> 00:08:18,098 +顾客状态是基于各产品 +和订阅组分别确定的 + +145 +00:08:18,131 --> 00:08:20,567 +因此 您可能需要考虑混合状态 + +146 +00:08:20,601 --> 00:08:23,937 +或其他可能的依赖项 + +147 +00:08:23,971 --> 00:08:26,240 +请思考一下非平台活动 + +148 +00:08:26,273 --> 00:08:30,377 +以及该类活动会如何影响 +顾客的产品状态 + +149 +00:08:30,410 --> 00:08:33,280 +以及 请务必查看 +App Store 服务器通知 + +150 +00:08:33,313 --> 00:08:36,683 +因为这对于在服务器间同步 + +151 +00:08:36,717 --> 00:08:39,319 +所有 App 内购买项目类型的状态非常重要 + +152 +00:08:39,353 --> 00:08:43,090 +在版本 2 中 新的通知类型和 +子类型 + +153 +00:08:43,123 --> 00:08:45,292 +能够近乎实时地 +将 28 个独特事件 + +154 +00:08:45,325 --> 00:08:48,929 +安全发送到您的服务器 + +155 +00:08:48,962 --> 00:08:52,399 +如果您想深入了解 +版本 2 的集成或迁移 + +156 +00:08:52,432 --> 00:08:56,970 +可以观看主题为 +“探索 App 内购买的集成和迁移”的视频 + +157 +00:08:57,004 --> 00:09:00,274 +在视频中 Alex 和 Gabriel +还介绍了 StoreKit 2 的兼容性 + +158 +00:09:00,307 --> 00:09:04,278 +原始的 StoreKit 框架 +以及最佳实践方式 + +159 +00:09:04,311 --> 00:09:07,614 +到目前为止 我们已经讨论了 +支持的顾客产品状态 + +160 +00:09:07,648 --> 00:09:11,151 +以及这种体验可以 +为您的顾客带来什么 + +161 +00:09:11,185 --> 00:09:14,221 +现在让我们来看看实现细节 + +162 +00:09:14,254 --> 00:09:16,323 +我将使用 StoreKit 演示 App + +163 +00:09:16,356 --> 00:09:20,027 +演示 App 已经更新了 +StoreKit 2 的主动恢复功能 + +164 +00:09:20,060 --> 00:09:24,565 +请注意 StoreKit 演示 App +可在本期视频中下载 + +165 +00:09:24,598 --> 00:09:28,569 +让我们看看 StoreKit 演示 +为新顾客提供的默认体验 + +166 +00:09:28,602 --> 00:09:31,405 +也就是还没有进行任何 App 内购买的顾客 + +167 +00:09:31,438 --> 00:09:34,942 +为了查看产品 +需要点击“商店”按钮 + +168 +00:09:34,975 --> 00:09:38,045 +屏幕上方展示了当前可用汽车库存 + +169 +00:09:38,078 --> 00:09:41,114 +这些术语非消耗型 App 内购买项目产品 + +170 +00:09:41,148 --> 00:09:45,519 +然后将导航服务设为 +每月自动续期订阅服务 + +171 +00:09:45,552 --> 00:09:50,190 +提供三种不同级别的服务供顾客选择 + +172 +00:09:50,224 --> 00:09:53,293 +下方有一个非续订订阅选项 + +173 +00:09:53,327 --> 00:09:55,729 +允许一次性的访问 + +174 +00:09:55,762 --> 00:09:58,398 +以上就是我们 App + +175 +00:09:58,432 --> 00:10:00,901 +提供给未消费顾客的新顾客体验 + +176 +00:10:00,934 --> 00:10:03,904 +现在让我们看看 App 如何确定 + +177 +00:10:03,937 --> 00:10:07,708 +该顾客在当前或过去是否有购买记录 + +178 +00:10:07,741 --> 00:10:10,310 +App 需要在启动后 + +179 +00:10:10,344 --> 00:10:12,646 +立即执行三个步骤 + +180 +00:10:12,679 --> 00:10:15,649 +最重要的是 在“购买”按钮 +出现在顾客界面前 + +181 +00:10:15,682 --> 00:10:19,119 +这些步骤就全部完成了 + +182 +00:10:19,853 --> 00:10:22,456 +第一步 App 需要开始监听 + +183 +00:10:22,489 --> 00:10:25,425 +来自 App Store 的交易 + +184 +00:10:25,459 --> 00:10:30,430 +这是 App Store 的最佳使用方法 +因为交易记录可能因为 + +185 +00:10:30,464 --> 00:10:33,166 +家庭共享询问购买、 +代码兑换、订阅自动续订、 + +186 +00:10:33,200 --> 00:10:35,936 +或者中断购买等情况 + +187 +00:10:35,969 --> 00:10:38,539 +随时显示 + +188 +00:10:38,572 --> 00:10:41,975 +此外 由于退款而失去访问权限 + +189 +00:10:42,009 --> 00:10:44,211 +或不再通过家庭共享而撤销的交易 + +190 +00:10:44,244 --> 00:10:47,347 +也可以被 App 接收 + +191 +00:10:47,381 --> 00:10:49,883 +等被授予访问权限后 + +192 +00:10:49,917 --> 00:10:52,152 +且顾客状态 +从活跃变为不活跃的过程中 + +193 +00:10:52,186 --> 00:10:56,356 +App 能在启动时更多应用此功能 + +194 +00:10:56,390 --> 00:11:00,527 +交易被发现后 +会被判定为未完成交易 + +195 +00:11:00,561 --> 00:11:03,330 +需要经过验证 交付给顾客 + +196 +00:11:03,363 --> 00:11:05,599 +并标记为已完成 + +197 +00:11:05,632 --> 00:11:08,435 +由此 您的 App 可以保证 +不错过任何交易 + +198 +00:11:08,468 --> 00:11:10,971 +并提供出色的顾客体验 + +199 +00:11:11,004 --> 00:11:16,043 +现在来看看 StoreKit 演示 App +是如何监听 StoreKit 2 交易的 + +200 +00:11:16,076 --> 00:11:18,946 +这里用了函数 listenForTransactions +即“监听交易” + +201 +00:11:18,979 --> 00:11:23,684 +该函数将为已登录的 +App Store 顾客 + +202 +00:11:23,717 --> 00:11:26,787 +返回任何未完成交易或更新交易 + +203 +00:11:26,820 --> 00:11:28,622 +对于发现的交易 + +204 +00:11:28,655 --> 00:11:32,626 +StoreKit 2 将验证交易 +的真实性 + +205 +00:11:32,659 --> 00:11:35,696 +接着 在我的 App 交付内容后 + +206 +00:11:35,729 --> 00:11:38,765 +授予访问权限或更新顾客产品状态 + +207 +00:11:38,799 --> 00:11:40,667 +然后完成交易 + +208 +00:11:40,701 --> 00:11:44,872 +向 App Store 表明 +购买已送达 + +209 +00:11:44,905 --> 00:11:48,642 +一旦交易完成 +它将不会在任何设备上 + +210 +00:11:48,675 --> 00:11:51,812 +通过 StoreKit 返回到您的 App + +211 +00:11:51,845 --> 00:11:54,448 +这第一个步骤对 +所有 App 都非常重要 + +212 +00:11:54,481 --> 00:11:58,185 +此后每次 App 启动时 +都会重复这一步骤 + +213 +00:11:58,218 --> 00:12:01,922 +第二步是确定顾客产品状态 + +214 +00:12:01,955 --> 00:12:06,326 +也就是要通过使用 currentEntitlements +即“当前授权” + +215 +00:12:06,360 --> 00:12:08,529 +来主动请求顾客的活跃交易 + +216 +00:12:08,562 --> 00:12:11,365 +特别是自动续期订阅 + +217 +00:12:11,398 --> 00:12:13,367 +此类订阅会改变顾客状态 + +218 +00:12:13,400 --> 00:12:16,737 +例如已取消 计费重试或待降级 + +219 +00:12:16,770 --> 00:12:22,576 +这种情况下 您可以使用函数 +Product.SubscriptionInfo.RenewalState + +220 +00:12:22,609 --> 00:12:27,214 +来通过 StoreKit 演示 +App 看看我们是如何做到这一点的 + +221 +00:12:27,247 --> 00:12:30,651 +从函数 updateCustomerProductStatus +即“更新顾客产品状态”开始 + +222 +00:12:30,684 --> 00:12:33,687 +该函数能够为每种长期 App 内购买项目类型 + +223 +00:12:33,720 --> 00:12:37,758 +跟踪顾客产品状态 + +224 +00:12:37,791 --> 00:12:40,427 +然后使用 StoreKit 2 的 +currentEntitlements 方法 + +225 +00:12:40,460 --> 00:12:43,997 +遍历每种购买类型 + +226 +00:12:44,031 --> 00:12:49,603 +顾客所有可能获得产品授权 +的交易都会被返回 + +227 +00:12:49,636 --> 00:12:52,940 +我们根据产品类型记录交易 + +228 +00:12:52,973 --> 00:12:55,642 +这是非消耗品的代码 + +229 +00:12:55,676 --> 00:12:58,846 +这是非续订订阅产品的 + +230 +00:12:58,879 --> 00:13:03,350 +为了确定顾客是活跃订阅者 +还是非活跃订阅者 + +231 +00:13:03,383 --> 00:13:06,553 +我为非续订订阅添加了额外的逻辑 + +232 +00:13:06,587 --> 00:13:09,423 +来计算到期日期 + +233 +00:13:09,456 --> 00:13:14,294 +最后 我要检查一个 +活跃的自动续期订阅 + +234 +00:13:14,328 --> 00:13:17,731 +并将该状态应用于订阅组 + +235 +00:13:17,764 --> 00:13:22,202 +考虑到非活动状态 +例如计费重试、过期和撤销 + +236 +00:13:22,236 --> 00:13:24,738 +可变订阅组状态使用的是 + +237 +00:13:24,771 --> 00:13:29,176 +Product.SubscriptionInfo.RenewalState 函数 + +238 +00:13:29,209 --> 00:13:31,411 +现在我们已经检索了用户的交易 + +239 +00:13:31,445 --> 00:13:35,682 +并确定了各产品或订阅组的顾客状态 + +240 +00:13:35,716 --> 00:13:38,519 +我们的 App 获得了 +能够支持为各种用例 + +241 +00:13:38,552 --> 00:13:40,687 +定制体验的逻辑 + +242 +00:13:40,721 --> 00:13:44,791 +让我们看看 StoreKit +演示 App 的源代码 + +243 +00:13:44,825 --> 00:13:46,994 +如果对于三种 App 内购买项目产品类型 + +244 +00:13:47,027 --> 00:13:49,796 +都没有发现活跃交易 + +245 +00:13:49,830 --> 00:13:52,900 +顾客将进行默认的新顾客体验 + +246 +00:13:52,933 --> 00:13:54,868 +就像我们之前看过的那样 + +247 +00:13:54,902 --> 00:13:58,672 +顾客将在“商店”页面 +看到简单的行为召唤 + +248 +00:13:58,705 --> 00:14:01,175 +如果顾客有活跃交易的记录 + +249 +00:14:01,208 --> 00:14:04,144 +App 启动时 此类顾客将 +看到已购买的服务 + +250 +00:14:04,178 --> 00:14:08,015 +各产品上的“购买”按钮 +也会相对进行更新 + +251 +00:14:08,048 --> 00:14:11,585 +所以 对于非消耗品 +我们将展示已购买产品与服务 + +252 +00:14:11,618 --> 00:14:14,421 +而 App 将显示已购的非消耗品 + +253 +00:14:14,454 --> 00:14:16,190 +或提供行动号召 + +254 +00:14:16,223 --> 00:14:19,092 +让顾客看到购买选项 + +255 +00:14:19,126 --> 00:14:21,695 +这里是对于活跃产品的处理方式 + +256 +00:14:21,728 --> 00:14:25,199 +在此情境下 顾客是导航服务 + +257 +00:14:25,232 --> 00:14:29,102 +非自动续期订阅与自动续期订阅 +的活跃订阅者 + +258 +00:14:29,136 --> 00:14:32,439 +最后是不活跃的订阅者 + +259 +00:14:32,472 --> 00:14:35,676 +那些订阅项已过期、被撤销 + +260 +00:14:35,709 --> 00:14:38,612 +或处于计费重试状态的顾客 + +261 +00:14:38,645 --> 00:14:41,915 +接下来让我们进入 +StoreKit 演示 App + +262 +00:14:41,949 --> 00:14:44,184 +来模拟一位非消耗型和 + +263 +00:14:44,218 --> 00:14:48,422 +自动续期订阅活跃顾客 + +264 +00:14:48,455 --> 00:14:52,226 +假设我购买了赛车并订阅了专业导航 + +265 +00:14:52,259 --> 00:14:54,595 +演示 App 将应用绿色复选标记 + +266 +00:14:54,628 --> 00:14:59,132 +表示确认这些购买已成功、已验证 + +267 +00:14:59,166 --> 00:15:01,068 +且已启用 + +268 +00:15:01,101 --> 00:15:03,570 +通过购买以上产品与服务 +我对于该非消耗品的顾客产品状态 + +269 +00:15:03,604 --> 00:15:06,440 +变为了已购买 + +270 +00:15:06,473 --> 00:15:10,177 +对于订阅项来说 我是活跃的订阅者 + +271 +00:15:10,210 --> 00:15:12,546 +现在 如果我将 App +安装在了新设备上 + +272 +00:15:12,579 --> 00:15:15,349 +当我第一次启动 +StoreKit 演示 App 时 + +273 +00:15:15,382 --> 00:15:19,720 +它将主动执行步骤一、二、三 + +274 +00:15:19,753 --> 00:15:24,324 +在这里 您可以看到演示 App +已主动恢复了我的两项交易 + +275 +00:15:24,358 --> 00:15:26,360 +而且根本不需要我来操作 + +276 +00:15:26,393 --> 00:15:27,828 +由于这是一个演示 App + +277 +00:15:27,861 --> 00:15:30,597 +产品的同步范围只能到这里了 + +278 +00:15:30,631 --> 00:15:33,800 +但在您的 App 中 +此过程将确保不会给活跃顾客 + +279 +00:15:33,834 --> 00:15:37,337 +推送已购产品的购买信息 + +280 +00:15:37,371 --> 00:15:41,308 +还会自动为顾客启用这些产品和服务 + +281 +00:15:41,875 --> 00:15:44,111 +这对于您已有的顾客来说 +是很棒的功能 + +282 +00:15:44,144 --> 00:15:48,015 +顾客无需登录或点击“恢复购买” + +283 +00:15:48,048 --> 00:15:49,316 +简简单单就能起效 + +284 +00:15:49,349 --> 00:15:53,921 +您的 App 可以使用 +现成的 API 和数据 + +285 +00:15:53,954 --> 00:15:57,391 +目前为止已经介绍了用 StoreKit 2 +实现该功能的三个步骤 + +286 +00:15:57,424 --> 00:16:01,328 +接下来 我想说说该如何在 +无法运用 StoreKit 2 强大功能的 + +287 +00:16:01,361 --> 00:16:03,430 +旧版本 iOS 上也为您的顾客 + +288 +00:16:03,463 --> 00:16:05,999 +带来同样的良好体验 + +289 +00:16:06,800 --> 00:16:10,437 +您需要在旧版 StoreKit 中执行 +与 StoreKit 2 相同的步骤 + +290 +00:16:10,470 --> 00:16:12,172 +来确定顾客产品状态 + +291 +00:16:12,206 --> 00:16:17,411 +在 iOS 7 或更高版本上 +主动恢复 App 内购买 + +292 +00:16:17,444 --> 00:16:22,015 +为此 您的服务器需要使用 +verifyReceipt 端点 + +293 +00:16:22,049 --> 00:16:25,352 +来验证和检索最新交易 + +294 +00:16:25,385 --> 00:16:29,556 +以确定顾客的产品状态 + +295 +00:16:29,590 --> 00:16:34,294 +App Store 安装 App 时 +设备上会显示 App 收据 + +296 +00:16:34,328 --> 00:16:37,998 +但请记住 在使用 Sandbox +或 TestFlight 进行测试时 + +297 +00:16:38,031 --> 00:16:39,867 +App 收据仅存在于 + +298 +00:16:39,900 --> 00:16:43,704 +App 内购买完成或恢复后 + +299 +00:16:43,737 --> 00:16:48,509 +App 无法找到 App 收据的情况 +应该只发生在 Sandbox 中 + +300 +00:16:48,542 --> 00:16:52,312 +您的 App 可以将这种情况 +等同于新顾客状态 + +301 +00:16:52,346 --> 00:16:55,883 +即没有发现 App 内购买记录的情况 + +302 +00:16:55,916 --> 00:16:58,252 +过去创建的 App 收据就足够 + +303 +00:16:58,285 --> 00:17:01,555 +从 App Store 检索最新交易了 + +304 +00:17:01,588 --> 00:17:04,424 +因此 就不需要 +顾客的操作来“恢复购买” + +305 +00:17:04,458 --> 00:17:06,693 +或者刷新收据 + +306 +00:17:06,727 --> 00:17:10,631 +只需在 verifyReceipt 请求中 +包含共享密钥 + +307 +00:17:10,664 --> 00:17:13,367 +就能够接收最新的非消耗型订阅 + +308 +00:17:13,400 --> 00:17:16,136 +非续订订阅 + +309 +00:17:16,170 --> 00:17:19,006 +和自动续期订阅的交易 + +310 +00:17:19,039 --> 00:17:23,610 +让我们回顾一下三个实施步骤 + +311 +00:17:23,644 --> 00:17:25,712 +区别在于第二步 + +312 +00:17:25,746 --> 00:17:29,683 +也就是识别顾客产品状态的步骤 + +313 +00:17:29,716 --> 00:17:34,121 +确定顾客产品状态的流程 +从设备上的 App 收据开始 + +314 +00:17:34,154 --> 00:17:38,992 +您的服务器也会用 App Store 的 +verifyReceipt 端点验证收据 + +315 +00:17:39,026 --> 00:17:41,528 +我们来看看这个过程 + +316 +00:17:41,562 --> 00:17:44,031 +首先 我们需要检索 App 收据 + +317 +00:17:44,064 --> 00:17:48,335 +请您确保使用的是 +appStoreReceiptURL 属性 + +318 +00:17:48,368 --> 00:17:52,706 +以开发者文档中的示例为准 + +319 +00:17:52,739 --> 00:17:55,976 +有了 App 收据 +来看看设备从设备发送到 + +320 +00:17:56,009 --> 00:18:00,047 +您的服务器和 App Store 的过程 + +321 +00:18:00,080 --> 00:18:02,683 +左侧是您在设备上的 App + +322 +00:18:02,716 --> 00:18:05,686 +它会首先检索 App 收据 + +323 +00:18:05,719 --> 00:18:08,088 +并将其发送到您的服务器 + +324 +00:18:08,121 --> 00:18:12,159 +然后使用 App Store verifyReceipt +端点对其进行验证 + +325 +00:18:12,192 --> 00:18:16,129 +验证结果将确定顾客产品状态 + +326 +00:18:16,163 --> 00:18:19,867 +状态信息会被发送到您的 App + +327 +00:18:19,900 --> 00:18:22,002 +为了确定顾客产品状态 + +328 +00:18:22,035 --> 00:18:23,904 +我们使用了 WWDC20 大会的 + +329 +00:18:23,937 --> 00:18:26,673 +授权引擎 + +330 +00:18:26,707 --> 00:18:31,011 +该引擎现已更新 +可支持非消耗型和非自动续期订阅 + +331 +00:18:31,044 --> 00:18:35,182 +在没有 App 内购买记录时 +也能处理新顾客状态 + +332 +00:18:36,517 --> 00:18:39,119 +如果您想要了解授权引擎的更多信息 + +333 +00:18:39,152 --> 00:18:42,990 +建议您查看 WWDC20 的 +“订阅服务架构”视频 + +334 +00:18:43,023 --> 00:18:45,092 +并下载示例项目 + +335 +00:18:45,125 --> 00:18:50,364 +您可以通过本视频的资源 +找到该视频链接以及更多内容 + +336 +00:18:50,864 --> 00:18:52,533 +这样就完成了第二步 + +337 +00:18:52,566 --> 00:18:55,769 +在这一步 App 将从您的服务器 +接收顾客产品状态 + +338 +00:18:56,336 --> 00:19:00,507 +现在 您的 App 将在启动时使用 +StoreKit 2 和旧版 StoreKit 框架 + +339 +00:19:00,541 --> 00:19:05,345 +立即个性化 App 体验 + +340 +00:19:05,379 --> 00:19:08,148 +最后 我还想分享一些最佳实践方法 + +341 +00:19:08,182 --> 00:19:12,653 +首先 请在您的 App 中 +保留“恢复购买”按钮 + +342 +00:19:12,686 --> 00:19:13,854 +虽然很少用到 + +343 +00:19:13,887 --> 00:19:16,723 +但在出现问题 或者顾客 +使用了其他 Apple ID 时 + +344 +00:19:16,757 --> 00:19:20,694 +该按钮能够让顾客 + +345 +00:19:20,727 --> 00:19:24,831 +强制 App 恢复其 Apple ID 的交易 + +346 +00:19:24,865 --> 00:19:29,770 +当您的 App 首次在设备上 +主动恢复顾客的 App 内购买时 + +347 +00:19:29,803 --> 00:19:33,574 +建议您优化 App 并安全存储数据 + +348 +00:19:33,607 --> 00:19:36,643 +这有助于确定顾客产品状态 + +349 +00:19:36,677 --> 00:19:40,647 +CloudKit 具有相当的灵活性 安全性 +以及跨设备同步的能力 + +350 +00:19:40,681 --> 00:19:45,052 +是个值得应用的功能 + +351 +00:19:45,085 --> 00:19:48,388 +使用 StoreKit 时 +进行实现测试非常重要 + +352 +00:19:48,422 --> 00:19:52,259 +有了 StoreKit 2 您可以使用 Sandbox +TestFlight 和 Xcode StoreKit + +353 +00:19:52,292 --> 00:19:57,364 +测试主动恢复的效果 + +354 +00:19:57,397 --> 00:19:59,766 +如果您使用的是旧版 StoreKit + +355 +00:19:59,800 --> 00:20:03,070 +请务必记住 在 Sandbox 和 +TestFlight 中进行测试时 + +356 +00:20:03,103 --> 00:20:06,206 +可能无法检索到 App 收据 + +357 +00:20:06,240 --> 00:20:10,077 +而在 App Store 安装 App 后 +必然产生 App 收据 + +358 +00:20:10,110 --> 00:20:11,945 +如果没有 App 收据 + +359 +00:20:11,979 --> 00:20:16,083 +建议您的 App 使用 +默认的新顾客体验 + +360 +00:20:16,116 --> 00:20:20,220 +以及 请确保您备有 +随时可用的“恢复购买”按钮 + +361 +00:20:20,254 --> 00:20:23,857 +总之 请您更新 App +主动检查交易记录 + +362 +00:20:23,891 --> 00:20:28,529 +此过程中 顾客无需点击 +或验证等任何操作 + +363 +00:20:28,562 --> 00:20:33,300 +请您允许 App +在启动时定制顾客体验 + +364 +00:20:33,333 --> 00:20:38,839 +以分别适应新顾客 活跃顾客 +和非活跃顾客的产品状态 + +365 +00:20:38,872 --> 00:20:42,009 +请在服务器间维护好 +针对所有 App 内购买项目类型的 + +366 +00:20:42,042 --> 00:20:45,145 +顾客交易状态 + +367 +00:20:45,179 --> 00:20:49,583 +实现 App Store 服务器通知 +版本 2 就能实现该功能 + +368 +00:20:49,616 --> 00:20:52,886 +由此 您的后端能够近乎实时地了解 + +369 +00:20:52,920 --> 00:20:55,556 +交易发生的任何变化 + +370 +00:20:55,589 --> 00:20:58,625 +比如退款或撤销交易 + +371 +00:20:58,659 --> 00:21:02,963 +或订阅续订 计费重试和服务到期 + +372 +00:21:03,597 --> 00:21:05,933 +感谢您的收看 请务必查看 + +373 +00:21:05,966 --> 00:21:09,069 +另一个视频 主题为 +“App 内购买的新功能” + +374 +00:21:09,102 --> 00:21:11,772 +在该视频中 Dani 和 Ian 将 +向您介绍有关 App 内购买的所有重大更新 + +375 +00:21:11,805 --> 00:21:15,776 +包括 StoreKit、Server API +和 Server Notifications Version 2 + +376 +00:21:16,243 --> 00:21:18,111 +感谢收看 祝您一切顺利 + +377 +00:21:18,145 --> 00:21:21,148 +[欢快的音乐] + diff --git a/zho/2022 Session 110429 Discover advancements in iOS camera capture - Depth, focus, and multitasking.srt b/zho/2022 Session 110429 Discover advancements in iOS camera capture - Depth, focus, and multitasking.srt new file mode 100644 index 0000000..1102563 --- /dev/null +++ b/zho/2022 Session 110429 Discover advancements in iOS camera capture - Depth, focus, and multitasking.srt @@ -0,0 +1,1532 @@ +1 +00:00:00,334 --> 00:00:06,340 +[欢快的音乐] + +2 +00:00:09,810 --> 00:00:11,478 +Nikolas Gelo:您好 +欢迎来到 + +3 +00:00:11,512 --> 00:00:14,147 +“发现 iOS 相机捕获功能的进展” + +4 +00:00:14,181 --> 00:00:16,383 +我是相机软件团队的 Nikolas Gelo + +5 +00:00:16,416 --> 00:00:20,754 +我将展示 iOS 和 iPadOS +新相机中一些令人兴奋的功能 + +6 +00:00:20,787 --> 00:00:25,025 +首先 我将讲解如何利用使用 AVFoundation 的 +LiDAR 扫描仪将深度信息以流媒体传输 + +7 +00:00:25,058 --> 00:00:28,495 +然后展示如何在您的 App 上 +通过面部自动对焦和自动曝光 + +8 +00:00:28,529 --> 00:00:31,565 +获得更好的面部渲染效果 + +9 +00:00:31,598 --> 00:00:36,303 +再带您了解 +高级 AVCaptureSession 流配置 + +10 +00:00:36,336 --> 00:00:38,772 +最后向您展示您的 App 将如何 + +11 +00:00:38,805 --> 00:00:41,675 +能够在处理多任务时使用相机 + +12 +00:00:41,708 --> 00:00:45,646 +我将讲解如何利用使用 AVFoundation 的 +LiDAR 扫描仪达成流式传输深度 + +13 +00:00:45,679 --> 00:00:50,150 +iPhone 12 Pro、iPhone 13 Pro +和 iPad Pro 均配备 + +14 +00:00:50,184 --> 00:00:53,887 +能够输出密集深度图的 +LiDAR 扫描仪 + +15 +00:00:53,921 --> 00:00:57,157 +LiDAR 扫描仪向周围环境 +发射光 + +16 +00:00:57,191 --> 00:01:00,594 +然后收集场景中表面反射的光 + +17 +00:01:00,627 --> 00:01:03,397 +通过测量光线从 LiDAR 发射至 +环境 + +18 +00:01:03,430 --> 00:01:07,401 +再反射回扫描仪的时间来估计深度 + +19 +00:01:07,434 --> 00:01:11,138 +这一过程每秒可运行数百万次 + +20 +00:01:11,171 --> 00:01:14,308 +我将向您展示在操作中 +使用 AVFoundation 的 LiDAR 扫描仪 + +21 +00:01:14,341 --> 00:01:17,945 +我在这台 +iPhone 13 Pro Max 上运行了一个 + +22 +00:01:17,978 --> 00:01:20,914 +使用了新 LiDAR 深度相机 +AVCaptureDevice 的 App + +23 +00:01:20,948 --> 00:01:24,551 +该 App 在直播摄像头视频流上 +呈现出流式深度数据 + +24 +00:01:24,585 --> 00:01:29,189 +蓝色表示近处的对象 +红色表示较远的对象 + +25 +00:01:29,223 --> 00:01:33,360 +拖动滑动条 +我可以调整深度的不透明度 + +26 +00:01:33,393 --> 00:01:36,430 +这个 App 还可以拍摄 +带有高分辨率深度图的照片 + +27 +00:01:36,463 --> 00:01:39,566 +当我拍照时 会应用相同的深度叠加 + +28 +00:01:39,600 --> 00:01:42,903 +但对于静止物体 分辨率甚至会更高 + +29 +00:01:42,936 --> 00:01:45,305 +这个 App 还有一个很好用的功能 + +30 +00:01:45,339 --> 00:01:49,076 +当我按下手电筒按钮时 App 会使用 +带有彩色图像的高分辨率深度图 + +31 +00:01:49,109 --> 00:01:52,880 +用 RealityKit +在场景上渲染出一个聚光灯 + +32 +00:01:52,913 --> 00:01:57,150 +我可以四处点击 +将聚光灯指向场景中的不同对象 + +33 +00:01:57,184 --> 00:01:59,720 +看这里用聚光灯效果突出了吉他 + +34 +00:01:59,753 --> 00:02:02,222 +或者如果我在墙角点击了正确的位置 + +35 +00:02:02,256 --> 00:02:04,691 +聚光灯会打出心形 + +36 +00:02:04,725 --> 00:02:08,028 +让我们把聚光灯重新 +移回到那把吉他上 看起来很酷 + +37 +00:02:09,363 --> 00:02:14,668 +LiDAR 扫描仪的 API +在 iPadOS 13.4 的 ARKit 中首次引入 + +38 +00:02:14,701 --> 00:02:19,039 +如果您还没有看过 +WWDC 2020 的演讲“探索 ARKit 4” + +39 +00:02:19,072 --> 00:02:21,508 +我建议您去观看 + +40 +00:02:21,542 --> 00:02:26,547 +iOS 15.4 有一项新增功能 +即您的 App 使用 AVFoundation 即可访问 LiDAR 扫描仪 + +41 +00:02:26,580 --> 00:02:28,982 +我们引入了一种新的 +AVCapture 设备类型 + +42 +00:02:29,016 --> 00:02:33,153 +内置 LiDAR 深度相机 +可传送视频和深度 + +43 +00:02:33,187 --> 00:02:36,924 +产生高质量、高精度的深度信息 + +44 +00:02:36,957 --> 00:02:40,194 +这个新 AVCaptureDevice +使用后置广角摄像头 + +45 +00:02:40,227 --> 00:02:43,764 +再使用 LiDAR 扫描 +仪传送视频以捕获深度 + +46 +00:02:43,797 --> 00:02:47,935 +广角摄像头 +可在视野中捕获视频和深度 + +47 +00:02:47,968 --> 00:02:50,304 +就像 TrueDepth AVCaptureDevice + +48 +00:02:50,337 --> 00:02:53,941 +它的所有格式都支持深度数据传送 + +49 +00:02:53,974 --> 00:02:57,110 +这个新 AVCaptureDevice 通过融合 + +50 +00:02:57,144 --> 00:02:59,546 +带有后置广角摄像头的彩色图像 +LiDAR 扫描仪的稀疏输出 + +51 +00:02:59,580 --> 00:03:02,449 +能产生高质量的深度数据 + +52 +00:03:02,482 --> 00:03:06,086 +LiDAR 和颜色输入可通过 +能够输出密集深度图的 + +53 +00:03:06,119 --> 00:03:08,455 +机器学习模型来处理 + +54 +00:03:08,488 --> 00:03:11,692 +由于 LiDAR 深度相机 +采用的是后置广角摄像头 + +55 +00:03:11,725 --> 00:03:14,761 +长焦和超广角相机也均可使用 + +56 +00:03:14,795 --> 00:03:17,030 +使用 AVCaptureMultiCamSession + +57 +00:03:17,064 --> 00:03:20,934 +这项功能对希望同时使用 +多个摄像头的 App 很有帮助 + +58 +00:03:20,968 --> 00:03:24,304 +LiDAR 深度相机 +可提供多种格式 + +59 +00:03:24,338 --> 00:03:27,107 +从 640 x 480 的视频分辨率 + +60 +00:03:27,140 --> 00:03:32,179 +到 4032 x 3024 的 +完整 12 兆像素图像 + +61 +00:03:32,212 --> 00:03:36,917 +流传输时 它可以输出高达 +320 x 240 的深度图 + +62 +00:03:36,950 --> 00:03:42,990 +拍摄照片可以捕获 +768 x 576 的深度图 + +63 +00:03:43,023 --> 00:03:47,961 +注意 16 x 9 和 4 x 3 格式 +的深度分辨率略有不同 + +64 +00:03:47,995 --> 00:03:50,998 +这是为了匹配视频的纵横比 + +65 +00:03:51,031 --> 00:03:53,867 +在 iPhone 12 Pro +iPhone 13 Pro 和 iPad Pro 第 5 代上 + +66 +00:03:53,901 --> 00:03:58,672 +可以使用 LiDAR 深度相机 +AVCaptureDevice + +67 +00:03:58,705 --> 00:04:03,477 +iPhone 13 Pro 可以 +使用后置摄像头的组合传送深度数据 + +68 +00:04:03,510 --> 00:04:07,147 +AVFoundation Capture API +将这些称为“虚拟设备” + +69 +00:04:07,181 --> 00:04:09,449 +它们由物理设备组成 + +70 +00:04:09,483 --> 00:04:11,451 +在 iPhone 13 Pro 的背面 + +71 +00:04:11,485 --> 00:04:15,255 +有四个虚拟 AVCaptureDevices +可供使用: + +72 +00:04:15,289 --> 00:04:18,192 +新 LiDAR 深度相机 +使用广角摄像头的 + +73 +00:04:18,225 --> 00:04:20,427 +LiDAR 扫描仪 + +74 +00:04:20,460 --> 00:04:24,231 +双摄像头使用了广角和长焦摄像头 + +75 +00:04:24,264 --> 00:04:25,766 +双广角摄像头 + +76 +00:04:25,799 --> 00:04:28,669 +使用了广角和超广角摄像头 + +77 +00:04:28,702 --> 00:04:30,003 +以及三摄像头 + +78 +00:04:30,037 --> 00:04:33,707 +使用了广角、超广角和长焦摄像头 + +79 +00:04:33,740 --> 00:04:37,611 +这些设备生成的深度类型存在差异 + +80 +00:04:37,644 --> 00:04:41,081 +LiDAR 深度相机能生成 +“绝对深度” + +81 +00:04:41,114 --> 00:04:45,586 +飞行时间技术 +能够计算真实世界的规模 + +82 +00:04:45,619 --> 00:04:49,690 +比方说 它很适用于 +测量等计算机视觉任务 + +83 +00:04:49,723 --> 00:04:52,125 +TrueDepth 摄像头 +双摄像头、双宽摄像头 + +84 +00:04:52,159 --> 00:04:56,296 +和三摄像头能生成 +相对的、基于视差的深度 + +85 +00:04:56,330 --> 00:05:00,734 +这会消耗更少的电量 +非常适合需要呈现照片效果的 App + +86 +00:05:00,767 --> 00:05:04,571 +AVFoundation 使用 +AVDepthData 类来表示深度 + +87 +00:05:04,605 --> 00:05:07,174 +此类的像素缓冲区包含深度 + +88 +00:05:07,207 --> 00:05:08,976 +还有可以描述它的其他属性 + +89 +00:05:09,009 --> 00:05:13,213 +其中包括深度数据类型 +准确率、是否过滤 + +90 +00:05:13,247 --> 00:05:16,149 +它像新 LiDAR 深度相机一样 + +91 +00:05:16,183 --> 00:05:18,118 +由具有深度功能的 +AVCaptureDevice 提供 + +92 +00:05:18,151 --> 00:05:20,888 +您可以从 AVCaptureDepthDataOutput +达成流式传输深度 + +93 +00:05:20,921 --> 00:05:25,425 +或从 AVCapturePhotoOutput +接收附加到照片的深度 + +94 +00:05:25,459 --> 00:05:27,728 +默认情况下会过滤深度数据 + +95 +00:05:27,761 --> 00:05:29,329 +过滤能降低噪音 + +96 +00:05:29,363 --> 00:05:32,566 +并填充深度图中的缺失值或孔 + +97 +00:05:32,599 --> 00:05:34,768 +非常适合用于视频和摄影 App + +98 +00:05:34,801 --> 00:05:37,070 +所以 使用深度图在彩色图像上 + +99 +00:05:37,104 --> 00:05:39,506 +应用效果时 不会出现伪影 + +100 +00:05:39,540 --> 00:05:43,110 +但是 计算机视觉 App +应该更容易处理未经过滤的深度数据 + +101 +00:05:43,143 --> 00:05:45,979 +保留深度图中的原始值 + +102 +00:05:46,013 --> 00:05:48,482 +禁用过滤时 LiDAR 深度相机 + +103 +00:05:48,515 --> 00:05:51,118 +会排除低置信点 + +104 +00:05:51,151 --> 00:05:53,187 +要禁用深度数据过滤 + +105 +00:05:53,220 --> 00:05:57,991 +可将 AVCaptureDepthDataOutput 上的 +isFilteringEnabled 属性设置为 false + +106 +00:05:58,025 --> 00:06:01,495 +当您从委托回调中收到 +AVDepthData 对象时 + +107 +00:06:01,528 --> 00:06:03,463 +它就不会被过滤 + +108 +00:06:03,497 --> 00:06:06,433 +由于 ARKit 已经提供了 +对 LiDAR 扫描仪的访问权限 + +109 +00:06:06,466 --> 00:06:09,503 +您可能会问 +“AVFoundation 相比如何?” + +110 +00:06:10,804 --> 00:06:14,141 +AVFoundation +专为视频和摄影 App 而设计 + +111 +00:06:14,174 --> 00:06:16,577 +您可以使用 AVFoundation +把 LiDAR 扫描仪捕获的 + +112 +00:06:16,610 --> 00:06:20,047 +深度数据嵌入高分辨率照片 + +113 +00:06:20,080 --> 00:06:23,183 +ARKit 顾名思义 最适合 + +114 +00:06:23,217 --> 00:06:24,852 +增强现实 App + +115 +00:06:24,885 --> 00:06:28,322 +有了 LiDAR 扫描仪 就可以 + +116 +00:06:28,355 --> 00:06:31,058 +使用 ARKit +场景几何和物体放置等功能 + +117 +00:06:31,091 --> 00:06:33,994 +AVFoundation 可提供 +高分辨率视频 + +118 +00:06:34,027 --> 00:06:36,763 +非常适合录制电影和拍照 + +119 +00:06:36,797 --> 00:06:42,236 +AVFoundation 的 LiDAR 深度相机 +可以输出高达 768 x 576 的深度 + +120 +00:06:42,269 --> 00:06:47,774 +高于 ARKit 深度分辨率 +256 x 192 的两倍 + +121 +00:06:47,808 --> 00:06:50,511 +ARKit 使用分辨率较低的 +深度图 + +122 +00:06:50,544 --> 00:06:54,982 +因此它可以针对其功能 +应用增强现实算法 + +123 +00:06:55,015 --> 00:06:59,686 +想要了解更多有关如何使用 +AVFoundation 捕获深度数据的“深入”信息 + +124 +00:06:59,720 --> 00:07:03,323 +观看我们 WWDC 2017 的课程 + +125 +00:07:03,357 --> 00:07:05,859 +“捕获 iPhone 摄影的深度” + +126 +00:07:05,893 --> 00:07:07,661 +我们很高兴看到 +您能在您的 App 中 + +127 +00:07:07,694 --> 00:07:10,430 +对 LiDAR 深度摄像头的趣用 + +128 +00:07:10,464 --> 00:07:15,068 +接下来 我将讨论 +自动对焦和自动曝光系统 + +129 +00:07:15,102 --> 00:07:18,372 +如何帮助提高 +App 场景中人脸的可见度 + +130 +00:07:18,405 --> 00:07:21,608 +自动对焦和自动曝光系统会分析场景 + +131 +00:07:21,642 --> 00:07:23,110 +捕获最佳图像 + +132 +00:07:23,143 --> 00:07:27,247 +自动对焦系统 +会调整镜头 保证焦点在主体上 + +133 +00:07:27,281 --> 00:07:29,883 +自动曝光系统则会平衡场景最亮的 + +134 +00:07:29,917 --> 00:07:33,654 +和最暗是区域 保证主体可见 + +135 +00:07:33,687 --> 00:07:36,156 +但是 有时拍照做出的自动调整 + +136 +00:07:36,190 --> 00:07:38,926 +不需要对焦在拍摄对象的脸部 + +137 +00:07:38,959 --> 00:07:41,595 +还有的时候 在明亮的背光下 + +138 +00:07:41,628 --> 00:07:44,831 +很难看见拍摄对象的脸 + +139 +00:07:44,865 --> 00:07:49,036 +数码单反相机和其他专业相机 +有一个共同特点:跟踪场景中的人脸 + +140 +00:07:49,069 --> 00:07:52,940 +动态调整焦点和曝光 确保人脸可见 + +141 +00:07:52,973 --> 00:07:58,612 +iOS 15.4 有一项新增功能 +焦点和曝光系统将为面部优先 + +142 +00:07:58,645 --> 00:08:01,849 +我们非常喜欢它的效果 +以至于我们在 iOS 15.4 + +143 +00:08:01,882 --> 00:08:04,852 +或更高版本上的 +所有 App 中启用了这项功能 + +144 +00:08:04,885 --> 00:08:07,354 +我会给您看一些例子 + +145 +00:08:07,387 --> 00:08:10,557 +没有面部自动对焦 相机的焦点 + +146 +00:08:10,591 --> 00:08:13,227 +一直在背景上而不会重新在脸上对焦 + +147 +00:08:13,260 --> 00:08:14,428 +再看一遍 + +148 +00:08:14,461 --> 00:08:16,964 +看看他转身时他的脸是如何失焦的 + +149 +00:08:16,997 --> 00:08:19,499 +并且背景中的树木保持锋利 + +150 +00:08:19,533 --> 00:08:23,637 +启用面部自动对焦后 +您可以清楚地看到他的脸 + +151 +00:08:23,670 --> 00:08:27,708 +当他把脸转开 +相机将焦点会转移到背景上 + +152 +00:08:28,742 --> 00:08:32,246 +把视频放在一起比较 差异会很明显 + +153 +00:08:32,279 --> 00:08:34,648 +右侧启用了面部自动对焦 + +154 +00:08:34,681 --> 00:08:37,618 +您可以在他的胡须中 +看到更清楚的细节 + +155 +00:08:37,651 --> 00:08:42,456 +在明亮的逆光场景中 +保持脸部曝光良好是一项挑战 + +156 +00:08:42,489 --> 00:08:45,359 +但是在自动曝光系统 +优先处理面部的情况下 + +157 +00:08:45,392 --> 00:08:47,561 +我们能很容易看到他 + +158 +00:08:48,896 --> 00:08:52,299 +放在一起比较 +可以再次看到这里的区别 + +159 +00:08:52,332 --> 00:08:55,969 +请注意 右侧图片中 +他的脸部曝光良好 + +160 +00:08:56,003 --> 00:08:57,938 +背景中的树木会显得更亮 + +161 +00:08:57,971 --> 00:08:59,339 +天空也是 + +162 +00:08:59,373 --> 00:09:03,310 +人脸优先时 +系统会调整整个场景的曝光 + +163 +00:09:04,545 --> 00:09:08,415 +在 iOS 15.4 中 +启用面部自动对焦和自动曝光时 + +164 +00:09:08,448 --> 00:09:11,718 +AVCaptureDevice +上有可控的新属性 + +165 +00:09:11,752 --> 00:09:14,955 +您可以控制设备 +是否会“自动调整”这些设置 + +166 +00:09:14,988 --> 00:09:17,224 +并决定何时启用 + +167 +00:09:17,257 --> 00:09:19,359 +在切换“isEnabled” +属性之前 + +168 +00:09:19,393 --> 00:09:23,030 +您必须首先禁用自动调整 + +169 +00:09:23,063 --> 00:09:26,600 +摄影 App +自动启用此行为效果会很好 + +170 +00:09:26,633 --> 00:09:28,302 +它应用于 Apple 的 +相机 App + +171 +00:09:28,335 --> 00:09:30,304 +也非常适合用于视频会议 App + +172 +00:09:30,337 --> 00:09:32,506 +可在通话期间保持面部可见 + +173 +00:09:32,539 --> 00:09:34,541 +FaceTime 就利用了这一点 + +174 +00:09:34,575 --> 00:09:36,944 +但有时 人脸驱动的 +自动对焦和自动曝光系统 + +175 +00:09:36,977 --> 00:09:40,480 +并不是 App 的最佳选择 + +176 +00:09:40,514 --> 00:09:43,183 +例如 如果您希望 +您的 App 为用户提供 + +177 +00:09:43,217 --> 00:09:46,887 +手动控制捕获的图像 +您可以考虑将其关闭 + +178 +00:09:48,355 --> 00:09:50,891 +如果您认为在您的 App 中 + +179 +00:09:50,924 --> 00:09:53,493 +面部自动对焦或自动曝光有误 +您可以选择关闭此行为 + +180 +00:09:53,527 --> 00:09:56,964 +首先锁定 AVCaptureDevice +进行配置 + +181 +00:09:56,997 --> 00:09:59,199 +然后 关闭面部自动对焦或自动曝光 + +182 +00:09:59,233 --> 00:10:02,002 +中的自动调整 + +183 +00:10:02,035 --> 00:10:05,772 +接着 禁用面部自动对焦或自动曝光 + +184 +00:10:05,806 --> 00:10:09,510 +最后 解锁设备进行配置 + +185 +00:10:10,511 --> 00:10:13,547 +我将接着谈谈如何使用高级流配置 + +186 +00:10:13,580 --> 00:10:18,085 +接收为您 App 的需求 +量身定制的音频和视频数据 + +187 +00:10:18,118 --> 00:10:20,521 +AVFoundation Capture API 允许 + +188 +00:10:20,554 --> 00:10:23,023 +开发人员使用相机构建沉浸式 App + +189 +00:10:23,056 --> 00:10:27,694 +AVCaptureSession 管理的是 +摄像头和麦克风等输入设备的数据流 + +190 +00:10:27,728 --> 00:10:31,031 +连接在可传送视频、音频、照片等 + +191 +00:10:31,064 --> 00:10:33,800 +的 AVCaptureOutputs 上 + +192 +00:10:33,834 --> 00:10:36,537 +让我们以一个常见的 +相机 App 用例为例: + +193 +00:10:36,570 --> 00:10:40,407 +将自定义效果(如过滤器或叠加) +应用于已录制的视频 + +194 +00:10:40,440 --> 00:10:42,409 +像这样的 App 将具有以下功能 + +195 +00:10:42,442 --> 00:10:46,847 +一个带有两个输入的 AVCaptureSession +需要连接两个输出的 + +196 +00:10:46,880 --> 00:10:51,752 +一个摄像头和一个麦克风 +分别用于视频数据和音频数据 + +197 +00:10:51,785 --> 00:10:54,121 +然后在视频数据上应用效果 + +198 +00:10:54,154 --> 00:10:56,423 +并将处理后的视频发送到两处 + +199 +00:10:56,456 --> 00:10:57,824 +一处为视频预览 + +200 +00:10:57,858 --> 00:11:00,127 +另一处为用于记录的 AVAssetWriter + +201 +00:11:00,160 --> 00:11:01,562 +音频数据也会发送 + +202 +00:11:01,595 --> 00:11:03,697 +到 AVAssetWriter + +203 +00:11:03,730 --> 00:11:07,601 +iOS 16 和 iPadOS 16 有一项新增功能 +App 可以同时使用 + +204 +00:11:07,634 --> 00:11:10,871 +多个 AVCaptureVideoDataOutputs + +205 +00:11:10,904 --> 00:11:14,775 +您可以自定义 +每个视频数据输出的分辨率 + +206 +00:11:14,808 --> 00:11:19,213 +稳定性、方向和像素格式 + +207 +00:11:19,246 --> 00:11:21,315 +让我们回到示例相机 App + +208 +00:11:21,348 --> 00:11:25,385 +这个 App 正在 +平衡冲突捕获要求 + +209 +00:11:25,419 --> 00:11:28,956 +它想要显示捕获内容的实时视频预览 + +210 +00:11:28,989 --> 00:11:31,959 +并录制高质量视频 供以后播放 + +211 +00:11:31,992 --> 00:11:36,063 +预览的分辨率需要刚好适合设备屏幕 + +212 +00:11:36,096 --> 00:11:39,466 +并且处理速度需要足够快 +才能实现低延迟预览 + +213 +00:11:39,499 --> 00:11:42,603 +但是在录制时 最好以高分辨率捕获 + +214 +00:11:42,636 --> 00:11:44,872 +同时应用质量效果 + +215 +00:11:44,905 --> 00:11:46,473 +在能添加第二个 + +216 +00:11:46,507 --> 00:11:48,075 +AVCaptureVideoDataOutput 的情况下 + +217 +00:11:48,108 --> 00:11:50,711 +可以扩展捕获图 + +218 +00:11:50,744 --> 00:11:52,679 +现在 可以优化 + +219 +00:11:52,713 --> 00:11:53,981 +视频数据输出了 + +220 +00:11:54,014 --> 00:11:55,849 +一个输出可以为预览提供 + +221 +00:11:55,883 --> 00:11:57,184 +较小的缓冲区 + +222 +00:11:57,217 --> 00:11:58,619 +另一个可以为录制提供 + +223 +00:11:58,652 --> 00:12:01,522 +全尺寸 4K 缓冲区 + +224 +00:12:01,555 --> 00:12:04,024 +此外 该 App 可以在 + +225 +00:12:04,057 --> 00:12:05,325 +较小的预览缓冲区上 + +226 +00:12:05,359 --> 00:12:07,160 +呈现更简单的、性能更好的效果 + +227 +00:12:07,194 --> 00:12:08,929 +并在录制时留下 + +228 +00:12:08,962 --> 00:12:11,565 +全尺寸缓冲区的优质效果 + +229 +00:12:11,598 --> 00:12:13,267 +现在该 App 不用再 + +230 +00:12:13,300 --> 00:12:14,501 +削弱其预览 + +231 +00:12:14,535 --> 00:12:16,503 +或录制的视频了 + +232 +00:12:17,671 --> 00:12:20,674 +使用单独的视频数据输出 + +233 +00:12:20,707 --> 00:12:24,311 +进行预览和录制的另一个原因 +是为了应用不同的稳定模式 + +234 +00:12:24,344 --> 00:12:26,947 +视频稳定会对视频捕获管道 + +235 +00:12:26,980 --> 00:12:28,582 +造成额外的延迟 + +236 +00:12:28,615 --> 00:12:31,018 +预览不需要延迟 + +237 +00:12:31,051 --> 00:12:34,188 +因为延迟太明显会造成内容很难捕获 + +238 +00:12:34,221 --> 00:12:36,557 +录制上可以应用稳定功能 + +239 +00:12:36,590 --> 00:12:38,959 +以便稍后观看视频时获得更好的体验 + +240 +00:12:38,992 --> 00:12:42,996 +因此您可以 +在低延迟预览视频数据输出上 + +241 +00:12:43,030 --> 00:12:45,098 +不应用任何稳定功能 + +242 +00:12:45,132 --> 00:12:48,702 +并将稳定功能 +应用到另一个上 供以后播放 + +243 +00:12:48,735 --> 00:12:52,739 +配置视频数据输出 +分辨率的方法有很多 + +244 +00:12:52,773 --> 00:12:56,677 +配置全尺寸输出 首先要 + +245 +00:12:56,710 --> 00:12:58,412 +禁用输出缓冲区尺寸的自动配置 + +246 +00:12:58,445 --> 00:13:02,282 +然后禁用预览大小中 +输出缓冲区的传递 + +247 +00:13:02,316 --> 00:13:04,918 +然而 在大多情况下 视频数据输出 + +248 +00:13:04,952 --> 00:13:08,455 +已配置为全尺寸输出 + +249 +00:13:08,488 --> 00:13:12,893 +配置预览大小的输出 +需要再次禁用自动配置 + +250 +00:13:12,926 --> 00:13:16,830 +然后启用预览大小中 +输出缓冲区的传递 + +251 +00:13:16,864 --> 00:13:21,535 +这在使用照片 +AVCaptureSessionPreset 时默认启用 + +252 +00:13:21,568 --> 00:13:25,272 +要请求自定义分辨率 +请指定宽度和高度 + +253 +00:13:25,305 --> 00:13:27,841 +在输出的视频设置字典中 + +254 +00:13:27,875 --> 00:13:31,245 +宽高的纵横比必须与源设备的 + +255 +00:13:31,278 --> 00:13:32,846 +activeFormat 纵横比匹配 + +256 +00:13:32,880 --> 00:13:35,616 +配置您的视频数据输出的方法有很多 + +257 +00:13:35,649 --> 00:13:39,186 +若要应用稳定 请像电影扩展一样 + +258 +00:13:39,219 --> 00:13:40,754 +将首选的稳定设置为模式 + +259 +00:13:40,787 --> 00:13:43,490 +会生成非常适合观看的视频 + +260 +00:13:43,524 --> 00:13:47,561 +您可以更改方向以接收纵向的缓冲区 + +261 +00:13:47,594 --> 00:13:52,399 +并且您可以指定像素格式 以接收 +10 位无损 YUV 缓冲区 + +262 +00:13:53,567 --> 00:13:55,536 +更多 AVCaptureVideoDataOutput + +263 +00:13:55,569 --> 00:14:00,274 +选择像素格式的信息 +请参阅“技术说明 3121” + +264 +00:14:01,375 --> 00:14:04,077 +从 iOS 16 和 iPadOS 16 开始 + +265 +00:14:04,111 --> 00:14:06,880 +除了可以使用多个视频数据输出 + +266 +00:14:06,914 --> 00:14:09,516 +App 可以在 +从 AVCaptureVideoDataOutput + +267 +00:14:09,550 --> 00:14:12,586 +和 AVCaptureAudioDataOutput 接收数据时 + +268 +00:14:12,619 --> 00:14:14,922 +使用 AVCaptureMovieFileOutput 进行录制 + +269 +00:14:14,955 --> 00:14:17,024 +要确定可以添加到会话中的内容 + +270 +00:14:17,057 --> 00:14:19,159 +您可以检查 +是否可以将输出添加到其中 + +271 +00:14:19,193 --> 00:14:21,528 +并查询会话的 hardwareCost 属性 + +272 +00:14:21,562 --> 00:14:25,065 +以确定系统是否可以支持您的配置 + +273 +00:14:25,098 --> 00:14:28,202 +您可以在接收 +带有电影文件输出的视频数据时 + +274 +00:14:28,235 --> 00:14:33,073 +录制和分析场景时检查视频 + +275 +00:14:33,106 --> 00:14:35,776 +接收带有电影文件输出的音频数据时 + +276 +00:14:35,809 --> 00:14:37,778 +您可以在录制时对音频进行采样 + +277 +00:14:37,811 --> 00:14:40,547 +并聆听正在录制的内容 + +278 +00:14:40,581 --> 00:14:42,316 +有了这样的捕获图 + +279 +00:14:42,349 --> 00:14:45,919 +您可以将录制机制卸载到 +AVCaptureMovieFileOutput + +280 +00:14:45,953 --> 00:14:50,224 +同时仍接收未压缩的视频和音频样本 + +281 +00:14:50,958 --> 00:14:53,493 +实现这些高级流配置 + +282 +00:14:53,527 --> 00:14:55,596 +不需要使用新的 API + +283 +00:14:55,629 --> 00:14:59,800 +我们可以让您使用现有 API +启用高级流配置 + +284 +00:15:01,068 --> 00:15:03,537 +最后 我将讨论 +您的 App 将如何 + +285 +00:15:03,570 --> 00:15:06,340 +在用户处理多任务时使用相机 + +286 +00:15:06,373 --> 00:15:09,409 +在 iPad 上 用户可以 +通过多种方式执行多项任务 + +287 +00:15:09,443 --> 00:15:14,114 +例如 使用分屏浏览 +同时阅读备忘录和录制语音备忘录 + +288 +00:15:14,147 --> 00:15:16,817 +或使用侧拉在 +全屏 Safari 浏览器的上方 + +289 +00:15:16,850 --> 00:15:19,520 +使用备忘录的浮动窗口 + +290 +00:15:19,553 --> 00:15:22,456 +使用 Picture in Picture +您可以继续播放视频 + +291 +00:15:22,489 --> 00:15:26,693 +同时添加观看 +更多 WWDC 视频的提醒 + +292 +00:15:26,727 --> 00:15:29,463 +借助 iPadOS 16 的 +全新 Stage Manager + +293 +00:15:29,496 --> 00:15:33,767 +用户可在大小不一的 +浮动窗口中打开多个 App + +294 +00:15:33,800 --> 00:15:36,970 +从 iOS 16 开始 +AVCaptureSessions 将能够 + +295 +00:15:37,004 --> 00:15:38,605 +在处理多任务时使用相机 + +296 +00:15:38,639 --> 00:15:41,508 +我们之前在多任务时阻止了相机访问 + +297 +00:15:41,542 --> 00:15:43,477 +因为担心在处理多任务时 + +298 +00:15:43,510 --> 00:15:46,246 +相机系统呈现的效果会不好 + +299 +00:15:46,280 --> 00:15:50,284 +像游戏这类资源密集型 App +会与使用相机的 App 一起运行 + +300 +00:15:50,317 --> 00:15:54,321 +可能会导致丢帧和其他延迟 +从而导致摄像头输入不佳 + +301 +00:15:54,354 --> 00:15:57,991 +用户在数月或数年后 +观看质量较差的视频的时候 + +302 +00:15:58,025 --> 00:16:00,894 +可能不记得这是他们 +在处理多任务处理时录制的视频 + +303 +00:16:00,928 --> 00:16:05,065 +提供良好的相机使用体验 +是我们的首要任务 + +304 +00:16:05,098 --> 00:16:07,601 +当系统检测到相机在多任务过程中 + +305 +00:16:07,634 --> 00:16:10,204 +录制视频时 将显示一个对话框 + +306 +00:16:10,237 --> 00:16:13,674 +告知用户视频的质量可能会不高 + +307 +00:16:13,707 --> 00:16:16,577 +这个对话框在录制完成后 + +308 +00:16:16,610 --> 00:16:20,314 +由 AVCaptureMovieFileOutput +或 AVAssetWriter 显示 + +309 +00:16:20,347 --> 00:16:23,050 +这个对话框只会显示一次 + +310 +00:16:23,083 --> 00:16:26,353 +可用“确定”按钮关闭 + +311 +00:16:26,386 --> 00:16:29,723 +AVCaptureSession +添加了两个新属性 + +312 +00:16:29,756 --> 00:16:33,527 +在支持并启用 +多任务相机访问时给予指示 + +313 +00:16:33,560 --> 00:16:36,697 +启用此功能的捕获会话将不再中断 + +314 +00:16:36,730 --> 00:16:41,468 +因为“视频设备 +不适用于多个前台 App” + +315 +00:16:41,502 --> 00:16:43,937 +某些 App 可能希望需要全屏 + +316 +00:16:43,971 --> 00:16:45,305 +使用相机 + +317 +00:16:45,339 --> 00:16:47,908 +如果您希望您的 App 不与其他 +前台 App 一起竞争系统资源 + +318 +00:16:47,941 --> 00:16:50,711 +这可能会很有用 + +319 +00:16:50,744 --> 00:16:55,048 +例如 ARKit 不支持 +在处理多任务时使用相机 + +320 +00:16:56,350 --> 00:16:59,720 +您应该确保您的 App 在与 +其他 App 一起运行时表现良好 + +321 +00:16:59,753 --> 00:17:02,422 +监控 App 的通知 +使您的 App 能够适应 + +322 +00:17:02,456 --> 00:17:04,658 +系统压力不断增加 + +323 +00:17:04,691 --> 00:17:08,295 +并采取措施减少压力的影响 +例如降低帧速率 + +324 +00:17:08,328 --> 00:17:10,264 +您可以通过请求较低分辨率、分箱 + +325 +00:17:10,297 --> 00:17:15,002 +或非 HDR 格式 +减少 App 在系统上的占用空间 + +326 +00:17:15,035 --> 00:17:18,472 +想了解更多保持性能最佳实践的信息 + +327 +00:17:18,505 --> 00:17:22,042 +请阅读文章 +“在处理多任务时访问相机” + +328 +00:17:23,243 --> 00:17:27,681 +此外 视频通话和视频会议 App +可以在系统提供的 Picture in Picture 窗口 + +329 +00:17:27,714 --> 00:17:30,817 +显示远程参与者 + +330 +00:17:30,851 --> 00:17:33,921 +现在 您 App 的用户可以 +在 iPad 上进行多任务处理时 + +331 +00:17:33,954 --> 00:17:36,323 +继续流畅地视频通话 + +332 +00:17:36,356 --> 00:17:41,128 +AVKit 在 iOS 15 中引入了 API +是为 App 指定一个可以显示 + +333 +00:17:41,161 --> 00:17:43,797 +远程呼叫参与者的视图控制器 + +334 +00:17:43,830 --> 00:17:46,366 +视频通话视图控制器允许您自定义 + +335 +00:17:46,400 --> 00:17:48,735 +窗口的内容 + +336 +00:17:48,769 --> 00:17:50,571 +要了解更多采用方法 + +337 +00:17:50,604 --> 00:17:55,008 +请参阅文章 +“采用 Picture in Picture 进行视频通话” + +338 +00:17:55,042 --> 00:17:58,045 +至此即为 +iOS 相机捕获技术的所有进步 + +339 +00:17:58,078 --> 00:18:02,182 +我展示了如何利用使用 AVFoundation 的 +LiDAR 扫描仪达成流式传输深度 + +340 +00:18:02,216 --> 00:18:05,185 +您的 App 将如何 +获得更好的面部渲染效果 + +341 +00:18:05,219 --> 00:18:08,956 +为您 App 量身定制的 +高级 AVCaptureSession 流配置 + +342 +00:18:08,989 --> 00:18:12,526 +和您的 App 如何 +在处理多任务时使用相机 + +343 +00:18:12,559 --> 00:18:14,695 +我希望您的 WWDC 精彩绝伦 + +344 +00:18:14,728 --> 00:18:19,433 +[欢快的音乐] + diff --git a/zho/2022 Session 110565 Display HDR video in EDR with AVFoundation and Metal.srt b/zho/2022 Session 110565 Display HDR video in EDR with AVFoundation and Metal.srt new file mode 100644 index 0000000..05af2ef --- /dev/null +++ b/zho/2022 Session 110565 Display HDR video in EDR with AVFoundation and Metal.srt @@ -0,0 +1,1710 @@ +1 +00:00:00,501 --> 00:00:08,509 +♪ ♪ + +2 +00:00:09,643 --> 00:00:13,647 +Ken Greenebaum: 大家好 欢迎来到 WWDC 2022 + +3 +00:00:13,680 --> 00:00:15,082 +我是 Ken Greenebaum + +4 +00:00:15,115 --> 00:00:18,352 +是 Apple 的 +显示和色彩技术团队的成员 + +5 +00:00:18,385 --> 00:00:21,388 +很高兴今年能举行三次 EDR 演讲 + +6 +00:00:21,421 --> 00:00:25,559 +希望您有机会观看 +“探索 iOS 上的 EDR” + +7 +00:00:25,592 --> 00:00:29,263 +我们在里面宣布了 +对 iOS 的 EDR API 支持 + +8 +00:00:29,296 --> 00:00:33,901 +还有 “借助 Core Image、Metal +和 SwiftUI 显示 EDR 内容” + +9 +00:00:33,934 --> 00:00:37,838 +一些开发者可能 +也看过我去年的 EDR 演讲 + +10 +00:00:37,871 --> 00:00:40,240 +我们在里面演示了 +如何通过使用 EDR + +11 +00:00:40,274 --> 00:00:43,177 +来使用 AVPlayer 播放 HDR 视频 + +12 +00:00:44,178 --> 00:00:46,246 +在这次演讲中 我们将深入探讨 + +13 +00:00:46,280 --> 00:00:49,550 +如何使用 Core Media 接口来实现 + +14 +00:00:49,583 --> 00:00:51,785 +不只是 EDR 播放 + +15 +00:00:51,818 --> 00:00:54,821 +而且还有如何解码和播放 HDR 视频 + +16 +00:00:54,855 --> 00:00:57,591 +使其进入您的 EDR 层或视图中 + +17 +00:00:59,326 --> 00:01:02,396 +然后 我们将继续讨论如何通过 + +18 +00:01:02,429 --> 00:01:05,732 +Core Video 的显示链接实时访问 + +19 +00:01:05,766 --> 00:01:08,101 +解码的视频帧 + +20 +00:01:08,135 --> 00:01:11,271 +将这些帧发送到 CoreImage Filter +或 Metal Shader + +21 +00:01:11,305 --> 00:01:13,473 +以添加颜色管理 视觉效果 + +22 +00:01:13,507 --> 00:01:15,909 +或应用其他信号处理 + +23 +00:01:15,943 --> 00:01:20,247 +最后 将生成的帧 +发送到 Metal 进行渲染 + +24 +00:01:20,280 --> 00:01:24,751 +首先 我们回顾一下 +与 EDR 兼容的视频媒体框架 + +25 +00:01:24,785 --> 00:01:28,522 +帮助您决定哪种最符合您的 App 要求 + +26 +00:01:30,057 --> 00:01:32,226 +接下来 我们将简要讨论高级 AVKit + +27 +00:01:32,259 --> 00:01:35,028 +和 AVFoundation framework + +28 +00:01:35,062 --> 00:01:37,764 +如果您的 App 需要直接播放 + +29 +00:01:37,798 --> 00:01:40,701 +这样可以完成 +播放 HDR 视频的所有工作 + +30 +00:01:42,302 --> 00:01:44,872 +最后 我们将讨论 + +31 +00:01:44,905 --> 00:01:48,175 +在 EDR 播放 +编辑或图像处理引擎中 + +32 +00:01:48,208 --> 00:01:51,979 +利用 Core Video 和 Metal +使用解码视频帧的最佳实践 + +33 +00:01:54,781 --> 00:01:58,752 +首先 我们快速了解一下 +Apple 的视频框架 + +34 +00:01:58,785 --> 00:02:01,355 +从最高级别的接口开始 + +35 +00:02:01,388 --> 00:02:03,323 +这些是最容易使用的 + +36 +00:02:03,357 --> 00:02:06,827 +并继续使用提供更多机会的底部框架 + +37 +00:02:06,860 --> 00:02:10,364 +但代价是增加代码的复杂性 + +38 +00:02:10,397 --> 00:02:13,467 +最好使用最高级别的框架 + +39 +00:02:13,500 --> 00:02:17,271 +以充分利用自动提供的优化 + +40 +00:02:17,304 --> 00:02:20,440 +这为我们进入演讲的主体内容 +做了准备 + +41 +00:02:20,474 --> 00:02:23,177 +我们将探索多种场景 + +42 +00:02:23,210 --> 00:02:24,945 +从简单的 EDR 播放 + +43 +00:02:24,978 --> 00:02:27,981 +到更复杂的解码视频帧管道 + +44 +00:02:28,015 --> 00:02:31,652 +再到 CoreImage +或 Metal 的实时处理 + +45 +00:02:31,685 --> 00:02:34,154 +最高级别 是 AVKit + +46 +00:02:34,188 --> 00:02:38,292 +使用 AVKit 您可以创建 +用于媒体播放的用户界面 + +47 +00:02:38,325 --> 00:02:41,562 +完成传输控件 章节导航 + +48 +00:02:41,595 --> 00:02:43,030 +画中画功能支持 + +49 +00:02:43,063 --> 00:02:45,632 +以及字幕和隐藏式字幕的显示 + +50 +00:02:45,666 --> 00:02:49,136 +AVKit 可以将 HDR 内容 +作为 EDR 播放 + +51 +00:02:49,169 --> 00:02:52,840 +我们将使用 +AVPlayerViewController 进行演示 + +52 +00:02:52,873 --> 00:02:57,377 +但如果您的 App 需要 +进一步处理视频帧 + +53 +00:02:57,411 --> 00:02:59,179 +则必须使用媒体框架 + +54 +00:02:59,213 --> 00:03:01,815 +这样才能使您更好地控制管道 + +55 +00:03:01,849 --> 00:03:04,618 +接下来是 AVFoundation + +56 +00:03:04,651 --> 00:03:07,688 +AVFoundation 是一个 +功能全面的框架 + +57 +00:03:07,721 --> 00:03:12,860 +用于在 Apple 平台上 +处理基于时间的视听媒体 + +58 +00:03:12,893 --> 00:03:16,096 +使用 AVFoundation +您可以轻松播放 创建 + +59 +00:03:16,129 --> 00:03:19,032 +和编辑 QuickTime 影片 +和 MPEG 4 文件 + +60 +00:03:19,066 --> 00:03:20,634 +播放 HLS 流 + +61 +00:03:20,667 --> 00:03:24,271 +并在您的 App 中 +构建强大的媒体功能 + +62 +00:03:24,304 --> 00:03:26,306 +在本次演讲中 +我们将探讨 AVPlayer + +63 +00:03:26,340 --> 00:03:30,577 +和相关的 AVPlayerLayer 接口的使用 + +64 +00:03:30,611 --> 00:03:35,182 +Core Video 是一个为 +数字视频提供管道模型的框架 + +65 +00:03:35,215 --> 00:03:37,417 +它通过将流程划分为多个独立的步骤 + +66 +00:03:37,451 --> 00:03:40,220 +简化处理视频的方式 + +67 +00:03:40,254 --> 00:03:43,790 +Core Video 还使您可以 +更轻松地访问和操作 + +68 +00:03:43,824 --> 00:03:46,527 +单个帧 而不必担心 + +69 +00:03:46,560 --> 00:03:48,262 +数据类型之间的转换 + +70 +00:03:48,295 --> 00:03:51,465 +或显示同步 + +71 +00:03:51,498 --> 00:03:53,534 +我们将用 Core Image 来演示 + +72 +00:03:53,567 --> 00:03:56,036 +DisplayLink 和使用 Core Image 的 +CVPixelBuffer + +73 +00:03:56,069 --> 00:03:59,239 +以及使用 Metal 的 +CVMetalTextureCache + +74 +00:03:59,273 --> 00:04:01,341 +接下来是 Video Toolbox + +75 +00:04:01,375 --> 00:04:04,011 +这是一个底层框架 +可以直接访问 + +76 +00:04:04,044 --> 00:04:06,446 +硬件编码器和解码器 + +77 +00:04:06,480 --> 00:04:10,784 +Video Toolbox 提供 +视频压缩和解压缩服务 + +78 +00:04:10,817 --> 00:04:13,253 +以及存储在 Core Video 像素缓冲区的 + +79 +00:04:13,287 --> 00:04:15,556 +光栅图像格式之间的转换服务 + +80 +00:04:15,589 --> 00:04:19,159 +VTDecompressionSession +是一个功能强大的底层接口 + +81 +00:04:19,193 --> 00:04:21,161 +超出了本次演讲的范围 + +82 +00:04:21,195 --> 00:04:24,631 +但高级开发者可能想要进一步研究 + +83 +00:04:24,665 --> 00:04:26,800 +最后是 Core Media + +84 +00:04:26,834 --> 00:04:30,537 +该框架定义了 AVFoundation +和其他高级媒体框架 + +85 +00:04:30,571 --> 00:04:33,373 +使用的媒体管道 + +86 +00:04:33,407 --> 00:04:37,110 +您可以始终使用 Core Media 的 +底层数据类型和接口 + +87 +00:04:37,144 --> 00:04:39,546 +来有效地处理媒体样本 + +88 +00:04:39,580 --> 00:04:41,648 +和管理媒体数据队列 + +89 +00:04:41,682 --> 00:04:45,319 +在接下来的演讲中 +我们将演示如何以及何时 + +90 +00:04:45,352 --> 00:04:47,688 +在您的 App 中使用这些框架 + +91 +00:04:47,721 --> 00:04:51,225 +首先 如何使用 AVKit 和 AVFoundation + +92 +00:04:51,258 --> 00:04:55,262 +来轻松播放渲染为 EDR 的 HDR 视频 + +93 +00:04:55,295 --> 00:04:59,399 +然后是 AVPlayer 的一系列 +更复杂的 App + +94 +00:04:59,433 --> 00:05:01,235 +渲染到您自己的层 + +95 +00:05:01,268 --> 00:05:05,105 +通过 CADisplayLink +访问单独解码的帧 + +96 +00:05:05,138 --> 00:05:09,243 +并将生成的 CVPixelBuffer +发送到 Core Image 进行处理 + +97 +00:05:09,276 --> 00:05:13,247 +最后 通过 CVMetalTextureCache +以 Metal 纹理方式 + +98 +00:05:13,280 --> 00:05:15,182 +访问解码帧 + +99 +00:05:15,215 --> 00:05:17,818 +以便在 Metal 中进行处理和渲染 + +100 +00:05:17,851 --> 00:05:22,322 +现在我们已经对 Apple 平台上的 +视频媒体层有了大致的了解 + +101 +00:05:22,356 --> 00:05:26,260 +我们将重点介绍 AVKit +和 AVFoundation framework + +102 +00:05:26,293 --> 00:05:28,795 +首先 我们来讨论一下 +使用 AVFoundation 的 + +103 +00:05:28,829 --> 00:05:30,597 +AVPlayer 接口 + +104 +00:05:30,631 --> 00:05:33,433 +播放 HDR 视频内容 + +105 +00:05:33,467 --> 00:05:35,969 +AVPlayer 是一个控制器对象 + +106 +00:05:36,003 --> 00:05:39,773 +用于管理媒体资源的播放和计时 + +107 +00:05:39,806 --> 00:05:44,244 +AVPlayer 接口可用于 +高性能 HDR 视频播放 + +108 +00:05:44,278 --> 00:05:47,314 +在可能的情况下 +自动将结果渲染为 EDR + +109 +00:05:48,282 --> 00:05:51,785 +使用 AVPlayer 您可以播放 +本地和远程基于文件的媒体 + +110 +00:05:51,818 --> 00:05:53,820 +如 QuickTime 影片 + +111 +00:05:53,854 --> 00:05:58,025 +以及使用 HLS 提供的流媒体 + +112 +00:05:58,058 --> 00:06:02,729 +本质上 AVPlayer 用于 +一次播放一个媒体资源 + +113 +00:06:02,763 --> 00:06:07,167 +您可以重用播放器实例 +来连续播放其他媒体资源 + +114 +00:06:07,201 --> 00:06:12,272 +甚至可以创建多个实例 +来同时播放一个以上的资源 + +115 +00:06:12,306 --> 00:06:17,277 +但 AVPlayer 一次只管理 +单个媒体资源的播放 + +116 +00:06:17,311 --> 00:06:21,348 +AVFoundation framework +还提供了一个名为 AVQueuePlayer 的 + +117 +00:06:21,381 --> 00:06:24,218 +AVPlayer 子类 您可以使用该子类 + +118 +00:06:24,251 --> 00:06:29,556 +创建和管理 +连续 HDR 媒体资源的排队和播放 + +119 +00:06:29,590 --> 00:06:33,193 +如果您的 App 需要简单地播放 +渲染到 EDR 的 HDR 视频媒体 + +120 +00:06:33,227 --> 00:06:37,164 +那么带有 +AVPlayerViewController 的 + +121 +00:06:37,197 --> 00:06:39,233 +AVPlayer 可能是最好的方法 + +122 +00:06:39,266 --> 00:06:41,668 +使用 AVPlayer 和 AVPlayerLayer + +123 +00:06:41,702 --> 00:06:45,405 +在 iOS 或 macOS 上 +播放您自己的视图 + +124 +00:06:46,640 --> 00:06:49,810 +这些是使用 AVPlayer 最简单的方法 + +125 +00:06:49,843 --> 00:06:51,845 +我们来看看这两者的示例 + +126 +00:06:51,879 --> 00:06:55,916 +首先 我们将介绍如何将 +AVFoundation 的 AVPlayer 接口 + +127 +00:06:55,949 --> 00:06:59,853 +与 AVKit 的 +AVPlayerViewController 结合使用 + +128 +00:06:59,887 --> 00:07:03,957 +这里 我们从媒体的 URL +实例化 AVPlayer 开始 + +129 +00:07:06,493 --> 00:07:09,630 +接下来 我们创建一个 +AVPlayerViewController + +130 +00:07:09,663 --> 00:07:12,332 +然后将我们的查看器控制器的 +播放器属性设置为 + +131 +00:07:12,366 --> 00:07:15,235 +我们刚刚从媒体的 URL +创建的播放器 + +132 +00:07:18,005 --> 00:07:23,076 +并以模式呈现视图控制器 +以开始播放视频 + +133 +00:07:23,110 --> 00:07:25,579 +AVKit 为您管理所有细节 + +134 +00:07:25,612 --> 00:07:29,116 +并将在支持 EDR 的显示器上 + +135 +00:07:29,149 --> 00:07:31,852 +自动播放 HDR 视频作为 EDR + +136 +00:07:31,885 --> 00:07:35,656 +正如我提到的 一些 App 需要在 +自己的视图中 + +137 +00:07:35,689 --> 00:07:37,491 +播放 HDR 视频媒体 + +138 +00:07:37,524 --> 00:07:42,563 +让我们看看如何使用 AVPlayer +和 AVPlayerLayer 来实现这一点 + +139 +00:07:42,596 --> 00:07:46,266 +为了在您自己的视图中 +以 EDR 的形式播放 HDR 视频媒体 + +140 +00:07:46,300 --> 00:07:51,371 +我们再次开始使用媒体的 URL +创建一个 AVPlayer + +141 +00:07:51,405 --> 00:07:54,474 +然而 这次我们用刚刚创建的播放器 + +142 +00:07:54,508 --> 00:07:57,444 +实例化了一个 AVPlayerLayer + +143 +00:07:57,477 --> 00:08:00,013 +接下来 我们需要在播放器层上 +设置边界 + +144 +00:08:00,047 --> 00:08:02,649 +这是我们从视图中获得的 + +145 +00:08:02,683 --> 00:08:05,385 +既然播放器层有了视图的边界 + +146 +00:08:05,419 --> 00:08:10,023 +我们可以将播放器层 +作为子层添加到视图中 + +147 +00:08:10,057 --> 00:08:12,926 +最后 为了播放 HDR 视频媒体 + +148 +00:08:12,960 --> 00:08:15,596 +我们调用了 AVPlayer 的播放方法 + +149 +00:08:15,629 --> 00:08:19,333 +那就是使用 AVPlayer +和 AVPlayerLayer + +150 +00:08:19,366 --> 00:08:23,971 +在您自己的层中将 HDR 视频媒体 +作为 EDR 播放所需的全部内容 + +151 +00:08:24,004 --> 00:08:26,139 +我们刚刚使用 AVPlayer 探索了 + +152 +00:08:26,173 --> 00:08:29,443 +两种最简单的 HDR 视频播放工作流程 + +153 +00:08:29,476 --> 00:08:34,014 +然而 许多 App 需要的 +不仅仅是简单的媒体播放 + +154 +00:08:35,282 --> 00:08:38,852 +例如 App 可能需要对视频 +进行图像处理 + +155 +00:08:38,886 --> 00:08:43,223 +如颜色分级或色度键控 + +156 +00:08:43,257 --> 00:08:48,095 +我们来探索一个从 AVPlayer +获取解码视频帧的工作流程 + +157 +00:08:48,128 --> 00:08:51,865 +应用 CoreImage filter +或 Metal shader 实时处理 + +158 +00:08:51,899 --> 00:08:55,369 +并将结果渲染为 EDR + +159 +00:08:55,402 --> 00:08:59,072 +我们将演示如何使用 AVPlayer +和 AVPlayerItem + +160 +00:08:59,106 --> 00:09:03,010 +从您的 HDR 视频媒体解码 EDR 帧 + +161 +00:09:03,043 --> 00:09:06,947 +从 Core Video 显示链接访问解码帧 + +162 +00:09:06,980 --> 00:09:11,919 +将生成的像素缓冲区发送到 +Core Image 或 Metal 进行处理 + +163 +00:09:11,952 --> 00:09:14,354 +然后在具有 EDR 支持的显示器上 + +164 +00:09:14,388 --> 00:09:17,958 +以 EDR 的形式在 +CAMetalLayer 中渲染结果 + +165 +00:09:17,991 --> 00:09:20,360 +考虑到这一点 我们将首先演示 + +166 +00:09:20,394 --> 00:09:23,330 +在 CAMetalLayer 上 +设置几个关键属性 + +167 +00:09:23,363 --> 00:09:28,202 +这些属性是确保 HDR 媒体 +正确渲染为 EDR 所必需的 + +168 +00:09:28,235 --> 00:09:30,337 +首先 我们需要获得 CAMetalLayer + +169 +00:09:30,370 --> 00:09:34,274 +然后将 HDR 视频内容渲染到它上面 + +170 +00:09:34,308 --> 00:09:37,177 +在该层上 我们通过将 + +171 +00:09:37,211 --> 00:09:40,614 +wantsExtendedDynamicRangeContent +标志设置为真来选择 EDR + +172 +00:09:42,883 --> 00:09:48,222 +请确保使用支持 Extended Dynamic Range +内容的像素格式 + +173 +00:09:48,255 --> 00:09:52,459 +对于下面的 AVPlayer 示例 +我们将把 CAMetalLayer 设置为 + +174 +00:09:52,492 --> 00:09:54,528 +使用半浮点像素格式 + +175 +00:09:54,561 --> 00:09:58,265 +但是结合 PQ 或 HLG 传递函数 + +176 +00:09:58,298 --> 00:10:01,535 +使用的 10 位格式也可以 + +177 +00:10:01,568 --> 00:10:03,904 +为了避免将结果限制为 SDR + +178 +00:10:03,937 --> 00:10:06,707 +我们还需要将层设置为 + +179 +00:10:06,740 --> 00:10:08,909 +EDR 兼容的扩展范围色彩空间 + +180 +00:10:10,577 --> 00:10:13,580 +在我们的示例中 +我们将半浮动 Metal 纹理设置为 + +181 +00:10:13,614 --> 00:10:18,151 +扩展的线性 Display P3 色彩空间 + +182 +00:10:18,185 --> 00:10:20,487 +我们只是初步了解了 EDR + +183 +00:10:20,521 --> 00:10:23,090 +色彩空间和像素缓冲区格式 + +184 +00:10:23,123 --> 00:10:25,626 +您可能想查看我去年的讲座 + +185 +00:10:25,659 --> 00:10:27,528 +“HDR rendering with EDR” + +186 +00:10:27,561 --> 00:10:31,999 +以及今年的 “探索 iOS 上的 EDR” +以了解更多信息 + +187 +00:10:33,300 --> 00:10:36,303 +现在 我们已经设置了 +CAMetalLayer 的基本属性 + +188 +00:10:36,336 --> 00:10:39,873 +我们还要继续演示 +使用 Core Image 或 Metal shader + +189 +00:10:39,907 --> 00:10:42,376 +添加实时图像处理 + +190 +00:10:42,409 --> 00:10:45,412 +我们将结合 AVPlayer 使用显示链接 + +191 +00:10:45,445 --> 00:10:48,415 +来实时访问解码的视频帧 + +192 +00:10:49,449 --> 00:10:53,820 +对于此工作流程 首先 +从 AVPlayerItem 创建 AVPlayer + +193 +00:10:53,854 --> 00:10:57,291 +接下来 实例化 +AVPlayerItemVideoOutput + +194 +00:10:57,324 --> 00:11:02,496 +为 EDR 配置适当的 +像素缓冲区格式和色彩空间 + +195 +00:11:02,529 --> 00:11:05,399 +然后创建并配置 Display Link + +196 +00:11:05,432 --> 00:11:08,669 +最后 运行 Display Link +将像素缓冲区发送到 + +197 +00:11:08,702 --> 00:11:11,805 +Core Image 或 Metal 进行处理 + +198 +00:11:11,839 --> 00:11:16,310 +我们将演示在 iOS 上 +使用的 CADisplayLink + +199 +00:11:16,343 --> 00:11:21,381 +在为 macOS 开发时 +请使用等效的 CVDisplayLink + +200 +00:11:21,415 --> 00:11:24,084 +这一次 我们选择从媒体的 URL +创建一个 + +201 +00:11:24,117 --> 00:11:26,486 +AVPlayerItem + +202 +00:11:26,520 --> 00:11:32,326 +并用我们刚刚创建的 AVPlayerItem +实例化 AVPlayer + +203 +00:11:32,359 --> 00:11:35,562 +现在我们创建一对字典 +来指定解码帧的 + +204 +00:11:35,596 --> 00:11:38,999 +色彩空间和像素缓冲区格式 + +205 +00:11:39,032 --> 00:11:41,635 +第一个字典 videoColorProperties + +206 +00:11:41,668 --> 00:11:45,172 +是指定色彩空间和传递函数的地方 + +207 +00:11:45,205 --> 00:11:48,475 +在本例中 +我们要求的是 Display P3 色彩空间 + +208 +00:11:48,509 --> 00:11:51,945 +该色彩空间对应于大多数 +Apple 显示器的色彩空间 + +209 +00:11:51,979 --> 00:11:55,115 +以及线性传递函数 +该传递函数允许 AVFoundation + +210 +00:11:55,148 --> 00:11:58,852 +保持 EDR 所需的扩展范围值 + +211 +00:12:00,153 --> 00:12:02,756 +第二个字典 outputVideoSettings + +212 +00:12:02,789 --> 00:12:06,026 +指定了像素缓冲区格式的特征 + +213 +00:12:06,059 --> 00:12:08,929 +并为我们刚刚创建的 +视频色彩属性字典 + +214 +00:12:08,962 --> 00:12:11,899 +提供了参考 + +215 +00:12:11,932 --> 00:12:17,504 +在本例中 我们请求广色域 +和半浮点像素缓冲区格式 + +216 +00:12:17,538 --> 00:12:20,908 +AVPlayerItemVideoOutput +非常有用 + +217 +00:12:20,941 --> 00:12:24,378 +它不仅可以将视频解码为 +我们在输出设置字典中 + +218 +00:12:24,411 --> 00:12:26,480 +指定的像素缓冲区格式 + +219 +00:12:26,513 --> 00:12:30,517 +还可以通过 +像素传输会话自动执行所需的 + +220 +00:12:30,551 --> 00:12:34,021 +任何色彩转换 + +221 +00:12:34,054 --> 00:12:36,890 +回想一下 +一个视频可能包含多个剪辑 + +222 +00:12:36,924 --> 00:12:39,393 +可能具有不同的色彩空间 + +223 +00:12:39,426 --> 00:12:42,796 +AVFoundation 会自动 +为我们管理这些 + +224 +00:12:42,829 --> 00:12:45,065 +正如我们即将演示的那样 + +225 +00:12:45,098 --> 00:12:48,368 +这种行为还允许将解码后的视频帧 + +226 +00:12:48,402 --> 00:12:51,338 +发送到 Metal 等底层框架 + +227 +00:12:51,371 --> 00:12:54,341 +而这些框架本身并不会 +自动将色彩空间转换为 + +228 +00:12:54,374 --> 00:12:56,643 +显示器的色彩空间 + +229 +00:12:57,377 --> 00:13:00,447 +现在 我们使用 +outputVideoSettings 字典 + +230 +00:13:00,480 --> 00:13:03,784 +创建 AVPlayerItemVideoOutput + +231 +00:13:03,817 --> 00:13:06,353 +第三步 我们设置 Display Link + +232 +00:13:06,386 --> 00:13:10,824 +用于实时访问解码的帧 + +233 +00:13:10,858 --> 00:13:15,562 +CADisplayLink 在每次 +显示更新时执行回调 + +234 +00:13:15,596 --> 00:13:19,366 +在我们的例子中 +我们调用了一个局部函数 + +235 +00:13:19,399 --> 00:13:24,805 +来获取 CVPixelBuffer +我们将把它发送给 CoreImage 进行处理 + +236 +00:13:24,838 --> 00:13:27,508 +接下来 我们创建一个 +视频播放器项目观察器 + +237 +00:13:27,541 --> 00:13:31,512 +以允许我们处理 +对指定 Player Item 属性的更改 + +238 +00:13:33,113 --> 00:13:35,516 +我们的示例将在 + +239 +00:13:35,549 --> 00:13:38,652 +每次 Player Item 的状态更改时 +执行此代码 + +240 +00:13:41,088 --> 00:13:44,191 +当播放器项目的状态更改为 +readyToPlay + +241 +00:13:44,224 --> 00:13:47,060 +我们将我们的 +AVPlayerItemVideoOutput + +242 +00:13:47,094 --> 00:13:52,165 +添加到刚刚返回的 +新 AVPlayerItem 中 + +243 +00:13:52,199 --> 00:13:57,070 +注册 CADisplayLink +将主运行循环设置为普通模式 + +244 +00:13:57,104 --> 00:13:59,673 +并通过调用视频播放器上的播放 + +245 +00:13:59,706 --> 00:14:02,976 +来启动 HDR 视频的实时解码 + +246 +00:14:04,478 --> 00:14:08,849 +最后 我们来看看 CADisplayLink +回调实现的例子 + +247 +00:14:08,882 --> 00:14:12,653 +我们之前称之为 +displayLinkCopyPixelBuffer + +248 +00:14:12,686 --> 00:14:15,355 +的局部函数 + +249 +00:14:15,389 --> 00:14:17,591 +HDR 视频开始播放后 + +250 +00:14:17,624 --> 00:14:22,629 +每次刷新显示时都会调用 +CADisplayLink 回调函数 + +251 +00:14:22,663 --> 00:14:27,401 +例如 对于典型的显示 +它可能每秒被调用 60次 + +252 +00:14:27,434 --> 00:14:30,671 +如果有一个新的 CVPixelBuffer +我们的代码 + +253 +00:14:30,704 --> 00:14:34,141 +就有机会更新显示的帧 + +254 +00:14:34,174 --> 00:14:37,611 +在每次显示回调时 +我们尝试复制一个 CVPixelBuffer + +255 +00:14:37,644 --> 00:14:40,447 +其中包含要在当前挂钟时间显示的 + +256 +00:14:40,480 --> 00:14:43,717 +解码视频帧 + +257 +00:14:43,750 --> 00:14:47,054 +然而 复制像素缓冲区调用可能会失败 + +258 +00:14:47,087 --> 00:14:50,123 +因为在每次显示器刷新时 +并不总是有新的 + +259 +00:14:50,157 --> 00:14:52,359 +CVPixelBuffer 可用 + +260 +00:14:52,392 --> 00:14:56,797 +尤其是当屏幕刷新率超过 +正在播放的视频的刷新率时 + +261 +00:14:56,830 --> 00:14:59,032 +如果没有新的 CVPixelBuffer + +262 +00:14:59,066 --> 00:15:01,735 +则调用失败 我们跳过渲染 + +263 +00:15:01,768 --> 00:15:06,373 +这会使前一帧保持在屏幕上 +以进行另一次显示刷新 + +264 +00:15:06,406 --> 00:15:10,143 +但如果复制成功 +那么我们在 CVPixelBuffer 中 + +265 +00:15:10,177 --> 00:15:12,112 +就有一个新的视频帧 + +266 +00:15:12,145 --> 00:15:16,350 +我们可以通过多种方式 +处理和渲染这个新的帧 + +267 +00:15:16,383 --> 00:15:19,219 +一个方法是将 CVPixelBuffer +发送到 Core Image + +268 +00:15:19,253 --> 00:15:21,388 +进行处理 + +269 +00:15:21,421 --> 00:15:24,424 +Core Image 可以将一个或多个 +CIFilter 串在一起 + +270 +00:15:24,458 --> 00:15:28,195 +以向视频帧提供 +GPU 加速的图像处理 + +271 +00:15:29,596 --> 00:15:33,066 +请注意 并非所有 CIFilter +都与 EDR 兼容 + +272 +00:15:33,100 --> 00:15:35,369 +并且可能在处理 HDR 内容时 +遇到问题 + +273 +00:15:35,402 --> 00:15:38,772 +包括钳位到 SDR 或更糟 + +274 +00:15:38,805 --> 00:15:42,476 +Core Image 提供了许多 +EDR 兼容的滤镜 + +275 +00:15:42,509 --> 00:15:46,180 +通过 +CICategoryHighDynamicRange + +276 +00:15:46,213 --> 00:15:49,917 +调用 filterNames 来枚举 +与 EDR 兼容的 CoreImage 滤镜 + +277 +00:15:49,950 --> 00:15:53,787 +在我们的示例中 我们将添加一个 +简单的色调效果 + +278 +00:15:53,820 --> 00:15:58,025 +现在 我们回到例子中 +并集成 Core Image + +279 +00:15:58,058 --> 00:16:01,461 +在每个生成新 CVPixelBuffer 的 +Display Link 回调上 + +280 +00:16:01,495 --> 00:16:04,398 +从该像素缓冲区创建 CIImage + +281 +00:16:06,099 --> 00:16:09,369 +实例化 CIFilter 以实现所需的效果 + +282 +00:16:09,403 --> 00:16:13,574 +我之所以使用色调滤镜 +是因为它没有参数 非常简单 + +283 +00:16:13,607 --> 00:16:16,810 +但系统中内置了许多 CIFilter + +284 +00:16:16,844 --> 00:16:20,314 +您也可以直接编写自己的滤镜 + +285 +00:16:20,347 --> 00:16:24,685 +将 CIFilter 的输入图像设置为 +我们刚刚创建的 CIImage + +286 +00:16:26,153 --> 00:16:29,022 +处理后的视频结果将出现在 + +287 +00:16:29,056 --> 00:16:32,326 +滤镜的输出图像中 + +288 +00:16:32,359 --> 00:16:37,097 +根据需要将尽可能多的 CIFilter +连接在一起 以实现您想要的效果 + +289 +00:16:37,130 --> 00:16:39,399 +然后使用 CIRenderDestination + +290 +00:16:39,433 --> 00:16:42,970 +将结果图像渲染到 +App 的视图代码中 + +291 +00:16:44,805 --> 00:16:50,043 +请参考 WWDC 2020 的演讲 +“Applying CI Effects to Video” + +292 +00:16:50,077 --> 00:16:51,845 +进一步了解有关此工作流程的信息 + +293 +00:16:51,879 --> 00:16:55,883 +另一个方法是使用 Metal +和自定义 Metal shader + +294 +00:16:55,916 --> 00:16:59,119 +来处理和渲染新的 CVPixelBuffer + +295 +00:16:59,152 --> 00:17:02,523 +我们将简要描述 +将 CVPixelBuffer 转换为 + +296 +00:17:02,556 --> 00:17:04,057 +Metal 纹理的过程 + +297 +00:17:04,091 --> 00:17:07,828 +然而 实现这种转换并保持最佳性能 +是一个有深度的话题 + +298 +00:17:07,861 --> 00:17:10,764 +最好留待下次讨论 + +299 +00:17:10,797 --> 00:17:13,400 +我们建议从 +CoreVideo 的 Metal 纹理缓存中 + +300 +00:17:13,433 --> 00:17:15,569 +导出 Metal 纹理 + +301 +00:17:15,602 --> 00:17:19,640 +并将此过程作为 +本次演讲的最后一个示例 + +302 +00:17:19,673 --> 00:17:24,711 +一般而言 该过程是从 +CVPixelBuffer 中获取 IOSurface + +303 +00:17:24,745 --> 00:17:27,014 +创建一个 MetalTextureDescriptor + +304 +00:17:27,047 --> 00:17:29,483 +然后使用 newTextureWithDescriptor + +305 +00:17:29,516 --> 00:17:32,319 +从该 Metal 设备 +创建一个 Metal 纹理 + +306 +00:17:33,887 --> 00:17:37,324 +但如果没有小心处理锁 +纹理可能会被 + +307 +00:17:37,357 --> 00:17:41,428 +重复使用和过度绘制 + +308 +00:17:41,461 --> 00:17:45,799 +此外 并不是所有的像素缓冲区格式 +都被 Metal 纹理支持 + +309 +00:17:45,832 --> 00:17:49,169 +这就是为什么我们在本例中 +使用半浮点 + +310 +00:17:49,203 --> 00:17:51,972 +由于这些复杂性 我们建议直接 + +311 +00:17:52,005 --> 00:17:56,677 +从 CoreVideo 获取 Metal 纹理 +正如我们现在将要演示的 + +312 +00:17:56,710 --> 00:18:00,147 +我们来进一步探索 +Core Video 和 Metal + +313 +00:18:00,180 --> 00:18:03,851 +如前所述 +CVMetalTextureCache 是使用 + +314 +00:18:03,884 --> 00:18:07,421 +CVPixelBuffer 和 Metal 的 +一种简单而有效的方法 + +315 +00:18:07,454 --> 00:18:10,757 +CVMetalTextureCache 很方便 +因为您可以直接 + +316 +00:18:10,791 --> 00:18:14,862 +从缓存中获得 Metal 纹理 +而不需要进一步的转换 + +317 +00:18:14,895 --> 00:18:18,031 +CVMetalTextureCache 自动在 + +318 +00:18:18,065 --> 00:18:21,101 +CVPixelBuffer 和 Metal 纹理 +之间建立桥梁 + +319 +00:18:21,134 --> 00:18:26,073 +从而简化代码并保持快速运行 + +320 +00:18:26,106 --> 00:18:28,876 +与 CVPixelBufferPool +结合使用时 + +321 +00:18:28,909 --> 00:18:32,646 +CVMetalTextureCache +还通过保持 + +322 +00:18:32,679 --> 00:18:36,116 +Metal 纹理到 IOSurface 的实时映射 +来提供性能优势 + +323 +00:18:37,784 --> 00:18:41,054 +最后 使用 CVMetalTextureCache + +324 +00:18:41,088 --> 00:18:43,557 +消除了手动跟踪 IOSurface 的需要 + +325 +00:18:43,590 --> 00:18:46,293 +现在是我们演讲的最后一个例子 + +326 +00:18:46,326 --> 00:18:49,196 +如何使用 CVMetalTextureCache + +327 +00:18:49,229 --> 00:18:51,698 +直接从 Core Video 中 +提取 Metal 纹理 + +328 +00:18:52,499 --> 00:18:55,469 +这里 我们从获取 +系统默认 Metal 设备开始 + +329 +00:18:55,502 --> 00:18:58,071 +我们用它来创建一个 Metal 纹理缓存 + +330 +00:18:58,105 --> 00:19:01,341 +然后实例化一个 +与 Metal 纹理缓存关联的 + +331 +00:19:01,375 --> 00:19:04,111 +Core Video Metal 纹理缓存 + +332 +00:19:04,144 --> 00:19:08,549 +然后可以使用它来访问 +解码的视频帧作为 Metal 纹理 + +333 +00:19:08,582 --> 00:19:13,353 +可以方便地直接在我们的 +Metal 引擎中使用 + +334 +00:19:13,387 --> 00:19:18,292 +在本例中 我们创建并使用 +Metal 系统默认设备 + +335 +00:19:18,325 --> 00:19:21,261 +接下来 我们使用 +CVMetalTextureCacheCreate + +336 +00:19:21,295 --> 00:19:23,530 +创建 CVMetalTextureCache + +337 +00:19:23,564 --> 00:19:26,967 +指定我们刚刚创建的 Metal 设备 + +338 +00:19:27,000 --> 00:19:29,970 +我们得到了创建 +Core Video Metal 纹理 + +339 +00:19:30,003 --> 00:19:33,574 +所需的 CVPixelBuffer 的 +高度和宽度 + +340 +00:19:33,607 --> 00:19:37,511 +然后 我们调用 +CVMetalTextureCacheCreateTextureFromImage + +341 +00:19:37,544 --> 00:19:40,247 +来实例化一个 +CVMetalTexture 对象 + +342 +00:19:40,280 --> 00:19:43,750 +并将其与 CVPixelBuffer 相关联 + +343 +00:19:43,784 --> 00:19:46,653 +最后 我们调用 +CVMetalTextureGetTexture + +344 +00:19:46,687 --> 00:19:50,057 +以获得所需的 Metal 纹理 + +345 +00:19:50,090 --> 00:19:54,394 +Swift App 应使用 +CVMetalTexture 的强引用 + +346 +00:19:54,428 --> 00:19:57,731 +但是 当使用对象 C 时 +您必须确保 Metal + +347 +00:19:57,764 --> 00:20:01,835 +在您释放 CVMetalTextureRef. +之前已经完成了您的纹理 + +348 +00:20:01,869 --> 00:20:05,806 +这可以使用 +metal 命令缓冲区完成处理程序来完成 + +349 +00:20:07,674 --> 00:20:09,042 +就是这些了 各位 + +350 +00:20:09,076 --> 00:20:11,678 +回顾一下 我们探讨了一些 + +351 +00:20:11,712 --> 00:20:14,715 +将 HDR 视频媒体渲染到 +EDR 的工作流程 + +352 +00:20:14,748 --> 00:20:17,684 +用于播放 编辑或图像处理 + +353 +00:20:18,685 --> 00:20:23,190 +大家学习了如何从 AVPlayer +切换到 AVKit 的 AVPlayerViewController + +354 +00:20:23,223 --> 00:20:26,360 +以播放 HDR 媒体 + +355 +00:20:26,393 --> 00:20:30,264 +大家还了解了如何使用 AVPlayer +和 AVPlayerLayer + +356 +00:20:30,297 --> 00:20:34,234 +在您自己的视图上显示 HDR 媒体 + +357 +00:20:34,268 --> 00:20:38,505 +最后 我们探讨了 +如何在播放过程中添加实时效果 + +358 +00:20:38,539 --> 00:20:42,009 +将 AVFoundation 的 AVPlayer +连接到 CoreVideo + +359 +00:20:42,042 --> 00:20:44,178 +然后连接到 Metal 进行渲染 + +360 +00:20:44,211 --> 00:20:46,947 +以及使用 CoreImage 滤镜 + +361 +00:20:46,980 --> 00:20:49,082 +和 metal shader 应用实时效果 + +362 +00:20:51,852 --> 00:20:55,789 +如您想深入了解 我会推荐几个 + +363 +00:20:55,822 --> 00:20:58,258 +与创建视频工作流程 + +364 +00:20:58,292 --> 00:21:02,429 +以及将 HDR 媒体与 EDR 整合 +相关的 WWDC 讲座 + +365 +00:21:02,462 --> 00:21:04,565 +我强烈推荐大家观看讲座 + +366 +00:21:04,598 --> 00:21:08,368 +“Edit and Playback HDR video +with AVFoundation” + +367 +00:21:08,402 --> 00:21:11,505 +这期讲座探讨了 +AVVideoComposition 的使用 + +368 +00:21:11,538 --> 00:21:17,211 +通过 applyingCIFiltersWithHandler +将效果应用到 HDR 媒体 + +369 +00:21:17,244 --> 00:21:20,414 +在本期讲座中 您还会学到 +如何使用自定义合成器 + +370 +00:21:20,447 --> 00:21:23,183 +当每个视频帧可供处理时 + +371 +00:21:23,217 --> 00:21:26,820 +它可以与 CVPixelBuffer 一起使用 + +372 +00:21:26,854 --> 00:21:29,857 +正如我在开始时提到的 +今年我们还将举办 + +373 +00:21:29,890 --> 00:21:33,827 +另外两场关于 EDR 的讲座 +“探索 iOS 上的 EDR” + +374 +00:21:33,861 --> 00:21:38,665 +我们在里面宣布了 EDR API +支持已扩展到包括 iOS + +375 +00:21:38,699 --> 00:21:44,204 +以及 “借助 Core Image、 +Metal 和 SwiftUI 显示 EDR 内容“ + +376 +00:21:44,238 --> 00:21:48,976 +这节讲座进一步探索 EDR +与其他媒体框架的集成 + +377 +00:21:49,009 --> 00:21:52,946 +希望您能把 HDR 视频整合到 macOS + +378 +00:21:52,980 --> 00:21:56,116 +和现在 iOS 上的开启了 EDR 的 App 中 + +379 +00:21:56,149 --> 00:21:57,751 +感谢收看 + diff --git a/zho/2022 Session 110929 Monday@WWDC22.srt b/zho/2022 Session 110929 Monday@WWDC22.srt new file mode 100644 index 0000000..48da558 --- /dev/null +++ b/zho/2022 Session 110929 Monday@WWDC22.srt @@ -0,0 +1,305 @@ +1 +00:00:00,000 --> 00:00:05,606 +♪ ♪ + +2 +00:00:05,672 --> 00:00:07,174 +欢迎来到总部 + +3 +00:00:07,241 --> 00:00:08,575 +我是Serenity Caldwell + +4 +00:00:08,642 --> 00:00:12,279 +这是您WWDC的首日简报 + +5 +00:00:12,346 --> 00:00:14,815 +iOS 16已准备好开启任务 + +6 +00:00:14,882 --> 00:00:16,884 +首站是全新的锁定屏幕 + +7 +00:00:16,950 --> 00:00:19,520 +有无数的字体 +颜色和小组件可供选择 + +8 +00:00:19,586 --> 00:00:21,655 +个性化您的iPhone + +9 +00:00:21,722 --> 00:00:24,091 +想要区分工作和家庭生活吗 + +10 +00:00:24,157 --> 00:00:26,393 +激活个人专注模式吧 + +11 +00:00:26,460 --> 00:00:28,295 +如果发送了尴尬的信息 + +12 +00:00:28,362 --> 00:00:29,897 +现在可以重新编辑补救 + +13 +00:00:29,963 --> 00:00:34,001 +更甚者 在别人看到前将其撤回 + +14 +00:00:34,067 --> 00:00:36,103 +通过同播共享 您可以与好友一起 + +15 +00:00:36,170 --> 00:00:37,704 +边发送信息 边共享播放电影节目 + +16 +00:00:37,771 --> 00:00:38,672 +哦 我喜欢 + +17 +00:00:38,739 --> 00:00:40,040 +想要给好友发送 + +18 +00:00:40,107 --> 00:00:41,108 +抠除背景的图片吗 + +19 +00:00:41,175 --> 00:00:44,178 +只需要长按 松开 发送 + +20 +00:00:44,244 --> 00:00:46,647 +与家人共享照片更便捷 + +21 +00:00:46,713 --> 00:00:48,849 +我们有iCloud共享图库 + +22 +00:00:48,916 --> 00:00:52,085 +我们还对未来的CarPlay车载 +先睹为快 + +23 +00:00:52,152 --> 00:00:54,254 +♪ + +24 +00:00:54,321 --> 00:00:56,557 +最后 “地图”App + +25 +00:00:56,623 --> 00:00:59,059 +可以规划高达15个途经点 + +26 +00:00:59,126 --> 00:01:02,062 +来看看Apple Watch的全新功能 + +27 +00:01:02,129 --> 00:01:04,965 +体能训练 +可以显示更多指标 如心率区间 + +28 +00:01:05,032 --> 00:01:06,900 +自定体能训练方式 + +29 +00:01:06,967 --> 00:01:09,002 +新增用药提醒更便捷 + +30 +00:01:09,069 --> 00:01:11,205 +还有一系列全新表盘 + +31 +00:01:11,271 --> 00:01:15,576 +天文表盘 月相表盘 +欢乐时光表盘 大都会表盘 + +32 +00:01:15,642 --> 00:01:18,779 +当然还有我们的……好朋友 + +33 +00:01:19,746 --> 00:01:22,249 +新一代Apple芯片已现身 + +34 +00:01:22,316 --> 00:01:23,717 +强大的M2芯片 + +35 +00:01:23,784 --> 00:01:26,753 +M2芯片强势驱动 + +36 +00:01:26,820 --> 00:01:27,855 +全新的MacBook Air + +37 +00:01:27,921 --> 00:01:30,691 +更薄 更轻 更快 前所未有 + +38 +00:01:30,757 --> 00:01:34,962 +我们将M2芯片 +配备到13英寸MacBook Pro上 + +39 +00:01:35,028 --> 00:01:37,464 +我们发布了全新的macOS Ventura + +40 +00:01:37,531 --> 00:01:40,667 +聚焦大升级 如增强图像搜索 + +41 +00:01:40,734 --> 00:01:41,602 +我们还介绍了 + +42 +00:01:41,668 --> 00:01:42,503 +台前调度 + +43 +00:01:42,569 --> 00:01:44,738 +现在 您可以快速轻松地 + +44 +00:01:44,805 --> 00:01:46,840 +在不同窗口和App之间切换 + +45 +00:01:46,907 --> 00:01:50,410 +您还可以定时发送 撤回已发送邮件 + +46 +00:01:50,477 --> 00:01:52,646 +我们有求必应 + +47 +00:01:52,713 --> 00:01:55,015 +为您介绍连续互通相机 + +48 +00:01:55,082 --> 00:01:56,984 +现在 您可以前所未有地 + +49 +00:01:57,050 --> 00:01:59,386 +让iPhone兼职网络摄像头 + +50 +00:01:59,453 --> 00:02:00,654 +别看了 这是 + +51 +00:02:00,721 --> 00:02:01,722 +iPadOS 16 + +52 +00:02:01,788 --> 00:02:03,724 +史上首次 您可以通过台前调度 + +53 +00:02:03,790 --> 00:02:05,959 +叠放多个窗口 + +54 +00:02:06,026 --> 00:02:07,494 +还有更好的 + +55 +00:02:07,561 --> 00:02:09,429 +在不同App 不同设备间的协作 + +56 +00:02:09,496 --> 00:02:12,299 +更便捷 今年下半年 + +57 +00:02:12,366 --> 00:02:14,635 +还有全新的实时协作App + +58 +00:02:14,701 --> 00:02:17,971 +我们在所有Apple平台都接入了新的API + +59 +00:02:18,038 --> 00:02:20,340 +WeatherKit提供全面的天气数据 + +60 +00:02:20,407 --> 00:02:23,777 +开发者可以通过Metal 3设计游戏 + +61 +00:02:23,844 --> 00:02:26,380 +SwiftUI更强大更灵活 + +62 +00:02:26,446 --> 00:02:28,815 +Swift Charts更上一层楼 + +63 +00:02:28,882 --> 00:02:30,384 +接下来介绍了Swift Regex + +64 +00:02:30,450 --> 00:02:33,587 +为所有开发者开放Xcode Cloud + +65 +00:02:33,654 --> 00:02:36,690 +恭喜Apple设计大奖12位获奖者 + +66 +00:02:36,757 --> 00:02:39,459 +以及所有入围作品 + +67 +00:02:39,526 --> 00:02:41,461 +让我们来看看第二天的内容 + +68 +00:02:41,528 --> 00:02:42,729 +专注模式过滤条件 + +69 +00:02:42,796 --> 00:02:43,897 +SwiftUI的新内容 + +70 +00:02:43,964 --> 00:02:45,098 +探索Metal 3 + +71 +00:02:45,165 --> 00:02:46,466 +带您走进增强现实的世界 + +72 +00:02:46,533 --> 00:02:47,634 +Xcode14的新内容 + +73 +00:02:47,701 --> 00:02:49,536 +以上是今天的简报 + +74 +00:02:49,603 --> 00:02:52,239 +明天别忘了继续汇报 + +75 +00:02:52,306 --> 00:02:59,012 +♪ + diff --git a/zho/2022 Session 110930 Tuesday@WWDC22.srt b/zho/2022 Session 110930 Tuesday@WWDC22.srt new file mode 100644 index 0000000..9b780bb --- /dev/null +++ b/zho/2022 Session 110930 Tuesday@WWDC22.srt @@ -0,0 +1,145 @@ +1 +00:00:00,000 --> 00:00:03,437 +♪♪ + +2 +00:00:03,504 --> 00:00:05,706 +准备好第二天的简报了吗 + +3 +00:00:05,772 --> 00:00:08,976 +那我们就直接开始吧 + +4 +00:00:09,042 --> 00:00:10,611 +首先 我们为您的SwiftUI App + +5 +00:00:10,677 --> 00:00:13,180 +搭建了全新的导航方式 + +6 +00:00:13,247 --> 00:00:15,549 +这项技术是我们的“主菜” + +7 +00:00:15,616 --> 00:00:19,386 +然后 我们了解了 +Xcode 14的更多新特性 + +8 +00:00:19,453 --> 00:00:21,121 +您可以选择适合自己的 + +9 +00:00:21,188 --> 00:00:22,556 +细节级别 + +10 +00:00:22,623 --> 00:00:24,558 +Jared为我们展示了 +全新的plug-ins + +11 +00:00:24,625 --> 00:00:27,928 +可将Apple框架 +嵌入到您的Unity游戏项目中 + +12 +00:00:27,995 --> 00:00:31,131 +Core Haptics Unity plug-in +让您可以 + +13 +00:00:31,198 --> 00:00:34,268 +更沉浸式地体验游戏 + +14 +00:00:34,334 --> 00:00:37,104 +RoomPlan提供了全新的 + +15 +00:00:37,171 --> 00:00:38,505 +3D扫描方式 + +16 +00:00:38,572 --> 00:00:40,407 +Apple以强势的方式 + +17 +00:00:40,474 --> 00:00:42,976 +帮助人们将世界移植到App中 + +18 +00:00:43,043 --> 00:00:44,878 +然后 Paul向开发者们展示了 + +19 +00:00:44,945 --> 00:00:48,448 +如何用色彩玩转SF Symbol + +20 +00:00:48,515 --> 00:00:51,818 +我们介绍了iOS的全新框架 Push to Talk + +21 +00:00:51,885 --> 00:00:52,819 +Trevor你好啊 + +22 +00:00:52,886 --> 00:00:55,255 +准备好分享你的WWDC幻灯片了吗 + +23 +00:00:55,322 --> 00:00:57,824 +Kevin你好 我过几分钟就好 + +24 +00:00:57,891 --> 00:00:59,927 +能听到吗 结束 + +25 +00:00:59,993 --> 00:01:02,396 +接下来是明天的一些剧透 + +26 +00:01:02,462 --> 00:01:03,864 +iPad App设计的新内容 + +27 +00:01:03,931 --> 00:01:05,199 +♪ + +28 +00:01:05,265 --> 00:01:06,533 +隐私部分的新内容 + +29 +00:01:06,600 --> 00:01:07,835 +♪ + +30 +00:01:07,901 --> 00:01:09,403 +为Swift Playgrounds +打造引人入胜的内容 + +31 +00:01:09,469 --> 00:01:10,571 +♪ + +32 +00:01:10,637 --> 00:01:12,172 +Swift中的Distributed Actor组件 + +33 +00:01:12,239 --> 00:01:13,106 +♪ + +34 +00:01:13,173 --> 00:01:15,876 +开发者们 我们保持联系 + +35 +00:01:15,943 --> 00:01:21,682 +♪ + diff --git a/zho/2022 Session 110931 Wednesday@WWDC22.srt b/zho/2022 Session 110931 Wednesday@WWDC22.srt new file mode 100644 index 0000000..fe6a94b --- /dev/null +++ b/zho/2022 Session 110931 Wednesday@WWDC22.srt @@ -0,0 +1,168 @@ +1 +00:00:00,000 --> 00:00:03,437 +♪ + +2 +00:00:03,504 --> 00:00:05,138 +既然我已经引起了你的注意 + +3 +00:00:05,205 --> 00:00:07,508 +接下来请看第三天的简报 + +4 +00:00:07,574 --> 00:00:09,476 +♪ + +5 +00:00:09,543 --> 00:00:11,178 +首先是与Lynn的培训 + +6 +00:00:11,245 --> 00:00:14,248 +探索App快捷指令的新设计 + +7 +00:00:14,314 --> 00:00:15,749 +你即将感受一场叹为观止的 + +8 +00:00:15,816 --> 00:00:17,050 +App快捷指令之旅 + +9 +00:00:17,117 --> 00:00:19,820 +然后我们与Mohammed共同探索了 + +10 +00:00:19,887 --> 00:00:20,821 +如何搭建桌面级iPad App + +11 +00:00:20,888 --> 00:00:22,556 +这让App能以 + +12 +00:00:22,623 --> 00:00:24,858 +最适配内容的方式进行展现 + +13 +00:00:24,925 --> 00:00:26,326 +同时为UI的前端界面 + +14 +00:00:26,393 --> 00:00:27,761 +带来更多功能 + +15 +00:00:27,828 --> 00:00:29,530 +然后研究如何利用 + +16 +00:00:29,596 --> 00:00:32,065 +iOS的镜头采集功能 + +17 +00:00:32,132 --> 00:00:33,600 +这个App还有一个王牌绝招 + +18 +00:00:33,667 --> 00:00:35,602 +我可以在场景的不同物件上点击 + +19 +00:00:35,669 --> 00:00:37,004 +开启聚光灯 + +20 +00:00:37,070 --> 00:00:38,405 +我们还展示了 +用SwiftUI为App创建 + +21 +00:00:38,472 --> 00:00:42,376 +全新炫酷的布局 +和浏览方式的强大工具 + +22 +00:00:42,442 --> 00:00:44,778 +SwiftUI有丰富的组件 + +23 +00:00:44,845 --> 00:00:47,514 +供你编辑App界面 + +24 +00:00:47,581 --> 00:00:50,117 +以下是明天的简报内容 + +25 +00:00:50,184 --> 00:00:53,487 +阿拉伯语设计 + +26 +00:00:53,554 --> 00:00:54,855 +将几何着色器转变为 +Meta网格着色器 + +27 +00:00:54,922 --> 00:00:56,089 +传统渲染流水线 + +28 +00:00:56,156 --> 00:00:57,124 +网格着色器流水线 + +29 +00:00:57,191 --> 00:00:59,059 +探索ARKit 6 + +30 +00:00:59,126 --> 00:01:00,127 +♪ + +31 +00:01:00,194 --> 00:01:01,228 +用Xcode +和自带检测器跟踪Hangs + +32 +00:01:01,295 --> 00:01:02,162 +♪ + +33 +00:01:02,229 --> 00:01:03,597 +什么是Hangs + +34 +00:01:03,664 --> 00:01:04,731 +信息协作设计 + +35 +00:01:04,798 --> 00:01:06,800 +♪ + +36 +00:01:06,867 --> 00:01:07,968 +进一步了解 + +37 +00:01:08,035 --> 00:01:10,537 +WidgetKit中的复杂功能 + +38 +00:01:10,604 --> 00:01:11,872 +放心大胆地冲吧 + +39 +00:01:11,939 --> 00:01:13,607 +以上是今天的内容 + +40 +00:01:13,674 --> 00:01:15,909 +等待下一步指令 + +41 +00:01:15,976 --> 00:01:20,981 +♪ + diff --git a/zho/2022 Session 110932 WWDC22 Day 4 recap.srt b/zho/2022 Session 110932 WWDC22 Day 4 recap.srt new file mode 100644 index 0000000..8be2c7b --- /dev/null +++ b/zho/2022 Session 110932 WWDC22 Day 4 recap.srt @@ -0,0 +1,146 @@ +1 +00:00:00,000 --> 00:00:04,705 +♪ + +2 +00:00:04,771 --> 00:00:07,941 +是时候来看看第四天的简报了 + +3 +00:00:08,008 --> 00:00:10,711 +开始吧 + +4 +00:00:10,777 --> 00:00:12,779 +我们和Raj一起看了 + +5 +00:00:12,846 --> 00:00:15,115 +如何用SwiftUI构建你的iPad界面 + +6 +00:00:15,182 --> 00:00:18,185 +更好地支持App状态恢复 深度链接 + +7 +00:00:18,252 --> 00:00:20,420 +以及更丰富的程式控制 + +8 +00:00:20,487 --> 00:00:21,755 +太酷了 + +9 +00:00:21,822 --> 00:00:24,558 +然后 Sara展示了 +如何在你的UIKit App中 + +10 +00:00:24,625 --> 00:00:26,426 +嵌入SwiftUI的功能 + +11 +00:00:26,493 --> 00:00:27,995 +在UIKit中 +可以使用view controller的地方 + +12 +00:00:28,061 --> 00:00:30,364 +就可以使用hosting controller + +13 +00:00:30,430 --> 00:00:31,732 +接下来 Brett带我们浏览了 + +14 +00:00:31,798 --> 00:00:33,100 +Vision框架的最新内容 + +15 +00:00:33,166 --> 00:00:35,602 +这是小狗在沙滩接水瓶的短片 + +16 +00:00:35,669 --> 00:00:38,472 +我们对其进行了光流计算 + +17 +00:00:38,539 --> 00:00:39,806 +我们也探索了如何让同播共享 + +18 +00:00:39,873 --> 00:00:42,509 +更加引人入胜 + +19 +00:00:42,576 --> 00:00:44,511 +把同播共享看作是一扇传送门 + +20 +00:00:44,578 --> 00:00:46,513 +通过不同的手机将人们传送到 + +21 +00:00:46,580 --> 00:00:48,115 +同一个地方 + +22 +00:00:48,182 --> 00:00:49,917 +Apple的界面编辑 + +23 +00:00:49,983 --> 00:00:51,718 +还向我们传授了一节语言课 + +24 +00:00:51,785 --> 00:00:54,488 +界面编辑始于 + +25 +00:00:54,555 --> 00:00:56,723 +对屏幕另一头的好奇心 + +26 +00:00:56,790 --> 00:00:59,526 +接下来是第五天的剧透 + +27 +00:00:59,593 --> 00:01:00,894 +效率提升:SwiftUI的后台任务 + +28 +00:01:00,961 --> 00:01:02,462 +♪ + +29 +00:01:02,529 --> 00:01:03,964 +发起Xcode Cloud快速可靠的测试 + +30 +00:01:04,031 --> 00:01:05,365 +♪ + +31 +00:01:05,432 --> 00:01:06,733 +创建可访问的单App模式体验 + +32 +00:01:06,800 --> 00:01:08,101 +♪ + +33 +00:01:08,168 --> 00:01:09,369 +PDFKit的新内容 + +34 +00:01:09,436 --> 00:01:10,838 +♪ + +35 +00:01:10,904 --> 00:01:14,041 +明天回来听取我们的最终报告吧 + +36 +00:01:14,107 --> 00:01:19,613 +♪ + diff --git a/zho/2022 Session 110933 WWDC22 Day 5 recap.srt b/zho/2022 Session 110933 WWDC22 Day 5 recap.srt new file mode 100644 index 0000000..c23447a --- /dev/null +++ b/zho/2022 Session 110933 WWDC22 Day 5 recap.srt @@ -0,0 +1,137 @@ +1 +00:00:00,000 --> 00:00:03,370 +♪ + +2 +00:00:03,437 --> 00:00:05,672 +是时候听取最终报告了 + +3 +00:00:05,739 --> 00:00:07,875 +♪ + +4 +00:00:07,941 --> 00:00:10,210 +首先 我们讨论了如何降低 + +5 +00:00:10,277 --> 00:00:11,812 +App的电池损耗 + +6 +00:00:11,879 --> 00:00:13,580 +设备屏幕是 + +7 +00:00:13,647 --> 00:00:14,982 +耗电量最多的 + +8 +00:00:15,048 --> 00:00:16,783 +我们学习了如何在Xcode中 + +9 +00:00:16,850 --> 00:00:18,886 +开发与iOS App结合的 +Swift Server App + +10 +00:00:18,952 --> 00:00:19,786 +使用Swift + +11 +00:00:19,853 --> 00:00:21,188 +来构建服务器组件 + +12 +00:00:21,255 --> 00:00:22,990 +可以弥补这一技术缺口 + +13 +00:00:23,056 --> 00:00:23,957 +然后 Neil向我们展示了 + +14 +00:00:24,024 --> 00:00:25,259 +如何通过ShazamKit + +15 +00:00:25,325 --> 00:00:27,094 +将Audio Catalogs与视频相匹配 + +16 +00:00:27,160 --> 00:00:28,762 +现在 针对Streamline应用 + +17 +00:00:28,829 --> 00:00:30,197 +自定义目录的问题 + +18 +00:00:30,264 --> 00:00:32,299 +我们有了若干重大更新 + +19 +00:00:32,366 --> 00:00:34,368 +我们探索了如何为iPad App + +20 +00:00:34,434 --> 00:00:35,536 +创建多窗口模式 + +21 +00:00:35,602 --> 00:00:36,703 +这是我开发的一款App + +22 +00:00:36,770 --> 00:00:38,572 +可以跟踪我的阅读列表 + +23 +00:00:38,639 --> 00:00:39,806 +这周的简报 + +24 +00:00:39,873 --> 00:00:42,376 +我们以一场友好的跨平台联机 + +25 +00:00:42,442 --> 00:00:43,977 +井字游戏结束 + +26 +00:00:44,044 --> 00:00:45,012 +设备与Apple TV的连接 + +27 +00:00:45,078 --> 00:00:46,914 +就是这么简单 + +28 +00:00:46,980 --> 00:00:49,416 +开发者们 我们的培训已完成 + +29 +00:00:49,483 --> 00:00:51,518 +你已经准备好开启任务了 + +30 +00:00:51,585 --> 00:00:53,587 +这一信息即将进入自毁程序 + +31 +00:00:53,654 --> 00:00:54,988 +倒计时3 2 + +32 +00:00:55,055 --> 00:00:56,423 +开玩笑的 + +33 +00:00:56,490 --> 00:00:58,258 +明年见啦 + +34 +00:00:58,325 --> 00:01:03,964 +♪ + diff --git a/zho/2022 Session 112 Platforms State of the Union (ASL).srt b/zho/2022 Session 112 Platforms State of the Union (ASL).srt new file mode 100644 index 0000000..f003294 --- /dev/null +++ b/zho/2022 Session 112 Platforms State of the Union (ASL).srt @@ -0,0 +1,5625 @@ +1 +00:00:00,334 --> 00:00:07,574 +♪ ♪ + +2 +00:00:09,243 --> 00:00:17,251 +♪ ♪ + +3 +00:00:22,356 --> 00:00:27,861 +欢迎来到 WWDC 2022 +State of the Union + +4 +00:00:27,895 --> 00:00:31,498 +我们总是兴奋地迎接 WWDC +因为它提供了非常好的契机 + +5 +00:00:31,532 --> 00:00:33,600 +让我们可以与你们所有人沟通 + +6 +00:00:33,634 --> 00:00:35,602 +分享我们最近的工作进展 + +7 +00:00:35,636 --> 00:00:39,940 +以及更好地理解 +你们需要我们的开发者平台提供什么 + +8 +00:00:39,973 --> 00:00:43,477 +你们作为开发者所做的工作太了不起了 + +9 +00:00:43,510 --> 00:00:48,015 +你们将奇思妙想变成现实 + +10 +00:00:48,048 --> 00:00:51,585 +将用户体验推向新高度 + +11 +00:00:51,618 --> 00:00:55,455 +而我们想帮助大家 +让你们的想法走得更远 + +12 +00:00:55,489 --> 00:00:58,592 +我们已经在 Keynote 主题演讲中涵盖了 + +13 +00:00:58,625 --> 00:01:02,296 +iPhone、iPad、Mac、Apple Watch +和 Apple TV 上的一些新功能 + +14 +00:01:02,329 --> 00:01:05,265 +还有 Apple 芯片令人难以置信的强大性能 + +15 +00:01:05,299 --> 00:01:09,069 +助力大家把最有雄心的想法变为现实 + +16 +00:01:09,102 --> 00:01:13,240 +我们今天要讲的内容很多 +首先来讲一些更新 + +17 +00:01:13,273 --> 00:01:17,678 +今年早些时候 我们开启了全新的 +Apple Developer Center + +18 +00:01:17,711 --> 00:01:20,981 +让大家和 Apple 的工程师和设计师 + +19 +00:01:21,014 --> 00:01:24,484 +一起沟通与协作 +且就在 Apple Park + +20 +00:01:24,518 --> 00:01:28,455 +去年秋天 +有成千上万跟你们一样的开发者在世界各地 + +21 +00:01:28,488 --> 00:01:30,657 +参加了我们全新的线上 Tech Talks + +22 +00:01:30,691 --> 00:01:36,463 +我们用 5 种语言在线直播了 +来自 11 个国家的数百场现场活动 + +23 +00:01:36,496 --> 00:01:38,899 +对我们来说 +Tech Talks 系列最棒的地方之一 + +24 +00:01:38,932 --> 00:01:40,300 +就是一对一会面 + +25 +00:01:40,334 --> 00:01:43,871 +这给我们提供了绝佳的机会 +了解大家的工作 + +26 +00:01:43,904 --> 00:01:46,773 +分享一些建议和指导 + +27 +00:01:46,807 --> 00:01:49,343 +去年秋季我们推出了 +Swift Playgrounds 4 + +28 +00:01:49,376 --> 00:01:53,247 +让大家有能力可以构建 app +并直接提交至 App Store + +29 +00:01:53,280 --> 00:01:55,148 +还提供了对 SwiftUI 的支持 + +30 +00:01:55,182 --> 00:01:59,653 +使其成为用于测试 +和 UI 原型设计的绝佳工具 + +31 +00:01:59,686 --> 00:02:02,489 +当然还有 Xcode Cloud + +32 +00:02:02,523 --> 00:02:04,124 +我们打造 Xcode Cloud 是为了帮助大家 + +33 +00:02:04,157 --> 00:02:07,294 +更快更容易地打造更好的 app + +34 +00:02:07,327 --> 00:02:09,630 +它是一项持续集成与交付服务 + +35 +00:02:09,663 --> 00:02:14,234 +且内置于 Xcode 采用云托管 + +36 +00:02:14,268 --> 00:02:18,205 +Xcode Cloud 支持所有 Apple 平台的开发 + +37 +00:02:18,238 --> 00:02:21,141 +它集成了 TestFlight 和 +App Store Connect + +38 +00:02:21,175 --> 00:02:24,545 +以及所有主要基于 Git 的源代码提供程序 + +39 +00:02:24,578 --> 00:02:30,150 +它甚至拥有各种 REST API +协助联结开发过程中的其他方面 + +40 +00:02:30,184 --> 00:02:34,121 +并保有高度的安全性 +来保护着你和你的项目 + +41 +00:02:34,154 --> 00:02:36,523 +我非常高兴地宣布 + +42 +00:02:36,557 --> 00:02:41,595 +Xcode Cloud 从今天起正式推出 + +43 +00:02:41,628 --> 00:02:43,997 +我们认为几乎每个开发团队 + +44 +00:02:44,031 --> 00:02:45,699 +都能从 Xcode Cloud 获益 + +45 +00:02:45,732 --> 00:02:49,937 +因此我们将其定价置在 +所有规模的开发者都可以使用的水平 + +46 +00:02:49,970 --> 00:02:53,340 +我们将提供每月 25 小时的订阅 + +47 +00:02:53,373 --> 00:02:56,610 +给所有 Apple Developer +Program 用户免费使用 + +48 +00:02:56,643 --> 00:02:59,179 +持续到 2023 年底 + +49 +00:02:59,213 --> 00:03:04,885 +大家还可以从 Developer app 中 +订阅任意一级 Xcode Cloud 服务 + +50 +00:03:04,918 --> 00:03:06,353 +今夏晚些时候推出 + +51 +00:03:06,386 --> 00:03:10,791 +今天 我们要来谈三大主题 + +52 +00:03:10,824 --> 00:03:15,829 +首先 我们想分享一下 +我们对 Apple 平台开发的愿景 + +53 +00:03:15,863 --> 00:03:19,666 +我们平台目前现状 +以及我们未来前进的方向 + +54 +00:03:19,700 --> 00:03:22,135 +然后 我们会分享一些激动人心的新方式 + +55 +00:03:22,169 --> 00:03:26,507 +让你开发的各种 app 与 Apple 平台的系统体验 +相互整合 + +56 +00:03:26,540 --> 00:03:30,310 +最后 我们要讨论各种强大的全新 API + +57 +00:03:30,344 --> 00:03:34,882 +并向大家展示它们可以如何 +帮助你的 app 实现更强大的功能 + +58 +00:03:34,915 --> 00:03:37,851 +首先看看我们对开发者平台的愿景 + +59 +00:03:37,885 --> 00:03:39,419 +以及它是如何持续进化的 + +60 +00:03:39,453 --> 00:03:42,456 +下面请 Josh 为你介绍 + +61 +00:03:43,323 --> 00:03:46,560 +优秀的开发者平台可以提供 + +62 +00:03:46,593 --> 00:03:49,696 +不同编程语言、框架和工具间的深度整合 + +63 +00:03:49,730 --> 00:03:52,232 +当三者完全相辅相成时 + +64 +00:03:52,266 --> 00:03:54,868 +我们就可以确保 +常见的任务可以轻松完成 + +65 +00:03:54,902 --> 00:03:57,137 +并且将实现不常见的任务也变为可能 + +66 +00:03:57,738 --> 00:04:01,175 +把这点做好 +可以缩短开发一款优质 app 要走的路 + +67 +00:04:01,208 --> 00:04:03,210 +并造福所有人 + +68 +00:04:03,243 --> 00:04:05,946 +用户可以获得一致的体验 + +69 +00:04:05,979 --> 00:04:08,715 +就像总是感觉到顺滑的滚动浏览 + +70 +00:04:08,749 --> 00:04:13,420 +而你也可以把时间和精力 +专注在构建你的 app 与众不同的地方 + +71 +00:04:13,453 --> 00:04:16,456 +随着设计的演变 +以及硬件的持续发展 + +72 +00:04:16,490 --> 00:04:20,360 +过去的前沿技术在今天变成了基础 + +73 +00:04:20,394 --> 00:04:23,864 +Objective-C 语言 +AppKit 和 UIKit 框架 + +74 +00:04:23,897 --> 00:04:27,801 +以及 Interface Builder +已经赋能多代开发者 + +75 +00:04:27,835 --> 00:04:30,370 +这些技术是为彼此而构建的 + +76 +00:04:30,404 --> 00:04:33,707 +并将在未来很长的一段时间内 +继续为我们提供良好的服务 + +77 +00:04:33,740 --> 00:04:37,411 +但随着时间推移 +新的抽象成为了必要 + +78 +00:04:37,444 --> 00:04:40,581 +过去一段时间 +大家已经看到我们在很努力地定义 + +79 +00:04:40,614 --> 00:04:44,985 +下一代紧密集成的语言、框架和工具 + +80 +00:04:45,018 --> 00:04:48,889 +这就是 Swift、SwiftUI 和 +Xcode Previews + +81 +00:04:49,857 --> 00:04:52,459 +在这样的开发平台上紧密集成 + +82 +00:04:52,492 --> 00:04:56,363 +需要这三部分一同设计和演变 + +83 +00:04:56,396 --> 00:04:59,466 +并相互驱动、带动 + +84 +00:04:59,499 --> 00:05:04,771 +Swift Result Builder 的灵感 +来自于 SwiftUI 的组成结构 + +85 +00:05:04,805 --> 00:05:09,910 +SwiftUI 的声明式视图 +背靠 Swift 值类型 + +86 +00:05:09,943 --> 00:05:15,716 +而 Xcode Previews 是专门为这两者而设计 +也是依靠这两者运行的 + +87 +00:05:15,749 --> 00:05:19,920 +他们之间相辅相成 +带来了我们迄今最优秀的开发平台 + +88 +00:05:19,953 --> 00:05:25,425 +今年 Swift、SwiftUI 和 Xcode +都有精彩的更新 + +89 +00:05:25,459 --> 00:05:27,461 +进一步实现我们的愿景 + +90 +00:05:27,494 --> 00:05:31,765 +让大家更容易地开发出色的 app +并适用于我们所有的软件平台 + +91 +00:05:31,798 --> 00:05:33,934 +而这一切都要从 Swift 开始 + +92 +00:05:33,967 --> 00:05:37,738 +现在请 Swift 团队的 Ben 为大家介绍 + +93 +00:05:39,907 --> 00:05:47,915 +♪ ♪ + +94 +00:05:49,650 --> 00:05:52,920 +Swift 具备了快速、现代与安全的特性 + +95 +00:05:52,953 --> 00:05:55,956 +它结合了强类型语言的速度 + +96 +00:05:55,989 --> 00:05:58,992 +以及易于阅读和编写的表达式语法 + +97 +00:05:59,026 --> 00:06:02,963 +它的设计消除了多种类别的编程错误 + +98 +00:06:02,996 --> 00:06:07,067 +Swift 绝对是在我们各个设备上 +开发 app 的最佳语言 + +99 +00:06:07,901 --> 00:06:09,536 +Swift 以开源形式在 Swift.org 上开发而成 + +100 +00:06:09,570 --> 00:06:13,407 +Swift.org 上有很棒的贡献者 + +101 +00:06:13,440 --> 00:06:15,209 +他们通过 Diversity in Swift + +102 +00:06:15,242 --> 00:06:18,212 +和 Swift Mentorship Program +等倡议互相支持 + +103 +00:06:18,245 --> 00:06:21,515 +并推动 Swift 的发展 +通过相关主题工作小组 + +104 +00:06:21,548 --> 00:06:24,384 +如 Swift on Server +和 C++ 互操作性等 + +105 +00:06:25,352 --> 00:06:27,921 +在过去一年 Swift 变得更加优秀 + +106 +00:06:27,955 --> 00:06:30,224 +包括增强了并发功能 + +107 +00:06:30,257 --> 00:06:33,260 +还推出了让 Swift 更易于读写的升级 + +108 +00:06:33,293 --> 00:06:35,329 +帮你定制工作流的工具 + +109 +00:06:35,362 --> 00:06:37,931 +以及惊人的后台性能提升 + +110 +00:06:37,965 --> 00:06:39,466 +这一切始于去年 + +111 +00:06:39,499 --> 00:06:41,535 +我们推出 Swift 并发功能的时候 + +112 +00:06:42,169 --> 00:06:47,307 +Swift 并发功能 +极大地简化了并行运行代码的读写 + +113 +00:06:47,341 --> 00:06:50,777 +仅第一年就在 App Store 中获得 +超过 40000 个 app 采用 + +114 +00:06:50,811 --> 00:06:52,779 +这可说是一项巨大的成就 + +115 +00:06:53,247 --> 00:06:57,918 +因为这对你的 app 代码库来说 +是一项根本且重要的提升 + +116 +00:06:57,951 --> 00:07:00,420 +所以现在可以将具有 Swift 并发的代码 + +117 +00:07:00,454 --> 00:07:04,424 +部署到过去三年内发布的 +所有操作系统上 + +118 +00:07:04,458 --> 00:07:08,529 +Swift 并发功能还带来了异步序列 + +119 +00:07:08,562 --> 00:07:11,231 +今年更为大家带来了全新的开源包 + +120 +00:07:11,265 --> 00:07:15,569 +将为 Swift 丰富的现有序列算法 +带来并发支持 + +121 +00:07:15,602 --> 00:07:17,938 +这称为异步算法 + +122 +00:07:17,971 --> 00:07:23,410 +例如 Swift 的序列协议支持 zip 算法 +可将两个序列组合在一起 + +123 +00:07:23,443 --> 00:07:28,081 +而异步算法则可以 +将两个异步序列组合在一起 + +124 +00:07:28,115 --> 00:07:31,885 +因为异步序列是直接集成在 Swift 语言中 + +125 +00:07:31,919 --> 00:07:34,755 +所以它们使用的是如“for”循环 +为大家所熟悉的结构 + +126 +00:07:34,788 --> 00:07:36,823 +而由于有 async/await 语法 + +127 +00:07:36,857 --> 00:07:38,825 +这看起来就像普通的直线代码 + +128 +00:07:38,859 --> 00:07:42,496 +你还可以使用熟悉的 try/catch 匹配符 +处理问题 + +129 +00:07:42,529 --> 00:07:46,633 +如网络上异步数据流的网络故障 + +130 +00:07:46,667 --> 00:07:49,369 +异步序列的一个关键之处在于 + +131 +00:07:49,403 --> 00:07:52,206 +它们是如何随着时间的推移传递数据值 + +132 +00:07:52,739 --> 00:07:57,311 +Swift 现在包含一套新的时钟类型 +用于表示时间单位 + +133 +00:07:57,344 --> 00:08:01,682 +而异步算法则在此基础上 +提供多种基于时间的算法 + +134 +00:08:01,715 --> 00:08:03,183 +就像这里的 throttle + +135 +00:08:03,217 --> 00:08:06,787 +可以减慢序列的更新 + +136 +00:08:06,820 --> 00:08:11,191 +Swift 的并发模型旨在让异步代码 + +137 +00:08:11,225 --> 00:08:13,961 +像同步代码一样简便且安全地进行编写 + +138 +00:08:13,994 --> 00:08:16,864 +其中很重要的一部分是 +Swift 的 actor 模型 + +139 +00:08:16,897 --> 00:08:19,800 +actor 让你可以使用线程安全 + +140 +00:08:19,833 --> 00:08:23,337 +并发执行的代码隔离数据 + +141 +00:08:23,370 --> 00:08:27,741 +Swift 可防止你意外于并行线程之间分享该状态 + +142 +00:08:27,774 --> 00:08:30,310 +定义一个主要的错误来源 + +143 +00:08:31,211 --> 00:08:35,649 +通过 async/await 即可简单高效地 +在不同 actors 之间传递信息 + +144 +00:08:35,682 --> 00:08:39,453 +现在 Swift 通过 +distributed actors + +145 +00:08:39,486 --> 00:08:41,221 +让 actor 隔离更进一步 + +146 +00:08:41,255 --> 00:08:45,859 +distributed actors 可在多个进程 +或设备间通信 + +147 +00:08:45,893 --> 00:08:48,929 +用“distributed”关键词标记 + +148 +00:08:48,962 --> 00:08:51,431 +那些可以远程访问的 actors 和方法 + +149 +00:08:51,465 --> 00:08:54,535 +无论是在你 Mac 上的独立进程之间 + +150 +00:08:54,568 --> 00:08:56,904 +还是不同设备间的点对点通信 + +151 +00:08:56,937 --> 00:09:00,541 +亦或者是从一个设备 +与你用 Swift on Server 编写的后端对话 + +152 +00:09:01,909 --> 00:09:06,079 +就像 actor 可以帮助 Swift +按照指定顺序访问你的数据来访问它们 + +153 +00:09:06,113 --> 00:09:09,349 +distributed actors +使用一种可插拔运输机制 + +154 +00:09:09,383 --> 00:09:12,553 +帮助 Swift 让数据在跨进程的场景可用 + +155 +00:09:12,819 --> 00:09:15,622 +Swift 编译器随后可以执行检查 + +156 +00:09:15,656 --> 00:09:19,159 +确保 distributed 环境中的行为是正确的 + +157 +00:09:19,193 --> 00:09:22,863 +让你可以继续开发你想要的功能 + +158 +00:09:23,297 --> 00:09:26,400 +distributed actors +和其他并发功能显示出 + +159 +00:09:26,433 --> 00:09:29,870 +Swift 代码的读写可以多么容易 + +160 +00:09:29,903 --> 00:09:33,106 +当增强功能被深度整合在语法中时 + +161 +00:09:33,140 --> 00:09:38,645 +下面由 Ken 来给大家介绍 +Swift 易用性的增强 + +162 +00:09:38,679 --> 00:09:42,316 +字符串是任何编程语言中 +最重要的功能之一 + +163 +00:09:42,349 --> 00:09:45,652 +但处理字符串可能会 +常常让人感到沮丧 + +164 +00:09:46,453 --> 00:09:48,322 +在开发者的工作中 + +165 +00:09:48,355 --> 00:09:53,260 +可能会碰到需要从类似这样的字符串中 +提取信息的时候 + +166 +00:09:53,293 --> 00:09:56,797 +编写解析字符串的代码很容易出错 + +167 +00:09:56,830 --> 00:09:58,799 +需要追踪很多细节 + +168 +00:09:58,832 --> 00:10:01,935 +而且最后生成的代码 +很难读懂及修改 + +169 +00:10:02,803 --> 00:10:06,473 +正则表达式是应对这一挑战的 +强大解决方式 + +170 +00:10:06,507 --> 00:10:09,810 +让你可以描述你期望在字符串中 +看到的匹配符 + +171 +00:10:09,843 --> 00:10:13,914 +并说明你想抓取哪些信息 + +172 +00:10:13,947 --> 00:10:20,387 +今年 Swift 将大幅提升 +有关正则表达式的开发者体验 + +173 +00:10:20,420 --> 00:10:23,390 +首先是推出一个 +全新的正则表达式字面值 + +174 +00:10:24,558 --> 00:10:26,393 +它们直接内置于语言当中 + +175 +00:10:26,426 --> 00:10:28,862 +Swift 编译器可以检查其是否正确 + +176 +00:10:28,896 --> 00:10:31,665 +在你用正则表达式提取信息时 + +177 +00:10:31,698 --> 00:10:34,134 +它们会解锁 Swift 类型系统的力量 + +178 +00:10:34,168 --> 00:10:39,206 +并且它们充分利用了 Swift +一流的 Unicode 支持 + +179 +00:10:39,239 --> 00:10:40,908 +我们一起来看一看 + +180 +00:10:40,941 --> 00:10:42,609 +我在开发一款叫 Food Truck 的 app + +181 +00:10:42,643 --> 00:10:46,413 +它可以管理从接单到追踪销售的所有环节 + +182 +00:10:46,446 --> 00:10:49,383 +有些订单是以字符串的形式出现的 +充满了数据 + +183 +00:10:49,416 --> 00:10:53,120 +正则表达式特别适合 +从中提取我想要的信息 + +184 +00:10:53,153 --> 00:10:56,857 +而在 Playground 中进行实验 +再合适不过了 + +185 +00:10:56,890 --> 00:10:58,926 +我先创建一个正则表达式字面值 + +186 +00:11:00,227 --> 00:11:02,229 +现在输入表达式 + +187 +00:11:02,262 --> 00:11:04,298 +提取下单人信息 + +188 +00:11:04,331 --> 00:11:05,866 +甜甜圈类型 + +189 +00:11:05,899 --> 00:11:07,968 +以及甜甜圈数量 + +190 +00:11:08,001 --> 00:11:10,771 +在我输入时 +正则表达式被语法高亮显示 + +191 +00:11:10,804 --> 00:11:14,041 +这有助于我确认表达式是正确的 + +192 +00:11:14,074 --> 00:11:14,942 +现在我来试试看 + +193 +00:11:16,109 --> 00:11:17,978 +使用上面的订单字符串 + +194 +00:11:18,011 --> 00:11:20,347 +并寻找正则表达式的第一个匹配项 + +195 +00:11:21,481 --> 00:11:24,318 +当我运行 Playground 时 +就可以通过内联结果 + +196 +00:11:24,351 --> 00:11:28,288 +看到正则表达式具体匹配到了 +字符串的哪些部分 + +197 +00:11:28,322 --> 00:11:31,258 +这里它就找到了我想要的信息 + +198 +00:11:31,291 --> 00:11:34,661 +Swift 的全新正则表达式支持 +并不止这些 + +199 +00:11:34,695 --> 00:11:36,396 +随着字面值变得越来越复杂 + +200 +00:11:36,430 --> 00:11:39,633 +就像这里 +它匹配的是日志文件的一部分 + +201 +00:11:39,666 --> 00:11:43,670 +Swift 提供了一种更好的方式 +来处理这些匹配符 + +202 +00:11:43,704 --> 00:11:45,305 +即正则表达式生成器 + +203 +00:11:46,773 --> 00:11:49,576 +可以很容易地用它把字面值转换为生成器 + +204 +00:11:50,377 --> 00:11:52,179 +现在我得到了代码 + +205 +00:11:52,212 --> 00:11:55,616 +这些代码更易读懂和修改 + +206 +00:11:55,649 --> 00:11:58,418 +我甚至还可以进一步简化它 + +207 +00:11:58,452 --> 00:12:00,854 +这里我在找的是一个十六进制的数字 + +208 +00:12:00,888 --> 00:12:03,390 +我可以用新的 +hexDigitCharacterClass + +209 +00:12:03,423 --> 00:12:06,493 +让我的意图更加明确 + +210 +00:12:06,527 --> 00:12:11,865 +这个生成器语法让我可以 +轻松创建和扩展表达式 + +211 +00:12:11,899 --> 00:12:14,601 +得到我想要的结果 + +212 +00:12:15,102 --> 00:12:19,606 +这就是强大的 Swift 中 +正则表达式所带来的全新开发者体验 + +213 +00:12:20,174 --> 00:12:21,742 +除了字符串语法 + +214 +00:12:21,775 --> 00:12:27,614 +Swift 也在透过对泛型语言特性的改进 +使其变得更加易于读写 + +215 +00:12:27,915 --> 00:12:30,984 +泛型为你每天使用的 Swift 功能提供支持 + +216 +00:12:31,018 --> 00:12:32,152 +比如数组类型 + +217 +00:12:32,186 --> 00:12:35,789 +它可以容纳任何类型的元素 +从字符串到你自定义的类型 + +218 +00:12:35,822 --> 00:12:42,563 +泛型代码使用占位符的概念来代替另一种类型 +可待之后再确定 + +219 +00:12:42,596 --> 00:12:45,432 +通过清除对类型的假设 + +220 +00:12:45,465 --> 00:12:48,068 +你可以更清楚地表达代码的意图 + +221 +00:12:48,101 --> 00:12:50,604 +并使其容易重复使用 + +222 +00:12:50,637 --> 00:12:53,307 +但这也可能使你的代码更难以阅读 + +223 +00:12:53,841 --> 00:12:58,779 +举例来说 如果你想以函数参数的形式 +处理一个宽泛的歌曲集合 + +224 +00:12:58,812 --> 00:13:02,216 +你就需要写出相当多的代码来表达这个意图 + +225 +00:13:03,050 --> 00:13:07,054 +如今在 Swift 中 +编写接受一些歌曲集合的函数 + +226 +00:13:07,087 --> 00:13:12,025 +就像使用关键词 some +告诉 Swift 参数是什么一样简单 + +227 +00:13:12,059 --> 00:13:15,562 +可以用更少的代码表达同样的意思 + +228 +00:13:15,596 --> 00:13:19,166 +在其它情况下 +你可能需要更多的动态行为 + +229 +00:13:19,199 --> 00:13:22,202 +比如这个音乐库的播放列表阵列 + +230 +00:13:22,236 --> 00:13:25,739 +它可能需要包含不同类型的歌曲集合 + +231 +00:13:25,772 --> 00:13:28,509 +譬如说歌曲集或歌曲阵列 + +232 +00:13:28,542 --> 00:13:31,278 +新的关键词 any +就可以在这种情况下帮上大忙了 + +233 +00:13:31,311 --> 00:13:33,547 +关键词 any 内置于 Swift 当中 + +234 +00:13:33,580 --> 00:13:38,018 +让你可以表达 +一个可以容纳任何歌曲集合的类型 + +235 +00:13:38,051 --> 00:13:41,355 +它也与通用函数无缝衔接 + +236 +00:13:41,388 --> 00:13:45,325 +透过采用熟悉的语法和更自然的关键词 + +237 +00:13:45,359 --> 00:13:48,662 +使用 Swift 编写泛型代码将更加轻而易举 + +238 +00:13:48,695 --> 00:13:52,466 +与 Swift 语言内置功能同等重要的 + +239 +00:13:52,499 --> 00:13:54,868 +就是为它而构建的相关工具了 + +240 +00:13:54,902 --> 00:13:58,772 +Swift Package Manager +让你可以轻松处理 app 的依赖项 + +241 +00:13:58,805 --> 00:14:01,074 +并可利用来自世界各地开发者 + +242 +00:14:01,108 --> 00:14:03,710 +所发布的优秀软件包 + +243 +00:14:03,744 --> 00:14:07,948 +迄今为止 这些开发者们 +已经发布了数以千计的 Swift 软件包 + +244 +00:14:07,981 --> 00:14:11,652 +提供代码来解决从验证到网络服务 +再到数据管理 + +245 +00:14:11,685 --> 00:14:14,955 +专业图形和可重复使用的 UI 组件 +各种疑难杂症 + +246 +00:14:14,988 --> 00:14:17,457 +今年 Swift Package Manager + +247 +00:14:17,491 --> 00:14:22,896 +将新增全新的 Package Plugins +来扩充你创建和构建代码的方式 + +248 +00:14:22,930 --> 00:14:26,400 +Plugins 是可以如同任何其他依赖项 + +249 +00:14:26,433 --> 00:14:28,902 +轻易地添加进项目的 Swift 软件包 + +250 +00:14:28,936 --> 00:14:32,339 +它们在运行新的 checkout 时 +自动下载并构建 + +251 +00:14:32,372 --> 00:14:35,008 +不过它们不是你 app 中的代码 + +252 +00:14:35,042 --> 00:14:36,743 +而是帮助你构建 app 的代码 + +253 +00:14:37,678 --> 00:14:41,281 +Package Plugins 可从命令行 +或 Xcode 中调用 + +254 +00:14:41,315 --> 00:14:44,585 +可以是构建阶段的一部分 +也可按需调用 + +255 +00:14:44,618 --> 00:14:46,653 +它们在沙盒环境中运行 + +256 +00:14:46,687 --> 00:14:50,157 +在读取或修改代码前会请求你的许可 + +257 +00:14:50,858 --> 00:14:54,428 +使用 Package Plugins 扩展你的工作流 +将可拥有无限的可能性 + +258 +00:14:54,461 --> 00:14:57,064 +你可以用它们检查和格式化你的代码 + +259 +00:14:57,097 --> 00:14:58,498 +并使用像 SwiftLint 和 SwiftFormat +这样的软件包 + +260 +00:14:58,532 --> 00:15:00,901 +来确保你的代码符合团队的风格指南 + +261 +00:15:00,934 --> 00:15:04,938 +或者用 Sourcery 等工具在构建时 +自动生成源代码 + +262 +00:15:04,972 --> 00:15:07,174 +或者做任何其他有助于你完成工作的事 + +263 +00:15:07,808 --> 00:15:10,677 +Package Plugins 可以 +很好地扩展 Xcode + +264 +00:15:10,711 --> 00:15:12,913 +仅需写一点 Swift 代码 + +265 +00:15:12,946 --> 00:15:14,548 +你可以透过以下两种方式来实现 + +266 +00:15:14,581 --> 00:15:17,484 +有按需使用的命令插件 + +267 +00:15:17,518 --> 00:15:20,654 +还有构建插件 +供你随时需进行项目构建时使用 + +268 +00:15:20,687 --> 00:15:22,689 +回到我们的 Food Truck app + +269 +00:15:22,723 --> 00:15:24,992 +这里是我创建的一个命令插件的代码 + +270 +00:15:26,627 --> 00:15:29,897 +我的团队对代码有种独特的审美 + +271 +00:15:29,930 --> 00:15:32,733 +我们喜欢让导入的语句按字符串长度排序 + +272 +00:15:32,766 --> 00:15:34,768 +由短到长 + +273 +00:15:34,801 --> 00:15:38,639 +由于 Package Plugins +就是用于定制和控制的 + +274 +00:15:38,672 --> 00:15:42,075 +我们创建了一个命令插件 +采用 SwiftFormat 来处理这个需求 + +275 +00:15:43,110 --> 00:15:45,812 +它可以找到所有本地修改的文件 + +276 +00:15:45,846 --> 00:15:48,148 +然后对导入进行排序 + +277 +00:15:48,182 --> 00:15:52,252 +这是一个我正在编辑的文件 +最上面的导入是尚未排序的 + +278 +00:15:52,286 --> 00:15:54,988 +我在整个项目中运行命令插件 + +279 +00:15:55,022 --> 00:15:58,525 +我可以选择任何数量的运行目标 +这里我就在全部目标上运行 + +280 +00:15:59,059 --> 00:16:01,295 +如果我愿意 +甚至还可以审查命令插件的代码 + +281 +00:16:01,328 --> 00:16:02,796 +我准备好了 +直接来运行这个命令 + +282 +00:16:03,564 --> 00:16:06,466 +就这么简单 +插件就会在我的文件上运行 + +283 +00:16:07,100 --> 00:16:10,070 +它找到了所有本地修改的文件 + +284 +00:16:10,103 --> 00:16:12,506 +然后以长度排序 + +285 +00:16:12,539 --> 00:16:15,542 +使用插件 能做的可不止是格式化 + +286 +00:16:15,576 --> 00:16:18,412 +你可以生成源代码、使用 git + +287 +00:16:18,445 --> 00:16:21,648 +甚至是使用自己的自定义错误和警告提示 + +288 +00:16:21,682 --> 00:16:25,052 +我还有另一个插件 +可以确保把我的代码很好被记录管理 + +289 +00:16:25,085 --> 00:16:29,122 +这是一个构建插件 +基于开源的 SwiftLint 软件包 + +290 +00:16:29,890 --> 00:16:33,727 +所以当我在构建的时候 +就可以轻松看到代码中 + +291 +00:16:33,760 --> 00:16:36,196 +所有需要添加文档的地方 + +292 +00:16:36,230 --> 00:16:40,000 +而且构建插件将一直延伸到 Xcode Cloud + +293 +00:16:40,033 --> 00:16:42,503 +可以作为每个构建的一部分运行 + +294 +00:16:42,536 --> 00:16:44,271 +有了 Swift Package Plugins + +295 +00:16:44,304 --> 00:16:46,607 +我和我的团队可以在本地和 Xcode Cloud + +296 +00:16:46,640 --> 00:16:49,576 +创建我们的命令 以及自定义我们的构建 + +297 +00:16:49,610 --> 00:16:51,945 +并与他人分享这些插件 + +298 +00:16:51,979 --> 00:16:55,182 +这仅需透过几行强大的 Swift 代码即可完成 + +299 +00:16:55,215 --> 00:16:57,618 +这就是 Package Plugins 的简要介绍 + +300 +00:16:57,651 --> 00:17:00,220 +它有各种方式来大幅提升你的开发工作流 + +301 +00:17:00,254 --> 00:17:04,324 +最后 Swift 还迎来了一些惊人的后台改进 + +302 +00:17:04,358 --> 00:17:06,293 +现在能以前所未有的速度构建 Swift 项目 + +303 +00:17:06,326 --> 00:17:10,864 +依靠新的并行化大幅提升链接时间可快达两倍 + +304 +00:17:10,898 --> 00:17:12,733 +并且 Swift 并发运行时间 + +305 +00:17:12,766 --> 00:17:15,502 +现在更紧密地与软件系统整合 + +306 +00:17:15,536 --> 00:17:18,672 +更好地确保异步任务的优先级 + +307 +00:17:18,705 --> 00:17:21,175 +帮助你的 app 保持高效和及时响应 + +308 +00:17:21,208 --> 00:17:26,413 +最后 用 Swift 编写的 app +在 iOS 16 上启动时间大大缩短 + +309 +00:17:26,446 --> 00:17:30,918 +像是 Lyft 和 Airbnb 等 app 的启动速度提升 +可仅为过去的一半 + +310 +00:17:30,951 --> 00:17:33,053 +这得益于动态链接器的改进 + +311 +00:17:33,086 --> 00:17:35,055 +有了这些后台的提升 + +312 +00:17:35,088 --> 00:17:36,723 +工具的新能力 + +313 +00:17:36,757 --> 00:17:39,760 +更加易于读写的演进版语法 + +314 +00:17:39,793 --> 00:17:41,628 +以及对并发功能的改进 + +315 +00:17:41,662 --> 00:17:44,665 +现在正是用 Swift 开发的最佳时机 + +316 +00:17:44,698 --> 00:17:49,636 +Swift 绝对是最佳语言用来 +开发跨我们所有设备的 app + +317 +00:17:49,670 --> 00:17:53,473 +但语言只是你构建优质 app 所需的一部分 + +318 +00:17:53,507 --> 00:17:57,477 +你必须把语言和强大的 +用户界面框架搭配起来 + +319 +00:17:57,511 --> 00:17:59,646 +下面由 Eliza 来给大家进一步说明 + +320 +00:17:59,680 --> 00:18:02,649 +强大的 UI 框架可以提供抽象 + +321 +00:18:02,683 --> 00:18:05,152 +让你更轻松地描述界面 + +322 +00:18:05,185 --> 00:18:08,188 +填充数据 以及保持更新 + +323 +00:18:08,222 --> 00:18:10,490 +它应该具有很好的扩展性 +适用于不同的复杂环境 + +324 +00:18:10,524 --> 00:18:13,060 +而且 它应该是为你的目标平台设计的 + +325 +00:18:13,093 --> 00:18:15,829 +让你可以充分利用设备的能力 + +326 +00:18:15,863 --> 00:18:20,868 +UI 框架应该助你一臂之力 +使你的 app 感到亲切且直观 + +327 +00:18:20,901 --> 00:18:23,704 +它应该让你可以轻松创建标准控制件 + +328 +00:18:23,737 --> 00:18:25,472 +和本地交互匹配模式 + +329 +00:18:25,506 --> 00:18:28,075 +并支持高级定制功能 + +330 +00:18:28,108 --> 00:18:30,477 +它还需要有富有表现力的 API + +331 +00:18:30,511 --> 00:18:33,413 +让你可以快速建立你的想法的原型 + +332 +00:18:33,447 --> 00:18:35,849 +并在一系列设备上看到结果 + +333 +00:18:36,416 --> 00:18:38,986 +SwiftUI 就可以提供这一切 且不止于此 + +334 +00:18:39,019 --> 00:18:42,456 +与 Swift 一样 SwiftUI 的设计旨在 + +335 +00:18:42,489 --> 00:18:44,491 +提供开发 app 的最佳方式 + +336 +00:18:44,525 --> 00:18:48,295 +它采用声明式语法 易于读写 + +337 +00:18:48,328 --> 00:18:52,766 +你只需描述界面的样子 而不是如何构建界面 + +338 +00:18:53,767 --> 00:18:56,336 +而这就是 SwiftUI 可发挥的空间 + +339 +00:18:56,370 --> 00:18:59,439 +为每个平台提供智能默认值 + +340 +00:18:59,473 --> 00:19:02,776 +SwiftUI 会自动保持界面的更新 + +341 +00:19:02,809 --> 00:19:05,412 +确保界面随底层数据模型的改动而变化 + +342 +00:19:05,445 --> 00:19:08,749 +因此你的 app 的 UI +永远不会陷入不一致的状态 + +343 +00:19:09,583 --> 00:19:13,153 +SwiftUI 为你处理所有这些细节 + +344 +00:19:13,187 --> 00:19:17,224 +这样你就可以把时间和精力专注在 +构建你的 app 与众不同的地方 + +345 +00:19:17,257 --> 00:19:20,861 +编写新的 UI 框架是一项巨大的工程 + +346 +00:19:20,894 --> 00:19:25,432 +自从推出 SwiftUI 以来 +我们持续扩大 SwiftUI 的 API 类型 + +347 +00:19:25,465 --> 00:19:27,000 +且都是基于大家的反馈 + +348 +00:19:27,668 --> 00:19:33,006 +今年 我们将让你在现有的各种 app 中 +逐步采用 SwiftUI 变得更容易 + +349 +00:19:33,040 --> 00:19:37,211 +同时我们还对它的性能和灵活性 +带来可观的提升 + +350 +00:19:37,244 --> 00:19:39,613 +首先是 app 导航 + +351 +00:19:39,646 --> 00:19:41,949 +一直以来 使用 SwiftUI + +352 +00:19:41,982 --> 00:19:46,286 +即可轻松创建许多 app 中 +常见的导航层次结构 + +353 +00:19:46,320 --> 00:19:49,523 +SwiftUI 在今年将会扩展这方面的支持 + +354 +00:19:49,556 --> 00:19:52,125 +推出全新的导航 API + +355 +00:19:52,693 --> 00:19:56,730 +新的导航 API 可以让你更容易地创建 + +356 +00:19:56,763 --> 00:19:59,466 +最适合你 app 需求的导航风格 + +357 +00:19:59,499 --> 00:20:03,604 +通过对 app 视图呈现的强大编程控制 + +358 +00:20:03,637 --> 00:20:06,373 +你可以轻松保存或选择恢复 + +359 +00:20:06,406 --> 00:20:10,177 +甚至替换导航栏的全部内容 + +360 +00:20:10,210 --> 00:20:13,313 +这在处理重要行为时十分有用 + +361 +00:20:13,347 --> 00:20:15,549 +如设置 app 的启动状态 + +362 +00:20:15,582 --> 00:20:18,385 +管理尺寸类别间的过渡 + +363 +00:20:18,418 --> 00:20:20,053 +以及对深度链接的响应 + +364 +00:20:20,988 --> 00:20:23,724 +SwiftUI 的另一项巨大改进 + +365 +00:20:23,757 --> 00:20:26,927 +是可以让你更好地控制 app 界面的布局 + +366 +00:20:27,661 --> 00:20:31,899 +许多 app 的界面可以用 SwiftUI 的 + +367 +00:20:31,932 --> 00:20:34,701 +水平或垂直元素堆栈模型来描述 + +368 +00:20:34,735 --> 00:20:37,404 +虽然这个模型可以处理很多常见布局 + +369 +00:20:37,437 --> 00:20:40,174 +但有时你需要更加灵活的工具 + +370 +00:20:40,207 --> 00:20:43,076 +今年 我们将加入全新的 grid API + +371 +00:20:43,110 --> 00:20:48,415 +让你轻松设置多行与多列排列的网格布局 + +372 +00:20:48,448 --> 00:20:50,951 +透过全新的自定义布局 API + +373 +00:20:50,984 --> 00:20:53,987 +将可让你的布局更上层楼 + +374 +00:20:54,021 --> 00:20:56,990 +自定义布局 API 带来了灵活性 + +375 +00:20:57,024 --> 00:20:59,593 +让你可以随心所欲设置你想要的布局 + +376 +00:20:59,626 --> 00:21:01,862 +例如 你可以创建流动式布局 + +377 +00:21:01,895 --> 00:21:05,299 +让视图像报纸内容一样排列 + +378 +00:21:05,332 --> 00:21:08,402 +当需要更多空间时 +将内容自动延伸至下一栏 + +379 +00:21:08,435 --> 00:21:12,406 +或者你可以创建放射式布局 +把视图做成圆环 + +380 +00:21:12,439 --> 00:21:13,941 +就像手表表盘的数字一样 + +381 +00:21:14,675 --> 00:21:19,379 +自定义布局 API 让你可以 +轻松重复使用你的布局逻辑 + +382 +00:21:19,413 --> 00:21:22,182 +使你的视图代码更简单 更易读 + +383 +00:21:22,216 --> 00:21:25,185 +SwiftUI 还在不断发展 + +384 +00:21:25,219 --> 00:21:27,521 +为你提供更多类型的界面元素 + +385 +00:21:27,554 --> 00:21:30,591 +比如通过半屏表单来展示二级页面 + +386 +00:21:30,624 --> 00:21:32,593 +并可以上下滑动 + +387 +00:21:32,626 --> 00:21:37,397 +有助于在较小的屏幕快速获取信息 + +388 +00:21:37,431 --> 00:21:39,933 +例如 SwiftUI 现在支持共享表单 + +389 +00:21:39,967 --> 00:21:41,668 +让你的 app 可以轻松利用 + +390 +00:21:41,702 --> 00:21:44,838 +用户设备上的所有共享扩展 + +391 +00:21:44,872 --> 00:21:49,009 +全新的 Transferable 协议支持共享表单 + +392 +00:21:49,042 --> 00:21:52,746 +并为传输 app 数据引入了一个安全类型的 API + +393 +00:21:53,747 --> 00:21:58,485 +为了让你更轻松地在现有 app 中 +逐步采用 SwiftUI + +394 +00:21:58,519 --> 00:22:03,390 +我们还推出了一个可以托管 SwiftUI 视图的 +特殊集合视图单元格 + +395 +00:22:03,423 --> 00:22:06,493 +如果你在 UIKit app 中已有一个集合视图 + +396 +00:22:06,527 --> 00:22:10,597 +那你现在就可以使用 SwiftUI 的声明式语法 +编写自定义单元格 + +397 +00:22:10,631 --> 00:22:15,102 +这些单元格与 UIKit 紧密集成 +支持轻扫动作 + +398 +00:22:15,135 --> 00:22:19,072 +单元格背景 +以及 UICollectionView 的其他功能 + +399 +00:22:19,106 --> 00:22:21,942 +今天 我们还要推出一个全新的框架 + +400 +00:22:21,975 --> 00:22:23,510 +更好地补充 SwiftUI + +401 +00:22:23,544 --> 00:22:26,880 +来让你能够呈现更多的界面 + +402 +00:22:26,914 --> 00:22:28,882 +下面请 Jo 给大家介绍 + +403 +00:22:28,916 --> 00:22:31,051 +数据在当今的世界随处可见 + +404 +00:22:31,084 --> 00:22:33,287 +数据可以帮助我们理解并做出决策 + +405 +00:22:33,320 --> 00:22:34,888 +以及发现新的视角 + +406 +00:22:34,922 --> 00:22:37,558 +一个精心设计、容易获取的数据可视化呈现 + +407 +00:22:37,591 --> 00:22:39,893 +能够以清晰自然的方式 + +408 +00:22:39,927 --> 00:22:42,462 +向用户传达复杂的信息 + +409 +00:22:42,496 --> 00:22:44,631 +赋能于他们的日常生活 + +410 +00:22:45,465 --> 00:22:48,535 +比如帮助显示他们健康的变化趋势 + +411 +00:22:48,569 --> 00:22:51,672 +强调他们个人目标的进度 + +412 +00:22:51,705 --> 00:22:53,640 +以及协助他们为未来做好准备 + +413 +00:22:54,308 --> 00:22:57,144 +今天 我们要推出一个新的框架 + +414 +00:22:57,177 --> 00:23:00,414 +帮助你的用户来解读 app 中的数据 + +415 +00:23:00,447 --> 00:23:03,717 +这就是 Swift Charts + +416 +00:23:03,750 --> 00:23:07,187 +Swift Charts 是一个可高度自定义的图表框架 + +417 +00:23:07,221 --> 00:23:08,889 +它基于 SwiftUI + +418 +00:23:08,922 --> 00:23:12,626 +可以轻松创建精美的可视化图表 + +419 +00:23:12,659 --> 00:23:15,762 +它使用与 SwiftUI 相同的声明式语法 + +420 +00:23:15,796 --> 00:23:19,433 +可轻松读写传达视觉信息的代码 + +421 +00:23:20,400 --> 00:23:23,170 +Swift Charts 让你可以自定义信息的呈现方式 + +422 +00:23:23,203 --> 00:23:25,439 +最大程度地符合你 app 的需求 + +423 +00:23:25,472 --> 00:23:28,008 +创建各种图表 从线图和柱状图 + +424 +00:23:28,041 --> 00:23:32,279 +到更复杂的热力图和流线图 + +425 +00:23:32,312 --> 00:23:34,147 +以及很多其他类型的图表 + +426 +00:23:35,182 --> 00:23:38,118 +由于 Swift Charts +是在 SwiftUI 的基础上所建立 + +427 +00:23:38,151 --> 00:23:40,654 +所以图表提供了非常好的辅助功能支持 + +428 +00:23:40,687 --> 00:23:43,924 +例如绝佳的、开箱即用的旁白体验 + +429 +00:23:43,957 --> 00:23:46,059 +并可轻松自定义 + +430 +00:23:46,093 --> 00:23:49,997 +以 SwiftUI 为基础也意味着 +你可以对图表进行动画处理 + +431 +00:23:50,030 --> 00:23:53,367 +给 app 提供你想要的外观和感觉 + +432 +00:23:53,400 --> 00:23:57,704 +当然 Swift Charts 支持我们所有的设备 + +433 +00:23:57,738 --> 00:23:59,806 +回到我们的 Food Truck app + +434 +00:23:59,840 --> 00:24:01,875 +这里就是在全面重新设计过的 Xcode 预览区中 + +435 +00:24:01,909 --> 00:24:05,312 +呈现美观的全新 Swift Charts 图表 + +436 +00:24:05,345 --> 00:24:09,349 +同时我还用了新的多列 SwiftUI 表格视图 + +437 +00:24:09,383 --> 00:24:12,719 +我来给大家展示一下 +创建这个图表有多么容易 + +438 +00:24:12,753 --> 00:24:14,087 +在我滚动页面时 + +439 +00:24:14,121 --> 00:24:17,357 +你可以在源代码编辑器中 +看到这个很棒的全新结构化标题 + +440 +00:24:17,391 --> 00:24:20,227 +这让我可以很容易看到我正在编辑的地方 + +441 +00:24:21,261 --> 00:24:22,696 +这里是图表的代码 + +442 +00:24:22,729 --> 00:24:26,600 +这其实是一个堆叠的柱状图 +但真的是看不出来差别 + +443 +00:24:26,633 --> 00:24:29,503 +我们来给每种甜甜圈一个不同的颜色 + +444 +00:24:30,871 --> 00:24:34,341 +如果我们把每种甜甜圈的条柱 +并排放在一起 + +445 +00:24:34,374 --> 00:24:36,677 +可能会更容易比较各种甜甜圈 + +446 +00:24:37,945 --> 00:24:40,681 +我非常喜欢的是 进行这些大的改动 + +447 +00:24:40,714 --> 00:24:43,050 +仅需几个简单的 modifier + +448 +00:24:43,083 --> 00:24:45,552 +我们还可以自定义样式 + +449 +00:24:45,586 --> 00:24:48,522 +让这些条柱对应甜甜圈的颜色 + +450 +00:24:48,555 --> 00:24:52,125 +我们甚至可以用另一个 modifier +给条柱添加注解 + +451 +00:24:53,327 --> 00:24:54,795 +看起来很棒 + +452 +00:24:54,828 --> 00:24:56,730 +预览现在默认是实时的 + +453 +00:24:56,763 --> 00:24:59,533 +所以我可以立即与视图进行互动 + +454 +00:24:59,566 --> 00:25:01,268 +我来更改一下排序 + +455 +00:25:01,301 --> 00:25:04,204 +看看条柱精美的动画 + +456 +00:25:04,238 --> 00:25:07,074 +而所有繁重的工作 +都是由 Swift Charts 来完成的 + +457 +00:25:07,107 --> 00:25:08,976 +我们来抓取更多数据 + +458 +00:25:09,009 --> 00:25:12,980 +图和表都会自动随模型的变化更新 + +459 +00:25:13,013 --> 00:25:17,184 +图甚至会重新计算 Y 轴 +反映出新的总计值 + +460 +00:25:17,217 --> 00:25:19,019 +让我再给大家看一张图 + +461 +00:25:19,052 --> 00:25:22,556 +我在这里做了一个线图 +我们把它添加到视图里 + +462 +00:25:22,589 --> 00:25:25,025 +我直接跳到实施 + +463 +00:25:25,058 --> 00:25:29,096 +Swift Charts 的线图有些很酷的选项 + +464 +00:25:29,129 --> 00:25:31,865 +我们可以为每种甜甜圈添加符号 + +465 +00:25:31,899 --> 00:25:34,134 +可以为线添加注解 + +466 +00:25:34,168 --> 00:25:38,672 +甚至可以采用各种差值策略平滑曲线 + +467 +00:25:38,705 --> 00:25:40,941 +我们这里用 catmullRom + +468 +00:25:40,974 --> 00:25:43,443 +最后 通过提供我自己的映射 + +469 +00:25:43,477 --> 00:25:45,579 +覆盖图表比例样式 + +470 +00:25:45,612 --> 00:25:49,082 +这样会使图表与 app 的配色方案更吻合 + +471 +00:25:49,116 --> 00:25:50,584 +非常棒 + +472 +00:25:50,617 --> 00:25:53,320 +重新设计的预览区使我比以往更容易看到 + +473 +00:25:53,353 --> 00:25:56,056 +我的视图在不同环境中的样子 + +474 +00:25:56,089 --> 00:25:58,292 +通过点击画布上的按钮 + +475 +00:25:58,325 --> 00:26:01,094 +我可以看到深色和浅色模式下的视图 + +476 +00:26:01,128 --> 00:26:04,631 +甚至可以看到所有的屏幕方向中的布局 + +477 +00:26:04,665 --> 00:26:07,367 +一个额外的预览都不用添加 + +478 +00:26:07,401 --> 00:26:09,870 +我们来放大看看横向模式 + +479 +00:26:09,903 --> 00:26:13,040 +看起来我的 UI 有点问题 + +480 +00:26:13,073 --> 00:26:14,441 +有几个控制按钮在屏幕之外 + +481 +00:26:14,474 --> 00:26:17,578 +而且图表的长宽比也很别扭 + +482 +00:26:17,611 --> 00:26:20,881 +我们来看看这个布局是在哪里描述的 + +483 +00:26:20,914 --> 00:26:24,218 +这里这些视图在一个隐含的 VStack 里 + +484 +00:26:25,352 --> 00:26:28,922 +今年 SwiftUI 中有些强大的全新 API + +485 +00:26:28,956 --> 00:26:31,391 +可以创建更多的灵活布局 + +486 +00:26:31,425 --> 00:26:34,027 +这里我来用 ViewThatFits + +487 +00:26:34,061 --> 00:26:36,263 +这会根据可用空间 + +488 +00:26:36,296 --> 00:26:39,266 +在垂直和水平堆栈之间切换 + +489 +00:26:40,667 --> 00:26:42,302 +这样看起来好多了 + +490 +00:26:42,336 --> 00:26:43,670 +现在把这个视图连接起来 + +491 +00:26:43,704 --> 00:26:45,639 +从主屏幕导航到这里 + +492 +00:26:46,673 --> 00:26:49,810 +我用的是 SwiftUI 全新的导航分屏浏览 + +493 +00:26:49,843 --> 00:26:51,612 +操作起来非常方便 + +494 +00:26:51,645 --> 00:26:55,082 +分屏浏览有一个侧边栏 可以追踪选择 + +495 +00:26:55,115 --> 00:27:00,521 +它还有个 NavigationStack +其内容随着侧边栏选择的变化进而调整 + +496 +00:27:00,554 --> 00:27:01,922 +我来跳到侧边栏 + +497 +00:27:01,955 --> 00:27:04,992 +为我们的甜甜圈冠军视图 +添加导航链接 + +498 +00:27:05,025 --> 00:27:07,494 +然后 就可以在这个互动预览中试试看 + +499 +00:27:08,262 --> 00:27:10,664 +我想在横向模式中看一下分屏浏览 + +500 +00:27:10,697 --> 00:27:12,933 +那我就用新的画布设置 + +501 +00:27:12,966 --> 00:27:15,202 +来旋转实时预览 + +502 +00:27:15,235 --> 00:27:16,837 +很棒 + +503 +00:27:16,870 --> 00:27:19,406 +我对它在 iPad 上的效果很满意 + +504 +00:27:19,439 --> 00:27:21,675 +但我现在想把它也带到 Mac 上 + +505 +00:27:21,708 --> 00:27:24,978 +而这只需点击几下即可做到 + +506 +00:27:25,012 --> 00:27:27,481 +我想充分利用 Mac SDK + +507 +00:27:27,514 --> 00:27:28,949 +所以我在这里使用原生 + +508 +00:27:31,218 --> 00:27:33,554 +因为我的 app 背后只有一个目标 + +509 +00:27:33,587 --> 00:27:35,589 +我可以共用几乎所有的代码 + +510 +00:27:35,622 --> 00:27:39,026 +而 SwiftUI 会让我的 app +在每个平台上看起来都很棒 + +511 +00:27:39,059 --> 00:27:42,429 +我也可以轻松添加针对不同设备的功能 + +512 +00:27:42,462 --> 00:27:45,299 +对 Mac app 我们来添加 +一个 menuBarExtra + +513 +00:27:45,332 --> 00:27:47,267 +这就是你屏幕右上角那些 + +514 +00:27:47,301 --> 00:27:49,002 +有用的小图标 + +515 +00:27:49,036 --> 00:27:52,072 +比如 Wi-Fi 和聚焦 + +516 +00:27:52,105 --> 00:27:55,142 +SwiftUI 为此提供了新的 API + +517 +00:27:55,175 --> 00:27:57,244 +我只需把它添加到我 app 的主体 + +518 +00:27:57,277 --> 00:27:59,146 +现在我们来为 Mac 运行试试看 + +519 +00:28:02,683 --> 00:28:06,553 +我们的甜甜圈冠军视图在 Mac 上 +看起来很棒 + +520 +00:28:06,587 --> 00:28:08,589 +这里就是那个 menuBarExtra + +521 +00:28:08,622 --> 00:28:09,990 +很方便 + +522 +00:28:10,023 --> 00:28:12,292 +这就是对 Swift Charts 的简要介绍 + +523 +00:28:12,326 --> 00:28:15,762 +以及 SwiftUI 和 Xcode 即将带来 +部分增强功能的说明 + +524 +00:28:15,796 --> 00:28:17,631 +现在交回给 Josh + +525 +00:28:17,664 --> 00:28:20,834 +我们正越来越多地使用 SwiftUI + +526 +00:28:20,868 --> 00:28:23,403 +并覆盖了我们的各个 app 和系统界面 + +527 +00:28:23,437 --> 00:28:25,973 +例如 iOS 新的锁定屏幕小组件 + +528 +00:28:26,006 --> 00:28:29,243 +就是由 SwiftUI 全新设计的 + +529 +00:28:29,276 --> 00:28:32,179 +而新的 Font Book app 也是用它 +完全重写的 + +530 +00:28:32,212 --> 00:28:36,283 +还有看起来很现代、超前的 +全新 macOS 系统设置 app + +531 +00:28:36,316 --> 00:28:37,818 +也是用它构建的 + +532 +00:28:37,851 --> 00:28:40,988 +Swift 和 SwiftUI 从一开始的设计目的 + +533 +00:28:41,021 --> 00:28:45,759 +就是用统一的原生语言和 API +适用于 Apple 的各个平台 + +534 +00:28:45,792 --> 00:28:48,629 +只需学习一次 即可用在所有地方 + +535 +00:28:48,662 --> 00:28:51,798 +无论你的愿景是在 Apple Watch 上 + +536 +00:28:51,832 --> 00:28:53,834 +提供一目了然的快速信息访问 + +537 +00:28:53,867 --> 00:28:57,104 +为 MacBook Pro 和 iPad 提供生产力工具 + +538 +00:28:57,137 --> 00:28:59,006 +在 iPhone 上提供新的体验 + +539 +00:28:59,039 --> 00:29:01,408 +还是为 Apple TV 提供新的放松方式 + +540 +00:29:01,441 --> 00:29:03,911 +Swift、SwiftUI 和 Xcode + +541 +00:29:03,944 --> 00:29:07,614 +提供了新一代的整合开发平台 + +542 +00:29:07,648 --> 00:29:10,884 +帮你开发的 app 适用于我们所有的产品 + +543 +00:29:10,918 --> 00:29:12,519 +如果你先前已开发的 app + +544 +00:29:12,553 --> 00:29:15,989 +同样也可以轻松地逐步采用这些新技术 + +545 +00:29:16,023 --> 00:29:19,526 +如果你是我们平台的新手 +或者要开始开发新的 app + +546 +00:29:19,560 --> 00:29:23,664 +最好的构建方式就是直接使用 +Swift 和 SwiftUI + +547 +00:29:23,697 --> 00:29:25,899 +当然 这只是个开始 + +548 +00:29:25,933 --> 00:29:29,870 +我们也在不断改进平台的用户体验 + +549 +00:29:29,903 --> 00:29:32,706 +为你们提供更多与用户互动的方式 + +550 +00:29:32,739 --> 00:29:35,075 +下面请 Sebastien 给你们来详细介绍 + +551 +00:29:36,376 --> 00:29:38,412 +开发 app 就是将各种想法 + +552 +00:29:38,445 --> 00:29:41,148 +代码和 API 转变为用户体验 + +553 +00:29:41,181 --> 00:29:42,482 +而最好的 app + +554 +00:29:42,516 --> 00:29:45,752 +就是能满足用户当下需求的 app + +555 +00:29:45,786 --> 00:29:49,456 +我们创建了各种方式 +让用户体验不仅限于你的 app 里 + +556 +00:29:49,489 --> 00:29:53,126 +更整合到不同 Apple 设备的系统体验中 + +557 +00:29:53,927 --> 00:29:57,664 +这段旅程从各种扩展方式开始 +以及与共享表单的整合 + +558 +00:29:57,698 --> 00:29:59,399 +还有自定义键盘 + +559 +00:29:59,433 --> 00:30:02,736 +最近 还增加了让你的 app 使用小组件 + +560 +00:30:02,769 --> 00:30:06,039 +在主屏幕显示关键信息的能力 + +561 +00:30:06,073 --> 00:30:07,875 +今年将有众多新的方式 + +562 +00:30:07,908 --> 00:30:10,978 +将你的 app 与我们各平台的系统体验相整合 + +563 +00:30:11,011 --> 00:30:15,482 +这要从锁定屏幕开始 +锁定屏幕得到了有史以来最大的更新 + +564 +00:30:15,516 --> 00:30:19,019 +我们重新设计了锁定屏幕的外观和运作方式 + +565 +00:30:19,052 --> 00:30:23,390 +为你的创意和各种 app +提供另一个与用户互动的地方 + +566 +00:30:23,423 --> 00:30:25,792 +让 Robert 来给大家介绍详情 + +567 +00:30:34,268 --> 00:30:35,802 +重新设计锁定屏幕的目的 + +568 +00:30:35,836 --> 00:30:38,805 +是让它更加个性化、更美观 + +569 +00:30:38,839 --> 00:30:40,674 +同时提高日常实用性 + +570 +00:30:40,707 --> 00:30:43,443 +在这个过程中 我们知道我们需要 + +571 +00:30:43,477 --> 00:30:46,413 +把小组件的强大功能 带到全新的锁定屏幕上 + +572 +00:30:46,446 --> 00:30:50,484 +小组件带来了出色的方式 +突出你 app 里的关键信息 + +573 +00:30:50,517 --> 00:30:53,487 +让用户一目了然 + +574 +00:30:53,520 --> 00:30:57,157 +它们让用户能够直接从主屏幕轻松获取 + +575 +00:30:57,191 --> 00:30:58,559 +丰富、及时的信息 + +576 +00:30:59,226 --> 00:31:02,796 +每当举起 iPhone 最先看到的就是锁定屏幕 + +577 +00:31:02,829 --> 00:31:05,432 +这里一直是查看日期时间 + +578 +00:31:05,465 --> 00:31:07,334 +了解重要信息的地方 + +579 +00:31:07,367 --> 00:31:11,038 +在思考如何以最佳的形式 +在这里显示更多信息时 + +580 +00:31:11,071 --> 00:31:13,574 +我们不用绞尽脑汁去寻找设计灵感 + +581 +00:31:14,208 --> 00:31:18,078 +Apple Watch 上的复杂功能已经提供了 +一目了然、相关 + +582 +00:31:18,111 --> 00:31:19,546 +最即时的信息 + +583 +00:31:19,580 --> 00:31:22,349 +并在用户需要时美观呈现这些内容 + +584 +00:31:23,016 --> 00:31:25,719 +这种设计语言自然地延伸到 iOS + +585 +00:31:25,752 --> 00:31:28,622 +恰如其分地出现在新的锁定屏幕上 + +586 +00:31:28,655 --> 00:31:31,825 +因此 利用 WidgetKit 我们将一些相同的设计 + +587 +00:31:31,859 --> 00:31:34,962 +带来锁定屏幕上的小组件 包括 Circular + +588 +00:31:34,995 --> 00:31:39,666 +可以展示一张小图、仪表或几个字符的文字 + +589 +00:31:39,700 --> 00:31:43,370 +Circular 小组件非常适合展示出 +你今天活动量是否已经足够 + +590 +00:31:43,403 --> 00:31:45,506 +还是需要出去跑跑步 + +591 +00:31:45,539 --> 00:31:48,175 +Rectangular 提供一个大画布 + +592 +00:31:48,208 --> 00:31:51,578 +可显示像天气预报这样的内容 + +593 +00:31:51,612 --> 00:31:54,515 +Inline 是一种强大的展示信息的方式 + +594 +00:31:54,548 --> 00:31:58,919 +可在 iPhone 的时钟上方 +显示少量文本和 SF 符号 + +595 +00:31:58,952 --> 00:32:02,990 +旁边是系统提供的日期字符串 +如 6 日星期一 + +596 +00:32:03,023 --> 00:32:08,328 +对了 所有这些小组件都可在 +iOS 和 watchOS 上使用 + +597 +00:32:08,362 --> 00:32:10,330 +因为从 watchOS 9 开始 + +598 +00:32:10,364 --> 00:32:13,567 +复杂功能也由 WidgetKit 提供支持 + +599 +00:32:13,600 --> 00:32:16,170 +这是首次可以在两个平台上 + +600 +00:32:16,203 --> 00:32:20,107 +使用相同的代码生成一目了然的数据 + +601 +00:32:20,140 --> 00:32:23,177 +WidgetKit 为你自动管理平台差异 + +602 +00:32:23,210 --> 00:32:25,479 +默认使用适合的系统字体 + +603 +00:32:25,512 --> 00:32:29,283 +并为锁定屏幕上的小组件上色 +提供最大的可读性 + +604 +00:32:29,316 --> 00:32:32,786 +具体如何使用 WidgetKit 以相同的代码 +为 iPhone 锁定屏幕 + +605 +00:32:32,819 --> 00:32:35,589 +和 Apple Watch 复杂功能创建小组件 + +606 +00:32:35,622 --> 00:32:37,524 +将由 Michael 为大家介绍 + +607 +00:32:39,793 --> 00:32:41,495 +无论是在 iPhone 锁定屏幕上创建小组件 + +608 +00:32:41,528 --> 00:32:44,798 +还是打造 Apple Watch 上的复杂功能 +都可以用 WidgetKit 轻松实现 + +609 +00:32:44,831 --> 00:32:47,401 +如果你已经做了主屏幕小组件 +那你就已经完成了大部分工作 + +610 +00:32:47,434 --> 00:32:49,870 +包括数据和时间线的更新方式 + +611 +00:32:49,903 --> 00:32:52,406 +在我们的 Food Truck app 中 +我们已经有了 systemSmall 小组件 + +612 +00:32:52,439 --> 00:32:54,107 +用户可以添加到主屏幕上 + +613 +00:32:54,141 --> 00:32:56,977 +查看他们今天已经完成了多少订单配额 + +614 +00:32:57,010 --> 00:32:59,513 +这类信息就非常适合显示在锁定屏幕 + +615 +00:32:59,546 --> 00:33:01,748 +或是手表表盘的复杂功能中 + +616 +00:33:01,782 --> 00:33:03,984 +我们先来建立 Circular 系列 + +617 +00:33:05,485 --> 00:33:08,255 +首先要在 Supported Families 阵列中 +声明对它的支持 + +618 +00:33:09,389 --> 00:33:12,025 +你可以看到我们在这里用了一些平台条件 + +619 +00:33:12,059 --> 00:33:15,762 +这是因为我们希望这个小组件能继续 +利用 systemSmall + +620 +00:33:15,796 --> 00:33:19,366 +支持 macOS 和 iOS +但 watchOS 无法使用这个系列 + +621 +00:33:20,200 --> 00:33:22,336 +于是我们增加了一个枚举值来定义这个视图 + +622 +00:33:24,004 --> 00:33:28,041 +我们使用仪表来显示 +从 0 到每日配额的订单量 + +623 +00:33:28,075 --> 00:33:30,844 +这样用户就能快速并且一目了然地看到进展 + +624 +00:33:31,678 --> 00:33:34,648 +我们在中间以文本形式显示当前订单量 + +625 +00:33:34,681 --> 00:33:37,217 +并显示一个甜甜圈符号 +好了 + +626 +00:33:37,251 --> 00:33:39,152 +我们在 Xcode Previews 中看看效果 + +627 +00:33:40,721 --> 00:33:41,755 +很棒 + +628 +00:33:41,788 --> 00:33:42,956 +在锁定屏幕上看起来很自然 + +629 +00:33:43,924 --> 00:33:45,826 +如果想一目了然地显示更多细节 + +630 +00:33:45,859 --> 00:33:48,328 +我们还可以添加对 Rectangular 系列的支持 + +631 +00:33:51,932 --> 00:33:54,735 +我们建一个 VStack 来实现这个视图 + +632 +00:33:54,768 --> 00:33:57,104 +首先给所展示的数据一个标题 + +633 +00:33:57,137 --> 00:33:58,805 +还有同样的甜甜圈符号 + +634 +00:33:59,506 --> 00:34:01,775 +将字体设置为标题样式 + +635 +00:34:01,808 --> 00:34:04,278 +这样在两个平台上都有很美观的效果 + +636 +00:34:04,311 --> 00:34:07,414 +然后用 widgetAccentable +modifier 确保它着重显示 + +637 +00:34:07,447 --> 00:34:10,784 +由于 Rectangular 系列提供了更多空间 + +638 +00:34:10,817 --> 00:34:13,554 +我们可以显示一个很酷的 +自定义分段式仪表 + +639 +00:34:13,587 --> 00:34:18,592 +同时让仪表标签显示 +当前订单数和每日配额 + +640 +00:34:18,625 --> 00:34:20,160 +回到画布 + +641 +00:34:20,194 --> 00:34:22,796 +我们也可以在预览中看到 +Rectangular 小组件 + +642 +00:34:22,829 --> 00:34:25,132 +我真的非常喜欢这个仪表 + +643 +00:34:25,165 --> 00:34:26,934 +现在我们来看看这个小组件 + +644 +00:34:26,967 --> 00:34:30,437 +在手表表盘以 Circular +复杂功能显示是什么效果 + +645 +00:34:32,573 --> 00:34:34,341 +相当好 所有信息都显示了 + +646 +00:34:34,374 --> 00:34:36,844 +但对复杂功能来说 我们还需考虑 + +647 +00:34:36,877 --> 00:34:38,145 +全彩渲染模式 + +648 +00:34:38,178 --> 00:34:41,248 +这是 Xcode Previews 中的默认模式 + +649 +00:34:41,281 --> 00:34:45,419 +我们来调整一下 +给每个仪表添加一点色调 + +650 +00:34:46,687 --> 00:34:49,756 +再给 Rectangular 标题添加一个前景色 + +651 +00:34:51,592 --> 00:34:53,093 +要在全彩中强调显示 + +652 +00:34:53,126 --> 00:34:56,697 +我们可以用环境属性检查渲染模式 + +653 +00:34:56,730 --> 00:35:00,133 +并在 Circular 和 +Rectangular 视图中 + +654 +00:35:00,167 --> 00:35:04,872 +用甜甜圈表情符号替换甜甜圈符号 + +655 +00:35:04,905 --> 00:35:06,139 +看起来很棒 + +656 +00:35:06,173 --> 00:35:08,041 +利用预览中的新变体 UI + +657 +00:35:08,075 --> 00:35:11,078 +完全无需创建任何代码 +我们可以改变预览颜色 + +658 +00:35:12,179 --> 00:35:14,181 +甚至同时预览多个颜色 + +659 +00:35:14,948 --> 00:35:18,018 +由于我们使用了默认的间距 +系统字体样式 + +660 +00:35:18,051 --> 00:35:19,620 +并适应了渲染模式 + +661 +00:35:19,653 --> 00:35:23,123 +同样的视图在锁定屏幕和手表表盘上 +看起来都相当自然 + +662 +00:35:23,156 --> 00:35:26,793 +如刚所示都是使用同样的代码 +就可以轻松制作 + +663 +00:35:26,827 --> 00:35:30,564 +iOS 16 全新锁定屏幕的小组件 +以及 watchOS 9 的复杂功能 + +664 +00:35:30,597 --> 00:35:33,800 +但这并不是唯一一种把 WidgetKit 的能力 +带到锁定屏幕的方式 + +665 +00:35:33,834 --> 00:35:35,435 +下面请 Matt 给大家介绍 + +666 +00:35:36,003 --> 00:35:37,070 +利用 WidgetKit + +667 +00:35:37,104 --> 00:35:39,806 +你可以让用户获取一目了然的信息 + +668 +00:35:39,840 --> 00:35:42,309 +但他们有时需要实时更新的信息 + +669 +00:35:42,342 --> 00:35:44,945 +或是与他们当前关心的活动或事件有关的信息 + +670 +00:35:44,978 --> 00:35:46,446 +这时该怎么做呢 + +671 +00:35:46,480 --> 00:35:51,118 +为此 我们正在探索一个新的功能 +称为实时活动 + +672 +00:35:51,151 --> 00:35:53,320 +实时活动让你更容易实时获取 + +673 +00:35:53,353 --> 00:35:55,122 +与正在发生的事情相关的信息 + +674 +00:35:55,155 --> 00:35:56,723 +直接显示在锁定屏幕上 + +675 +00:35:56,757 --> 00:36:00,027 +比如比赛的最新得分 + +676 +00:36:00,060 --> 00:36:03,497 +叫车进程或体能训练进度 + +677 +00:36:03,530 --> 00:36:06,066 +直接显示在锁定屏幕上并且实时更新 + +678 +00:36:06,099 --> 00:36:09,703 +就像小组件一样 你可以用 +WidgetKit 创建实时活动 + +679 +00:36:09,736 --> 00:36:12,406 +差别在于实时活动所呈现的信息和状态 + +680 +00:36:12,439 --> 00:36:14,208 +是实时更新的 + +681 +00:36:14,241 --> 00:36:16,210 +由于它们是用 SwiftUI 构建的 + +682 +00:36:16,243 --> 00:36:19,580 +你甚至可以将状态间的更新做成动画 + +683 +00:36:19,613 --> 00:36:21,615 +这些更新确保你的实时活动 + +684 +00:36:21,648 --> 00:36:25,452 +在用户浏览时显示最新的信息 + +685 +00:36:25,485 --> 00:36:30,490 +实时活动将于今年晚些时候 +在 iOS 16 更新中开始提供 + +686 +00:36:30,524 --> 00:36:32,993 +这就是全新锁定屏幕的最新进展 + +687 +00:36:33,026 --> 00:36:34,094 +这些超棒的更新 + +688 +00:36:34,127 --> 00:36:38,398 +可以让你在用户最需要的时候 +为他们提供一目了然的信息 + +689 +00:36:39,132 --> 00:36:42,603 +接下来 我们来谈一谈增强协作体验的全新方式 + +690 +00:36:42,636 --> 00:36:44,938 +由 Pierre 来给大家介绍 + +691 +00:36:44,972 --> 00:36:46,974 +协作同步是非常重要的 无论是在 + +692 +00:36:47,007 --> 00:36:50,511 +iOS、iPadOS 还是 macOS 上 + +693 +00:36:50,544 --> 00:36:53,380 +这在很大程度上是得益于大量丰富的 app + +694 +00:36:53,413 --> 00:36:55,015 +很多正是由你们来开发的 + +695 +00:36:55,048 --> 00:36:57,885 +来支持所有远距离协作的团队们 + +696 +00:36:57,918 --> 00:37:01,588 +工作上的协作 例如 Airtable 中的产品路线图 + +697 +00:37:01,622 --> 00:37:06,226 +还有娱乐上的协作 +例如在 Redfin 上寻找你的梦想家园 + +698 +00:37:06,260 --> 00:37:08,095 +无论是工作还是娱乐 + +699 +00:37:08,128 --> 00:37:11,265 +协作通常从对话开始 + +700 +00:37:11,298 --> 00:37:13,800 +通过全新的 Messages +Collaboration API + +701 +00:37:13,834 --> 00:37:16,970 +你可以把 app 的现有协作体验 + +702 +00:37:17,004 --> 00:37:18,772 +融入信息 app 和 FaceTime 通话 + +703 +00:37:18,805 --> 00:37:21,708 +当用户在你的 app 中分享内容链接时 + +704 +00:37:21,742 --> 00:37:25,412 +这个 API 可以让你更轻松地 +将连接标记为协作性的 + +705 +00:37:25,445 --> 00:37:27,514 +以实现无缝的体验 + +706 +00:37:27,548 --> 00:37:29,650 +我们提供你所需的标识符 + +707 +00:37:29,683 --> 00:37:32,152 +这样你可以在接收方轻点链接加入时 + +708 +00:37:32,186 --> 00:37:33,987 +立即提供访问权 + +709 +00:37:34,021 --> 00:37:36,924 +当然 这都是在不影响隐私的前提下进行的 + +710 +00:37:36,957 --> 00:37:40,994 +信息身份和 app 身份将保持私密 不会被分享 + +711 +00:37:41,028 --> 00:37:44,831 +最棒的是 你可以用你的 app 很可能已经在用的 + +712 +00:37:44,865 --> 00:37:47,301 +现有技术来实现这一点 + +713 +00:37:47,334 --> 00:37:51,471 +只需一个对象 用户就可以发起协作 + +714 +00:37:51,505 --> 00:37:54,575 +有两种他们已经很熟悉的方式来进行操作 + +715 +00:37:54,608 --> 00:37:57,277 +一是共享表单 我们已经提供更新 + +716 +00:37:57,311 --> 00:37:59,446 +将协作放在非常重要的位置 + +717 +00:37:59,479 --> 00:38:01,014 +二是通过拖放 + +718 +00:38:01,048 --> 00:38:03,750 +分享你想协作的内容 + +719 +00:38:03,784 --> 00:38:06,954 +仅需直接将内容拖到信息 app 的对话中 + +720 +00:38:06,987 --> 00:38:10,557 +一旦协作开始 你甚至可以把内容更新通知 + +721 +00:38:10,591 --> 00:38:14,061 +直接发布在信息 app 的对话中 + +722 +00:38:14,094 --> 00:38:17,798 +只需几行代码 用户就可以回到 +你的 app 中进行协作 + +723 +00:38:17,831 --> 00:38:21,034 +仅需在信息 app 中轻点一下 + +724 +00:38:21,068 --> 00:38:22,703 +利用协作弹窗 + +725 +00:38:22,736 --> 00:38:27,908 +用户可以从你的 app 里 +直接回到信息 app 或 FaceTime 通话中 + +726 +00:38:27,941 --> 00:38:29,943 +利用 Messages +Collaboration API + +727 +00:38:29,977 --> 00:38:33,780 +你的 app 可以深度整合到信息 app +和 FaceTime 通话的架构中 + +728 +00:38:33,814 --> 00:38:37,684 +我们给你的用户提供强大的通信工具 + +729 +00:38:37,718 --> 00:38:40,754 +这样你就可以专注于你的 app + +730 +00:38:40,787 --> 00:38:42,422 +提供强大的协作工具 + +731 +00:38:42,456 --> 00:38:46,860 +这将提升 iOS、iPadOS +和 macOS 上的协作功能 + +732 +00:38:46,894 --> 00:38:48,695 +创造一致的体验 + +733 +00:38:48,729 --> 00:38:52,399 +它深深扎根于协作者之间的联系 + +734 +00:38:52,432 --> 00:38:53,934 +无论是用于工作还是娱乐 + +735 +00:38:53,967 --> 00:38:56,470 +接下来 Ari 将给大家介绍 + +736 +00:38:56,503 --> 00:38:59,072 +一个新的框架 App Intents + +737 +00:38:59,106 --> 00:39:02,609 +我非常高兴可以给各位介绍 App Intents 框架 + +738 +00:39:02,643 --> 00:39:05,245 +它把你的 app 的功能开放给系统 + +739 +00:39:05,279 --> 00:39:09,183 +这样用户就可以通过 Siri 和快捷指令 +自动使用这些功能 + +740 +00:39:09,216 --> 00:39:11,552 +人们喜欢在使用 app 时使用快捷指令 + +741 +00:39:11,585 --> 00:39:15,022 +快捷指令让用户可以快速完成任务 +仅需询问 Siri + +742 +00:39:15,055 --> 00:39:18,325 +或快速轻点主屏幕上的快捷指令 + +743 +00:39:18,358 --> 00:39:21,428 +让我们惊叹的是用户组合使用 app 的能力 + +744 +00:39:21,461 --> 00:39:25,299 +用自定义快捷指令 +把它们组合成新的功能 + +745 +00:39:25,332 --> 00:39:29,703 +目前 用户必须先手动添加快捷指令 +之后才能使用它们 + +746 +00:39:29,736 --> 00:39:34,041 +我们在 iOS 16 中将通过新的 +App Intents 框架 把这个过程自动化 + +747 +00:39:35,075 --> 00:39:39,112 +App Intents 与快捷指令一起 +形成 app 快捷指令 + +748 +00:39:39,146 --> 00:39:41,281 +供用户直接通过 Siri 使用 + +749 +00:39:41,315 --> 00:39:43,116 +无需预先设置 + +750 +00:39:43,150 --> 00:39:46,386 +可以说 “嘿 Siri 用 Roomba 打扫厨房” + +751 +00:39:46,420 --> 00:39:47,988 +而且不只是 Siri + +752 +00:39:48,021 --> 00:39:49,990 +app 快捷指令让你的用户 + +753 +00:39:50,023 --> 00:39:52,693 +可以在整个系统中使用你的 app 的功能 + +754 +00:39:52,726 --> 00:39:56,330 +像是在聚焦中 当用户搜索你的 app 时 + +755 +00:39:56,363 --> 00:39:58,532 +你的快捷指令也会显示出来 + +756 +00:39:58,565 --> 00:40:02,302 +并且你的快捷指令会被 +直接推荐在 app 推荐下面 + +757 +00:40:02,336 --> 00:40:06,306 +无需采用任何额外 API 如 donations + +758 +00:40:06,340 --> 00:40:09,409 +你的快捷指令还会立即出现在 +快捷指令 app 中 + +759 +00:40:09,443 --> 00:40:11,512 +用户可以轻点运行 + +760 +00:40:12,179 --> 00:40:17,584 +App Intents 是我们在 iOS 10 中引入的 +SiriKit Intents 框架的下一步 + +761 +00:40:17,618 --> 00:40:21,021 +如果你用各种 intent +来整合小组件或是 domain + +762 +00:40:21,054 --> 00:40:22,389 +比如媒体或信息 + +763 +00:40:22,422 --> 00:40:25,626 +你应该继续使用 SiriKit Intents 框架 + +764 +00:40:25,659 --> 00:40:29,062 +但对为 Siri 和快捷指令 +构建自定义 intent 的开发者 + +765 +00:40:29,096 --> 00:40:31,298 +你应该升级至 App Intents + +766 +00:40:31,331 --> 00:40:34,501 +你可以在 Xcode 中轻松 +升级到 App Intents + +767 +00:40:34,535 --> 00:40:37,804 +仅需点击 intent 定 +义文件中的 Convert 按钮 + +768 +00:40:37,838 --> 00:40:40,841 +Xcode 会生成对等的 App Intents 源代码 + +769 +00:40:40,874 --> 00:40:43,310 +然后你用你的 intent 处理代码来填补空白 + +770 +00:40:43,343 --> 00:40:46,580 +用 App Intents 进行开发真的非常容易 + +771 +00:40:46,613 --> 00:40:49,716 +因为它是为 Swift 特意设计的 + +772 +00:40:49,750 --> 00:40:52,085 +所以需要的代码要少得多 + +773 +00:40:52,119 --> 00:40:55,455 +你所写的 Swift 代码 就是唯一的数据源 + +774 +00:40:55,489 --> 00:40:57,758 +也没有需要同步保留 额外的 intent 定义文件 + +775 +00:40:57,791 --> 00:41:00,060 +或代码生成 + +776 +00:41:00,093 --> 00:41:02,696 +并且这些代码很容易添加到你的项目中 + +777 +00:41:02,729 --> 00:41:05,232 +你不需要重新设计你的代码库 + +778 +00:41:05,265 --> 00:41:08,335 +哪怕你有 Objective-C 代码 +你仍然可以在 App Intents 中使用它们 + +779 +00:41:08,368 --> 00:41:09,970 +只要用 Swift 代码封装一下 + +780 +00:41:10,003 --> 00:41:13,373 +一个 app intent 表示用户在你的 app 中 +可以做的事情 + +781 +00:41:13,407 --> 00:41:16,610 +并且使从你的 app 外完成该操作成为可能 + +782 +00:41:16,643 --> 00:41:19,346 +你可以定义 intent 并添加 app 快捷指令 + +783 +00:41:19,379 --> 00:41:21,048 +仅需几行代码 + +784 +00:41:21,081 --> 00:41:23,250 +我们来一起试一试 + +785 +00:41:23,283 --> 00:41:25,953 +回到 Food Truck app +我这里有个很棒的图表视图 + +786 +00:41:25,986 --> 00:41:30,557 +可以让我看到不同时间段内 +最畅销的五种甜甜圈 + +787 +00:41:30,591 --> 00:41:32,459 +比如今天或本周 + +788 +00:41:32,492 --> 00:41:34,628 +我想把它显示给 Siri 和快捷指令 + +789 +00:41:34,661 --> 00:41:37,397 +这样用户就可以飞快地调出它 + +790 +00:41:37,431 --> 00:41:40,834 +首先 在 Xcode 中 我进入 +一个新的 Swift 文件 + +791 +00:41:40,868 --> 00:41:44,171 +导入 App Intents 和 SwiftUI 框架 + +792 +00:41:45,672 --> 00:41:47,541 +然后给这个 intent 下定义 + +793 +00:41:47,574 --> 00:41:50,878 +要通过定义一个符合 AppIntent 协议的结构 + +794 +00:41:50,911 --> 00:41:53,247 +我来给它加一个 title + +795 +00:41:53,280 --> 00:41:57,251 +再添加一个 parameter +来定义具体哪个时间段的趋势 + +796 +00:41:57,284 --> 00:42:01,221 +它使用的是已经在我的代码库中 +定义的时间框架枚举 + +797 +00:42:01,255 --> 00:42:04,925 +我需要扩展它 以符合 AppEnum 协议 + +798 +00:42:04,958 --> 00:42:08,662 +这样我们就可以为每个枚举情况 +提取人类可读的名称 + +799 +00:42:08,695 --> 00:42:11,064 +如 “今天” 和 “本周” + +800 +00:42:11,098 --> 00:42:15,569 +接下来 在 intent 这里 +加上 perform 方法 + +801 +00:42:15,602 --> 00:42:19,640 +这里 返回的是一个包含 SwiftUI 视图的结果 + +802 +00:42:19,673 --> 00:42:22,643 +我还可以加入一个对话或输出值 + +803 +00:42:22,676 --> 00:42:26,380 +我希望用户可以自动使用这个 intent +而不用设置 + +804 +00:42:26,413 --> 00:42:28,115 +所以我要定义一个 app 快捷指令 + +805 +00:42:30,017 --> 00:42:32,719 +这包括用户可以对 Siri 说的短语 + +806 +00:42:32,753 --> 00:42:34,488 +好调用这个 intent + +807 +00:42:34,521 --> 00:42:38,258 +这个短语必须包括 app 的名称作为变量 + +808 +00:42:38,292 --> 00:42:40,894 +我还包括了时间段参数 + +809 +00:42:40,928 --> 00:42:43,964 +所以用户可以说 “Food Truck 今日趋势” + +810 +00:42:43,997 --> 00:42:46,967 +或 “Food Truck 本周趋势” + +811 +00:42:47,000 --> 00:42:50,470 +我需要做的最后一件事 +就是让用户可以发现这个快捷指令 + +812 +00:42:50,504 --> 00:42:52,673 +用户需要在某个时候看到这个短语 + +813 +00:42:52,706 --> 00:42:54,474 +以便知道他们可以对 Siri 说什么 + +814 +00:42:54,508 --> 00:42:57,778 +所以我就切换到前五甜甜圈视图文件 + +815 +00:42:57,811 --> 00:42:59,546 +就是我们刚刚看的那个 + +816 +00:42:59,580 --> 00:43:01,648 +我在这里添加一个 SiriTip + +817 +00:43:03,217 --> 00:43:07,387 +现在我就可以构建并运行这个 app +然后在我的手机上试试看 + +818 +00:43:07,421 --> 00:43:08,455 +我们来试一试 + +819 +00:43:10,958 --> 00:43:13,594 +我可以看到快捷指令出现在了快捷指令 app 中 + +820 +00:43:13,627 --> 00:43:15,863 +每个参数值都有变量 + +821 +00:43:15,896 --> 00:43:19,433 +我可以轻点运行一个 + +822 +00:43:19,466 --> 00:43:22,769 +也可通过说那句短语 从 Siri 运行 + +823 +00:43:22,803 --> 00:43:24,838 +“Food Truck 今日趋势” + +824 +00:43:26,640 --> 00:43:30,010 +我还可以说 “Food Truck 本周趋势” + +825 +00:43:32,279 --> 00:43:34,681 +当用户进到 app 的前五视图时 + +826 +00:43:34,715 --> 00:43:36,783 +他们会看到我们在底部添加的这个提示 + +827 +00:43:36,817 --> 00:43:40,320 +从而了解对 Siri 说什么可以使用该功能 + +828 +00:43:40,354 --> 00:43:43,657 +最后 用户在聚焦中搜索该 app 时 + +829 +00:43:43,690 --> 00:43:45,759 +可以访问这些功能 就像这样 + +830 +00:43:47,995 --> 00:43:50,130 +非常有用 + +831 +00:43:50,163 --> 00:43:53,100 +App Intents 让你前所未有地轻松打造 + +832 +00:43:53,133 --> 00:43:58,772 +各种 app 功能 整合于系统体验中 +并跨越各个平台 + +833 +00:43:58,805 --> 00:44:01,275 +下面 Ricky 将给大家带来一些 + +834 +00:44:01,308 --> 00:44:03,210 +关于认证技术的重大进展 + +835 +00:44:03,877 --> 00:44:05,445 +从我们记事开始 + +836 +00:44:05,479 --> 00:44:08,048 +我们就一直在创建和使用密码 + +837 +00:44:08,081 --> 00:44:10,250 +但密码有着严重的问题 + +838 +00:44:10,284 --> 00:44:14,421 +如网络钓鱼、多账号使用同一密码、网站泄露 + +839 +00:44:14,454 --> 00:44:18,091 +好消息是 我们可以携起手来解决这一问题 + +840 +00:44:18,125 --> 00:44:21,161 +现在 我们用通行密钥就可以了 + +841 +00:44:21,195 --> 00:44:24,131 +通行密钥将简化你的认证流程 + +842 +00:44:24,164 --> 00:44:27,434 +解决密码的首要安全问题 + +843 +00:44:27,467 --> 00:44:30,737 +通行密钥的设计理念让它无比易用 + +844 +00:44:30,771 --> 00:44:34,274 +通行密钥复用了之前的自动填充信息界面 + +845 +00:44:34,308 --> 00:44:37,778 +并使用面容 ID 和触控 ID 进行生物识别验证 + +846 +00:44:37,811 --> 00:44:41,448 +这些元素创造了从密码的无缝过渡 + +847 +00:44:41,481 --> 00:44:44,985 +同时大大提升了安全性 + +848 +00:44:45,018 --> 00:44:47,187 +让我们来看看通行密钥的实际应用 + +849 +00:44:47,988 --> 00:44:50,090 +用通行密钥设置账户的话 + +850 +00:44:50,123 --> 00:44:52,359 +我就不需要创建密码了 + +851 +00:44:52,392 --> 00:44:57,497 +我在这里输入用户名 +并将通行密钥保存到我的 iCloud 钥匙串中 + +852 +00:44:57,531 --> 00:45:01,969 +这个通行密钥就安全同步到 +我所有其他 Apple 设备上了 + +853 +00:45:02,002 --> 00:45:06,106 +重新登录是一件轻而易举的事 + +854 +00:45:06,139 --> 00:45:09,309 +面容 ID 验证 就搞定 + +855 +00:45:09,343 --> 00:45:12,546 +通行密钥建立在开放的行业标准上 + +856 +00:45:12,579 --> 00:45:14,281 +且各个平台都在持续采用 + +857 +00:45:14,314 --> 00:45:17,584 +我可以用我刚刚在 iPhone 上创建的通行密钥 + +858 +00:45:17,618 --> 00:45:21,088 +在我朋友的 PC 上登录 Food Truck 网站 + +859 +00:45:21,121 --> 00:45:25,192 +在网站上 输入我的用户名 +点击提交 + +860 +00:45:25,225 --> 00:45:28,896 +选择用手机登陆 + +861 +00:45:28,929 --> 00:45:31,331 +扫描二维码 + +862 +00:45:31,365 --> 00:45:36,570 +让 PC 和 iPhone 建立安全连接 + +863 +00:45:36,603 --> 00:45:39,139 +登录成功 + +864 +00:45:39,173 --> 00:45:42,543 +在我自己 Mac 的 Safari 浏览器上 +登录更加简单 + +865 +00:45:42,576 --> 00:45:45,612 +我的通行密钥已经在这里了 +得益于 iCloud 钥匙串 + +866 +00:45:45,646 --> 00:45:49,283 +所以我可以直接从网站的用户名栏登录 + +867 +00:45:49,316 --> 00:45:53,120 +将通行密钥整合到现有登录流程中非常容易 + +868 +00:45:53,153 --> 00:45:57,424 +例如 这个网站的用户名栏允许我用通行密钥登录 + +869 +00:45:57,457 --> 00:45:59,092 +也可用密码登录 + +870 +00:45:59,126 --> 00:46:03,864 +如果我输入一个有密码的账号的用户名 + +871 +00:46:03,897 --> 00:46:05,432 +我也可以快速登录 + +872 +00:46:05,465 --> 00:46:08,235 +使用通行密钥 出力的是设备 + +873 +00:46:08,268 --> 00:46:10,604 +而且每次都是安全的 + +874 +00:46:10,637 --> 00:46:12,139 +创建通行密钥时 + +875 +00:46:12,172 --> 00:46:16,977 +设备会生成一个独特密钥 +专用于创建它的网站或 app + +876 +00:46:17,010 --> 00:46:19,713 +并且这个密钥会受到生物识别的保护 + +877 +00:46:19,746 --> 00:46:22,282 +不可能有弱通行密钥 + +878 +00:46:22,316 --> 00:46:25,219 +这些密钥不会被遗忘、无法重新使用 +或者被猜出来 + +879 +00:46:25,252 --> 00:46:28,388 +通行密钥的基础是公钥加密技术 + +880 +00:46:28,422 --> 00:46:32,092 +这让服务器端的凭证泄露成为历史 + +881 +00:46:32,125 --> 00:46:35,429 +不同于之前 在服务器上存储加盐哈希密码 + +882 +00:46:35,462 --> 00:46:40,567 +存在泄漏和被破解的风险 +现在只需要将对应的公钥保存在上面 + +883 +00:46:40,601 --> 00:46:43,103 +公钥被设计为真正公开的 + +884 +00:46:43,136 --> 00:46:45,405 +对黑客完全没有价值 + +885 +00:46:45,439 --> 00:46:49,209 +这极大地降低了你作为网站所有者的风险 + +886 +00:46:49,243 --> 00:46:52,179 +还有非常重要的一点 + +887 +00:46:52,212 --> 00:46:55,215 +有了通行密钥 +我们今天所知的凭证钓鱼将不复存在 + +888 +00:46:55,249 --> 00:46:59,453 +消除了用户面临的头号安全漏洞 + +889 +00:46:59,486 --> 00:47:03,524 +通行密钥与设置它们的网站或 app 有内在联系 + +890 +00:47:03,557 --> 00:47:07,828 +因此 用户永远不会被骗在错误的网站上 +使用他们的通行密钥 + +891 +00:47:07,861 --> 00:47:09,530 +而且 与密码不同的是 + +892 +00:47:09,563 --> 00:47:12,366 +将通行密钥输入或复制到 + +893 +00:47:12,399 --> 00:47:14,501 +看上去非常逼真的假网站是不可能的 + +894 +00:47:14,535 --> 00:47:18,238 +甚至不可能将任何信息泄露给偷看到你密码的人 + +895 +00:47:18,272 --> 00:47:21,141 +把这一切放在一起时 +我们看到的就是 + +896 +00:47:21,175 --> 00:47:23,644 +账户安全的崭新时代 + +897 +00:47:23,677 --> 00:47:27,748 +在你的 app 和网站里支持 通行密钥仅需几步 + +898 +00:47:27,781 --> 00:47:31,084 +首先 教你的帐户后端存储公钥 + +899 +00:47:31,118 --> 00:47:33,687 +并发出身份验证挑战 + +900 +00:47:33,720 --> 00:47:36,190 +然后 在网站和 app 中 + +901 +00:47:36,223 --> 00:47:38,058 +给用户提供通行密钥 + +902 +00:47:38,091 --> 00:47:42,329 +并采用 API 来创建新的通行密钥以及用它登录 + +903 +00:47:42,362 --> 00:47:46,934 +通行密钥基于 Web 认证标准 + +904 +00:47:46,967 --> 00:47:49,870 +这个标准是跨行业的平台供应商和服务所有者 + +905 +00:47:49,903 --> 00:47:53,407 +共同努力的结果 + +906 +00:47:53,440 --> 00:47:56,610 +这标准本身非常成熟 +并且有详细的对应文档 + +907 +00:47:56,643 --> 00:47:59,112 +通行密钥非常适合它 + +908 +00:47:59,146 --> 00:48:02,683 +所有这一切已经准备就绪 +你现在就可开始构建 + +909 +00:48:02,716 --> 00:48:06,453 +新一代的安全保护 流畅的用户体验 + +910 +00:48:06,486 --> 00:48:10,824 +并能在转换过渡期与密码顺畅地使用 + +911 +00:48:10,858 --> 00:48:12,459 +交回给你 Sebastien + +912 +00:48:12,492 --> 00:48:15,195 +大家刚刚看到的是一些最新的方式 + +913 +00:48:15,229 --> 00:48:19,733 +能让你的 app 整合到 +跨我们所有平台的系统体验中 + +914 +00:48:19,766 --> 00:48:24,137 +除了这些可以整合的特性 +还有大量新的 API 和框架 + +915 +00:48:24,171 --> 00:48:25,672 +跨我们所有的平台 + +916 +00:48:25,706 --> 00:48:29,476 +能在今年为你和你的 app 带来更多的可能性 + +917 +00:48:30,310 --> 00:48:32,312 +我想先给大家介绍一些 + +918 +00:48:32,346 --> 00:48:35,782 +然后再更深入讲解另外几个 + +919 +00:48:35,816 --> 00:48:38,418 +我们先来看 iPadOS + +920 +00:48:38,452 --> 00:48:42,923 +有了 iPadOS 16 你可以打造出 +iPad 上各类前所未有的强大 app + +921 +00:48:42,956 --> 00:48:46,326 +并且带来和桌面级 app 一致的体验 + +922 +00:48:46,360 --> 00:48:49,930 +例如流畅的查找和替换体验用于 UI 文本视图 + +923 +00:48:49,963 --> 00:48:52,132 +让你打造的 app 可以直接调用 + +924 +00:48:52,165 --> 00:48:54,434 +以及对导航栏、工具栏 + +925 +00:48:54,468 --> 00:48:56,403 +文档菜单的更新 + +926 +00:48:56,436 --> 00:48:59,339 +它们会让你的用户能更轻松地管理文档 + +927 +00:48:59,373 --> 00:49:01,575 +以及自定义他们的体验 + +928 +00:49:01,608 --> 00:49:05,746 +为了让 iPad 更好地与其他硬件搭配使用 + +929 +00:49:05,779 --> 00:49:07,748 +我们为 iPad 推出了 DriverKit + +930 +00:49:07,781 --> 00:49:11,285 +解锁 M1 芯片的惊人性能 + +931 +00:49:11,318 --> 00:49:13,987 +它与目前在 Mac 上可用的 API 相同 + +932 +00:49:14,021 --> 00:49:18,358 +让你可以轻松地向更多用户提供对 + +933 +00:49:18,392 --> 00:49:21,261 +USB、音频和 PCI 设备的支持 + +934 +00:49:22,596 --> 00:49:25,532 +此外 watchOS 也正在为各类 app 创造新的机会 + +935 +00:49:25,566 --> 00:49:28,702 +通过与各类系统服务 更深层度的整合 + +936 +00:49:28,735 --> 00:49:31,238 +watchOS 9 的 CallKit 框架 + +937 +00:49:31,271 --> 00:49:33,740 +包括一个新的 VoIP 背景模式 + +938 +00:49:33,774 --> 00:49:37,211 +让 app 可以直接从 Apple Watch 上 +发起语音通话 + +939 +00:49:37,244 --> 00:49:41,882 +带来熟悉的用户体验 +正如 FaceTime 音频通话和打电话那样 + +940 +00:49:41,915 --> 00:49:46,687 +通过蓝牙连接的医疗设备获得了 +更强大的连接能力和数据传输 + +941 +00:49:46,720 --> 00:49:50,290 +能在检测到危急情况时及时发出提示 + +942 +00:49:51,692 --> 00:49:55,629 +tvOS 16 为你提供了新的方法 +来创造连接性的体验 + +943 +00:49:55,662 --> 00:49:57,397 +让你把 Apple TV 上的 app + +944 +00:49:57,431 --> 00:50:01,902 +与附近设备上的 iPhone、iPad +或 Apple Watch app 相连 + +945 +00:50:01,935 --> 00:50:05,072 +这样 锻炼可以使用 Apple Watch 的运动数据 + +946 +00:50:05,105 --> 00:50:06,740 +或者你可以把 iPhone 或 iPad + +947 +00:50:06,773 --> 00:50:10,177 +用作回合制游戏的自定义手柄 + +948 +00:50:10,210 --> 00:50:14,147 +tvOS 负责管理设备的发现和连接 + +949 +00:50:14,181 --> 00:50:16,450 +所以你的 app 甚至无需在另一部设备上运行 + +950 +00:50:16,483 --> 00:50:18,719 +事实上 如果你的 app 还没被安装 + +951 +00:50:18,752 --> 00:50:23,757 +用户会被自动提示从 App Store下载它 + +952 +00:50:23,790 --> 00:50:27,694 +对于手机和 iPad +还有提供给广告商的新工具 + +953 +00:50:27,728 --> 00:50:31,465 +我们知道 有效的广告对大家的很多业务很重要 + +954 +00:50:31,498 --> 00:50:34,401 +这就是为什么我们创建了 SKAdNetwork + +955 +00:50:34,434 --> 00:50:37,204 +这是一个帮助广告网络和广告商的 API + +956 +00:50:37,237 --> 00:50:40,574 +可在不追踪用户的前提下衡量广告活动的指标 + +957 +00:50:40,607 --> 00:50:44,945 +我们很高兴看到许多第三方广告网络都采用了它 + +958 +00:50:44,978 --> 00:50:47,681 +我们听到了广告网络和开发者的反馈 + +959 +00:50:47,714 --> 00:50:51,151 +并在今年对 SKAdNetwork 进行了一些改进 + +960 +00:50:51,185 --> 00:50:53,020 +回应了许多强烈要求的功能 + +961 +00:50:53,053 --> 00:50:55,489 +为大家提供极大的灵活性 + +962 +00:50:55,522 --> 00:50:58,659 +同时不影响隐私 + +963 +00:50:59,793 --> 00:51:02,362 +在 iPhone 和 iPad 上 有些很酷的新功能 + +964 +00:51:02,396 --> 00:51:07,034 +基于增强现实和激光雷达扫描仪 +用到了 ScanKit 与 RoomPlan + +965 +00:51:07,067 --> 00:51:13,607 +这些 API 让你的 app 以 USD 和 USDZ +格式创建信息丰富的 3D 参数化房间模型 + +966 +00:51:13,640 --> 00:51:16,743 +你可以创建各种工作流和体验 + +967 +00:51:16,777 --> 00:51:20,347 +从建筑和设计 到零售、酒店行业 + +968 +00:51:20,380 --> 00:51:23,951 +这些模型包括了家具分类 + +969 +00:51:23,984 --> 00:51:29,423 +包括沙发、橱柜、电视等类别 +没错 甚至还有厨房水槽 + +970 +00:51:29,456 --> 00:51:31,225 +去年 我们推出了专注模式 + +971 +00:51:31,258 --> 00:51:33,927 +适用于 iPhone、iPad +Mac 和 Apple Watch + +972 +00:51:33,961 --> 00:51:39,633 +让你的 app 根据用户的专注模式去管理通知 + +973 +00:51:39,666 --> 00:51:43,170 +今年 我们将通过专注模式过滤条件 +进一步加强这项功能 + +974 +00:51:43,203 --> 00:51:46,773 +专注模式过滤条件建立在 App Intents 之上 + +975 +00:51:46,807 --> 00:51:50,377 +让你根据用户当前的专注模式调整 app 的内容 + +976 +00:51:50,410 --> 00:51:53,213 +例如 app 可以创建专注模式过滤条件 + +977 +00:51:53,247 --> 00:51:57,818 +在用户设置为工作模式时 仅显示工作账号 + +978 +00:51:57,851 --> 00:52:01,388 +而这些例子仅是冰山一角 + +979 +00:52:01,421 --> 00:52:04,458 +在各个层面都有新的工具和 API + +980 +00:52:04,491 --> 00:52:06,093 +为你提供所需要的功能 + +981 +00:52:06,126 --> 00:52:08,362 +让你的 app 更进一步 + +982 +00:52:08,395 --> 00:52:11,098 +以及创造全新的 app 和体验 + +983 +00:52:11,131 --> 00:52:13,534 +下面 我们来深入讲解一下 + +984 +00:52:13,567 --> 00:52:14,902 +首先就是 Metal + +985 +00:52:14,935 --> 00:52:18,038 +这项技术将各种体验带入全新境界 + +986 +00:52:18,071 --> 00:52:20,941 +更多详情 请 Sarah 来介绍 + +987 +00:52:20,974 --> 00:52:27,981 +♪ ♪ + +988 +00:52:29,249 --> 00:52:32,286 +Metal 是个强大的图形处理和计算 API + +989 +00:52:32,319 --> 00:52:34,888 +帮助你打造出令人惊叹的各类游戏和专业级 app + +990 +00:52:34,922 --> 00:52:36,423 +覆盖 Apple 的各个平台 + +991 +00:52:36,456 --> 00:52:38,325 +Metal 让你可以充分利用 Apple 打造的 + +992 +00:52:38,358 --> 00:52:41,895 +带来突破性能的图形处理器和统一内存系统 + +993 +00:52:41,929 --> 00:52:46,700 +覆盖搭载了 Apple 芯片的最新 +iPhone、iPad、Mac 产品线 + +994 +00:52:46,733 --> 00:52:50,771 +今年 我们将推出 Metal 3 + +995 +00:52:50,804 --> 00:52:52,506 +带来强大的新功能 + +996 +00:52:52,539 --> 00:52:55,275 +助你以更高的帧率渲染沉浸式画面 + +997 +00:52:55,309 --> 00:52:58,312 +并将计算性能推向新高 + +998 +00:52:58,345 --> 00:53:01,014 +例如 机器学习框架 Pytorch + +999 +00:53:01,048 --> 00:53:03,183 +将迎来巨大的性能提升 + +1000 +00:53:03,217 --> 00:53:05,085 +它现在使用新的 Metal 后端 + +1001 +00:53:05,118 --> 00:53:07,554 +使用图形处理器来进行机器学习训练 + +1002 +00:53:07,588 --> 00:53:10,257 +当然最受关注的领域就是游戏 + +1003 +00:53:10,290 --> 00:53:12,192 +首先是游戏加载 + +1004 +00:53:12,226 --> 00:53:14,494 +这是游戏体验的一个关键因素 + +1005 +00:53:14,528 --> 00:53:17,197 +会影响启动时间和新关卡加载 + +1006 +00:53:17,231 --> 00:53:19,900 +现在的游戏带来细节丰富的游戏体验 + +1007 +00:53:19,933 --> 00:53:22,269 +基于高画质的素材 + +1008 +00:53:22,302 --> 00:53:26,273 +将这些素材快速地从硬盘加载到图形处理器 +是件有挑战的事 + +1009 +00:53:26,306 --> 00:53:30,177 +通常 游戏会在加载画面时进行素材加载 + +1010 +00:53:30,210 --> 00:53:32,679 +一种加快游戏启动的方式 + +1011 +00:53:32,713 --> 00:53:34,815 +是加载并绘制一个较低质量的版本 + +1012 +00:53:34,848 --> 00:53:37,484 +直到高质量的视觉画面加载完毕 + +1013 +00:53:37,518 --> 00:53:39,620 +这并不是理想的游戏体验 + +1014 +00:53:39,653 --> 00:53:43,156 +因为用户会更长时间看到低画质 + +1015 +00:53:43,190 --> 00:53:46,260 +Metal 3 带来了快速资源加载 + +1016 +00:53:46,293 --> 00:53:47,628 +基于 Metal IO API + +1017 +00:53:47,661 --> 00:53:51,431 +利用 Apple 图形处理器的统一内存架构 + +1018 +00:53:51,465 --> 00:53:53,100 +减少加载开销 + +1019 +00:53:53,133 --> 00:53:57,871 +确保每台 Apple 芯片 +Mac 所配的高速 SSD 存储 + +1020 +00:53:57,905 --> 00:54:01,575 +在队列中有足够的请求 从而最大限度地提高通量 + +1021 +00:54:01,608 --> 00:54:04,878 +这个新的 API 会提供更快更一致的性能 + +1022 +00:54:04,912 --> 00:54:07,814 +从而把更多的时间留给理想画质的绘制 + +1023 +00:54:09,149 --> 00:54:12,152 +除了将资源从硬盘加载到内存以外 + +1024 +00:54:12,186 --> 00:54:14,955 +着色器编译也会影响游戏加载 + +1025 +00:54:14,988 --> 00:54:19,193 +着色器总是需要根据用户的 +独特硬件配置进行编译 + +1026 +00:54:19,226 --> 00:54:22,129 +由于 PC 硬件种类繁多 + +1027 +00:54:22,162 --> 00:54:24,464 +这通常需要在运行时完成 + +1028 +00:54:24,498 --> 00:54:27,734 +这种游戏中的编译会影响玩家体验 + +1029 +00:54:27,768 --> 00:54:31,338 +导致掉帧、帧率下降、加载时间延长 + +1030 +00:54:31,371 --> 00:54:35,375 +相比之下 Apple 芯片和 +Metal 3 的设计相辅相成 + +1031 +00:54:35,409 --> 00:54:37,144 +支持所有 Apple 设备 + +1032 +00:54:37,177 --> 00:54:39,546 +现在 有了离线着色器编译 + +1033 +00:54:39,580 --> 00:54:43,183 +你可以在项目构建时 +生成图形处理器着色器二进制文件 + +1034 +00:54:43,217 --> 00:54:46,153 +让你能够消除游戏中的着色器编译 + +1035 +00:54:46,186 --> 00:54:49,389 +减少加载时间 提升渲染性能 + +1036 +00:54:49,423 --> 00:54:54,127 +游戏的另一个重点是提供丰富 +充满细节的素材 + +1037 +00:54:54,161 --> 00:54:57,331 +提高游戏图形视觉保真度的一个方法是 + +1038 +00:54:57,364 --> 00:55:01,335 +生成更复杂的几何网格 + +1039 +00:55:01,368 --> 00:55:03,871 +之前是在中央处理器上进行界面评估 + +1040 +00:55:03,904 --> 00:55:06,340 +生成几何图形 + +1041 +00:55:06,373 --> 00:55:08,442 +再提交给图形处理器进行渲染 + +1042 +00:55:08,475 --> 00:55:11,078 +挑战在于 这可能会带来延迟 + +1043 +00:55:11,111 --> 00:55:13,447 +并占用不可预测的内存空间 + +1044 +00:55:13,480 --> 00:55:16,483 +Metal 3 引入了新的 +Mesh Shading API + +1045 +00:55:16,517 --> 00:55:22,289 +让你能够从一个渲染通道中 +精确控制优化的几何处理管线 + +1046 +00:55:22,322 --> 00:55:25,192 +对象着色器决定生成多少网格 + +1047 +00:55:25,225 --> 00:55:27,461 +网格着色器生成实际的几何图像 + +1048 +00:55:27,494 --> 00:55:29,897 +然后直接发给光栅化渲染器 + +1049 +00:55:29,930 --> 00:55:33,267 +避免了多次内存访问 提高了性能 + +1050 +00:55:33,300 --> 00:55:36,069 +玩家也希望以最高的帧率 + +1051 +00:55:36,103 --> 00:55:37,838 +看到这些令人惊叹的视觉效果 + +1052 +00:55:37,871 --> 00:55:41,074 +但以超高分辨率渲染高级图像 + +1053 +00:55:41,108 --> 00:55:42,809 +可能会耗费宝贵的毫秒 + +1054 +00:55:42,843 --> 00:55:46,079 +MetalFX 上采样功能帮你以每帧更短的时间 + +1055 +00:55:46,113 --> 00:55:47,781 +来渲染沉浸式画面 + +1056 +00:55:47,814 --> 00:55:49,349 +它是这样运作的 + +1057 +00:55:49,383 --> 00:55:52,819 +以前 你会以原始分辨率渲染全帧 + +1058 +00:55:52,853 --> 00:55:56,256 +但图形处理器的渲染时间可能无法达到目标帧时间 + +1059 +00:55:56,290 --> 00:56:00,093 +现在 你能以较低的分辨率 +渲染同样的复杂场景 + +1060 +00:56:00,127 --> 00:56:03,197 +从而满足目标帧时间 +然后利用 MetalFX 框架 + +1061 +00:56:03,230 --> 00:56:07,668 +执行时间抗锯齿 并上采样至目标分辨率 + +1062 +00:56:07,701 --> 00:56:10,637 +有了 Apple 芯片和 Metal 3 优化的功能 + +1063 +00:56:10,671 --> 00:56:13,106 +游戏将在 Mac 上前所未有地大放异彩 + +1064 +00:56:13,140 --> 00:56:14,808 +游戏开发者也表示赞同 + +1065 +00:56:14,842 --> 00:56:18,245 +许多顶尖的游戏工作室正在着手 +将他们的游戏带到 Mac 上 + +1066 +00:56:18,278 --> 00:56:21,281 +比如 Grid Legends 利用 Apple 芯片 + +1067 +00:56:21,315 --> 00:56:23,617 +助你全速前进 + +1068 +00:56:23,650 --> 00:56:27,387 +而 Resident Evil Village +使用 MetalFX 上采样等功能 + +1069 +00:56:27,421 --> 00:56:31,358 +以最高分辨率提供美到惊心动魄的画面 + +1070 +00:56:31,391 --> 00:56:33,961 +还有 No Man's Sky +利用 Metal 3 的优势 + +1071 +00:56:33,994 --> 00:56:37,564 +在 Mac 和 iPad 上探索丰富、广阔的世界 + +1072 +00:56:37,598 --> 00:56:42,336 +Metal 3 令人难以置信 +它将提升你的 app 的性能 + +1073 +00:56:42,369 --> 00:56:44,605 +以及提供惊艳的游戏体验 + +1074 +00:56:44,638 --> 00:56:49,109 +现在 我们来看看 MapKit 的发展方向 +请 Kathy 给大家介绍 + +1075 +00:56:49,142 --> 00:56:51,278 +无论你是要导航前往你最喜欢的餐厅 + +1076 +00:56:51,311 --> 00:56:52,980 +计划下一个假期 + +1077 +00:56:53,013 --> 00:56:55,849 +还是只是在地图上查看 +你最喜欢的美食车停在哪里 + +1078 +00:56:55,883 --> 00:57:00,487 +我们都无比依赖我们的设备 +帮我们探索周边的世界 + +1079 +00:57:00,521 --> 00:57:04,391 +MapKit 是帮助用户探索和导航的好方法 + +1080 +00:57:04,424 --> 00:57:07,361 +它提供了丰富而灵活的地图和位置服务 + +1081 +00:57:07,394 --> 00:57:11,465 +由 Apple 地图驱动 开发者可免费使用 + +1082 +00:57:11,498 --> 00:57:15,669 +利用 MapKit 你可以在你的 app 中 +显示地图或卫星图像 + +1083 +00:57:15,702 --> 00:57:17,604 +找到并调出兴趣点 + +1084 +00:57:17,638 --> 00:57:19,239 +添加注释和覆盖物 + +1085 +00:57:19,273 --> 00:57:21,408 +获取路线等等 + +1086 +00:57:21,441 --> 00:57:23,844 +MapKit 由我们的全新地图提供支持 + +1087 +00:57:23,877 --> 00:57:26,246 +经过 Apple 彻底重新设计 + +1088 +00:57:26,280 --> 00:57:28,248 +它提供了更好的细节和准确性 + +1089 +00:57:28,282 --> 00:57:31,952 +并能为你的 app 带来有用的地图和位置服务 + +1090 +00:57:31,985 --> 00:57:34,421 +在 iOS 16 中 我们将在新地图的基础上 + +1091 +00:57:34,454 --> 00:57:37,191 +推出有史以来对 MapKit 最大的更新 + +1092 +00:57:37,224 --> 00:57:42,029 +首先是向所有开发者提供 +3D City Experience + +1093 +00:57:42,062 --> 00:57:45,032 +你的 app 用户将能看到令人难以置信的细节 + +1094 +00:57:45,065 --> 00:57:47,801 +包括 3D 高度信息、转弯车道 + +1095 +00:57:47,835 --> 00:57:49,269 +人行横道、自行车道等 + +1096 +00:57:49,303 --> 00:57:52,039 +还有惊人的手工打造的 3D 地标 + +1097 +00:57:52,072 --> 00:57:54,508 +如金门大桥或渡轮大厦 + +1098 +00:57:54,541 --> 00:57:57,411 +地图的新增细节让你可以提供 + +1099 +00:57:57,444 --> 00:58:01,181 +前所未有的背景和精确度 + +1100 +00:58:01,215 --> 00:58:06,887 +例如 你可以在人行横道和自行车道起始点间 +显示一个兴趣点 + +1101 +00:58:06,920 --> 00:58:09,156 +没有其他数字地图能让你做到这一点 + +1102 +00:58:09,189 --> 00:58:12,359 +而我们可以让你非常轻松地实现它 + +1103 +00:58:12,392 --> 00:58:14,261 +为了给大家展示 我们来创造一个体验 + +1104 +00:58:14,294 --> 00:58:20,400 +让用户利用新地图的细节 +轻松找到他们最喜欢的美食车停在哪里 + +1105 +00:58:20,434 --> 00:58:25,038 +像这样的地图视图会在可用时 +自动获得 3D City Experience + +1106 +00:58:25,072 --> 00:58:28,242 +只需将部署目标设置为 iOS 16 即可 + +1107 +00:58:28,275 --> 00:58:31,578 +接下来 我可以用非常详细的地图 + +1108 +00:58:31,612 --> 00:58:35,315 +来显示美食车的确切位置 + +1109 +00:58:35,349 --> 00:58:39,353 +MapKit 拥有强大的控件 +让我们在 3D 空间中定位相机 + +1110 +00:58:39,386 --> 00:58:42,122 +以创建精确的地图视图 + +1111 +00:58:42,155 --> 00:58:44,658 +这里 我可以选择我们希望被放大的距离 + +1112 +00:58:44,691 --> 00:58:48,762 +通过将相机的中心坐标距离设置为 600 米即可 + +1113 +00:58:48,795 --> 00:58:51,999 +通过调整俯仰和朝向 倾斜相机查看 3D 视图 + +1114 +00:58:52,032 --> 00:58:55,002 +你可以看到令人惊叹的有用细节 +如转弯车道 + +1115 +00:58:55,035 --> 00:58:57,771 +人行横道 甚至还有树木 + +1116 +00:58:57,804 --> 00:59:00,474 +默认情况下 高度信息将被压平 + +1117 +00:59:00,507 --> 00:59:03,410 +为了帮助用户了解他们将遇到的地形 + +1118 +00:59:03,443 --> 00:59:07,814 +我可以用 preferredConfiguration +将 elevationStyle 设置为 ‘realistic’ + +1119 +00:59:07,848 --> 00:59:09,783 +以包含 3D 高度信息 + +1120 +00:59:10,851 --> 00:59:15,255 +从 MapKit 的路线规划 API 中 +添加注释或路线源时 + +1121 +00:59:15,289 --> 00:59:17,457 +MapKit 会自动处理高度信息 + +1122 +00:59:17,491 --> 00:59:19,927 +并会通过将其置于 3D 地形之上 + +1123 +00:59:19,960 --> 00:59:23,830 +调整注释或路线 + +1124 +00:59:23,864 --> 00:59:26,466 +通过添加慢速平移 为相机朝向进行动画处理 + +1125 +00:59:26,500 --> 00:59:29,736 +可以让地图视图变得生动 + +1126 +00:59:29,770 --> 00:59:31,438 +当用户切换到深色模式时 + +1127 +00:59:31,471 --> 00:59:34,241 +地图也会与 UI 的其他部分一同调整 + +1128 +00:59:34,274 --> 00:59:39,646 +我们非常高兴能通过 iOS 16 +向开发者提供这项沉浸式的体验 + +1129 +00:59:39,680 --> 00:59:43,817 +此外 我们还将另一个很受欢迎的 +Apple 地图功能带到了 MapKit + +1130 +00:59:43,851 --> 00:59:45,452 +那就是 四处看看 + +1131 +00:59:45,485 --> 00:59:48,956 +这是一种从视平线角度探索世界的好方法 + +1132 +00:59:48,989 --> 00:59:52,392 +提供了高分辨率的 3D 图像和流畅的动画 + +1133 +00:59:52,426 --> 00:59:55,295 +用户只需轻点就可在街道上移动 + +1134 +00:59:56,997 --> 00:59:59,900 +我可以在地图下面添加一个静态的 +四处看看预览 + +1135 +00:59:59,933 --> 01:00:03,604 +仅需放入一个 View Controller +并指定 MapItem + +1136 +01:00:03,637 --> 01:00:07,241 +四处看看视图会自动插入正确的位置 + +1137 +01:00:07,274 --> 01:00:09,610 +用户轻点预览时 我可以选择提供 + +1138 +01:00:09,643 --> 01:00:11,512 +全屏的四处看看视图 + +1139 +01:00:11,545 --> 01:00:13,480 +用户可以看到地址 + +1140 +01:00:13,514 --> 01:00:15,349 +图像采集日期 + +1141 +01:00:15,382 --> 01:00:17,584 +还能通过轻点自由移动 + +1142 +01:00:17,618 --> 01:00:20,420 +更好地了解周边环境 + +1143 +01:00:20,454 --> 01:00:23,223 +还有一项新的、呼声很高的功能 + +1144 +01:00:23,257 --> 01:00:26,026 +将在 iOS 16 中登陆 MapKit + +1145 +01:00:26,059 --> 01:00:28,295 +Apple Maps Server API + +1146 +01:00:28,328 --> 01:00:30,163 +Maps Server API 是 REST 接口 + +1147 +01:00:30,197 --> 01:00:33,367 +支持 MapKit 最常用功能中的四项 + +1148 +01:00:33,400 --> 01:00:36,537 +地理编码 可将经纬度转换为地址 + +1149 +01:00:36,570 --> 01:00:38,872 +逆地理编码 实现的是相反的功能 + +1150 +01:00:38,906 --> 01:00:41,608 +将地址转换为 GPS 坐标 + +1151 +01:00:41,642 --> 01:00:44,111 +搜索 以及到达时间 + +1152 +01:00:44,144 --> 01:00:46,914 +我们新的 Maps Server API + +1153 +01:00:46,947 --> 01:00:51,385 +能让你自己的后端服务更丰富 性能更强 + +1154 +01:00:51,418 --> 01:00:55,989 +当然 MapKit 建立在与 Apple 地图相同的 +隐私保护基础上 + +1155 +01:00:56,023 --> 01:00:59,226 +不会将用户的数据与他们的身份关联起来 + +1156 +01:00:59,259 --> 01:01:01,895 +也不会保留用户去过的地方的历史 + +1157 +01:01:01,929 --> 01:01:05,499 +这就是对 iOS 16 中 +MapKit 新功能的简单介绍 + +1158 +01:01:05,532 --> 01:01:08,936 +现在轮到介绍天气了 +至少是如何将天气建入你的 app + +1159 +01:01:08,969 --> 01:01:10,637 +交给 Novall + +1160 +01:01:10,671 --> 01:01:14,975 +我们今天宣布了要把天气 app +带到 iPad 和 Mac 上 + +1161 +01:01:15,008 --> 01:01:17,377 +并推出强大的新功能 + +1162 +01:01:17,411 --> 01:01:21,081 +包括恶劣天气通知、丰富的细节视图 + +1163 +01:01:21,114 --> 01:01:25,018 +以及未来十天的每小时温度和降水预报 + +1164 +01:01:25,052 --> 01:01:29,256 +等各种各样的体验 跨各个 Apple 设备和平台 + +1165 +01:01:29,289 --> 01:01:32,659 +这些体验也将因我们提供的天气数据而优化提升 + +1166 +01:01:32,693 --> 01:01:35,295 +无论是向 Siri 询问今天的天气预报 + +1167 +01:01:35,329 --> 01:01:38,232 +还是绕过水灾区域重新规划导航路线 + +1168 +01:01:38,265 --> 01:01:42,035 +所有这一切都内置于我们的 Apple 天气服务中 + +1169 +01:01:42,069 --> 01:01:45,372 +Apple 天气提供了世界级的全球天气预报 + +1170 +01:01:45,405 --> 01:01:48,041 +利用高分辨率气象模型 + +1171 +01:01:48,075 --> 01:01:50,911 +结合机器学习和预测算法 + +1172 +01:01:50,944 --> 01:01:53,447 +Apple 天气提供当前天气 + +1173 +01:01:53,480 --> 01:01:56,517 +10 天内的每小时预报、每日预报 + +1174 +01:01:56,550 --> 01:02:00,354 +以及历史天气 方便你评估数据趋势 + +1175 +01:02:00,387 --> 01:02:03,090 +在一些国家和地区还提供 + +1176 +01:02:03,123 --> 01:02:06,860 +恶劣天气警报和每分钟降水信息 + +1177 +01:02:06,894 --> 01:02:10,330 +预报功能包括未来 10 天的每小时温度 + +1178 +01:02:10,364 --> 01:02:15,068 +降水、紫外线指数预报 以及更多信息 + +1179 +01:02:15,102 --> 01:02:19,173 +所有这些数据都可通过 WeatherKit 获取到 + +1180 +01:02:19,206 --> 01:02:23,210 +WeatherKit 是原生的 Swift API +适用于所有 Apple 平台 + +1181 +01:02:23,243 --> 01:02:25,612 +并且是一个可以从任何地方使用的 REST API + +1182 +01:02:25,646 --> 01:02:29,449 +这些 API 可以提供准确、超本地化的天气预报 + +1183 +01:02:29,483 --> 01:02:33,787 +为你的用户提供信息 +帮助他们保持安全 做好准备 + +1184 +01:02:33,820 --> 01:02:36,190 +我来通过一个简短的演示向你介绍 + +1185 +01:02:36,223 --> 01:02:39,593 +通过 WeatherKit 很棒的 Swift API +获取天气信息多么容易 + +1186 +01:02:39,626 --> 01:02:41,862 +我们再回到 Food Truck app + +1187 +01:02:41,895 --> 01:02:44,231 +为了确保我的顾客不被雨淋 + +1188 +01:02:44,264 --> 01:02:47,968 +我设置的 app 能推荐一个天空晴朗的停车点 + +1189 +01:02:48,001 --> 01:02:50,470 +我来展示一下我是如何获得天气信息的 + +1190 +01:02:50,504 --> 01:02:53,240 +我这里有一份安全停车点的清单 + +1191 +01:02:53,273 --> 01:02:56,109 +我已在 Xcode 中添加了 WeatherKit 功能 + +1192 +01:02:56,143 --> 01:02:58,545 +仅需几行代码即可 + +1193 +01:02:58,579 --> 01:03:01,648 +利用 Swift 并发功能 请求天气信息非常简单 + +1194 +01:03:01,682 --> 01:03:06,019 +我们调用 weather(for:) on WeatherService +并传入位置 + +1195 +01:03:06,053 --> 01:03:11,391 +然后我就可以获得我的 app 所需的相关数据 +如天气状况 + +1196 +01:03:11,425 --> 01:03:17,898 +降水、云层覆盖 + +1197 +01:03:17,931 --> 01:03:21,068 +现在我有了每个停车位所需的数据 + +1198 +01:03:21,101 --> 01:03:22,369 +在我运行 app 时 + +1199 +01:03:22,402 --> 01:03:26,740 +我的自定义视图就已经更新为 +推荐一个天空晴朗的位置 + +1200 +01:03:28,509 --> 01:03:30,777 +你可以通过各种方式使用天气数据 + +1201 +01:03:30,811 --> 01:03:33,714 +让你的 app 提供更好的体验 + +1202 +01:03:33,747 --> 01:03:36,617 +你可能会用天气预报帮你管理库存 + +1203 +01:03:36,650 --> 01:03:40,587 +预测冰淇淋馅甜甜圈在大热天会很受欢迎 + +1204 +01:03:40,621 --> 01:03:43,123 +所以你该多备一些冰淇淋 + +1205 +01:03:43,156 --> 01:03:45,292 +为我们的美食车获取天气数据仅需这样简单的操作 + +1206 +01:03:45,325 --> 01:03:48,595 +大家可以用 WeatherKit 做的事还有更多 + +1207 +01:03:48,629 --> 01:03:50,964 +与 Apple 对隐私保护的承诺一致 + +1208 +01:03:50,998 --> 01:03:54,201 +位置信息仅用于提供天气预报 + +1209 +01:03:54,234 --> 01:03:57,504 +不会与任何个人身份信息相关联 + +1210 +01:03:57,538 --> 01:04:00,374 +并且永不分享或出售 + +1211 +01:04:00,407 --> 01:04:02,509 +保护隐私是我们共同的责任 + +1212 +01:04:02,543 --> 01:04:05,279 +通过 WeatherKit 你可以获得准确的天气数据 + +1213 +01:04:05,312 --> 01:04:08,081 +同时保护用户隐私 + +1214 +01:04:08,115 --> 01:04:11,251 +因为我们想让大家很容易就能 +开始使用 WeatherKit + +1215 +01:04:11,285 --> 01:04:15,722 +所以我们将每月 50 万次 +weather(for:location) API 调用 + +1216 +01:04:15,756 --> 01:04:18,358 +包含在你们的 Apple +Developer Program 订阅中 + +1217 +01:04:18,392 --> 01:04:22,095 +需求量更大的开发者 +将可购买额外的服务级别 + +1218 +01:04:22,129 --> 01:04:24,665 +今年秋天起即可从开发者 app 中购买 + +1219 +01:04:24,698 --> 01:04:26,800 +这就是 WeatherKit + +1220 +01:04:26,834 --> 01:04:30,904 +由 Apple 天气服务提供的准确、超本地化的天气预报 + +1221 +01:04:30,938 --> 01:04:35,642 +我们将从 Beta 测试版开始 +现在就可以在所有平台上使用 + +1222 +01:04:35,676 --> 01:04:39,913 +你可以有很多有创意的方法 +将 WeatherKit 用在你的 app 中 + +1223 +01:04:39,947 --> 01:04:41,715 +现在交给 Ryan 来给我们介绍 + +1224 +01:04:41,748 --> 01:04:44,351 +你的 app 可以通过实况文本看到什么 + +1225 +01:04:44,384 --> 01:04:47,054 +我们的用户非常喜欢实况文本 + +1226 +01:04:47,087 --> 01:04:48,522 +我们也听到你们中的很多人 + +1227 +01:04:48,555 --> 01:04:50,757 +都想把它加入到你们的 app 中 + +1228 +01:04:50,791 --> 01:04:54,127 +因此 今年我们将通过两个新的 API +扩展 VisionKit + +1229 +01:04:54,161 --> 01:04:56,330 +让你们可以做到这一点 + +1230 +01:04:57,631 --> 01:05:01,702 +实况文本 API 解锁了分析图像内容的能力 + +1231 +01:05:01,735 --> 01:05:04,371 +让用户可以与照片和暂停视频帧中的 + +1232 +01:05:04,404 --> 01:05:07,374 +文字和二维码互动 + +1233 +01:05:07,407 --> 01:05:08,775 +并提供快速操作 + +1234 +01:05:08,809 --> 01:05:10,844 +这样你的用户仅需轻点 + +1235 +01:05:10,878 --> 01:05:13,380 +即可根据相关数据完成操作 + +1236 +01:05:13,413 --> 01:05:15,749 +它非常适合任何显示视觉媒体的 app + +1237 +01:05:15,782 --> 01:05:19,386 +如 Apollo for Reddit 或 Vimeo + +1238 +01:05:19,419 --> 01:05:23,757 +而 Data Scanner API 则解锁了 +分析实时摄像头画面的能力 + +1239 +01:05:23,790 --> 01:05:27,694 +它极大地简化了扫描文本和条码的流程 + +1240 +01:05:27,728 --> 01:05:31,331 +你所需要做的就是添加覆盖物或自定义控件 + +1241 +01:05:31,365 --> 01:05:35,169 +使实况摄像头体验符合你 app 的需求 + +1242 +01:05:35,202 --> 01:05:39,139 +这特别适合依赖二维码的消费类 app + +1243 +01:05:39,173 --> 01:05:42,543 +或者是企业 app 如仓库后区库存管理 + +1244 +01:05:42,576 --> 01:05:44,211 +取货和包装送货服务 + +1245 +01:05:44,244 --> 01:05:45,679 +以及自助结账机 + +1246 +01:05:46,547 --> 01:05:48,982 +实况文本 API 和数据扫描 API + +1247 +01:05:49,016 --> 01:05:51,652 +支持自动检测 9 种语言 + +1248 +01:05:51,685 --> 01:05:54,655 +包括今年新增的日文和韩文 + +1249 +01:05:55,656 --> 01:05:59,293 +这些 VisionKit API 将多年的计算机视觉创新 + +1250 +01:05:59,326 --> 01:06:02,396 +带给你的 app 且仅需几行代码 + +1251 +01:06:02,429 --> 01:06:04,431 +下面交给 Jenny 来为各位展示 + +1252 +01:06:04,464 --> 01:06:07,935 +给大家快速展示一下 +回到我们超棒的快闪 Food Truck app + +1253 +01:06:07,968 --> 01:06:11,471 +我们正在做一个促销活动 +如果用户在社交频道发布一张照片 + +1254 +01:06:11,505 --> 01:06:15,209 +手持带有 #freedonut 标签 +和他们在 app 上的地址的牌子 + +1255 +01:06:15,242 --> 01:06:18,212 +我们就会把车开到他们的地址 +赠送一个免费甜甜圈 + +1256 +01:06:18,245 --> 01:06:20,147 +我们来看看我们甜甜圈的社交频道 + +1257 +01:06:20,180 --> 01:06:22,416 +我们想把实况文本功能添加到图片上 + +1258 +01:06:22,449 --> 01:06:25,652 +这样司机就可以提取文本 获得送餐地址 + +1259 +01:06:26,453 --> 01:06:29,223 +这就到新的实况文本 API 派上用场的时候了 + +1260 +01:06:29,256 --> 01:06:32,326 +我可以很容易地在我的视图上面 +添加一个 ImageInteraction + +1261 +01:06:32,359 --> 01:06:35,896 +这将会添加一个实况文本按钮 +并且支持快速操作 + +1262 +01:06:35,929 --> 01:06:39,132 +实况文本按钮通常位于右下角 + +1263 +01:06:39,166 --> 01:06:41,401 +但我的 app 中已经有个爱心按钮了 + +1264 +01:06:41,435 --> 01:06:44,238 +所以我可以使用自定义嵌入物调整它的位置 + +1265 +01:06:44,271 --> 01:06:48,275 +我还可以设置按钮的配置 +自定义按钮风格 + +1266 +01:06:48,308 --> 01:06:50,577 +让它与我的 app 更匹配 + +1267 +01:06:50,611 --> 01:06:54,848 +现在我已经添加好了 我可以轻点实况文本按钮 + +1268 +01:06:54,882 --> 01:06:56,316 +选择文本 + +1269 +01:06:56,350 --> 01:06:58,919 +或者用快速操作轻松抓取地址 + +1270 +01:07:00,487 --> 01:07:03,657 +我很喜欢的是用户不用学习新的交互模式 + +1271 +01:07:03,690 --> 01:07:08,295 +因为它提供了与实况文本相同的易用性 + +1272 +01:07:08,328 --> 01:07:10,430 +UI 都是一致且熟悉的 + +1273 +01:07:10,464 --> 01:07:12,499 +与操作系统充分整合 + +1274 +01:07:12,533 --> 01:07:16,503 +但我还是可以调整位置 +哪怕我已经有了自己的自定义 UI + +1275 +01:07:17,237 --> 01:07:19,273 +当然 就像任何优秀送餐 app 一样 + +1276 +01:07:19,306 --> 01:07:22,476 +我们也希望为顾客提供最好的服务 + +1277 +01:07:22,509 --> 01:07:25,479 +确保他们得到正确的甜甜圈 + +1278 +01:07:25,512 --> 01:07:28,982 +所以 我们通过二维码追踪甜甜圈订单 + +1279 +01:07:29,016 --> 01:07:33,420 +使用新的数据扫描 API +我可以轻松添加该功能 + +1280 +01:07:33,453 --> 01:07:35,923 +让它成为与顾客互动的第一步 + +1281 +01:07:35,956 --> 01:07:38,025 +现在这个按钮什么都做不了 + +1282 +01:07:38,058 --> 01:07:41,094 +但我可以很容易地实例化一个 +新的数据扫描对象 + +1283 +01:07:41,128 --> 01:07:44,231 +它可以寻找文本、二维码或条码 + +1284 +01:07:44,264 --> 01:07:46,466 +然后我可以将其导入我的 app + +1285 +01:07:46,500 --> 01:07:49,169 +仅需几行代码 我就可以调出相机 + +1286 +01:07:49,203 --> 01:07:53,373 +指明我想要二维码 然后开始扫描 + +1287 +01:07:53,407 --> 01:07:55,542 +当司机轻点二维码时 + +1288 +01:07:55,576 --> 01:07:58,011 +我想显示出扫描成功 + +1289 +01:07:58,045 --> 01:08:00,147 +我可以在 Xcode 中添加委托处理程序 + +1290 +01:08:03,517 --> 01:08:07,354 +并在轻点时向用户显示扫描成功的提示 + +1291 +01:08:07,387 --> 01:08:10,257 +这样我就可以开始处理订单了 + +1292 +01:08:10,290 --> 01:08:15,562 +现在我运行 app 时 +会调出带有相机视图的视图控制器 + +1293 +01:08:15,596 --> 01:08:16,930 +我可以看到引导信息 + +1294 +01:08:16,964 --> 01:08:20,200 +以及高亮显示二维码的标线视图 + +1295 +01:08:20,234 --> 01:08:23,570 +我轻点二维码时 就可以看到扫描成功了 + +1296 +01:08:23,604 --> 01:08:25,973 +甜甜圈订单已确认 + +1297 +01:08:26,006 --> 01:08:30,444 +就这样简单 我的 #freedonut 已经上路了 + +1298 +01:08:30,477 --> 01:08:31,512 +利用 VisionKit + +1299 +01:08:31,545 --> 01:08:34,448 +全新的实况文本 API +和数据扫描 API + +1300 +01:08:34,481 --> 01:08:38,919 +你可以轻松将这些强大的视觉功能 +带给你的 app + +1301 +01:08:38,952 --> 01:08:41,288 +好 现在交回给 Susan + +1302 +01:08:41,321 --> 01:08:44,725 +对 app 开发来说 这真是个激动人心的时代 + +1303 +01:08:44,758 --> 01:08:49,229 +Xcode Cloud 现在已经准备就绪 +帮你更快地构建更优秀的 app + +1304 +01:08:49,263 --> 01:08:51,265 +Swift 和 SwiftUI + +1305 +01:08:51,298 --> 01:08:57,571 +更便于你讲奇思妙想融入 app 中 +并且适用于 Apple 的各个平台 + +1306 +01:08:57,604 --> 01:09:00,307 +还有很酷的新方法 帮你把你的想法 + +1307 +01:09:00,340 --> 01:09:02,776 +并和系统体验相整合 + +1308 +01:09:02,809 --> 01:09:04,878 +锁定屏幕小组件和实时活动 + +1309 +01:09:04,912 --> 01:09:07,481 +把你的 app 带到锁定屏幕上 + +1310 +01:09:07,514 --> 01:09:10,250 +Messages Collaboration 让你的用户 + +1311 +01:09:10,284 --> 01:09:13,353 +可以无比轻松地联络和协作 + +1312 +01:09:13,387 --> 01:09:17,791 +而 App Intents 可以帮你把 app +和 Siri 整合在一起 + +1313 +01:09:17,824 --> 01:09:19,826 +还有各种全新的 API + +1314 +01:09:19,860 --> 01:09:22,362 +以及对现有 API 的重大更新 + +1315 +01:09:22,396 --> 01:09:27,000 +如 WeatherKit、MapKit +实况文本和 Metal + +1316 +01:09:27,034 --> 01:09:28,869 +而这还不是全部 + +1317 +01:09:28,902 --> 01:09:32,072 +今年的 WWDC 又是一大盛事 + +1318 +01:09:32,105 --> 01:09:34,241 +175 场讲座 + +1319 +01:09:34,274 --> 01:09:39,012 +数百个实验室以及数字聊天室活动 +贯穿整个星期 + +1320 +01:09:39,046 --> 01:09:41,315 +我们迫不及待在这周与大家见面 + +1321 +01:09:41,348 --> 01:09:44,518 +更重要的是 这周的主角是你们 + +1322 +01:09:44,551 --> 01:09:47,421 +我们迫不及待地想看到你们的下一个大作 + +1323 +01:09:47,454 --> 01:09:49,256 +谢谢大家! + +1324 +01:09:49,289 --> 01:09:57,297 +♪ ♪ + +1325 +01:10:06,340 --> 01:10:14,348 +. + diff --git a/zho/2022 Session 113 Apple Design Awards (ASL).srt b/zho/2022 Session 113 Apple Design Awards (ASL).srt new file mode 100644 index 0000000..911649d --- /dev/null +++ b/zho/2022 Session 113 Apple Design Awards (ASL).srt @@ -0,0 +1,1689 @@ +1 +00:00:00,000 --> 00:00:03,504 +(Apple设计大奖) + +2 +00:00:04,972 --> 00:00:09,543 +(2022年Apple设计大奖) + +3 +00:00:09,610 --> 00:00:13,780 +♪♪ + +4 +00:00:13,847 --> 00:00:18,285 +♪♪ + +5 +00:00:18,352 --> 00:00:23,590 +♪♪ + +6 +00:00:23,657 --> 00:00:28,562 +设计对我来说是一种表达自我的途径 + +7 +00:00:28,629 --> 00:00:31,398 +就像写歌或写书一样 + +8 +00:00:31,465 --> 00:00:33,767 +虽然我没学过音乐 + +9 +00:00:33,834 --> 00:00:36,603 +我也写不出华丽的词藻 + +10 +00:00:36,670 --> 00:00:39,406 +但我会编程 + +11 +00:00:39,473 --> 00:00:42,042 +设计就像一个机会 + +12 +00:00:42,109 --> 00:00:46,813 +你可以借机创造出美观且 + +13 +00:00:46,880 --> 00:00:49,650 +实用的东西 + +14 +00:00:49,716 --> 00:00:52,085 +设计在生活中无处不在 + +15 +00:00:52,152 --> 00:00:55,522 +设计会在每个层面上影响人们的生活 + +16 +00:00:55,589 --> 00:00:58,425 +设计 决定了那将是一次绝佳体验 + +17 +00:00:58,492 --> 00:01:01,295 +还是一次噩梦之旅 + +18 +00:01:01,361 --> 00:01:04,731 +没有设计 就不会有惊喜了 + +19 +00:01:04,798 --> 00:01:08,168 +这不仅涉及外观方面 +还在于好不好用 + +20 +00:01:08,235 --> 00:01:12,973 +设计也是最有效的讲述形式之一 + +21 +00:01:13,040 --> 00:01:15,475 +我认为设计经常需要做减法 + +22 +00:01:15,542 --> 00:01:17,611 +化繁为简 + +23 +00:01:17,678 --> 00:01:19,980 +就像一步一脚印地 + +24 +00:01:20,047 --> 00:01:21,048 +爬上高山 + +25 +00:01:21,114 --> 00:01:23,884 +一开始你手里是一张白纸 + +26 +00:01:23,951 --> 00:01:26,420 +然后你把它变成 + +27 +00:01:26,486 --> 00:01:27,454 +一件很酷的东西 + +28 +00:01:27,521 --> 00:01:29,790 +当你完成了好的设计 把它展示给别人 + +29 +00:01:29,857 --> 00:01:32,192 +它会为人们提供便捷 + +30 +00:01:32,259 --> 00:01:34,494 +而这件事曾经做起来非常繁琐 + +31 +00:01:34,561 --> 00:01:36,430 +我觉得这是一件很酷的事情 + +32 +00:01:36,496 --> 00:01:39,666 +我们第一次约会时 + +33 +00:01:39,733 --> 00:01:43,170 +他说他是用户体验设计师 + +34 +00:01:43,237 --> 00:01:46,607 +当时我想 我要是问那是什么职业 + +35 +00:01:46,673 --> 00:01:48,275 +会不会显得笨笨的 + +36 +00:01:48,342 --> 00:01:50,110 +♪♪ + +37 +00:01:50,177 --> 00:01:52,279 +实际设计工作更偏重于功能性 + +38 +00:01:52,346 --> 00:01:53,247 +令人愉悦 + +39 +00:01:53,313 --> 00:01:54,481 +可爱 + +40 +00:01:54,548 --> 00:01:55,816 +-令人感到舒心 +-安逸 + +41 +00:01:55,883 --> 00:01:57,484 +-充满力量 +-令人跃跃欲试 + +42 +00:01:57,551 --> 00:01:59,253 +-超炫 +-实实在在 + +43 +00:01:59,319 --> 00:02:00,220 +简单但充满乐趣 + +44 +00:02:00,287 --> 00:02:00,854 +好玩 + +45 +00:02:00,921 --> 00:02:02,089 +以及美观 + +46 +00:02:02,155 --> 00:02:05,292 +♪♪ + +47 +00:02:05,359 --> 00:02:08,195 +让我想想 我喜欢设计吗 + +48 +00:02:09,696 --> 00:02:11,465 +其实有时候超讨厌它 + +49 +00:02:11,532 --> 00:02:15,402 +不过不会持续很久 + +50 +00:02:15,469 --> 00:02:18,071 +所以总体上 我想我还是喜欢设计的 + +51 +00:02:18,138 --> 00:02:20,707 +某种程度上 我逃不出设计的掌心 + +52 +00:02:20,774 --> 00:02:23,911 +我无法想象生活没有设计会是什么样 + +53 +00:02:23,977 --> 00:02:25,712 +怎么会有人讨厌设计呢 + +54 +00:02:25,779 --> 00:02:27,681 +它像魔法 + +55 +00:02:27,748 --> 00:02:28,982 +除此之外我什么都不会 + +56 +00:02:29,049 --> 00:02:33,787 +我知道我的用户 +能通过我App里的设计 + +57 +00:02:33,854 --> 00:02:34,888 +感受到我的想法 + +58 +00:02:34,955 --> 00:02:38,859 +我认为设计确实为我们的生活方式 + +59 +00:02:38,926 --> 00:02:41,628 +带来了改变 + +60 +00:02:41,695 --> 00:02:45,265 +♪♪ + +61 +00:02:45,332 --> 00:02:50,838 +我的灵感主要来源于 +在大自然中的漫步 + +62 +00:02:50,904 --> 00:02:54,007 +每次我去散步 + +63 +00:02:54,074 --> 00:02:55,909 +都感觉灵思如泉涌 + +64 +00:02:55,976 --> 00:02:57,644 +灵感可能来自任何地方 + +65 +00:02:57,711 --> 00:03:01,181 +不一定非得是博物馆或者画廊 + +66 +00:03:01,248 --> 00:03:03,817 +可以来自大自然 可以来自城市 + +67 +00:03:03,884 --> 00:03:04,785 +当夜色四合 + +68 +00:03:04,852 --> 00:03:06,553 +人们都休息的时候 + +69 +00:03:06,620 --> 00:03:09,456 +整个世界都陷入沉睡 + +70 +00:03:09,523 --> 00:03:14,127 +这让我能更容易地进入状态 + +71 +00:03:14,194 --> 00:03:17,364 +如果能让我远离科技 + +72 +00:03:17,431 --> 00:03:20,100 +离开电脑和手机 + +73 +00:03:20,167 --> 00:03:23,003 +我就可以进行一些深层次的思考 + +74 +00:03:23,070 --> 00:03:27,674 +我想创造一些现实中看不到的东西 + +75 +00:03:27,741 --> 00:03:29,743 +我当时住在曼谷 车水马龙的地方 + +76 +00:03:29,810 --> 00:03:31,011 +交通喧嚣拥挤 + +77 +00:03:31,078 --> 00:03:34,081 +所以开发游戏也是一种 + +78 +00:03:34,147 --> 00:03:36,750 +逃离现实的途径 + +79 +00:03:36,817 --> 00:03:39,553 +设计会面对的最大挑战是 + +80 +00:03:39,620 --> 00:03:43,690 +你做的假设经常是错的 + +81 +00:03:43,757 --> 00:03:46,159 +我会将巫术作为灵感是因为 + +82 +00:03:46,226 --> 00:03:49,096 +英国进行选举时 + +83 +00:03:49,162 --> 00:03:52,099 +有一群人 + +84 +00:03:52,165 --> 00:03:54,835 +决定要对政府下诅咒 + +85 +00:03:54,902 --> 00:03:56,370 +我觉得他们应该是异教徒吧 + +86 +00:03:56,436 --> 00:04:00,807 +♪♪ + +87 +00:04:00,874 --> 00:04:03,143 +总的来说我遇过的最大挫折是什么? + +88 +00:04:03,210 --> 00:04:04,945 +这是个好问题 + +89 +00:04:05,012 --> 00:04:06,647 +最大的挫折 有很多的 + +90 +00:04:06,713 --> 00:04:07,347 +你等等 + +91 +00:04:07,414 --> 00:04:09,950 +是指我个人还是我事业中的败笔? + +92 +00:04:10,017 --> 00:04:11,485 +嗯…… + +93 +00:04:11,552 --> 00:04:13,987 +让我想想…… + +94 +00:04:14,054 --> 00:04:17,090 +要回答这问题很难不得罪人哦 + +95 +00:04:17,157 --> 00:04:18,992 +每一件事都是 + +96 +00:04:19,059 --> 00:04:22,596 +失败是任何创作过程的一部分 + +97 +00:04:22,663 --> 00:04:26,466 +我们花了很多时间努力做整合 +一个月又一个月的不懈坚持 + +98 +00:04:26,533 --> 00:04:28,502 +以期呈递一份优秀的作品 + +99 +00:04:28,569 --> 00:04:31,104 +我们经历的最大挫折是在发行时 + +100 +00:04:31,171 --> 00:04:34,775 +发现游戏里的等级不够 + +101 +00:04:34,842 --> 00:04:37,878 +我们删掉了App的主要功能 + +102 +00:04:37,945 --> 00:04:40,113 +一夜之间 + +103 +00:04:40,180 --> 00:04:42,115 +我们失去了20%的用户 + +104 +00:04:42,182 --> 00:04:44,685 +很有意思的经历吧 + +105 +00:04:44,751 --> 00:04:47,254 +一些用户发来了很不错的反馈 + +106 +00:04:47,321 --> 00:04:50,490 +其实我们都不愿意承认它很糟糕 + +107 +00:04:50,557 --> 00:04:52,993 +我们跟高兴当时做出了修改 + +108 +00:04:53,060 --> 00:04:55,529 +我的格言是 +如果一天里我有了50个想法 + +109 +00:04:55,596 --> 00:04:58,232 +49个一无是处 + +110 +00:04:58,298 --> 00:05:01,101 +1个精妙绝伦 那这一天就非常棒 + +111 +00:05:01,168 --> 00:05:04,037 +应该是久久卡在某一困境里 + +112 +00:05:04,104 --> 00:05:07,608 +找不到出路的窘境吧 + +113 +00:05:07,674 --> 00:05:09,943 +把目光投向管理 经济和法律领域 + +114 +00:05:10,010 --> 00:05:11,979 +似乎会更容易成功 + +115 +00:05:12,045 --> 00:05:16,083 +但是自从2007年iPhone面世后 + +116 +00:05:16,149 --> 00:05:17,851 +我就一门心思扎进这里面了 + +117 +00:05:17,918 --> 00:05:19,753 +回过头来看看 +但我认为我经历的最大挫折 + +118 +00:05:19,820 --> 00:05:21,221 +反而是好事 + +119 +00:05:21,288 --> 00:05:24,091 +因为它助我走到今天的高度 + +120 +00:05:24,157 --> 00:05:26,693 +♪♪ + +121 +00:05:26,760 --> 00:05:28,996 +去年早些时候 我正在开发一款App + +122 +00:05:29,062 --> 00:05:32,733 +帮助有语言障碍的用户通电话 + +123 +00:05:32,799 --> 00:05:34,501 +完成之后 + +124 +00:05:34,568 --> 00:05:36,203 +我又想开发一款类似的 + +125 +00:05:36,270 --> 00:05:38,839 +但功能是反过来的App + +126 +00:05:38,906 --> 00:05:40,107 +帮助听障用户通电话 + +127 +00:05:40,174 --> 00:05:42,409 +让他们可以看到对方讲了什么 + +128 +00:05:42,476 --> 00:05:46,146 +对我来说一切的开始于 +我想要解决自己遇到的问题 + +129 +00:05:46,213 --> 00:05:47,881 +也就是我平时总不爱喝水 + +130 +00:05:47,948 --> 00:05:49,716 +我工作总是一坐几小时不动弹 + +131 +00:05:49,783 --> 00:05:52,819 +直到觉得口渴难忍才想起来没喝水 + +132 +00:05:52,886 --> 00:05:57,157 +让喝水成为你这一天里的快乐时刻 + +133 +00:05:57,224 --> 00:05:59,760 +我的孩子们…… + +134 +00:05:59,826 --> 00:06:02,596 +只要是列在清单上的事他们就会去做 +为了就是稍后可以划掉 + +135 +00:06:02,663 --> 00:06:06,466 +我们希望能帮助你戒掉某个习惯 + +136 +00:06:06,533 --> 00:06:10,137 +并在那一刻感到快乐 + +137 +00:06:10,204 --> 00:06:14,074 +我当时在闲逛 +看到了一个坏掉的霓虹灯牌 + +138 +00:06:14,141 --> 00:06:15,809 +灵感在那一刻迸发出来 + +139 +00:06:15,876 --> 00:06:18,679 +我们想设计世界上最好用的闹钟App + +140 +00:06:18,745 --> 00:06:22,883 +为此我们拜访了很多家具店 + +141 +00:06:22,950 --> 00:06:27,955 +感受各种闹钟拿在手上的感觉 + +142 +00:06:28,021 --> 00:06:30,991 +最初我们是想帮助自己 + +143 +00:06:31,058 --> 00:06:33,193 +当时我们在开会 + +144 +00:06:33,260 --> 00:06:35,829 +但是没有趁手的工具可以 + +145 +00:06:35,896 --> 00:06:37,064 +一边做笔记 + +146 +00:06:37,130 --> 00:06:40,501 +一边跟别人开会、交谈 + +147 +00:06:40,567 --> 00:06:42,870 +于是我们想给自己开发一个App + +148 +00:06:42,936 --> 00:06:46,940 +深入了解过包容性的意义之后 + +149 +00:06:47,007 --> 00:06:49,776 +我们构建产品的方式真的被改变了 + +150 +00:06:49,843 --> 00:06:52,913 +我当时坐在缆车里 遇到了一家人 + +151 +00:06:52,980 --> 00:06:56,016 +他们说想要能够 + +152 +00:06:56,083 --> 00:06:58,819 +把今年和去年的滑雪能力进行对比 + +153 +00:06:58,886 --> 00:07:00,521 +我回家后就着手编写程序 + +154 +00:07:00,587 --> 00:07:02,823 +一周后就在App Store上架了 + +155 +00:07:02,890 --> 00:07:05,459 +专注工作时不要摸手机 + +156 +00:07:05,526 --> 00:07:09,963 +煮面条时不要总打开锅盖 + +157 +00:07:10,030 --> 00:07:13,166 +这就是贯穿Focus Noodles的思想 + +158 +00:07:13,233 --> 00:07:16,003 +让用户可以心无旁骛 + +159 +00:07:16,069 --> 00:07:19,940 +放下手机 集中精力做事 + +160 +00:07:20,007 --> 00:07:21,508 +如果你喜欢某件事 + +161 +00:07:21,575 --> 00:07:23,877 +就总能找到一个方法来精进自己 + +162 +00:07:23,944 --> 00:07:26,847 +我希望让大家爱上学中文 + +163 +00:07:26,914 --> 00:07:29,483 +我希望让其更有趣味性 更好玩 + +164 +00:07:29,550 --> 00:07:31,552 +让大家享受学习的过程 + +165 +00:07:31,618 --> 00:07:32,753 +人们把这当成一个游戏 + +166 +00:07:32,819 --> 00:07:34,188 +我们可以使用我们的技术 + +167 +00:07:34,254 --> 00:07:38,058 +把它构建成追踪你身体的游戏 + +168 +00:07:38,125 --> 00:07:40,694 +让你的手臂跟随身体来运动 + +169 +00:07:40,761 --> 00:07:42,396 +并合上节奏的律动 + +170 +00:07:42,462 --> 00:07:44,264 +音乐节奏类游戏一般都是这样 + +171 +00:07:44,331 --> 00:07:45,966 +这就是我们设计“活力街” + +172 +00:07:46,033 --> 00:07:47,835 +的灵感来源 + +173 +00:07:47,901 --> 00:07:49,169 +这有点像编舞 + +174 +00:07:49,236 --> 00:07:50,838 +就像教你如何跳舞一样 + +175 +00:07:50,904 --> 00:07:53,640 +我们正在进行一项长期项目 + +176 +00:07:53,707 --> 00:07:55,475 +我们知道做一个很快的小项目 + +177 +00:07:55,542 --> 00:07:57,911 +会很有趣 + +178 +00:07:57,978 --> 00:08:00,547 +我们永远不会对此失去动力 + +179 +00:08:00,614 --> 00:08:04,017 +这个游戏是说 你谋杀了你的丈夫 + +180 +00:08:04,084 --> 00:08:08,989 +你的目标是确保别人发觉不了这件事 + +181 +00:08:09,056 --> 00:08:11,658 +Rebel Girls + +182 +00:08:11,725 --> 00:08:17,097 +就像你的崇尚女权主义的阿姨 +她很和善 + +183 +00:08:17,164 --> 00:08:18,999 +且阅历丰富 + +184 +00:08:19,066 --> 00:08:23,670 +她的目标就是向你传授 + +185 +00:08:23,737 --> 00:08:25,005 +珍贵的价值观 + +186 +00:08:25,072 --> 00:08:26,940 +赋能女孩们去成为 + +187 +00:08:27,007 --> 00:08:30,677 +最自信的一代女性 + +188 +00:08:30,744 --> 00:08:34,681 +这个App旨在于你痛失爱人时 + +189 +00:08:34,748 --> 00:08:36,049 +做你的密友 与你慰藉 + +190 +00:08:36,116 --> 00:08:37,217 +智能的备忘录 + +191 +00:08:37,284 --> 00:08:39,419 +会提醒你必须做的事项 + +192 +00:08:39,486 --> 00:08:40,187 +同时 + +193 +00:08:40,254 --> 00:08:41,955 +它提示的仅仅是 +你现在当前必须做的那些 + +194 +00:08:42,022 --> 00:08:45,592 +同时也允许我们为您代办 + +195 +00:08:45,659 --> 00:08:46,660 +我们的Behind the Frame + +196 +00:08:46,727 --> 00:08:49,563 +总体上是一款密室逃生游戏 + +197 +00:08:49,630 --> 00:08:54,701 +像一部吉卜力风格的可以玩的动画 + +198 +00:08:54,768 --> 00:08:58,105 +我们研究过吉卜力风格的配色方案 + +199 +00:08:58,172 --> 00:09:00,340 +以及文艺复兴时期的画作 + +200 +00:09:00,407 --> 00:09:05,479 +Townscaper的玩法就是 +你来修建美丽的房子 + +201 +00:09:05,546 --> 00:09:07,181 +这就是主要内容 + +202 +00:09:07,247 --> 00:09:09,049 +主旨就是让你 + +203 +00:09:09,116 --> 00:09:11,018 +最终能够接触到 + +204 +00:09:11,084 --> 00:09:13,954 +现实中接触不到的美术品 + +205 +00:09:14,021 --> 00:09:16,857 +♪♪ + +206 +00:09:16,924 --> 00:09:19,126 +我觉得为创意人群设计工具的 + +207 +00:09:19,193 --> 00:09:21,695 +最大挑战之一是 + +208 +00:09:21,762 --> 00:09:24,031 +艺术家想创造的作品 +很多时候都是很复杂的作品 + +209 +00:09:24,097 --> 00:09:26,700 +所以挑战在于 +我们要如何在实现强大功能同时 + +210 +00:09:26,767 --> 00:09:29,636 +还让它保持实用且简单 + +211 +00:09:29,703 --> 00:09:33,006 +对于半路出家 没有经验的人 + +212 +00:09:33,073 --> 00:09:34,975 +它要足够易上手 + +213 +00:09:35,042 --> 00:09:38,412 +同时还要兼顾便捷和专业性 + +214 +00:09:38,478 --> 00:09:41,315 +对一个东西做简化其实是很复杂的 + +215 +00:09:41,381 --> 00:09:44,952 +有很多边边角角的细节 + +216 +00:09:45,018 --> 00:09:48,622 +会影响用户体验 + +217 +00:09:48,689 --> 00:09:51,258 +笨重感在所难免 + +218 +00:09:51,325 --> 00:09:53,393 +接下来4年半的开发任务 + +219 +00:09:53,460 --> 00:09:55,996 +就是各种的“瘦身”工作 + +220 +00:09:56,063 --> 00:09:59,333 +思考如何剥离那些会让人分心的东西 + +221 +00:09:59,399 --> 00:10:01,702 +努力帮助用户集中注意力 + +222 +00:10:01,768 --> 00:10:05,105 +这是我们的最终目标 + +223 +00:10:05,172 --> 00:10:06,807 +相当困难 + +224 +00:10:06,874 --> 00:10:08,775 +我们知道 + +225 +00:10:08,842 --> 00:10:11,345 +平面设计起源于案头工作时代 + +226 +00:10:11,411 --> 00:10:15,516 +近10年没有发生过太多革新 + +227 +00:10:15,582 --> 00:10:18,952 +这就类似于设计一幢建筑 + +228 +00:10:19,019 --> 00:10:21,255 +两者都需要做好导航 + +229 +00:10:21,321 --> 00:10:22,856 +网站也好 App也罢 + +230 +00:10:22,923 --> 00:10:24,424 +都有不同的视图 + +231 +00:10:24,491 --> 00:10:25,392 +要有入口 + +232 +00:10:25,459 --> 00:10:26,793 +有些地方要有出口 + +233 +00:10:26,860 --> 00:10:28,295 +要有不同的房间 + +234 +00:10:28,362 --> 00:10:29,997 +相关体验都要很顺畅丝滑 + +235 +00:10:30,063 --> 00:10:33,834 +我的水彩技术很糟糕 + +236 +00:10:33,901 --> 00:10:37,704 +我的编程能力是HTML水平 + +237 +00:10:37,771 --> 00:10:40,807 +我要一路过来说服其他人 + +238 +00:10:40,874 --> 00:10:42,809 +与我一起构建这些东西 + +239 +00:10:42,876 --> 00:10:47,047 +当我们将成品推出时 +市面上没有其他同类的水彩游戏 + +240 +00:10:47,114 --> 00:10:48,448 +甚至没有水彩相关的App + +241 +00:10:48,515 --> 00:10:50,017 +所以我们在所有细节里 + +242 +00:10:50,083 --> 00:10:51,718 +投入大量精力 + +243 +00:10:51,785 --> 00:10:53,220 +让水的流动符合现实 + +244 +00:10:53,287 --> 00:10:56,223 +打造优秀的App用户体验 + +245 +00:10:56,290 --> 00:10:58,392 +超越极限从来不是问题 + +246 +00:10:58,458 --> 00:11:00,627 +整个团队都很喜欢超越自我极限 + +247 +00:11:00,694 --> 00:11:02,629 +他们乐于看到一个角色能走多远 + +248 +00:11:02,696 --> 00:11:05,732 +或者这个场景的故事线能有多丰富 + +249 +00:11:05,799 --> 00:11:07,167 +挑战之处在于 + +250 +00:11:07,234 --> 00:11:08,702 +把界限设定在合理可达的位置 + +251 +00:11:08,769 --> 00:11:11,572 +如果你创造的是 +人们在现实生活中看不到的东西 + +252 +00:11:11,638 --> 00:11:14,741 +让用户们发出惊叹 + +253 +00:11:14,808 --> 00:11:18,478 +这就会让我们感到满足 + +254 +00:11:19,613 --> 00:11:23,483 +对 这就是 +我们选择视错觉为主题的原因 + +255 +00:11:23,550 --> 00:11:26,253 +对大多数人来说 +当你看到视错觉图片 + +256 +00:11:26,320 --> 00:11:27,788 +往往会忍不住发出惊叹 + +257 +00:11:27,855 --> 00:11:30,324 +这是一个很棘手的问题 + +258 +00:11:30,390 --> 00:11:32,593 +我们要确保用户可以在巴士上玩 + +259 +00:11:32,659 --> 00:11:34,728 +但却注意不到自己其实在车上 + +260 +00:11:34,795 --> 00:11:37,531 +这种沉浸感需要许多细枝末节来构成 + +261 +00:11:37,598 --> 00:11:38,999 +而非那些显而易见的大的方面 + +262 +00:11:39,066 --> 00:11:42,603 +像是疾驰的噪音 +排气口的声音之类的 + +263 +00:11:42,669 --> 00:11:45,305 +我们App里有巨大的几何体和景观 + +264 +00:11:45,372 --> 00:11:47,941 +还有很多我们希望能 +快速创建并自定义修改的东西 + +265 +00:11:48,008 --> 00:11:50,444 +我们会用我们设计的工具 + +266 +00:11:50,511 --> 00:11:53,380 +让它自动进行“乐高”化构建 + +267 +00:11:53,447 --> 00:11:57,017 +我们的目标是为触控设备 + +268 +00:11:57,084 --> 00:11:59,186 +设计一套非常集中化的体验 + +269 +00:11:59,253 --> 00:12:00,754 +让玩家可以不假思索地 + +270 +00:12:00,821 --> 00:12:03,123 +与这个世界互动 + +271 +00:12:03,190 --> 00:12:04,992 +这听起来可能很简单 很容易 + +272 +00:12:05,058 --> 00:12:07,561 +但实际上这是最难实现的事情之一 + +273 +00:12:07,628 --> 00:12:12,733 +MARVEL Future Revolution 是一款 +开放性世界的 超级英雄主题的 + +274 +00:12:12,799 --> 00:12:16,069 +动作大型多人在线角色扮演手游 +或简称MMORPG + +275 +00:12:16,136 --> 00:12:18,972 +你和你的伙伴们一起 + +276 +00:12:19,039 --> 00:12:22,910 +联手你最爱的漫威超级英雄 +一起在这里拯救世界 + +277 +00:12:22,976 --> 00:12:24,411 +在这里你可以真正地 + +278 +00:12:24,478 --> 00:12:26,813 +体验超级英雄的感觉 + +279 +00:12:26,880 --> 00:12:29,383 +还可以随身带到任何地方 + +280 +00:12:29,449 --> 00:12:31,785 +我想从最初开始 + +281 +00:12:31,852 --> 00:12:33,587 +我们就很清楚我们是想制作一款游戏 + +282 +00:12:33,654 --> 00:12:37,591 +其中有音乐 也有故事 + +283 +00:12:37,658 --> 00:12:40,561 +你知道的 任何事都可以做成游戏 + +284 +00:12:40,627 --> 00:12:43,964 +游戏里有个角色叫加布里埃尔 +他陷入了昏迷 + +285 +00:12:44,031 --> 00:12:48,001 +你需要通过音乐来解锁记忆 + +286 +00:12:48,068 --> 00:12:51,371 +制作这款游戏是个庞大的工程 + +287 +00:12:51,438 --> 00:12:54,808 +但是这也是个非常棒的游戏 + +288 +00:12:54,875 --> 00:12:56,476 +我想 相机是件令人愉悦的东西 + +289 +00:12:56,543 --> 00:13:00,080 +也许我们可以将类似的愉悦体验 + +290 +00:13:00,147 --> 00:13:01,949 +赋与iPhone摄像头 + +291 +00:13:02,015 --> 00:13:04,451 +我每月每周都会收到大家的邮件 + +292 +00:13:04,518 --> 00:13:06,320 +告诉我说 我很喜欢它 + +293 +00:13:06,386 --> 00:13:07,487 +帮了我很多 + +294 +00:13:07,554 --> 00:13:09,857 +这太酷了 + +295 +00:13:09,923 --> 00:13:12,926 +我们开发的这款App可以说服用户 + +296 +00:13:12,993 --> 00:13:15,329 +放弃开私家车 + +297 +00:13:15,395 --> 00:13:17,164 +且让公共交通工具的乘坐充满了乐趣 + +298 +00:13:17,231 --> 00:13:18,031 +从此 + +299 +00:13:18,098 --> 00:13:20,267 +我们的动力变成了 + +300 +00:13:20,334 --> 00:13:23,170 +通过我们的App +对人们的交通工具选择产生影响 + +301 +00:13:23,237 --> 00:13:26,740 +心理健康是很需要关注的需求之一 + +302 +00:13:26,807 --> 00:13:31,144 +这里非常需要设计者和产品构思者 + +303 +00:13:31,211 --> 00:13:34,815 +有相应的技能组合 +来将大量的关注导向于 + +304 +00:13:34,882 --> 00:13:38,886 +以前被忽视的人群 + +305 +00:13:38,952 --> 00:13:41,989 +其表现方式就是我们所谓的 + +306 +00:13:42,055 --> 00:13:45,993 +“打开大门 释放关心” + +307 +00:13:46,059 --> 00:13:49,096 +App和游戏必须应对社会变迁 + +308 +00:13:49,162 --> 00:13:51,698 +一款有包容性的游戏或App + +309 +00:13:51,765 --> 00:13:53,967 +会让每个人都感觉自在 + +310 +00:13:54,034 --> 00:13:55,402 +每个人都可以…… + +311 +00:13:55,469 --> 00:13:58,305 +既能娱乐 又能够与他人社交 + +312 +00:13:58,372 --> 00:14:01,041 +这种真实使我们能够 + +313 +00:14:01,108 --> 00:14:04,611 +不仅仅象征性地体现多元化 +而是加入真正的多元化 + +314 +00:14:04,678 --> 00:14:07,581 +我认为若我们想看到社会变化 + +315 +00:14:07,648 --> 00:14:10,617 +那就得展示出来 尤其是在娱乐方面 + +316 +00:14:10,684 --> 00:14:13,921 +因为这向人们展示了我们的方向 + +317 +00:14:13,987 --> 00:14:16,056 +我真的开始觉得 + +318 +00:14:16,123 --> 00:14:18,458 +“你看 我现在可以制作一些 +有助于人们的东西 + +319 +00:14:18,525 --> 00:14:21,094 +帮这个世界解决一点问题” + +320 +00:14:21,161 --> 00:14:23,797 +我觉得尤其是过去这两年 + +321 +00:14:23,864 --> 00:14:25,933 +我们看清了前进的方向 + +322 +00:14:25,999 --> 00:14:28,202 +看清了我们生活的哪些方面里 + +323 +00:14:28,268 --> 00:14:29,703 +数字化的分量会越来越重 + +324 +00:14:29,770 --> 00:14:37,811 +而我们作为人类 +要如何塑造日常生活体验 + +325 +00:14:37,878 --> 00:14:40,447 +我可以分享给年轻开发者的小诀窍是 + +326 +00:14:40,514 --> 00:14:43,951 +坚守你最初的想法 + +327 +00:14:44,017 --> 00:14:45,619 +如果你仅仅从喜欢的其他游戏 + +328 +00:14:45,686 --> 00:14:48,121 +汲取灵感 + +329 +00:14:48,188 --> 00:14:49,957 +那你只能创造出另一个游戏 + +330 +00:14:50,023 --> 00:14:54,027 +尝试 失败 再尝试 再失败 +然后继续下一次尝试 + +331 +00:14:54,094 --> 00:14:56,797 +尽你所能去创造 + +332 +00:14:56,864 --> 00:14:58,098 +项目不一定非得很大 + +333 +00:14:58,165 --> 00:15:00,501 +不一定非得惊天动地 + +334 +00:15:00,567 --> 00:15:02,336 +但是你尝试创作的越多 +你关于如何创作的经验就越多 + +335 +00:15:02,402 --> 00:15:06,006 +要明白什么时候该放手 +不要再徒劳地修修补补 + +336 +00:15:06,073 --> 00:15:07,608 +明确搞清楚你的目标是什么 + +337 +00:15:07,674 --> 00:15:09,776 +再来组建队伍着手开始 + +338 +00:15:09,843 --> 00:15:11,011 +不要沮丧 + +339 +00:15:11,078 --> 00:15:13,080 +放弃自己的一些假设 + +340 +00:15:13,146 --> 00:15:14,515 +你想要决定市场要什么 + +341 +00:15:14,581 --> 00:15:15,849 +是行不通的 + +342 +00:15:15,916 --> 00:15:17,851 +还是做一些 + +343 +00:15:17,918 --> 00:15:18,719 +自己有动力坚持做 + +344 +00:15:18,785 --> 00:15:21,088 +自己真的想实现的东西吧 + +345 +00:15:21,154 --> 00:15:24,224 +你可以偷师 但要从最好的人那里偷 + +346 +00:15:24,291 --> 00:15:28,529 +永远要记得加入自己的一缕巧思 + +347 +00:15:28,595 --> 00:15:29,429 +去找灵感吧 + +348 +00:15:29,496 --> 00:15:31,765 +去外面 去周遭寻找灵感 + +349 +00:15:31,832 --> 00:15:33,233 +看看现在有什么技术 + +350 +00:15:33,300 --> 00:15:35,736 +想想如何从全新的出发点 + +351 +00:15:35,802 --> 00:15:40,541 +根据你的偏好和长处来利用这些技术 + +352 +00:15:40,607 --> 00:15:47,047 +Apple设计大奖就像是奥斯卡 + +353 +00:15:47,114 --> 00:15:50,784 +我都不敢相信 我当时热泪盈眶 + +354 +00:15:50,851 --> 00:15:54,454 +我不知道我该跟谁分享这份惊喜 +我觉得 我的天 + +355 +00:15:54,521 --> 00:15:57,925 +这是多么令人惊喜的事情 + +356 +00:15:57,991 --> 00:16:01,428 +可房间里没人能与我一起分享快乐 + +357 +00:16:01,495 --> 00:16:04,898 +我记得当时他都哭了 + +358 +00:16:04,965 --> 00:16:07,501 +这对我也意义重大 + +359 +00:16:07,568 --> 00:16:10,804 +因为是我让他辞职的 + +360 +00:16:10,871 --> 00:16:13,473 +他们都还在睡吗?别这样 + +361 +00:16:13,540 --> 00:16:17,411 +这可是Apple设计大奖哎 + +362 +00:16:17,477 --> 00:16:21,381 +我收到邮件的第一反应是 + +363 +00:16:21,448 --> 00:16:23,550 +“嗯 这可能是垃圾邮件” + +364 +00:16:23,617 --> 00:16:27,087 +我心想“这垃圾邮件还挺好” + +365 +00:16:27,154 --> 00:16:29,957 +然后我跟团队聊到了这个 + +366 +00:16:30,023 --> 00:16:34,494 +然后每个人都惊呼“什么?什么?” + +367 +00:16:34,561 --> 00:16:37,297 +我想对其他决赛选手说什么? + +368 +00:16:37,364 --> 00:16:38,665 +祝你们好运 + +369 +00:16:38,732 --> 00:16:41,001 +无论最后花落谁家 + +370 +00:16:41,068 --> 00:16:43,136 +你们都交出了一份杰作 + +371 +00:16:43,203 --> 00:16:48,542 +现在我们入围了 +Apple设计大奖的决赛 + +372 +00:16:48,609 --> 00:16:52,880 +我感觉现在每一天都立于人生巅峰 + +373 +00:16:52,946 --> 00:16:55,249 +我们做到了 + +374 +00:16:55,315 --> 00:16:57,184 +我第一次听到这消息时 + +375 +00:16:57,251 --> 00:16:58,719 +非常激动 + +376 +00:16:58,785 --> 00:17:02,422 +我希望他们会回顾一下 + +377 +00:17:02,489 --> 00:17:04,858 +自己去年甚至更早的进度和工作 + +378 +00:17:04,925 --> 00:17:06,994 +干得漂亮 祝贺大家 + +379 +00:17:07,060 --> 00:17:08,195 +恭喜大家 + +380 +00:17:08,262 --> 00:17:09,263 +恭喜 + +381 +00:17:09,329 --> 00:17:10,464 +恭喜啦 + +382 +00:17:10,531 --> 00:17:12,266 +能与诸位并列是我的荣幸 + +383 +00:17:12,332 --> 00:17:13,700 +干的漂亮 + +384 +00:17:13,767 --> 00:17:15,402 +让我们继续努力吧 + +385 +00:17:15,469 --> 00:17:20,707 +你们持续的工作和创造以及努力 + +386 +00:17:20,774 --> 00:17:22,409 +会带来不同 + +387 +00:17:22,476 --> 00:17:24,578 +♪♪ + +388 +00:17:24,645 --> 00:17:27,848 +(Apple设计大奖获奖者) + +389 +00:17:27,915 --> 00:17:29,917 +(“兼容并蓄”获奖者) + +390 +00:17:29,983 --> 00:17:32,052 +(游戏 - Wylde Flowers) + +391 +00:17:32,119 --> 00:17:34,888 +(App - Procreate) + +392 +00:17:34,955 --> 00:17:37,057 +(“乐趣横生”获奖者) + +393 +00:17:37,124 --> 00:17:38,825 +(游戏 - Overboard!) + +394 +00:17:38,892 --> 00:17:42,029 +(App - (Not Boring) Habits) + +395 +00:17:42,095 --> 00:17:44,031 +(“优越互动”获奖者) + +396 +00:17:44,097 --> 00:17:45,899 +(游戏 - A Musical Story) + +397 +00:17:45,966 --> 00:17:49,102 +(App - Slopes) + +398 +00:17:49,169 --> 00:17:51,205 +(“社会影响”获奖者) + +399 +00:17:51,271 --> 00:17:52,973 +(游戏 - Gibbon: Beyond the Trees) + +400 +00:17:53,040 --> 00:17:56,176 +(App - Rebel Girls) + +401 +00:17:56,243 --> 00:17:57,911 +(“视觉图像”获奖者) + +402 +00:17:57,978 --> 00:18:00,013 +(游戏 - LEGO® Star Wars™: Castaways) + +403 +00:18:00,080 --> 00:18:03,250 +(App - Halide Mark II - 专业相机) + +404 +00:18:03,317 --> 00:18:05,352 +(“创新思维”获奖者) + +405 +00:18:05,419 --> 00:18:07,120 +(游戏 - MARVEL Future Revolution) + +406 +00:18:07,187 --> 00:18:10,324 +(App - Odio) + +407 +00:18:10,390 --> 00:18:13,427 +(Apple设计大奖获奖者) + +408 +00:18:13,493 --> 00:18:16,897 +♪♪ + +409 +00:18:16,964 --> 00:18:20,767 +♪♪ + +410 +00:18:20,834 --> 00:18:25,405 +♪♪ + +411 +00:18:25,472 --> 00:18:30,043 +♪♪ + +412 +00:18:31,912 --> 00:18:34,014 +♪♪ + +413 +00:18:34,081 --> 00:18:38,919 +♪♪ +