@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (264) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/LICENSE +0 -10
  3. package/docs/facts.json +1 -1
  4. package/manifest.json +266 -267
  5. package/package.json +2 -2
  6. package/pipeline/scripts/_notices.mjs +1 -1
  7. package/pipeline/skills/.skill-manifest.json +68 -68
  8. package/pipeline/skills/shared/README.md +70 -70
  9. package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
  10. package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
  11. package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
  12. package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
  13. package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
  14. package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
  15. package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
  16. package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
  17. package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
  18. package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
  19. package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
  20. package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +339 -277
  21. package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
  22. package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +105 -122
  23. package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +143 -166
  24. package/pipeline/skills/shared/external/app-store-review/SKILL.md +307 -326
  25. package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
  26. package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
  27. package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
  28. package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +333 -360
  29. package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
  30. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
  31. package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
  32. package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
  33. package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
  34. package/pipeline/skills/shared/external/authentication/SKILL.md +265 -381
  35. package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
  36. package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +133 -178
  37. package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
  38. package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
  39. package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
  40. package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
  41. package/pipeline/skills/shared/external/background-processing/SKILL.md +270 -382
  42. package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
  43. package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +169 -317
  44. package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
  45. package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
  46. package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
  47. package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
  48. package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
  49. package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
  50. package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
  51. package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
  52. package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
  53. package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +226 -376
  54. package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
  55. package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
  56. package/pipeline/skills/shared/external/core-data/SKILL.md +292 -368
  57. package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
  58. package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
  59. package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
  60. package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
  61. package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
  62. package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
  63. package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
  64. package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
  65. package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
  66. package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
  67. package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
  68. package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
  69. package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
  70. package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
  71. package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
  72. package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
  73. package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
  74. package/pipeline/skills/shared/external/device-integrity/SKILL.md +230 -353
  75. package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
  76. package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
  77. package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
  78. package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
  79. package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
  80. package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
  81. package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
  82. package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
  83. package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
  84. package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
  85. package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
  86. package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
  87. package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
  88. package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
  89. package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
  90. package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
  91. package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
  92. package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
  93. package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
  94. package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
  95. package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
  96. package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
  97. package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
  98. package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
  99. package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
  100. package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
  101. package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
  102. package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
  103. package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
  104. package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
  105. package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
  106. package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
  107. package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
  108. package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
  109. package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
  110. package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
  111. package/pipeline/skills/shared/external/mapkit-location/SKILL.md +295 -267
  112. package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
  113. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
  114. package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
  115. package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
  116. package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
  117. package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
  118. package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
  119. package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
  120. package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
  121. package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
  122. package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
  123. package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
  124. package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
  125. package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
  126. package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
  127. package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
  128. package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
  129. package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
  130. package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
  131. package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
  132. package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
  133. package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
  134. package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
  135. package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
  136. package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
  137. package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
  138. package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
  139. package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
  140. package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
  141. package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
  142. package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
  143. package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
  144. package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
  145. package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
  146. package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
  147. package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
  148. package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
  149. package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
  150. package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
  151. package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
  152. package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
  153. package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
  154. package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
  155. package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
  156. package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
  157. package/pipeline/skills/shared/external/storekit/references/core-patterns.md +298 -242
  158. package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
  159. package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
  160. package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
  161. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
  162. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
  163. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
  164. package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
  165. package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
  166. package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
  167. package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
  168. package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
  169. package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
  170. package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
  171. package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
  172. package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +303 -351
  173. package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
  174. package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
  175. package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
  176. package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
  177. package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
  178. package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
  179. package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
  180. package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
  181. package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
  182. package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
  183. package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
  184. package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
  185. package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
  186. package/pipeline/skills/shared/external/swift-security/SKILL.md +180 -161
  187. package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
  188. package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
  189. package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +408 -476
  190. package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
  191. package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
  192. package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
  193. package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
  194. package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
  195. package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
  196. package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +352 -472
  197. package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
  198. package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
  199. package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
  200. package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +396 -457
  201. package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
  202. package/pipeline/skills/shared/external/swift-testing/SKILL.md +188 -175
  203. package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
  204. package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +80 -84
  205. package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
  206. package/pipeline/skills/shared/external/swiftdata/SKILL.md +392 -256
  207. package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
  208. package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
  209. package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
  210. package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
  211. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
  212. package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
  213. package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
  214. package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
  215. package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
  216. package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
  217. package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
  218. package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
  219. package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
  220. package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
  221. package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
  222. package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
  223. package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
  224. package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
  225. package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
  226. package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
  227. package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
  228. package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
  229. package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
  230. package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
  231. package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +193 -168
  232. package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
  233. package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +132 -133
  234. package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
  235. package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +106 -140
  236. package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
  237. package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
  238. package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
  239. package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
  240. package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
  241. package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
  242. package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
  243. package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
  244. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
  245. package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
  246. package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
  247. package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
  248. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
  249. package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
  250. package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
  251. package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
  252. package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
  253. package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
  254. package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
  255. package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
  256. package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
  257. package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
  258. package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
  259. package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
  260. package/pipeline/skills/shared/external/weatherkit/SKILL.md +152 -310
  261. package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
  262. package/pipeline/skills/shared/external/widgetkit/SKILL.md +216 -288
  263. package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +414 -719
  264. package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
@@ -1,411 +1,322 @@
1
- # CoreLocation Patterns Reference
1
+ # CoreLocation Patterns
2
2
 
3
- Extended patterns for CoreLocation on iOS 17+ with modern Swift concurrency.
4
- Import `CoreLocation` in every file that uses these APIs.
5
-
6
- ```swift
7
- import CoreLocation
8
- ```
9
-
10
- ---
3
+ Modern CoreLocation with Swift concurrency, iOS 17 and later unless a heading
4
+ says otherwise. Import `CoreLocation` in each file that uses these types.
11
5
 
12
6
  ## Contents
13
7
 
14
- - [CLLocationUpdate.liveUpdates() (iOS 17+)](#cllocationupdateliveupdates-ios-17)
15
- - [CLServiceSession (iOS 18+)](#clservicesession-ios-18)
16
- - [CLMonitor for Geofencing (iOS 17+)](#clmonitor-for-geofencing-ios-17)
8
+ - [CLLocationUpdate.liveUpdates()](#cllocationupdateliveupdates)
9
+ - [Service Sessions (iOS 18+)](#service-sessions-ios-18)
10
+ - [Geofences with CLMonitor (iOS 17+)](#geofences-with-clmonitor-ios-17)
17
11
  - [CLBackgroundActivitySession](#clbackgroundactivitysession)
18
- - [Significant Location Change Monitoring](#significant-location-change-monitoring)
19
- - [Visit Monitoring](#visit-monitoring)
20
- - [Region Monitoring Migration (CLCircularRegion to CLMonitor)](#region-monitoring-migration-clcircularregion-to-clmonitor)
21
- - [Location Accuracy Management](#location-accuracy-management)
22
- - [Testing Location in Simulator](#testing-location-in-simulator)
23
- - [Privacy and Info.plist Keys](#privacy-and-infoplist-keys)
24
- - [Common Pitfalls](#common-pitfalls)
12
+ - [Coarse Updates from Significant Changes](#coarse-updates-from-significant-changes)
13
+ - [Visits](#visits)
14
+ - [Moving Off CLCircularRegion](#moving-off-clcircularregion)
15
+ - [Choosing Accuracy](#choosing-accuracy)
16
+ - [Simulating Position](#simulating-position)
17
+ - [Info.plist Privacy Keys](#infoplist-privacy-keys)
18
+ - [Pitfalls](#pitfalls)
25
19
  - [References](#references)
26
20
 
27
- ## CLLocationUpdate.liveUpdates() (iOS 17+)
21
+ ## CLLocationUpdate.liveUpdates()
28
22
 
29
23
  ### Basic Usage
30
24
 
31
25
  ```swift
32
- func startReceivingLocation() async {
33
- for try await update in CLLocationUpdate.liveUpdates() {
34
- guard let location = update.location else { continue }
35
- print("Lat: \(location.coordinate.latitude), Lon: \(location.coordinate.longitude)")
36
- print("Accuracy: \(location.horizontalAccuracy)m")
26
+ func logPositions() async throws {
27
+ for try await reading in CLLocationUpdate.liveUpdates() {
28
+ guard let here = reading.location else { continue }
29
+ let lat = here.coordinate.latitude
30
+ let lon = here.coordinate.longitude
31
+ let errorMetres = here.horizontalAccuracy
32
+ _ = (lat, lon, errorMetres)
37
33
  }
38
34
  }
39
35
  ```
40
36
 
41
37
  ### Full Implementation with Filtering
42
38
 
43
- Filter out stale, inaccurate, or duplicate updates to avoid unnecessary UI
44
- refreshes and reduce battery impact.
39
+ Filtering keeps the UI from redrawing on noise and saves battery. Each rule
40
+ below drops a sample that should never reach the screen.
45
41
 
46
42
  ```swift
43
+ import CoreLocation
44
+ import Observation
45
+
47
46
  @MainActor
48
47
  @Observable
49
- final class LocationService {
50
- var currentLocation: CLLocation?
51
- var isTracking = false
52
-
53
- private var trackingTask: Task<Void, Never>?
54
- private var lastReportedLocation: CLLocation?
55
-
56
- /// Minimum distance in meters between reported locations.
57
- private let distanceFilter: CLLocationDistance = 10
58
- /// Maximum acceptable horizontal accuracy in meters.
59
- private let accuracyThreshold: CLLocationAccuracy = 100
60
- /// Maximum acceptable age for a delivered location.
61
- private let maximumLocationAge: TimeInterval = 15
62
-
63
- func startTracking() {
64
- guard !isTracking else { return }
65
- isTracking = true
66
-
67
- trackingTask = Task {
48
+ final class HikeLocator {
49
+ private(set) var position: CLLocation?
50
+ private(set) var isRunning = false
51
+ private var feed: Task<Void, Never>?
52
+ private var lastPublished: CLLocation?
53
+
54
+ private let minimumMove: CLLocationDistance = 10
55
+ private let worstAccuracy: CLLocationAccuracy = 100
56
+ private let oldestAge: TimeInterval = 15
57
+ private let fastestSpeed: CLLocationSpeed = 80
58
+
59
+ func start() {
60
+ guard !isRunning else { return }
61
+ isRunning = true
62
+ feed = Task {
68
63
  do {
69
- let updates = CLLocationUpdate.liveUpdates(.default)
70
-
71
- for try await update in updates {
64
+ for try await reading in CLLocationUpdate.liveUpdates(.default) {
72
65
  if Task.isCancelled { break }
73
-
74
- // Skip updates without a location
75
- guard let location = update.location else { continue }
76
-
77
- // Skip inaccurate readings
78
- guard location.horizontalAccuracy >= 0,
79
- location.horizontalAccuracy < accuracyThreshold else {
80
- continue
81
- }
82
-
83
- // Skip stale readings
84
- guard abs(location.timestamp.timeIntervalSinceNow) < maximumLocationAge else {
85
- continue
86
- }
87
-
88
- // Skip impossible movement when speed/course are available
89
- if location.speed >= 0, location.speed > 80 {
90
- continue
91
- }
92
- if location.course >= 0, location.courseAccuracy < 0 {
93
- continue
94
- }
95
-
96
- // Skip if the user has not moved enough
97
- if let last = lastReportedLocation,
98
- location.distance(from: last) < distanceFilter {
99
- continue
100
- }
101
-
102
- lastReportedLocation = location
103
- currentLocation = location
66
+ guard let fix = reading.location, accept(fix) else { continue }
67
+ lastPublished = fix
68
+ position = fix
104
69
  }
105
70
  } catch is CancellationError {
106
- // Expected when tracking stops.
107
71
  } catch {
108
- currentLocation = nil
72
+ position = nil
109
73
  }
110
-
111
- isTracking = false
74
+ isRunning = false
112
75
  }
113
76
  }
114
77
 
115
- func stopTracking() {
116
- trackingTask?.cancel()
117
- trackingTask = nil
118
- isTracking = false
78
+ func stop() {
79
+ feed?.cancel()
80
+ feed = nil
81
+ isRunning = false
82
+ }
83
+
84
+ private func accept(_ fix: CLLocation) -> Bool {
85
+ if fix.horizontalAccuracy < 0 || fix.horizontalAccuracy >= worstAccuracy { return false }
86
+ if abs(fix.timestamp.timeIntervalSinceNow) >= oldestAge { return false }
87
+ if fix.speed >= 0 && fix.speed > fastestSpeed { return false }
88
+ if fix.course >= 0 && fix.courseAccuracy < 0 { return false }
89
+ if let lastPublished, fix.distance(from: lastPublished) < minimumMove { return false }
90
+ return true
119
91
  }
120
92
  }
121
93
  ```
122
94
 
123
- ### LiveConfiguration Options
124
-
125
- `CLLocationUpdate.liveUpdates(_:)` accepts a `LiveConfiguration` parameter:
126
-
127
- ```swift
128
- // Default: balanced power and accuracy
129
- CLLocationUpdate.liveUpdates(.default)
95
+ The rules: accuracy must be valid (not negative) and under 100 m; the sample
96
+ must be younger than 15 s; a speed above 80 m/s is a glitch; a course without
97
+ a valid course accuracy is ignored; moves under 10 m from the last published
98
+ fix are not worth a redraw. `start()` refuses to run twice.
130
99
 
131
- // Best for navigation: highest accuracy, most frequent updates
132
- CLLocationUpdate.liveUpdates(.automotiveNavigation)
133
-
134
- // Fitness tracking
135
- CLLocationUpdate.liveUpdates(.fitness)
100
+ ### LiveConfiguration Options
136
101
 
137
- // Other-navigation (non-automotive)
138
- CLLocationUpdate.liveUpdates(.otherNavigation)
102
+ `CLLocationUpdate.liveUpdates(_:)` takes a `LiveConfiguration`:
139
103
 
140
- // Airborne: for drone or aviation apps
141
- CLLocationUpdate.liveUpdates(.airborne)
142
- ```
104
+ | Value | Tuned for |
105
+ |-------|-----------|
106
+ | `.default` | balanced power and accuracy |
107
+ | `.automotiveNavigation` | turn-by-turn driving, where precision and update rate matter most |
108
+ | `.otherNavigation` | navigation that is not by car |
109
+ | `.fitness` | workouts |
110
+ | `.airborne` | drones and aviation |
143
111
 
144
- ### Handling Diagnostics and Degraded Behavior (iOS 18+)
112
+ ### Diagnostics and Fallbacks (iOS 18+)
145
113
 
146
- Keep every `liveUpdates()` stream in an owned `Task` so the feature can cancel
147
- it when the map, route, or monitoring workflow stops. Treat diagnostics and bad
148
- location samples as state changes: update UI, fall back to cached/manual input,
149
- or suspend background work instead of continuing an invisible loop.
114
+ Own every `liveUpdates()` stream in a stored `Task` and cancel it when the
115
+ map, route or monitoring flow ends. Treat a diagnostic or a bad sample as a
116
+ change of state: update the UI, fall back to cached or typed input, or pause
117
+ background work. A loop that silently waits forever is the failure mode.
150
118
 
151
119
  ```swift
152
- for try await update in CLLocationUpdate.liveUpdates() {
153
- // Check authorization status (iOS 18+)
154
- if update.authorizationDenied {
155
- // User denied location; prompt to open Settings
156
- break
157
- }
158
-
159
- if update.authorizationDeniedGlobally {
160
- // Location Services disabled system-wide
161
- break
162
- }
163
-
164
- if update.insufficientlyInUse {
165
- // App does not meet in-use requirements
166
- continue
167
- }
168
-
169
- if update.locationUnavailable {
170
- // Temporarily unable to determine location; keep iterating
171
- continue
172
- }
173
-
174
- if update.stationary {
175
- // Device stopped moving; updates will pause
176
- continue
120
+ @available(iOS 18, *)
121
+ func watch(onDenied: @escaping @MainActor () -> Void) async throws {
122
+ for try await reading in CLLocationUpdate.liveUpdates() {
123
+ if reading.authorizationDenied {
124
+ await onDenied()
125
+ break
126
+ }
127
+ if reading.authorizationDeniedGlobally { break }
128
+ if reading.insufficientlyInUse { continue }
129
+ if reading.locationUnavailable { continue }
130
+ if reading.stationary { continue }
131
+ if let fix = reading.location { _ = fix }
177
132
  }
178
-
179
- guard let location = update.location else { continue }
180
- // Use location
181
133
  }
182
134
  ```
183
135
 
184
- Note: `authorizationDenied`, `authorizationDeniedGlobally`,
185
- `insufficientlyInUse`, `locationUnavailable`, and `stationary` are only
186
- available on iOS 18+. On iOS 17, check `update.location == nil` to detect
187
- unavailable location.
136
+ | Diagnostic (iOS 18+) | Meaning | Response |
137
+ |----------------------|---------|----------|
138
+ | `authorizationDenied` | the user said no | stop location work, show a Settings path |
139
+ | `authorizationDeniedGlobally` | Location Services are off for the device | explain the system switch |
140
+ | `authorizationRestricted` | parental or MDM restriction | explain; no Settings fix for the user |
141
+ | `insufficientlyInUse` | the app is not in a state that allows updates | pause; resume when the user returns to the feature |
142
+ | `locationUnavailable` | temporarily cannot locate | keep iterating; let the user type a place or use the last known or visible area |
143
+ | `accuracyLimited` | only approximate location | search a wider radius and size geofences generously; ask for precise location only when the user starts something that needs it |
144
+ | `stationary` | device stopped moving; updates pause | nothing to do; they resume on movement |
188
145
 
189
- Map diagnostics to user-visible behavior instead of silently waiting:
146
+ Availability: all of these are iOS 18 properties. On iOS 17 the only related
147
+ property is `isStationary`, which iOS 18 deprecates in favour of
148
+ `stationary`; detect unavailability on iOS 17 by `location == nil` on the update.
190
149
 
191
- - `authorizationDenied`: stop location work and show a Settings recovery path.
192
- - `authorizationDeniedGlobally`: explain that system Location Services are off.
193
- - `insufficientlyInUse`: suspend live updates until the feature is active again.
194
- - `locationUnavailable`: keep the feature usable with cached, typed, or map-region
195
- input while waiting for recovery.
196
- - Reduced or approximate accuracy: widen search/geofence assumptions or request
197
- full accuracy only from a user-triggered feature that needs it.
150
+ Before publishing any fix, check that horizontal accuracy is valid, the
151
+ timestamp is recent and the movement is plausible. `speed` and `course` are
152
+ negative when unknown; read them only when non-negative.
198
153
 
199
- Before publishing a location, filter for valid horizontal accuracy, acceptable
200
- timestamp age, and plausible movement. Use `speed` and `course` only when their
201
- values are valid; negative values mean the measurement is unavailable.
154
+ ## Service Sessions (iOS 18+)
202
155
 
203
- ---
204
-
205
- ## CLServiceSession (iOS 18+)
156
+ `CLServiceSession` is iOS 18 and later, and unavailable on macOS.
206
157
 
207
158
  ### Setup and Lifecycle
208
159
 
209
- `CLServiceSession` declares your authorization requirements for a feature.
210
- Hold a strong reference for the session's entire duration.
160
+ The session announces what a feature needs. Keep a strong reference for as
161
+ long as the feature runs; dropping it tells the system you are done.
211
162
 
212
163
  ```swift
164
+ @available(iOS 18, *)
213
165
  @MainActor
214
166
  @Observable
215
- final class LocationFeature {
216
- private var serviceSession: CLServiceSession?
217
- private var locationTask: Task<Void, Never>?
167
+ final class NearbyFeature {
168
+ private var session: CLServiceSession?
169
+ private var feed: Task<Void, Never>?
170
+ private(set) var here: CLLocation?
218
171
 
219
172
  func activate() {
220
- // Declare that this feature needs when-in-use authorization
221
- serviceSession = CLServiceSession(authorization: .whenInUse)
222
-
223
- locationTask = Task {
173
+ session = CLServiceSession(authorization: .whenInUse)
174
+ feed = Task {
224
175
  do {
225
- for try await update in CLLocationUpdate.liveUpdates() {
226
- guard let location = update.location else { continue }
227
- // process location
176
+ for try await reading in CLLocationUpdate.liveUpdates() {
177
+ if let fix = reading.location { here = fix }
228
178
  }
229
179
  } catch is CancellationError {
230
- // Expected when the feature stops.
231
180
  } catch {
232
- // Show a degraded state or retry from user action.
181
+ here = nil
233
182
  }
234
183
  }
235
184
  }
236
185
 
237
186
  func deactivate() {
238
- locationTask?.cancel()
239
- locationTask = nil
240
- // Release the session to signal you no longer need location
241
- serviceSession = nil
187
+ feed?.cancel()
188
+ feed = nil
189
+ session = nil
242
190
  }
243
191
  }
244
192
  ```
245
193
 
194
+ On an unexpected error, move to a degraded state and offer retry rather than
195
+ leaving the screen spinning.
196
+
246
197
  ### Full Accuracy Request
247
198
 
248
- Request full accuracy when the user has granted approximate-only permission:
199
+ When the user granted only approximate location, ask for precision for one
200
+ feature:
249
201
 
250
202
  ```swift
251
- // Requires Info.plist:
252
- // NSLocationTemporaryUsageDescriptionDictionary
253
- // NearbySearchPurpose: "Show nearby stores within walking distance."
254
-
255
- let session = CLServiceSession(
256
- authorization: .whenInUse,
257
- fullAccuracyPurposeKey: "NearbySearchPurpose"
258
- )
203
+ @available(iOS 18, *)
204
+ func preciseSession() -> CLServiceSession {
205
+ CLServiceSession(authorization: .whenInUse, fullAccuracyPurposeKey: "TrailNavigation")
206
+ }
259
207
  ```
260
208
 
261
- ### Always Authorization
262
-
263
- Only use `.always` when you need the system to relaunch your app in the
264
- background for significant location changes after termination.
209
+ The key must exist in Info.plist under
210
+ `NSLocationTemporaryUsageDescriptionDictionary`, mapped to a sentence the user
211
+ will read.
265
212
 
266
- ```swift
267
- let session = CLServiceSession(authorization: .always)
268
- ```
213
+ ### Always Authorization
269
214
 
270
- Requires `NSLocationAlwaysAndWhenInUseUsageDescription` in Info.plist.
215
+ `CLServiceSession(authorization: .always)` is for one case: the system must
216
+ relaunch the app in the background after termination, for significant
217
+ location changes. It requires `NSLocationAlwaysAndWhenInUseUsageDescription`.
271
218
 
272
219
  ### Implicit vs. Explicit Sessions
273
220
 
274
- On iOS 18+, `CLLocationUpdate.liveUpdates()` and `CLMonitor` create an
275
- implicit `CLServiceSession` behind the scenes if you do not create one. You
276
- need an explicit session when:
221
+ If the app has no session, iOS 18 makes one on its behalf as soon as
222
+ `liveUpdates()` or `CLMonitor` starts. Create one explicitly when:
277
223
 
278
- - You require `.always` authorization
279
- - You need full accuracy via `fullAccuracyPurposeKey`
280
- - You want to enforce explicit session management (add
281
- `NSLocationRequireExplicitServiceSession` to Info.plist)
224
+ - the feature needs `.always`;
225
+ - the feature needs full accuracy through `fullAccuracyPurposeKey`;
226
+ - Info.plist sets `NSLocationRequireExplicitServiceSession`, which turns
227
+ implicit sessions off.
282
228
 
283
- ---
229
+ ## Geofences with CLMonitor (iOS 17+)
284
230
 
285
- ## CLMonitor for Geofencing (iOS 17+)
231
+ `CLMonitor` is iOS 17 and macOS 14 and later; it is not available on watchOS,
232
+ tvOS or visionOS.
286
233
 
287
234
  ### Basic Setup
288
235
 
289
- Use `CLMonitor` for modern condition monitoring. It is an `actor`, so its
290
- async APIs require `await`.
236
+ `CLMonitor` is an `actor`, so every call is `await`ed. Create it with a name,
237
+ add conditions, and read one `events` sequence.
291
238
 
292
239
  ```swift
240
+ import CoreLocation
241
+
242
+ struct Geofence: Sendable {
243
+ let id: String
244
+ let center: CLLocationCoordinate2D
245
+ let radius: CLLocationDistance
246
+ }
247
+
293
248
  @available(iOS 17, *)
294
- actor GeofenceMonitor {
249
+ actor ParkGates {
295
250
  private var monitor: CLMonitor?
296
- private var monitoringTask: Task<Void, any Error>?
251
+ private var listener: Task<Void, any Error>?
297
252
 
298
- func startMonitoring(regions: [GeofenceRegion]) async {
299
- let monitor = await CLMonitor("myAppGeofences")
253
+ func start(_ fences: [Geofence], onChange: @escaping @Sendable (String, Bool) -> Void) async {
254
+ let monitor = await CLMonitor("park-gates")
300
255
  self.monitor = monitor
301
-
302
- // Add circular geographic conditions
303
- for region in regions {
304
- let condition = CLMonitor.CircularGeographicCondition(
305
- center: region.center,
306
- radius: region.radius
307
- )
308
- await monitor.add(condition, identifier: region.id)
256
+ for fence in fences {
257
+ let area = CLMonitor.CircularGeographicCondition(center: fence.center, radius: fence.radius)
258
+ await monitor.add(area, identifier: fence.id)
309
259
  }
310
-
311
- // Listen for events
312
- monitoringTask = Task {
313
- for try await event in await monitor.events {
314
- switch event.state {
315
- case .satisfied:
316
- // Device entered the region
317
- handleEntry(identifier: event.identifier)
318
- case .unsatisfied:
319
- // Device exited the region
320
- handleExit(identifier: event.identifier)
321
- case .unknown:
322
- break
323
- default:
324
- break
260
+ listener = Task {
261
+ for try await change in await monitor.events {
262
+ switch change.state {
263
+ case .satisfied: onChange(change.identifier, true)
264
+ case .unsatisfied: onChange(change.identifier, false)
265
+ default: break
325
266
  }
326
267
  }
327
268
  }
328
269
  }
329
270
 
330
- func stopMonitoring() async {
331
- monitoringTask?.cancel()
332
- monitoringTask = nil
333
-
271
+ func stop() async {
272
+ listener?.cancel()
273
+ listener = nil
334
274
  if let monitor {
335
- for identifier in await monitor.identifiers {
336
- await monitor.remove(identifier)
275
+ for id in await monitor.identifiers {
276
+ await monitor.remove(id)
337
277
  }
338
278
  }
339
279
  monitor = nil
340
280
  }
341
-
342
- private func handleEntry(identifier: String) {
343
- print("Entered region: \(identifier)")
344
- }
345
-
346
- private func handleExit(identifier: String) {
347
- print("Exited region: \(identifier)")
348
- }
349
- }
350
-
351
- struct GeofenceRegion: Identifiable {
352
- let id: String
353
- let center: CLLocationCoordinate2D
354
- let radius: CLLocationDistance
355
281
  }
356
282
  ```
357
283
 
358
- ### Critical CLMonitor Rules
359
-
360
- 1. **Maximum 20 conditions per app.** Adding more causes excess conditions
361
- to report `unmonitored` state. This limit is per-app, not per-monitor.
284
+ `.satisfied` means the device is inside (entry), `.unsatisfied` outside
285
+ (exit); `.unknown` and anything else are ignored. `event.identifier` names the
286
+ condition.
362
287
 
363
- 2. **Do not recreate CLMonitor instances rapidly.** Creating a monitor with
364
- the same name while one is still alive crashes the app. Reuse the instance
365
- and call `add`/`remove` to change conditions.
366
-
367
- 3. **Subscribe to `events` exactly once per CLMonitor.** Cancelling and
368
- re-subscribing causes the new subscription to immediately cancel. Keep a
369
- single long-lived subscription.
370
-
371
- 4. **Use diffing for condition updates.** Instead of removing all conditions
372
- and re-adding them, calculate which to add and which to remove.
288
+ ### Critical CLMonitor Rules
373
289
 
374
- 5. **Target iOS 18+ for best results.** Pair `CLMonitor` with
375
- `CLServiceSession` for reliable authorization management.
290
+ - At most 20 conditions per app, counted across all monitors. Extra ones
291
+ report the `unmonitored` state.
292
+ - Never recreate a monitor quickly. Creating one with the name of a live
293
+ monitor crashes the app. Keep one and call `add` and `remove`.
294
+ - Subscribe to `events` once per monitor. Cancelling and subscribing again
295
+ gives a subscription that ends immediately; keep one long-lived listener.
296
+ - Change conditions by diffing (add the new, remove the gone), not by
297
+ removing everything and adding it back.
298
+ - Where possible, target iOS 18 and pair `CLMonitor` with a `CLServiceSession`
299
+ so authorization is handled reliably.
376
300
 
377
301
  ### Adding Conditions with Initial State
378
302
 
379
- Specify an assumed initial state to avoid spurious events on first add:
380
-
381
- ```swift
382
- await monitor.add(condition, identifier: "office", assuming: .unsatisfied)
383
- ```
384
-
385
- Use `.unsatisfied` when you believe the device is outside the region. Use
386
- `.satisfied` when you believe the device is inside.
303
+ `add(_:identifier:assuming:)` supplies the state you believe is true, which
304
+ avoids a spurious first event. Pass `.unsatisfied` when the device is
305
+ believed outside, `.satisfied` when inside.
387
306
 
388
307
  ### Updating Conditions Dynamically
389
308
 
390
309
  ```swift
391
- func updateRegions(_ newRegions: [GeofenceRegion]) async {
392
- guard let monitor else { return }
393
-
394
- let existingIDs = Set(await monitor.identifiers)
395
- let newIDs = Set(newRegions.map(\.id))
396
-
397
- // Remove stale conditions
398
- for id in existingIDs.subtracting(newIDs) {
399
- await monitor.remove(id)
310
+ @available(iOS 17, *)
311
+ func sync(_ monitor: CLMonitor, to fences: [Geofence]) async {
312
+ let current = Set(await monitor.identifiers)
313
+ let wanted = Set(fences.map(\.id))
314
+ for gone in current.subtracting(wanted) {
315
+ await monitor.remove(gone)
400
316
  }
401
-
402
- // Add new conditions
403
- for region in newRegions where !existingIDs.contains(region.id) {
404
- let condition = CLMonitor.CircularGeographicCondition(
405
- center: region.center,
406
- radius: region.radius
407
- )
408
- await monitor.add(condition, identifier: region.id, assuming: .unsatisfied)
317
+ for fence in fences where !current.contains(fence.id) {
318
+ let area = CLMonitor.CircularGeographicCondition(center: fence.center, radius: fence.radius)
319
+ await monitor.add(area, identifier: fence.id, assuming: .unsatisfied)
409
320
  }
410
321
  }
411
322
  ```
@@ -413,365 +324,300 @@ func updateRegions(_ newRegions: [GeofenceRegion]) async {
413
324
  ### Checking Last Known State
414
325
 
415
326
  ```swift
416
- if let record = await monitor.record(for: "office") {
417
- let lastState = record.lastEvent.state
418
- let lastDate = record.lastEvent.date
419
- print("Region 'office' was \(lastState) at \(lastDate)")
327
+ @available(iOS 17, *)
328
+ func lastSeen(_ monitor: CLMonitor, fence id: String) async -> (CLMonitor.Event.State, Date)? {
329
+ let saved = await monitor.record(for: id)
330
+ guard let last = saved?.lastEvent else { return nil }
331
+ return (last.state, last.date)
420
332
  }
421
333
  ```
422
334
 
423
- ---
424
-
425
335
  ## CLBackgroundActivitySession
426
336
 
427
- Allow a when-in-use authorized app to receive location updates in the
428
- background. Requires the `Location updates` background mode capability.
337
+ Available from iOS 17; not on macOS or tvOS. It lets an app with when-in-use
338
+ authorization keep receiving location in the background. It needs the
339
+ Location updates background mode, and while it is held the system shows the
340
+ blue location indicator.
429
341
 
430
342
  ```swift
431
343
  @available(iOS 17, *)
432
- actor BackgroundLocationTracker {
433
- private var backgroundSession: CLBackgroundActivitySession?
434
- private var serviceSession: CLServiceSession?
435
- private var trackingTask: Task<Void, Never>?
436
-
437
- func startBackgroundTracking() {
438
- // Declare authorization intent (iOS 18+)
439
- serviceSession = CLServiceSession(authorization: .whenInUse)
440
-
441
- // Start background activity session -- shows blue location indicator
442
- backgroundSession = CLBackgroundActivitySession()
443
-
444
- trackingTask = Task {
344
+ actor WorkoutRecorder {
345
+ private var background: CLBackgroundActivitySession?
346
+ private var service: AnyObject?
347
+ private var feed: Task<Void, Never>?
348
+ private var trail: [CLLocation] = []
349
+
350
+ func begin() {
351
+ if #available(iOS 18, *) {
352
+ service = CLServiceSession(authorization: .whenInUse)
353
+ }
354
+ background = CLBackgroundActivitySession()
355
+ feed = Task {
445
356
  do {
446
- for try await update in CLLocationUpdate.liveUpdates(.fitness) {
447
- guard let location = update.location else { continue }
448
- // Record location for fitness tracking, navigation, etc.
449
- await recordLocation(location)
357
+ for try await reading in CLLocationUpdate.liveUpdates(.fitness) {
358
+ if let fix = reading.location { record(fix) }
450
359
  }
451
- } catch is CancellationError {
452
- // Expected when background tracking stops.
453
- } catch {
454
- // Persist an error state or retry from user action.
455
- }
360
+ } catch {}
456
361
  }
457
362
  }
458
363
 
459
- func stopBackgroundTracking() {
460
- trackingTask?.cancel()
461
- trackingTask = nil
462
- backgroundSession?.invalidate()
463
- backgroundSession = nil
464
- serviceSession = nil
364
+ private func record(_ fix: CLLocation) {
365
+ trail.append(fix)
465
366
  }
466
367
 
467
- private func recordLocation(_ location: CLLocation) async {
468
- // Persist to database, update Live Activity, etc.
368
+ func finish() {
369
+ feed?.cancel()
370
+ feed = nil
371
+ background?.invalidate()
372
+ background = nil
373
+ service = nil
469
374
  }
470
375
  }
471
376
  ```
472
377
 
473
378
  ### Background Requirements Summary
474
379
 
475
- To receive location in the background you need ALL of these:
476
-
477
- 1. `Background Modes > Location updates` capability enabled.
478
- 2. `NSLocationWhenInUseUsageDescription` in Info.plist.
479
- 3. `.whenInUse` or `.always` authorization granted.
480
- 4. Either a `CLBackgroundActivitySession` held or a Live Activity running.
481
- 5. An active `CLLocationUpdate` or `CLMonitor` subscription.
380
+ Background location works only when all of these hold:
482
381
 
483
- `.always` authorization is NOT required for background location. The
484
- difference: with `.always`, the system can relaunch your terminated app for
485
- significant location changes. With `.whenInUse` + background session, the
486
- app must be running (foreground or suspended).
382
+ 1. Background Modes > Location updates is enabled.
383
+ 2. Info.plist has `NSLocationWhenInUseUsageDescription`.
384
+ 3. The user granted `.whenInUse` or `.always`.
385
+ 4. The app holds a `CLBackgroundActivitySession`, or runs a Live Activity
386
+ (see `live-activities`).
387
+ 5. A `CLLocationUpdate` or `CLMonitor` subscription is active.
487
388
 
488
- ---
389
+ `.always` is not needed for this. What `.always` adds is relaunch: after the
390
+ app has been terminated, a significant move can bring it back. With
391
+ `.whenInUse` plus a background session, the app must still be running,
392
+ in the foreground or suspended.
489
393
 
490
- ## Significant Location Change Monitoring
394
+ ## Coarse Updates from Significant Changes
491
395
 
492
- Use when you only need coarse location updates at ~500-meter intervals.
493
- Extremely battery efficient because it piggybacks on cellular tower changes.
396
+ Coarse updates, roughly every 500 m, driven by cell tower changes and cheap on
397
+ battery. There is no `CLLocationUpdate` equivalent, so this stays on
398
+ `CLLocationManager`, which is legacy but valid:
494
399
 
495
400
  ```swift
496
- // Legacy CLLocationManager approach (still valid, no modern replacement)
497
- let manager = CLLocationManager()
498
- manager.startMonitoringSignificantLocationChanges()
499
-
500
- // The delegate receives updates when the device moves ~500m+ from the
501
- // last reported location. Updates arrive 1-5 minutes apart.
401
+ let coarseManager = CLLocationManager()
402
+ coarseManager.startMonitoringSignificantLocationChanges()
502
403
  ```
503
404
 
504
- There is no `CLLocationUpdate` equivalent for significant location changes.
505
- Use `CLLocationManager` for this specific use case.
506
-
507
- ---
405
+ The delegate hears about moves of 500 m or more, typically 1 to 5 minutes
406
+ apart.
508
407
 
509
- ## Visit Monitoring
408
+ ## Visits
510
409
 
511
- Detect when the user arrives at or departs from a place. Useful for
512
- journaling, check-in, and context-aware features.
410
+ Arrivals and departures at places, for journaling, check-ins or context-aware
411
+ features.
513
412
 
514
413
  ```swift
515
- let manager = CLLocationManager()
516
- manager.startMonitoringVisits()
517
-
518
- // Delegate callback:
519
- func locationManager(_ manager: CLLocationManager, didVisit visit: CLVisit) {
520
- let coordinate = visit.coordinate
521
- let arrivalDate = visit.arrivalDate
522
- let departureDate = visit.departureDate
523
- // departureDate == .distantFuture means the user is still at the location
414
+ final class VisitLog: NSObject, CLLocationManagerDelegate {
415
+ private let manager = CLLocationManager()
416
+
417
+ func start() {
418
+ manager.delegate = self
419
+ manager.startMonitoringVisits()
420
+ }
421
+
422
+ func locationManager(_ manager: CLLocationManager, didVisit stop: CLVisit) {
423
+ let stillThere = stop.departureDate == .distantFuture
424
+ _ = (stop.coordinate, stop.arrivalDate, stillThere)
425
+ }
524
426
  }
525
427
  ```
526
428
 
527
- ---
429
+ A `departureDate` of `.distantFuture` means the user has not left yet.
528
430
 
529
- ## Region Monitoring Migration (CLCircularRegion to CLMonitor)
431
+ ## Moving Off CLCircularRegion
530
432
 
531
433
  ### Older Delegate Approach
532
434
 
533
435
  ```swift
534
- let region = CLCircularRegion(center: coordinate, radius: 200, identifier: "office")
535
- region.notifyOnEntry = true
536
- region.notifyOnExit = true
537
- manager.startMonitoring(for: region)
436
+ let gate = CLCircularRegion(center: gateCenter, radius: 200, identifier: "north-gate")
437
+ gate.notifyOnEntry = true
438
+ gate.notifyOnExit = true
439
+ legacyManager.startMonitoring(for: gate)
538
440
  ```
539
441
 
540
442
  ### Modern Approach (iOS 17+)
541
443
 
542
444
  ```swift
543
- // MODERN
544
- let monitor = await CLMonitor("appMonitor")
545
- let condition = CLMonitor.CircularGeographicCondition(center: coordinate, radius: 200)
546
- await monitor.add(condition, identifier: "office")
547
-
548
- for try await event in await monitor.events {
549
- if event.identifier == "office" {
550
- switch event.state {
551
- case .satisfied: handleEntry()
552
- case .unsatisfied: handleExit()
445
+ @available(iOS 17, *)
446
+ func watchGate(_ center: CLLocationCoordinate2D) async throws {
447
+ let monitor = await CLMonitor("gates")
448
+ await monitor.add(CLMonitor.CircularGeographicCondition(center: center, radius: 200),
449
+ identifier: "north-gate")
450
+ for try await change in await monitor.events where change.identifier == "north-gate" {
451
+ switch change.state {
452
+ case .satisfied: break
453
+ case .unsatisfied: break
553
454
  default: break
554
455
  }
555
456
  }
556
457
  }
557
458
  ```
558
459
 
559
- Key differences:
560
-
561
- | Aspect | CLCircularRegion | CLMonitor |
562
- |--------|-----------------|-----------|
563
- | API style | Delegate callbacks | Async sequence |
564
- | Max regions | 20 per app | 20 per app |
565
- | Entry/exit | Separate booleans | State enum (satisfied/unsatisfied) |
566
- | Concurrency | @objc delegate | Actor-based |
567
- | Min iOS | iOS 7 | iOS 17 |
460
+ | | `CLCircularRegion` | `CLMonitor` |
461
+ |-|--------------------|-------------|
462
+ | Shape of the API | callbacks on a delegate | an async sequence of events |
463
+ | Region limit | 20 for the whole app | same 20, shared |
464
+ | Entry and exit | two booleans | one state enum (satisfied, unsatisfied) |
465
+ | Concurrency | `@objc` delegate | actor |
466
+ | Minimum iOS | 7 | 17 |
568
467
 
569
- ---
570
-
571
- ## Location Accuracy Management
468
+ ## Choosing Accuracy
572
469
 
573
470
  ### Accuracy Levels for CLLocationManager
574
471
 
575
- ```swift
576
- manager.desiredAccuracy = kCLLocationAccuracyBest // GPS, ~5m, highest power
577
- manager.desiredAccuracy = kCLLocationAccuracyNearestTenMeters // ~10m
578
- manager.desiredAccuracy = kCLLocationAccuracyHundredMeters // WiFi, ~100m
579
- manager.desiredAccuracy = kCLLocationAccuracyKilometer // Cell tower, ~1km
580
- manager.desiredAccuracy = kCLLocationAccuracyThreeKilometers // ~3km, lowest power
581
- manager.desiredAccuracy = kCLLocationAccuracyReduced // ~5km, privacy-safe
582
- ```
472
+ Set with `manager.desiredAccuracy`:
583
473
 
584
- ### Activity Type (Influences Power Management)
474
+ | Constant | Roughly | Source and cost |
475
+ |----------|---------|-----------------|
476
+ | `kCLLocationAccuracyBest` | 5 m | GPS, most power |
477
+ | `kCLLocationAccuracyNearestTenMeters` | 10 m | |
478
+ | `kCLLocationAccuracyHundredMeters` | 100 m | Wi-Fi |
479
+ | `kCLLocationAccuracyKilometer` | 1 km | cell towers |
480
+ | `kCLLocationAccuracyThreeKilometers` | 3 km | least power |
481
+ | `kCLLocationAccuracyReduced` | 5 km | approximate, privacy-preserving |
585
482
 
586
- ```swift
587
- manager.activityType = .other // Default
588
- manager.activityType = .automotiveNavigation // Highway speeds, high accuracy
589
- manager.activityType = .fitness // Walking/running
590
- manager.activityType = .otherNavigation // Boats, trains
591
- manager.activityType = .airborne // Drones, aircraft (iOS 12+)
592
- ```
483
+ ### Activity Type
593
484
 
594
- ### CLLocationUpdate has no filtering
485
+ `manager.activityType` guides power management:
595
486
 
596
- `CLLocationUpdate.liveUpdates()` does not support `desiredAccuracy` or
597
- `distanceFilter`. Filter the stream yourself:
487
+ | Value | Use |
488
+ |-------|-----|
489
+ | `.other` | default |
490
+ | `.automotiveNavigation` | highway speeds, high accuracy |
491
+ | `.fitness` | walking and running |
492
+ | `.otherNavigation` | boats, trains |
493
+ | `.airborne` | drones and aircraft (iOS 12+) |
598
494
 
599
- ```swift
600
- for try await update in CLLocationUpdate.liveUpdates() {
601
- guard let location = update.location,
602
- location.horizontalAccuracy < 50,
603
- location.horizontalAccuracy >= 0 else { continue }
604
- // Use filtered location
605
- }
606
- ```
607
-
608
- ---
609
-
610
- ## Testing Location in Simulator
611
-
612
- ### Set a fixed simulated location
495
+ ### CLLocationUpdate has no filtering
613
496
 
614
- In Xcode: Debug > Simulate Location > choose a city or custom coordinate.
497
+ `liveUpdates()` has neither `desiredAccuracy` nor `distanceFilter`. Pick a
498
+ `LiveConfiguration` and filter the stream yourself, for example keep only
499
+ fixes with `horizontalAccuracy >= 0 && horizontalAccuracy < 50`.
615
500
 
616
- ### GPX File for a Moving Route
501
+ ## Simulating Position
617
502
 
618
- Create a `.gpx` file and add it to your Xcode project:
503
+ - One fixed spot: Xcode Debug > Simulate Location, then a city or a custom
504
+ coordinate.
505
+ - A moving path: add a `.gpx` file to the project and pick it under Edit
506
+ Scheme > Run > Options > Default Location.
619
507
 
620
508
  ```xml
621
509
  <?xml version="1.0"?>
622
- <gpx version="1.1" creator="Xcode">
623
- <wpt lat="37.3349" lon="-122.0090">
624
- <time>2025-01-01T00:00:00Z</time>
625
- <name>Apple Park</name>
510
+ <gpx creator="Xcode" version="1.1">
511
+ <wpt lat="47.6062" lon="-122.3321">
512
+ <name>Start</name>
513
+ <time>2026-01-01T09:00:00Z</time>
626
514
  </wpt>
627
- <wpt lat="37.3318" lon="-122.0312">
628
- <time>2025-01-01T00:01:00Z</time>
629
- <name>Infinite Loop</name>
630
- </wpt>
631
- <wpt lat="37.3230" lon="-122.0322">
632
- <time>2025-01-01T00:02:00Z</time>
633
- <name>De Anza College</name>
515
+ <wpt lat="47.6097" lon="-122.3331">
516
+ <name>Market</name>
517
+ <time>2026-01-01T09:05:00Z</time>
634
518
  </wpt>
635
519
  </gpx>
636
520
  ```
637
521
 
638
- Set this file in the scheme: Edit Scheme > Run > Options > Default Location.
639
-
640
- The simulator interpolates between waypoints using timestamps. Playback loops
641
- automatically when it reaches the last waypoint.
522
+ The simulator moves between waypoints at the pace their timestamps imply and
523
+ starts over after the last one.
642
524
 
643
525
  ### Programmatic Simulation in Tests
644
526
 
645
- Use `CLLocationManager` with XCTest by injecting a location protocol:
527
+ Unit tests need a position source they control. Hide the stream behind a
528
+ protocol and inject a fake:
646
529
 
647
530
  ```swift
648
- protocol LocationProviding: Sendable {
649
- func updates() -> AsyncStream<CLLocation>
531
+ protocol PositionSource: Sendable {
532
+ func positions() -> AsyncStream<CLLocation>
650
533
  }
651
534
 
652
- // Production
653
- struct LiveLocationProvider: LocationProviding {
654
- func updates() -> AsyncStream<CLLocation> {
535
+ struct DevicePositionSource: PositionSource {
536
+ func positions() -> AsyncStream<CLLocation> {
655
537
  AsyncStream { continuation in
656
- Task {
657
- for try await update in CLLocationUpdate.liveUpdates() {
658
- if let location = update.location {
659
- continuation.yield(location)
538
+ let pump = Task {
539
+ do {
540
+ for try await reading in CLLocationUpdate.liveUpdates() {
541
+ if let fix = reading.location { continuation.yield(fix) }
660
542
  }
661
- }
543
+ } catch {}
662
544
  continuation.finish()
663
545
  }
546
+ continuation.onTermination = { _ in pump.cancel() }
664
547
  }
665
548
  }
666
549
  }
667
550
 
668
- // Test mock
669
- struct MockLocationProvider: LocationProviding {
670
- let locations: [CLLocation]
551
+ struct ScriptedPositionSource: PositionSource {
552
+ let script: [CLLocation]
671
553
 
672
- func updates() -> AsyncStream<CLLocation> {
554
+ func positions() -> AsyncStream<CLLocation> {
673
555
  AsyncStream { continuation in
674
- for location in locations {
675
- continuation.yield(location)
676
- }
556
+ for fix in script { continuation.yield(fix) }
677
557
  continuation.finish()
678
558
  }
679
559
  }
680
560
  }
681
561
  ```
682
562
 
683
- ---
563
+ The same seam works for code still on `CLLocationManager`: wrap the delegate
564
+ behind the protocol and feed the scripted source in XCTest or Swift Testing.
684
565
 
685
- ## Privacy and Info.plist Keys
566
+ ## Info.plist Privacy Keys
686
567
 
687
568
  ### Required Keys
688
569
 
689
- | Key | When to add |
690
- |-----|-------------|
691
- | `NSLocationWhenInUseUsageDescription` | Always, for any location use |
692
- | `NSLocationAlwaysAndWhenInUseUsageDescription` | Only if requesting `.always` |
570
+ | Key | When |
571
+ |-----|------|
572
+ | `NSLocationWhenInUseUsageDescription` | every app that reads location at all |
573
+ | `NSLocationAlwaysAndWhenInUseUsageDescription` | only when requesting `.always` |
693
574
 
694
575
  ### Optional Keys
695
576
 
696
- | Key | Purpose |
697
- |-----|---------|
698
- | `NSLocationTemporaryUsageDescriptionDictionary` | Per-feature full-accuracy descriptions |
699
- | `NSLocationRequireExplicitServiceSession` | Force explicit `CLServiceSession` usage (iOS 18+) |
700
- | `NSLocationDefaultAccuracyReduced` | Default to approximate location |
701
- | `UIBackgroundModes` (includes `location`) | Background location updates |
577
+ | Key | Effect |
578
+ |-----|--------|
579
+ | `NSLocationTemporaryUsageDescriptionDictionary` | purpose strings for per-feature full accuracy |
580
+ | `NSLocationRequireExplicitServiceSession` | disables implicit `CLServiceSession` (iOS 18+) |
581
+ | `NSLocationDefaultAccuracyReduced` | the app starts with approximate location |
582
+ | `UIBackgroundModes` containing `location` | background location updates |
702
583
 
703
584
  ### Usage Description Best Practices
704
585
 
705
- **Good:** "Shows nearby coffee shops within walking distance so you can find your next stop quickly."
586
+ Say what the user gets. "Shows trailheads within a short drive of you" is a
587
+ reason; "This app uses your location." is not, and App Review rejects vague
588
+ purpose strings.
706
589
 
707
- **Bad:** "This app uses your location."
708
-
709
- App Review rejects vague usage descriptions. Be specific about what the user
710
- gains from sharing their location.
711
-
712
- ---
713
-
714
- ## Common Pitfalls
590
+ ## Pitfalls
715
591
 
716
592
  ### CLMonitor crash on rapid recreation
717
593
 
718
- ```swift
719
- // CRASH -- creating a monitor with a name already in use
720
- let monitorA = await CLMonitor("myMonitor")
721
- // ... immediately discard monitorA ...
722
- let monitorB = await CLMonitor("myMonitor") // NSInternalInconsistencyException
723
- ```
724
-
725
- Fix: reuse the existing monitor instance. Only create a new one after the
726
- old one has been fully torn down (conditions removed, reference released,
727
- NOT in the same run loop).
594
+ A second `CLMonitor` created with a name that is still in use raises
595
+ `NSInternalInconsistencyException`. Reuse the monitor. Make a new one only
596
+ after full teardown (conditions removed, reference released) and never in the
597
+ same run loop turn.
728
598
 
729
- ### Accuracy-limited updates need explicit handling
599
+ ### Approximate location arrives rarely
730
600
 
731
- Approximate location may update infrequently. On iOS 18+, check diagnostic
732
- properties such as `accuracyLimited` and `locationUnavailable`; otherwise,
733
- treat `update.location == nil` as a state change and provide a degraded
734
- experience instead of spinning or timing out.
601
+ Approximate location can arrive rarely. On iOS 18 check `accuracyLimited` and
602
+ `locationUnavailable`; on iOS 17 treat `location == nil` on the update as a state
603
+ change. Either way, give a degraded experience instead of a spinner or a
604
+ timeout.
735
605
 
736
606
  ### Forgetting to hold CLBackgroundActivitySession
737
607
 
738
- ```swift
739
- // WRONG -- session is immediately deallocated
740
- func startBackground() {
741
- let _ = CLBackgroundActivitySession()
742
- // ^ No strong reference; session ends immediately
743
- }
744
-
745
- // CORRECT -- hold as a stored property
746
- private var bgSession: CLBackgroundActivitySession?
747
-
748
- func startBackground() {
749
- bgSession = CLBackgroundActivitySession()
750
- }
751
- ```
608
+ `_ = CLBackgroundActivitySession()` deallocates at once and the session ends
609
+ with it. Store it in a property.
752
610
 
753
611
  ### Not checking horizontalAccuracy
754
612
 
755
- ```swift
756
- // WRONG -- using location with negative accuracy (invalid)
757
- guard let location = update.location else { continue }
758
- updateMap(location) // May have accuracy of -1 (invalid)
759
-
760
- // CORRECT
761
- guard let location = update.location,
762
- location.horizontalAccuracy >= 0 else { continue }
763
- updateMap(location)
764
- ```
765
-
766
- A `horizontalAccuracy` of -1 means the coordinate is invalid.
767
-
768
- ---
613
+ A `horizontalAccuracy` of -1 marks the coordinate invalid. Check
614
+ `horizontalAccuracy >= 0` before using any fix.
769
615
 
770
616
  ## References
771
617
 
772
- - Apple docs: [CLLocationUpdate](https://sosumi.ai/documentation/CoreLocation/CLLocationUpdate)
773
- - Apple docs: [CLServiceSession](https://sosumi.ai/documentation/CoreLocation/CLServiceSession)
774
- - Apple docs: [CLMonitor](https://sosumi.ai/documentation/CoreLocation/CLMonitor)
775
- - Apple docs: [CLBackgroundActivitySession](https://sosumi.ai/documentation/CoreLocation/CLBackgroundActivitySession)
776
- - Apple docs: [Requesting authorization](https://sosumi.ai/documentation/CoreLocation/requesting-authorization-to-use-location-services)
777
- - Apple docs: [Handling background location](https://sosumi.ai/documentation/CoreLocation/handling-location-updates-in-the-background)
618
+ - [CLLocationUpdate](https://developer.apple.com/documentation/corelocation/cllocationupdate)
619
+ - [CLServiceSession](https://developer.apple.com/documentation/corelocation/clservicesession)
620
+ - [CLMonitor](https://developer.apple.com/documentation/corelocation/clmonitor)
621
+ - [CLBackgroundActivitySession](https://developer.apple.com/documentation/corelocation/clbackgroundactivitysession)
622
+ - [Location authorization](https://developer.apple.com/documentation/corelocation/requesting-authorization-to-use-location-services)
623
+ - [Background location updates](https://developer.apple.com/documentation/corelocation/handling-location-updates-in-the-background)