@mmerterden/multi-agent-pipeline 20.7.0 → 20.8.1
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.
- package/CHANGELOG.md +21 -0
- package/LICENSE +0 -10
- package/docs/facts.json +1 -1
- package/manifest.json +285 -285
- package/package.json +3 -3
- package/pipeline/lib/redact.mjs +3 -2
- package/pipeline/scripts/_notices.mjs +1 -1
- package/pipeline/scripts/gen-skills-index.mjs +13 -1
- package/pipeline/scripts/pre-commit-check.sh +4 -0
- package/pipeline/skills/.skill-manifest.json +69 -69
- package/pipeline/skills/shared/README.md +70 -70
- package/pipeline/skills/shared/external/alarmkit/SKILL.md +373 -381
- package/pipeline/skills/shared/external/alarmkit/evals/evals.json +23 -18
- package/pipeline/skills/shared/external/alarmkit/references/alarmkit-patterns.md +328 -378
- package/pipeline/skills/shared/external/app-clips/SKILL.md +260 -160
- package/pipeline/skills/shared/external/app-clips/evals/evals.json +27 -27
- package/pipeline/skills/shared/external/app-clips/references/data-handoff-notifications-location.md +150 -83
- package/pipeline/skills/shared/external/app-clips/references/routing-and-experiences.md +135 -83
- package/pipeline/skills/shared/external/app-clips/references/size-capabilities-and-promotion.md +143 -85
- package/pipeline/skills/shared/external/app-intents/SKILL.md +302 -304
- package/pipeline/skills/shared/external/app-intents/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-intents/references/appintents-advanced.md +594 -894
- package/pipeline/skills/shared/external/app-store-optimization/SKILL.md +345 -277
- package/pipeline/skills/shared/external/app-store-optimization/evals/evals.json +27 -23
- package/pipeline/skills/shared/external/app-store-optimization/references/keyword-research-methodology.md +107 -121
- package/pipeline/skills/shared/external/app-store-optimization/references/product-page-variants.md +145 -165
- package/pipeline/skills/shared/external/app-store-review/SKILL.md +306 -326
- package/pipeline/skills/shared/external/app-store-review/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/app-store-review/references/privacy-manifest.md +105 -67
- package/pipeline/skills/shared/external/app-store-review/references/review-checklists.md +114 -101
- package/pipeline/skills/shared/external/apple-on-device-ai/SKILL.md +335 -360
- package/pipeline/skills/shared/external/apple-on-device-ai/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-conversion.md +215 -322
- package/pipeline/skills/shared/external/apple-on-device-ai/references/coreml-optimization.md +161 -256
- package/pipeline/skills/shared/external/apple-on-device-ai/references/foundation-models.md +277 -387
- package/pipeline/skills/shared/external/apple-on-device-ai/references/mlx-swift.md +196 -210
- package/pipeline/skills/shared/external/authentication/SKILL.md +277 -381
- package/pipeline/skills/shared/external/authentication/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/authentication/references/keychain-biometric.md +135 -178
- package/pipeline/skills/shared/external/authentication/references/passkeys.md +111 -147
- package/pipeline/skills/shared/external/avkit/SKILL.md +267 -364
- package/pipeline/skills/shared/external/avkit/evals/evals.json +26 -26
- package/pipeline/skills/shared/external/avkit/references/avkit-patterns.md +375 -493
- package/pipeline/skills/shared/external/background-processing/SKILL.md +274 -384
- package/pipeline/skills/shared/external/background-processing/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/background-processing/references/background-task-patterns.md +173 -321
- package/pipeline/skills/shared/external/callkit-voip/SKILL.md +290 -371
- package/pipeline/skills/shared/external/callkit-voip/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/callkit-voip/references/callkit-patterns.md +175 -343
- package/pipeline/skills/shared/external/cloudkit-sync/SKILL.md +292 -381
- package/pipeline/skills/shared/external/cloudkit-sync/evals/evals.json +33 -30
- package/pipeline/skills/shared/external/cloudkit-sync/references/cloudkit-patterns.md +227 -355
- package/pipeline/skills/shared/external/contacts-framework/SKILL.md +197 -346
- package/pipeline/skills/shared/external/contacts-framework/evals/evals.json +19 -21
- package/pipeline/skills/shared/external/contacts-framework/references/contacts-patterns.md +169 -308
- package/pipeline/skills/shared/external/core-bluetooth/SKILL.md +228 -376
- package/pipeline/skills/shared/external/core-bluetooth/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/core-bluetooth/references/ble-patterns.md +257 -337
- package/pipeline/skills/shared/external/core-data/SKILL.md +302 -368
- package/pipeline/skills/shared/external/core-data/evals/evals.json +30 -27
- package/pipeline/skills/shared/external/core-motion/SKILL.md +235 -324
- package/pipeline/skills/shared/external/core-motion/evals/evals.json +31 -27
- package/pipeline/skills/shared/external/core-motion/references/motion-patterns.md +210 -310
- package/pipeline/skills/shared/external/core-nfc/SKILL.md +292 -366
- package/pipeline/skills/shared/external/core-nfc/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/core-nfc/references/nfc-patterns.md +233 -329
- package/pipeline/skills/shared/external/coreml/SKILL.md +323 -367
- package/pipeline/skills/shared/external/coreml/evals/evals.json +24 -21
- package/pipeline/skills/shared/external/coreml/references/coreml-swift-integration.md +562 -565
- package/pipeline/skills/shared/external/cryptokit/SKILL.md +253 -394
- package/pipeline/skills/shared/external/cryptokit/evals/evals.json +20 -18
- package/pipeline/skills/shared/external/cryptokit/references/cryptokit-patterns.md +299 -488
- package/pipeline/skills/shared/external/debugging-instruments/SKILL.md +270 -323
- package/pipeline/skills/shared/external/debugging-instruments/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/debugging-instruments/references/instruments-guide.md +167 -315
- package/pipeline/skills/shared/external/debugging-instruments/references/lldb-patterns.md +140 -193
- package/pipeline/skills/shared/external/device-integrity/SKILL.md +236 -353
- package/pipeline/skills/shared/external/device-integrity/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/device-integrity/references/device-integrity-patterns.md +159 -197
- package/pipeline/skills/shared/external/energykit/SKILL.md +225 -392
- package/pipeline/skills/shared/external/energykit/evals/evals.json +29 -28
- package/pipeline/skills/shared/external/energykit/references/energykit-patterns.md +174 -470
- package/pipeline/skills/shared/external/eventkit-calendar/SKILL.md +261 -383
- package/pipeline/skills/shared/external/eventkit-calendar/evals/evals.json +25 -22
- package/pipeline/skills/shared/external/eventkit-calendar/references/eventkit-patterns.md +165 -268
- package/pipeline/skills/shared/external/healthkit/SKILL.md +252 -303
- package/pipeline/skills/shared/external/healthkit/evals/evals.json +24 -23
- package/pipeline/skills/shared/external/healthkit/references/healthkit-patterns.md +369 -523
- package/pipeline/skills/shared/external/homekit-matter/SKILL.md +233 -348
- package/pipeline/skills/shared/external/homekit-matter/evals/evals.json +27 -22
- package/pipeline/skills/shared/external/homekit-matter/references/matter-commissioning.md +199 -305
- package/pipeline/skills/shared/external/ios-accessibility/SKILL.md +368 -340
- package/pipeline/skills/shared/external/ios-accessibility/evals/evals.json +28 -27
- package/pipeline/skills/shared/external/ios-accessibility/references/a11y-patterns.md +314 -260
- package/pipeline/skills/shared/external/ios-accessibility/references/media-accessibility.md +97 -67
- package/pipeline/skills/shared/external/ios-accessibility/references/nutrition-labels.md +165 -101
- package/pipeline/skills/shared/external/ios-localization/SKILL.md +258 -371
- package/pipeline/skills/shared/external/ios-localization/evals/evals.json +23 -23
- package/pipeline/skills/shared/external/ios-localization/references/formatstyle-locale.md +283 -491
- package/pipeline/skills/shared/external/ios-localization/references/string-catalogs.md +313 -440
- package/pipeline/skills/shared/external/ios-networking/SKILL.md +265 -341
- package/pipeline/skills/shared/external/ios-networking/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/ios-networking/references/background-websocket.md +425 -652
- package/pipeline/skills/shared/external/ios-networking/references/file-storage-patterns.md +143 -285
- package/pipeline/skills/shared/external/ios-networking/references/lightweight-clients.md +93 -53
- package/pipeline/skills/shared/external/ios-networking/references/network-framework.md +231 -456
- package/pipeline/skills/shared/external/ios-networking/references/urlsession-patterns.md +517 -784
- package/pipeline/skills/shared/external/ios-simulator/SKILL.md +265 -393
- package/pipeline/skills/shared/external/ios-simulator/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/ios-simulator/references/simctl-commands.md +177 -270
- package/pipeline/skills/shared/external/live-activities/SKILL.md +318 -360
- package/pipeline/skills/shared/external/live-activities/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/live-activities/references/activitykit-patterns.md +478 -710
- package/pipeline/skills/shared/external/localization-reuse-map/SKILL.md +3 -3
- package/pipeline/skills/shared/external/localization-reuse-map/example-mapping.json +1 -1
- package/pipeline/skills/shared/external/localization-reuse-map/reference/format-and-output.md +8 -7
- package/pipeline/skills/shared/external/localization-reuse-map/reference/publish-and-snapshot.md +2 -2
- package/pipeline/skills/shared/external/localization-reuse-map/reference/sources-and-recipes.md +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/_shared.py +100 -0
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-artifact.py +45 -26
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/build-spreadsheet.py +14 -16
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-annotations.py +12 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/fetch-legacy-labels.py +2 -1
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/publish-confluence.py +6 -5
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/render-overlay.py +44 -18
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-legacy-values.py +5 -2
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/resolve-new-values.py +10 -11
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/scan-screen-keys.py +4 -33
- package/pipeline/skills/shared/external/localization-reuse-map/scripts/verify-map.py +12 -59
- package/pipeline/skills/shared/external/mapkit-location/SKILL.md +297 -267
- package/pipeline/skills/shared/external/mapkit-location/evals/evals.json +28 -24
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-corelocation-patterns.md +378 -532
- package/pipeline/skills/shared/external/mapkit-location/references/mapkit-patterns.md +397 -499
- package/pipeline/skills/shared/external/metrickit-diagnostics/SKILL.md +165 -348
- package/pipeline/skills/shared/external/metrickit-diagnostics/evals/evals.json +26 -23
- package/pipeline/skills/shared/external/metrickit-diagnostics/references/metrickit-patterns.md +123 -130
- package/pipeline/skills/shared/external/musickit-audio/SKILL.md +189 -315
- package/pipeline/skills/shared/external/musickit-audio/evals/evals.json +22 -21
- package/pipeline/skills/shared/external/musickit-audio/references/musickit-patterns.md +181 -270
- package/pipeline/skills/shared/external/natural-language/SKILL.md +188 -340
- package/pipeline/skills/shared/external/natural-language/evals/evals.json +21 -21
- package/pipeline/skills/shared/external/natural-language/references/translation-patterns.md +171 -225
- package/pipeline/skills/shared/external/passkit-wallet/SKILL.md +258 -392
- package/pipeline/skills/shared/external/passkit-wallet/evals/evals.json +30 -29
- package/pipeline/skills/shared/external/passkit-wallet/references/wallet-passes.md +164 -231
- package/pipeline/skills/shared/external/pdfkit/SKILL.md +312 -344
- package/pipeline/skills/shared/external/pdfkit/evals/evals.json +19 -19
- package/pipeline/skills/shared/external/pdfkit/references/pdfkit-patterns.md +413 -624
- package/pipeline/skills/shared/external/pencilkit-drawing/SKILL.md +242 -358
- package/pipeline/skills/shared/external/pencilkit-drawing/evals/evals.json +25 -21
- package/pipeline/skills/shared/external/pencilkit-drawing/references/pencilkit-patterns.md +161 -226
- package/pipeline/skills/shared/external/permissionkit/SKILL.md +282 -400
- package/pipeline/skills/shared/external/permissionkit/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/permissionkit/references/permissionkit-patterns.md +237 -350
- package/pipeline/skills/shared/external/photos-camera-media/SKILL.md +276 -325
- package/pipeline/skills/shared/external/photos-camera-media/references/av-playback.md +299 -545
- package/pipeline/skills/shared/external/photos-camera-media/references/camera-capture.md +344 -588
- package/pipeline/skills/shared/external/photos-camera-media/references/image-loading-caching.md +316 -660
- package/pipeline/skills/shared/external/photos-camera-media/references/photokit-patterns.md +270 -416
- package/pipeline/skills/shared/external/push-notifications/SKILL.md +312 -340
- package/pipeline/skills/shared/external/push-notifications/evals/evals.json +27 -26
- package/pipeline/skills/shared/external/push-notifications/references/notification-patterns.md +328 -485
- package/pipeline/skills/shared/external/push-notifications/references/rich-notifications.md +327 -560
- package/pipeline/skills/shared/external/realitykit-ar/SKILL.md +218 -410
- package/pipeline/skills/shared/external/realitykit-ar/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/realitykit-ar/references/realitykit-patterns.md +221 -348
- package/pipeline/skills/shared/external/shareplay-activities/SKILL.md +222 -393
- package/pipeline/skills/shared/external/shareplay-activities/evals/evals.json +23 -24
- package/pipeline/skills/shared/external/shareplay-activities/references/shareplay-patterns.md +280 -420
- package/pipeline/skills/shared/external/skill-creator/template.md +7 -1
- package/pipeline/skills/shared/external/speech-recognition/SKILL.md +217 -421
- package/pipeline/skills/shared/external/speech-recognition/evals/evals.json +23 -26
- package/pipeline/skills/shared/external/speech-recognition/references/speechanalyzer-patterns.md +133 -125
- package/pipeline/skills/shared/external/storekit/SKILL.md +228 -204
- package/pipeline/skills/shared/external/storekit/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/storekit/references/app-review-guidelines.md +98 -109
- package/pipeline/skills/shared/external/storekit/references/core-patterns.md +302 -241
- package/pipeline/skills/shared/external/storekit/references/storekit-advanced.md +356 -649
- package/pipeline/skills/shared/external/swift-api-design-guidelines/SKILL.md +274 -399
- package/pipeline/skills/shared/external/swift-api-design-guidelines/evals/evals.json +22 -24
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/argument-labels-and-parameters.md +107 -108
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/conventions-and-special-rules.md +93 -165
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/naming-and-clarity.md +99 -137
- package/pipeline/skills/shared/external/swift-api-design-guidelines/references/side-effects-and-mutating-pairs.md +77 -120
- package/pipeline/skills/shared/external/swift-architecture/SKILL.md +334 -350
- package/pipeline/skills/shared/external/swift-architecture/evals/evals.json +22 -22
- package/pipeline/skills/shared/external/swift-charts/SKILL.md +208 -394
- package/pipeline/skills/shared/external/swift-charts/evals/evals.json +27 -30
- package/pipeline/skills/shared/external/swift-charts/references/charts-patterns.md +351 -762
- package/pipeline/skills/shared/external/swift-codable/SKILL.md +339 -343
- package/pipeline/skills/shared/external/swift-codable/evals/evals.json +20 -20
- package/pipeline/skills/shared/external/swift-concurrency/SKILL.md +304 -351
- package/pipeline/skills/shared/external/swift-concurrency/evals/evals.json +27 -24
- package/pipeline/skills/shared/external/swift-concurrency/references/approachable-concurrency.md +65 -80
- package/pipeline/skills/shared/external/swift-concurrency/references/async-algorithms.md +48 -84
- package/pipeline/skills/shared/external/swift-concurrency/references/bridging-interop.md +134 -79
- package/pipeline/skills/shared/external/swift-concurrency/references/concurrency-patterns.md +145 -167
- package/pipeline/skills/shared/external/swift-concurrency/references/diagnostics.md +62 -50
- package/pipeline/skills/shared/external/swift-concurrency/references/swiftui-concurrency.md +92 -121
- package/pipeline/skills/shared/external/swift-concurrency/references/synchronization-primitives.md +177 -241
- package/pipeline/skills/shared/external/swift-formatstyle/SKILL.md +258 -234
- package/pipeline/skills/shared/external/swift-language/SKILL.md +342 -382
- package/pipeline/skills/shared/external/swift-language/evals/evals.json +24 -27
- package/pipeline/skills/shared/external/swift-language/references/swift-attributes-interop.md +79 -56
- package/pipeline/skills/shared/external/swift-language/references/swift-patterns-extended.md +297 -340
- package/pipeline/skills/shared/external/swift-security/SKILL.md +183 -162
- package/pipeline/skills/shared/external/swift-security/evals/evals.json +25 -25
- package/pipeline/skills/shared/external/swift-security/references/biometric-authentication.md +314 -469
- package/pipeline/skills/shared/external/swift-security/references/certificate-trust.md +411 -476
- package/pipeline/skills/shared/external/swift-security/references/common-anti-patterns.md +260 -530
- package/pipeline/skills/shared/external/swift-security/references/compliance-owasp-mapping.md +270 -477
- package/pipeline/skills/shared/external/swift-security/references/credential-storage-patterns.md +573 -571
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-public-key.md +370 -441
- package/pipeline/skills/shared/external/swift-security/references/cryptokit-symmetric.md +332 -433
- package/pipeline/skills/shared/external/swift-security/references/keychain-access-control.md +346 -468
- package/pipeline/skills/shared/external/swift-security/references/keychain-fundamentals.md +375 -491
- package/pipeline/skills/shared/external/swift-security/references/keychain-item-classes.md +431 -432
- package/pipeline/skills/shared/external/swift-security/references/keychain-sharing.md +328 -425
- package/pipeline/skills/shared/external/swift-security/references/migration-legacy-stores.md +341 -579
- package/pipeline/skills/shared/external/swift-security/references/secure-enclave.md +397 -457
- package/pipeline/skills/shared/external/swift-security/references/testing-security-code.md +354 -614
- package/pipeline/skills/shared/external/swift-testing/SKILL.md +191 -175
- package/pipeline/skills/shared/external/swift-testing/evals/evals.json +26 -24
- package/pipeline/skills/shared/external/swift-testing/references/testing-advanced.md +81 -84
- package/pipeline/skills/shared/external/swift-testing/references/testing-patterns.md +317 -433
- package/pipeline/skills/shared/external/swiftdata/SKILL.md +394 -256
- package/pipeline/skills/shared/external/swiftdata/evals/evals.json +24 -24
- package/pipeline/skills/shared/external/swiftdata/references/core-data-coexistence.md +206 -402
- package/pipeline/skills/shared/external/swiftdata/references/indexing.md +59 -52
- package/pipeline/skills/shared/external/swiftdata/references/predicate-pitfalls.md +57 -33
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-advanced.md +354 -747
- package/pipeline/skills/shared/external/swiftdata/references/swiftdata-queries.md +300 -508
- package/pipeline/skills/shared/external/swiftlint/SKILL.md +175 -226
- package/pipeline/skills/shared/external/swiftlint/references/adoption-and-configuration.md +141 -208
- package/pipeline/skills/shared/external/swiftlint/references/custom-rules-and-analyze.md +100 -109
- package/pipeline/skills/shared/external/swiftlint/references/plugins-run-scripts-and-integrations.md +159 -179
- package/pipeline/skills/shared/external/swiftlint/references/rule-reference.md +383 -18
- package/pipeline/skills/shared/external/swiftlint/references/rules-suppressions-and-baselines.md +143 -229
- package/pipeline/skills/shared/external/swiftui-animation/SKILL.md +283 -366
- package/pipeline/skills/shared/external/swiftui-animation/references/animation-advanced.md +396 -608
- package/pipeline/skills/shared/external/swiftui-animation/references/core-animation-bridge.md +336 -385
- package/pipeline/skills/shared/external/swiftui-gestures/SKILL.md +239 -349
- package/pipeline/skills/shared/external/swiftui-gestures/references/gesture-patterns.md +228 -310
- package/pipeline/skills/shared/external/swiftui-layout-components/SKILL.md +260 -249
- package/pipeline/skills/shared/external/swiftui-layout-components/references/form.md +92 -74
- package/pipeline/skills/shared/external/swiftui-layout-components/references/grids.md +112 -177
- package/pipeline/skills/shared/external/swiftui-layout-components/references/list.md +61 -64
- package/pipeline/skills/shared/external/swiftui-layout-components/references/scrollview.md +94 -134
- package/pipeline/skills/shared/external/swiftui-liquid-glass/SKILL.md +193 -225
- package/pipeline/skills/shared/external/swiftui-liquid-glass/references/liquid-glass.md +173 -327
- package/pipeline/skills/shared/external/swiftui-navigation/SKILL.md +201 -168
- package/pipeline/skills/shared/external/swiftui-navigation/references/deeplinks.md +127 -150
- package/pipeline/skills/shared/external/swiftui-navigation/references/navigationstack.md +134 -133
- package/pipeline/skills/shared/external/swiftui-navigation/references/sheets.md +152 -117
- package/pipeline/skills/shared/external/swiftui-navigation/references/tabview.md +111 -138
- package/pipeline/skills/shared/external/swiftui-patterns/SKILL.md +316 -252
- package/pipeline/skills/shared/external/swiftui-patterns/references/architecture-patterns.md +341 -332
- package/pipeline/skills/shared/external/swiftui-patterns/references/deprecated-migration.md +547 -854
- package/pipeline/skills/shared/external/swiftui-patterns/references/design-polish.md +485 -537
- package/pipeline/skills/shared/external/swiftui-patterns/references/platform-and-sharing.md +417 -499
- package/pipeline/skills/shared/external/swiftui-performance/SKILL.md +213 -376
- package/pipeline/skills/shared/external/swiftui-performance/references/demystify-swiftui-performance-wwdc23.md +86 -175
- package/pipeline/skills/shared/external/swiftui-performance/references/optimizing-swiftui-performance-instruments.md +89 -195
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-hangs-in-your-app.md +95 -182
- package/pipeline/skills/shared/external/swiftui-performance/references/understanding-improving-swiftui-performance.md +71 -149
- package/pipeline/skills/shared/external/swiftui-performance/references/wwdc-session-sources.md +21 -27
- package/pipeline/skills/shared/external/swiftui-uikit-interop/SKILL.md +303 -295
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/hosting-migration.md +204 -387
- package/pipeline/skills/shared/external/swiftui-uikit-interop/references/representable-recipes.md +469 -683
- package/pipeline/skills/shared/external/swiftui-webkit/SKILL.md +140 -186
- package/pipeline/skills/shared/external/swiftui-webkit/references/loading-and-observation.md +75 -86
- package/pipeline/skills/shared/external/swiftui-webkit/references/local-content-and-custom-schemes.md +63 -60
- package/pipeline/skills/shared/external/swiftui-webkit/references/migration-and-fallbacks.md +69 -137
- package/pipeline/skills/shared/external/swiftui-webkit/references/navigation-and-javascript.md +95 -67
- package/pipeline/skills/shared/external/tipkit/SKILL.md +220 -335
- package/pipeline/skills/shared/external/tipkit/references/tipkit-patterns.md +356 -494
- package/pipeline/skills/shared/external/vision-framework/SKILL.md +260 -375
- package/pipeline/skills/shared/external/vision-framework/references/vision-requests.md +393 -515
- package/pipeline/skills/shared/external/vision-framework/references/visionkit-scanner.md +363 -539
- package/pipeline/skills/shared/external/weatherkit/SKILL.md +160 -315
- package/pipeline/skills/shared/external/weatherkit/references/weatherkit-patterns.md +288 -407
- package/pipeline/skills/shared/external/widgetkit/SKILL.md +224 -288
- package/pipeline/skills/shared/external/widgetkit/references/widgetkit-advanced.md +416 -719
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +0 -39
|
@@ -1,87 +1,109 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: mapkit-location
|
|
3
|
-
description: "
|
|
3
|
+
description: "MapKit and CoreLocation on iOS and macOS: SwiftUI Map, markers, annotations, polylines and overlays, camera control, user location tracking, CLLocationUpdate streams, location authorization, geocoding and reverse geocoding, search and autocomplete, directions, routes and ETA, CLMonitor geofencing and region monitoring, background location, distance math. Use when implementing, reviewing or improving anything built on maps, coordinates, addresses, places, directions or distances."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# MapKit
|
|
8
|
+
# MapKit and CoreLocation
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
`
|
|
10
|
+
Two frameworks do the work here. MapKit draws the map and answers questions
|
|
11
|
+
about places (search, geocoding, routes). CoreLocation tells you where the
|
|
12
|
+
device is and when it crosses a boundary. Since iOS 17 both have a Swift-first
|
|
13
|
+
surface: a SwiftUI `Map` whose content is written in a `MapContentBuilder`
|
|
14
|
+
closure, the async sequence `CLLocationUpdate.liveUpdates()` for position, and
|
|
15
|
+
the `CLMonitor` actor for geofences. Write new code against those; reach for
|
|
16
|
+
`MKMapView` or `CLLocationManager` only for the gaps named below.
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
[references/mapkit-corelocation-patterns.md](references/mapkit-corelocation-patterns.md) when the task involves
|
|
18
|
-
location update lifecycle, geofencing, background location, testing, or privacy keys.
|
|
18
|
+
Baseline: iOS 17. Sections that need a later release say so, and code that
|
|
19
|
+
needs it carries `@available`.
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
Longer material lives in two references:
|
|
21
22
|
|
|
22
|
-
- [
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- [
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
- [Review Checklist](#review-checklist)
|
|
31
|
-
- [References](#references)
|
|
23
|
+
- [Map patterns](references/mapkit-patterns.md): a complete
|
|
24
|
+
map screen, custom annotations, camera control, search with autocomplete,
|
|
25
|
+
routes, Look Around, snapshots, dense annotations, iOS 26 place APIs,
|
|
26
|
+
coordinate helpers, accessibility.
|
|
27
|
+
- [Location patterns](references/mapkit-corelocation-patterns.md):
|
|
28
|
+
the location update lifecycle, diagnostics, `CLServiceSession`, `CLMonitor`
|
|
29
|
+
geofencing, background location, legacy `CLLocationManager` cases, accuracy,
|
|
30
|
+
simulator testing, Info.plist privacy keys.
|
|
32
31
|
|
|
33
|
-
##
|
|
32
|
+
## Scope
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
In scope: maps, markers and annotations, overlays, routes, search and
|
|
35
|
+
geocoding, the user's position, `CLMonitor` geofencing and the rules for
|
|
36
|
+
location in the background.
|
|
36
37
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
4. Configure map style with `.mapStyle()`.
|
|
42
|
-
5. Add map controls with `.mapControls { }`.
|
|
43
|
-
6. Handle selection with a `selection:` binding.
|
|
38
|
+
Neighbouring work belongs elsewhere. MapKit does not draw CarPlay templates,
|
|
39
|
+
launch App Clips or pair Bluetooth hardware, so never claim it does. What this
|
|
40
|
+
skill owns is the handoff point: a geofence event, a search result or a route
|
|
41
|
+
that the other framework then acts on.
|
|
44
42
|
|
|
45
|
-
|
|
43
|
+
| Topic | Where it goes |
|
|
44
|
+
|-------|---------------|
|
|
45
|
+
| CarPlay map templates, navigation alerts, CarPlay UI | CarPlay framework guidance (no skill in this collection) |
|
|
46
|
+
| App Clip invocation from a place card, size limits, handoff to the full app | `app-clips` |
|
|
47
|
+
| Pairing a beacon or accessory when a geofence fires | `core-bluetooth`, or AccessorySetupKit |
|
|
48
|
+
| A Live Activity used to keep background location alive | `live-activities` |
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
2. On iOS 18+, create a `CLServiceSession` to manage authorization.
|
|
49
|
-
3. Iterate `CLLocationUpdate.liveUpdates()` in a `Task`.
|
|
50
|
-
4. Filter updates by distance or accuracy before updating the UI.
|
|
51
|
-
5. Stop the task when location tracking is no longer needed.
|
|
50
|
+
## Workflows
|
|
52
51
|
|
|
53
|
-
###
|
|
52
|
+
### 1. Put places on a map
|
|
54
53
|
|
|
55
|
-
1.
|
|
56
|
-
2.
|
|
57
|
-
3.
|
|
58
|
-
|
|
54
|
+
1. `import MapKit` (and `SwiftUI`).
|
|
55
|
+
2. Create a `Map`. Bind a `MapCameraPosition` if code needs to move the camera.
|
|
56
|
+
3. Inside the content closure add `Marker`, `Annotation`, `MapPolyline`,
|
|
57
|
+
`MapPolygon` or `MapCircle`.
|
|
58
|
+
4. Pick a look with `.mapStyle(...)`.
|
|
59
|
+
5. Add controls with `.mapControls { ... }`.
|
|
60
|
+
6. For tap-to-select, pass a `selection:` binding.
|
|
59
61
|
|
|
60
|
-
###
|
|
62
|
+
### 2. Follow the user's position
|
|
61
63
|
|
|
62
|
-
1.
|
|
63
|
-
2.
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
1. Put a `NSLocationWhenInUseUsageDescription` string in Info.plist.
|
|
65
|
+
2. On iOS 18 and later, create a `CLServiceSession` when the feature starts
|
|
66
|
+
and keep it until the feature ends; it drives the authorization prompt.
|
|
67
|
+
3. Iterate `CLLocationUpdate.liveUpdates()` inside a `Task` that you keep.
|
|
68
|
+
4. Drop samples that are inaccurate, old or implausible before the UI sees them.
|
|
69
|
+
5. Cancel the task as soon as the feature no longer needs position.
|
|
66
70
|
|
|
67
|
-
###
|
|
71
|
+
### 3. Find places
|
|
68
72
|
|
|
69
|
-
|
|
73
|
+
1. Feed typed text to an `MKLocalSearchCompleter` for suggestions.
|
|
74
|
+
2. Wait at least 300 ms after the last keystroke before updating the query.
|
|
75
|
+
3. Turn the picked suggestion into an `MKLocalSearch.Request` for full results.
|
|
76
|
+
4. Show the `MKMapItem` results as markers, a list, or both.
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
### 4. Route between two places
|
|
79
|
+
|
|
80
|
+
1. Build an `MKDirections.Request` with a source and destination `MKMapItem`.
|
|
81
|
+
2. Choose a mode in `transportType` (car, walking, transit or cycling).
|
|
82
|
+
3. `try await MKDirections(request:).calculate()`.
|
|
83
|
+
4. Draw `MapPolyline(route.polyline)`.
|
|
84
|
+
|
|
85
|
+
### 5. Review existing code
|
|
86
|
+
|
|
87
|
+
Go through the [Review Checklist](#review-checklist) below.
|
|
88
|
+
|
|
89
|
+
## SwiftUI Map (iOS 17+)
|
|
90
|
+
|
|
91
|
+
A SwiftUI map file imports both `SwiftUI` and `MapKit`.
|
|
72
92
|
|
|
73
93
|
```swift
|
|
74
|
-
import MapKit
|
|
75
94
|
import SwiftUI
|
|
95
|
+
import MapKit
|
|
76
96
|
|
|
77
|
-
struct
|
|
78
|
-
@State private var
|
|
97
|
+
struct TrailheadMap: View {
|
|
98
|
+
@State private var camera: MapCameraPosition = .automatic
|
|
99
|
+
|
|
100
|
+
private let lot = CLLocationCoordinate2D(latitude: 46.852, longitude: -121.760)
|
|
101
|
+
private let summit = CLLocationCoordinate2D(latitude: 46.853, longitude: -121.727)
|
|
79
102
|
|
|
80
103
|
var body: some View {
|
|
81
|
-
Map(position: $
|
|
82
|
-
Marker("
|
|
83
|
-
Marker("
|
|
84
|
-
coordinate: infiniteLoop)
|
|
104
|
+
Map(position: $camera) {
|
|
105
|
+
Marker("Parking", coordinate: lot)
|
|
106
|
+
Marker("Summit", systemImage: "mountain.2.fill", coordinate: summit)
|
|
85
107
|
}
|
|
86
108
|
.mapStyle(.standard(elevation: .realistic))
|
|
87
109
|
.mapControls {
|
|
@@ -93,173 +115,175 @@ struct PlaceMap: View {
|
|
|
93
115
|
}
|
|
94
116
|
```
|
|
95
117
|
|
|
96
|
-
### Marker
|
|
118
|
+
### Marker or Annotation
|
|
97
119
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
120
|
+
- `Marker(_:systemImage:coordinate:)` draws the system balloon. It is the
|
|
121
|
+
cheapest way to flag a spot, VoiceOver reads its title, and `.tint(_:)`
|
|
122
|
+
recolours it.
|
|
123
|
+
- `Annotation(_:coordinate:anchor:content:)` puts any SwiftUI view at a
|
|
124
|
+
coordinate. `anchor` is a `UnitPoint`; `.bottom` makes the bottom edge of
|
|
125
|
+
the view touch the coordinate, which suits pin-shaped content.
|
|
102
126
|
|
|
103
|
-
|
|
104
|
-
Annotation("
|
|
105
|
-
Image(systemName: "
|
|
127
|
+
```swift
|
|
128
|
+
Annotation("Ranger station", coordinate: station, anchor: .bottom) {
|
|
129
|
+
Image(systemName: "house.fill")
|
|
106
130
|
.padding(6)
|
|
107
|
-
.background(.blue.gradient, in: .circle)
|
|
108
131
|
.foregroundStyle(.white)
|
|
132
|
+
.background(Circle().fill(.green.gradient))
|
|
109
133
|
}
|
|
110
134
|
```
|
|
111
135
|
|
|
112
|
-
### Overlays
|
|
136
|
+
### Overlays
|
|
113
137
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// Polygon (area highlight)
|
|
121
|
-
MapPolygon(coordinates: parkBoundary)
|
|
122
|
-
.foregroundStyle(.green.opacity(0.3))
|
|
123
|
-
.stroke(.green, lineWidth: 2)
|
|
124
|
-
|
|
125
|
-
// Circle (radius around a point)
|
|
126
|
-
MapCircle(center: storeCoord, radius: 500)
|
|
127
|
-
.foregroundStyle(.red.opacity(0.15))
|
|
128
|
-
.stroke(.red, lineWidth: 1)
|
|
129
|
-
}
|
|
130
|
-
```
|
|
138
|
+
| Content | Draws | Styling |
|
|
139
|
+
|---------|-------|---------|
|
|
140
|
+
| `MapPolyline(coordinates:)` | a line through the points | `.stroke(.orange, lineWidth: 4)` |
|
|
141
|
+
| `MapPolygon(coordinates:)` | a filled area | `.foregroundStyle(.teal.opacity(0.25))` plus `.stroke(...)` for the edge |
|
|
142
|
+
| `MapCircle(center:radius:)` | a circle, radius in metres | `.foregroundStyle(...)` and `.stroke(...)` |
|
|
131
143
|
|
|
132
|
-
### Camera
|
|
144
|
+
### Camera position
|
|
133
145
|
|
|
134
|
-
`MapCameraPosition`
|
|
135
|
-
|
|
136
|
-
`.userLocation(fallback:)`, `.camera`, `.item`, `.rect`,
|
|
137
|
-
|
|
138
|
-
|
|
146
|
+
`MapCameraPosition` is what the map is showing. Bound to the map, it moves
|
|
147
|
+
when the user pans and moves the map when code assigns it. Its constructors:
|
|
148
|
+
`.region`, `.userLocation(fallback:)`, `.camera`, `.item`, `.rect`,
|
|
149
|
+
`.automatic`. Animated moves, framing all content and reading the visible
|
|
150
|
+
region are in [Camera Control](references/mapkit-patterns.md#camera-control).
|
|
139
151
|
|
|
140
|
-
### Map
|
|
152
|
+
### Map styles
|
|
141
153
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
154
|
+
| Modifier | Result |
|
|
155
|
+
|----------|--------|
|
|
156
|
+
| `.mapStyle(.standard)` | default road map |
|
|
157
|
+
| `.mapStyle(.standard(elevation: .realistic, showsTraffic: true))` | roads, 3D terrain, live traffic |
|
|
158
|
+
| `.mapStyle(.imagery)` | satellite |
|
|
159
|
+
| `.mapStyle(.imagery(elevation: .realistic))` | satellite in 3D |
|
|
160
|
+
| `.mapStyle(.hybrid)` | satellite with labels |
|
|
161
|
+
| `.mapStyle(.hybrid(elevation: .realistic, showsTraffic: true))` | labelled satellite, 3D terrain, live traffic |
|
|
150
162
|
|
|
151
|
-
###
|
|
163
|
+
### Interaction modes
|
|
152
164
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
| Modifier | Allows |
|
|
166
|
+
|----------|--------|
|
|
167
|
+
| `.mapInteractionModes(.all)` | pan, zoom, rotate, pitch (the default) |
|
|
168
|
+
| `.mapInteractionModes(.pan)` | panning only |
|
|
169
|
+
| `.mapInteractionModes([.pan, .zoom])` | moving and zooming, no rotation or tilt |
|
|
170
|
+
| `.mapInteractionModes([])` | nothing; a static picture |
|
|
171
|
+
|
|
172
|
+
### Selection
|
|
159
173
|
|
|
160
|
-
|
|
174
|
+
The value in `.tag(_:)` must have the same type as the `selection` binding,
|
|
175
|
+
or taps select nothing.
|
|
161
176
|
|
|
162
177
|
```swift
|
|
163
|
-
|
|
178
|
+
struct CampsiteMap: View {
|
|
179
|
+
let sites: [Campsite]
|
|
180
|
+
@State private var chosen: MKMapItem?
|
|
181
|
+
@State private var headline = ""
|
|
164
182
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
var body: some View {
|
|
184
|
+
Map(selection: $chosen) {
|
|
185
|
+
ForEach(sites) { site in
|
|
186
|
+
Marker(site.name, coordinate: site.coordinate)
|
|
187
|
+
.tag(site.mapItem)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
.onChange(of: chosen) { _, item in
|
|
191
|
+
guard let item else { return }
|
|
192
|
+
headline = item.name ?? ""
|
|
193
|
+
}
|
|
169
194
|
}
|
|
170
195
|
}
|
|
171
|
-
.onChange(of: selectedMarker) { _, newValue in
|
|
172
|
-
guard let item = newValue else { return }
|
|
173
|
-
// React to selection
|
|
174
|
-
}
|
|
175
196
|
```
|
|
176
197
|
|
|
177
|
-
## CoreLocation
|
|
198
|
+
## CoreLocation
|
|
178
199
|
|
|
179
200
|
### CLLocationUpdate.liveUpdates() (iOS 17+)
|
|
180
201
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
202
|
+
One async sequence replaces the `CLLocationManagerDelegate` callbacks. Each
|
|
203
|
+
element is a `CLLocationUpdate` whose `location` is optional. Rules:
|
|
204
|
+
|
|
205
|
+
- Store the iterating `Task` in a property; cancelling it is how tracking stops.
|
|
206
|
+
- Throw away samples with invalid or poor accuracy, old timestamps or
|
|
207
|
+
impossible jumps before they touch map UI or background work.
|
|
208
|
+
- On iOS 18 and later the update also carries diagnostics (authorization
|
|
209
|
+
denied, Location Services off system-wide, location unavailable, app not
|
|
210
|
+
sufficiently in use). React with a visible fallback instead of waiting on a
|
|
211
|
+
sequence that will not deliver.
|
|
188
212
|
|
|
189
213
|
```swift
|
|
190
214
|
import CoreLocation
|
|
215
|
+
import Observation
|
|
191
216
|
|
|
192
217
|
@MainActor
|
|
193
218
|
@Observable
|
|
194
|
-
final class
|
|
195
|
-
var
|
|
196
|
-
private var
|
|
219
|
+
final class RunTracker {
|
|
220
|
+
private(set) var lastFix: CLLocation?
|
|
221
|
+
private var stream: Task<Void, Never>?
|
|
197
222
|
|
|
198
|
-
func
|
|
199
|
-
|
|
223
|
+
func begin() {
|
|
224
|
+
stream?.cancel()
|
|
225
|
+
stream = Task {
|
|
200
226
|
do {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
location.horizontalAccuracy < 50 else { continue }
|
|
207
|
-
currentLocation = location
|
|
227
|
+
for try await reading in CLLocationUpdate.liveUpdates() {
|
|
228
|
+
guard let fix = reading.location,
|
|
229
|
+
fix.horizontalAccuracy >= 0,
|
|
230
|
+
fix.horizontalAccuracy < 50 else { continue }
|
|
231
|
+
lastFix = fix
|
|
208
232
|
}
|
|
209
233
|
} catch is CancellationError {
|
|
210
|
-
// Expected when tracking stops.
|
|
211
234
|
} catch {
|
|
212
|
-
|
|
235
|
+
lastFix = nil
|
|
213
236
|
}
|
|
214
237
|
}
|
|
215
238
|
}
|
|
216
239
|
|
|
217
|
-
func
|
|
218
|
-
|
|
219
|
-
|
|
240
|
+
func end() {
|
|
241
|
+
stream?.cancel()
|
|
242
|
+
stream = nil
|
|
220
243
|
}
|
|
221
244
|
}
|
|
222
245
|
```
|
|
223
246
|
|
|
247
|
+
Diagnostics, the full filter set and a mapping from each state to UI are in
|
|
248
|
+
the [location reference](references/mapkit-corelocation-patterns.md#diagnostics-and-fallbacks-ios-18).
|
|
249
|
+
|
|
224
250
|
### CLServiceSession (iOS 18+)
|
|
225
251
|
|
|
226
|
-
|
|
227
|
-
|
|
252
|
+
A `CLServiceSession` states what authorization a feature needs, for as long
|
|
253
|
+
as the feature runs. Store it in a property and release it when the feature
|
|
254
|
+
ends. On iOS 18 `liveUpdates()` and `CLMonitor` create a session implicitly
|
|
255
|
+
when you have not; create one yourself when you need `.always` or full
|
|
256
|
+
accuracy. It is not available on macOS.
|
|
228
257
|
|
|
229
258
|
```swift
|
|
230
|
-
|
|
231
|
-
let
|
|
259
|
+
@available(iOS 18, *)
|
|
260
|
+
let nearbySession = CLServiceSession(
|
|
232
261
|
authorization: .whenInUse,
|
|
233
|
-
fullAccuracyPurposeKey: "
|
|
262
|
+
fullAccuracyPurposeKey: "NearbyTrails"
|
|
234
263
|
)
|
|
235
|
-
// Hold `session` as a stored property; release it when done.
|
|
236
264
|
```
|
|
237
265
|
|
|
238
|
-
|
|
239
|
-
`CLServiceSession` if you do not create one explicitly. Create one explicitly
|
|
240
|
-
when you need `.always` authorization or full accuracy.
|
|
266
|
+
### Authorization
|
|
241
267
|
|
|
242
|
-
|
|
268
|
+
- `NSLocationWhenInUseUsageDescription` is required for any location use.
|
|
269
|
+
- `NSLocationAlwaysAndWhenInUseUsageDescription` only when the feature truly
|
|
270
|
+
needs `.always`.
|
|
243
271
|
|
|
244
|
-
|
|
245
|
-
// Info.plist keys (required):
|
|
246
|
-
// NSLocationWhenInUseUsageDescription
|
|
247
|
-
// NSLocationAlwaysAndWhenInUseUsageDescription (only if .always needed)
|
|
272
|
+
A denied user should see why the feature is empty and a way out:
|
|
248
273
|
|
|
249
|
-
|
|
250
|
-
struct
|
|
274
|
+
```swift
|
|
275
|
+
struct LocationOffView: View {
|
|
251
276
|
@Environment(\.openURL) private var openURL
|
|
252
277
|
|
|
253
278
|
var body: some View {
|
|
254
279
|
ContentUnavailableView {
|
|
255
|
-
Label("Location
|
|
280
|
+
Label("Location is off", systemImage: "location.slash")
|
|
256
281
|
} description: {
|
|
257
|
-
Text("
|
|
282
|
+
Text("Allow location access to see trails near you.")
|
|
258
283
|
} actions: {
|
|
259
284
|
Button("Open Settings") {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
285
|
+
guard let settings = URL(string: UIApplication.openSettingsURLString) else { return }
|
|
286
|
+
openURL(settings)
|
|
263
287
|
}
|
|
264
288
|
}
|
|
265
289
|
}
|
|
@@ -268,164 +292,170 @@ struct LocationPermissionView: View {
|
|
|
268
292
|
|
|
269
293
|
## Geocoding
|
|
270
294
|
|
|
271
|
-
###
|
|
295
|
+
### MKGeocodingRequest and MKReverseGeocodingRequest (iOS 26+)
|
|
296
|
+
|
|
297
|
+
MapKit now geocodes by itself and returns `MKMapItem`, which carries more than
|
|
298
|
+
a placemark: an `MKAddress` and `MKAddressRepresentations` for formatting.
|
|
299
|
+
Both initializers are failable; `mapItems` is an async throwing property.
|
|
272
300
|
|
|
273
301
|
```swift
|
|
274
|
-
|
|
302
|
+
@available(iOS 26, *)
|
|
303
|
+
func lookUp(_ text: String) async throws -> MKMapItem? {
|
|
304
|
+
guard let request = MKGeocodingRequest(addressString: text) else { return nil }
|
|
305
|
+
return try await request.mapItems.first
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Reverse lookup is `MKReverseGeocodingRequest(location:)`. Formatting and
|
|
310
|
+
batch lookups are in [Geocoding and Places on iOS 26](references/mapkit-patterns.md#geocoding-and-places-on-ios-26).
|
|
311
|
+
|
|
312
|
+
### CLGeocoder (available since iOS 5, deprecated in iOS 26)
|
|
275
313
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
314
|
+
Use it only while the deployment target is below iOS 26. The SDK's deprecation
|
|
315
|
+
messages point reverse lookups to `MKReverseGeocodingRequest` and forward
|
|
316
|
+
lookups to `MKGeocodingRequest`. Every `CLPlacemark`
|
|
317
|
+
field is optional. `CLGeocoder` is not `Sendable`, so Swift 6 rejects one
|
|
318
|
+
shared global instance; make a geocoder for each lookup instead.
|
|
319
|
+
|
|
320
|
+
```swift
|
|
321
|
+
func coordinate(for address: String) async throws -> CLLocationCoordinate2D? {
|
|
322
|
+
try await CLGeocoder().geocodeAddressString(address).first?.location?.coordinate
|
|
280
323
|
}
|
|
281
324
|
|
|
282
|
-
|
|
283
|
-
let
|
|
284
|
-
let
|
|
285
|
-
|
|
286
|
-
let address = [placemark.name, placemark.locality, placemark.administrativeArea]
|
|
325
|
+
func label(for spot: CLLocation) async throws -> String {
|
|
326
|
+
let marks = try await CLGeocoder().reverseGeocodeLocation(spot)
|
|
327
|
+
guard let mark = marks.first else { return "" }
|
|
328
|
+
return [mark.name, mark.locality, mark.administrativeArea]
|
|
287
329
|
.compactMap { $0 }
|
|
288
330
|
.joined(separator: ", ")
|
|
289
331
|
}
|
|
290
332
|
```
|
|
291
333
|
|
|
292
|
-
### MKGeocodingRequest and MKReverseGeocodingRequest (iOS 26+)
|
|
293
|
-
|
|
294
|
-
New MapKit-native geocoding returns `MKMapItem` with richer data and `MKAddress`
|
|
295
|
-
/ `MKAddressRepresentations` for flexible address formatting. Construct
|
|
296
|
-
`MKGeocodingRequest(addressString:)` or `MKReverseGeocodingRequest(location:)` and
|
|
297
|
-
await `.mapItems`. See [references/mapkit-patterns.md](references/mapkit-patterns.md) ("iOS 26 New
|
|
298
|
-
APIs") for both, plus `MKAddressRepresentations` formatting.
|
|
299
|
-
|
|
300
334
|
## Search
|
|
301
335
|
|
|
302
|
-
### MKLocalSearchCompleter (
|
|
303
|
-
|
|
304
|
-
Set `queryFragment` on an `MKLocalSearchCompleter` and read `results` from its
|
|
305
|
-
delegate for suggestions. Debounce input (300ms+) and constrain `completer.region`
|
|
306
|
-
to the visible map region.
|
|
336
|
+
### MKLocalSearchCompleter (autocomplete)
|
|
307
337
|
|
|
308
|
-
|
|
338
|
+
Set `queryFragment` and read `results` from the delegate. Debounce input by
|
|
339
|
+
300 ms or more and set `completer.region` to the visible map region so
|
|
340
|
+
suggestions stay local.
|
|
309
341
|
|
|
310
|
-
|
|
311
|
-
results:
|
|
342
|
+
### MKLocalSearch (full results)
|
|
312
343
|
|
|
313
344
|
```swift
|
|
314
|
-
func
|
|
315
|
-
let request = MKLocalSearch.Request(completion:
|
|
345
|
+
func places(for pick: MKLocalSearchCompletion) async throws -> [MKMapItem] {
|
|
346
|
+
let request = MKLocalSearch.Request(completion: pick)
|
|
316
347
|
request.resultTypes = [.pointOfInterest, .address]
|
|
317
|
-
let
|
|
318
|
-
return
|
|
348
|
+
let reply = try await MKLocalSearch(request: request).start()
|
|
349
|
+
return reply.mapItems
|
|
319
350
|
}
|
|
320
351
|
```
|
|
321
352
|
|
|
322
|
-
For
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
353
|
+
For free text, set `request.naturalLanguageQuery` and `request.region`
|
|
354
|
+
instead of passing a completion. The delegate-based service and the
|
|
355
|
+
`.searchable` screen are in
|
|
356
|
+
[Autocomplete Search](references/mapkit-patterns.md#autocomplete-search).
|
|
326
357
|
|
|
327
358
|
## Directions
|
|
328
359
|
|
|
360
|
+
`MKMapItem` and `MKRoute` are not `Sendable`. Keep the helper on the main
|
|
361
|
+
actor, where the SwiftUI view that calls it already runs, so the items never
|
|
362
|
+
cross an isolation boundary:
|
|
363
|
+
|
|
329
364
|
```swift
|
|
330
|
-
|
|
331
|
-
|
|
365
|
+
@MainActor
|
|
366
|
+
func fastestRoute(
|
|
367
|
+
from start: MKMapItem,
|
|
368
|
+
to end: MKMapItem,
|
|
369
|
+
by mode: MKDirectionsTransportType = .automobile
|
|
370
|
+
) async throws -> MKRoute? {
|
|
332
371
|
let request = MKDirections.Request()
|
|
333
|
-
request.source =
|
|
334
|
-
request.destination =
|
|
335
|
-
request.transportType =
|
|
336
|
-
let
|
|
337
|
-
|
|
338
|
-
return response.routes.first
|
|
372
|
+
request.source = start
|
|
373
|
+
request.destination = end
|
|
374
|
+
request.transportType = mode
|
|
375
|
+
let reply = try await MKDirections(request: request).calculate()
|
|
376
|
+
return reply.routes.first
|
|
339
377
|
}
|
|
340
378
|
```
|
|
341
379
|
|
|
342
|
-
###
|
|
380
|
+
### Drawing the route
|
|
343
381
|
|
|
344
382
|
```swift
|
|
345
|
-
|
|
383
|
+
struct FerryRouteMap: View {
|
|
384
|
+
let pier: MKMapItem
|
|
385
|
+
let island: MKMapItem
|
|
386
|
+
@State private var route: MKRoute?
|
|
346
387
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
388
|
+
var body: some View {
|
|
389
|
+
Map {
|
|
390
|
+
if let route {
|
|
391
|
+
MapPolyline(route.polyline).stroke(.teal, lineWidth: 5)
|
|
392
|
+
}
|
|
393
|
+
Marker(item: pier)
|
|
394
|
+
Marker(item: island)
|
|
395
|
+
}
|
|
396
|
+
.task { route = try? await fastestRoute(from: pier, to: island) }
|
|
351
397
|
}
|
|
352
|
-
Marker("Start", coordinate: startCoord)
|
|
353
|
-
Marker("End", coordinate: endCoord)
|
|
354
|
-
}
|
|
355
|
-
.task {
|
|
356
|
-
route = try? await getDirections(from: startItem, to: endItem)
|
|
357
398
|
}
|
|
358
399
|
```
|
|
359
400
|
|
|
360
|
-
###
|
|
401
|
+
### Travel time only, and cycling
|
|
361
402
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
Directions
|
|
403
|
+
- `MKDirections.calculateETA()` returns `expectedTravelTime` without route
|
|
404
|
+
geometry; use it when a label is all you need
|
|
405
|
+
([ETA Calculation](references/mapkit-patterns.md#eta-calculation)).
|
|
406
|
+
- Bike routes: `request.transportType = .cycling`, iOS 14 and later
|
|
407
|
+
([Cycling Directions](references/mapkit-patterns.md#cycling-directions-ios-14)).
|
|
367
408
|
|
|
368
409
|
## PlaceDescriptor (iOS 26+)
|
|
369
410
|
|
|
370
|
-
|
|
371
|
-
|
|
411
|
+
`PlaceDescriptor`, from `GeoToolbox`, describes a place by coordinate or
|
|
412
|
+
address when you have no MapKit place ID. `MKMapItemRequest` resolves it into
|
|
413
|
+
a full `MKMapItem`.
|
|
372
414
|
|
|
373
415
|
```swift
|
|
374
416
|
import GeoToolbox
|
|
417
|
+
import MapKit
|
|
375
418
|
|
|
376
419
|
@available(iOS 26, *)
|
|
377
|
-
func
|
|
378
|
-
let
|
|
379
|
-
|
|
380
|
-
commonName: name
|
|
381
|
-
)
|
|
382
|
-
let request = MKMapItemRequest(placeDescriptor: descriptor)
|
|
383
|
-
return try await request.mapItem
|
|
420
|
+
func mapItem(near point: CLLocationCoordinate2D, named name: String) async throws -> MKMapItem {
|
|
421
|
+
let place = PlaceDescriptor(representations: [.coordinate(point)], commonName: name)
|
|
422
|
+
return try await MKMapItemRequest(placeDescriptor: place).mapItem
|
|
384
423
|
}
|
|
385
424
|
```
|
|
386
425
|
|
|
387
426
|
## Common Mistakes
|
|
388
427
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
for
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
**DON'T:** Let `liveUpdates()` run from an unowned task after the map/view is gone.
|
|
401
|
-
**DO:** Store the `Task`, cancel it when the feature stops, and filter invalid, inaccurate, stale, or impossible movement fixes.
|
|
402
|
-
|
|
403
|
-
**DON'T:** Force-unwrap `CLPlacemark` properties - they are all optional.
|
|
404
|
-
**DO:** Use nil-coalescing: `placemark.locality ?? "Unknown"`.
|
|
405
|
-
|
|
406
|
-
**DON'T:** Fire `MKLocalSearchCompleter` queries on every keystroke.
|
|
407
|
-
**DO:** Debounce with `.task(id: searchText)` + `Task.sleep(for: .milliseconds(300))`.
|
|
408
|
-
|
|
409
|
-
**DON'T:** Silently fail when location authorization is denied.
|
|
410
|
-
**DO:** Detect `.denied` status and show an alert with a Settings deep link.
|
|
411
|
-
|
|
412
|
-
**DON'T:** Assume geocoding always succeeds - handle empty results and network errors.
|
|
428
|
+
| Mistake | Do instead |
|
|
429
|
+
|---------|-----------|
|
|
430
|
+
| Asking for Always authorization at launch | Start with when-in-use; ask for `.always` only for a background feature that needs relaunch after termination |
|
|
431
|
+
| No `CLServiceSession` on iOS 18+ | Hold one for the life of the feature |
|
|
432
|
+
| A `CLLocationManagerDelegate` just to read position on iOS 17+ | Iterate `liveUpdates()`; less code, same result |
|
|
433
|
+
| Ignoring diagnostics (denied, off system-wide, unavailable) | Switch to a reduced mode, point the user at Settings, and leave search and manual entry usable |
|
|
434
|
+
| `liveUpdates()` in a task nobody owns | Keep the `Task` in a property and cancel it with the screen; filter bad fixes |
|
|
435
|
+
| Force-unwrapping `CLPlacemark` fields | They are all optional: `mark.locality ?? "Unknown"` |
|
|
436
|
+
| Querying the completer on every keystroke | `.task(id: text)` plus `Task.sleep(for: .milliseconds(300))` |
|
|
437
|
+
| Silent failure when denied | Detect `.denied` and offer a Settings link |
|
|
438
|
+
| Assuming geocoding returns something | Plan for zero matches and for being offline |
|
|
413
439
|
|
|
414
440
|
## Review Checklist
|
|
415
441
|
|
|
416
|
-
- [ ]
|
|
417
|
-
- [ ]
|
|
418
|
-
- [ ] `CLLocationUpdate` task cancelled when not needed
|
|
419
|
-
- [ ]
|
|
420
|
-
- [ ]
|
|
421
|
-
- [ ] Geocoding
|
|
422
|
-
- [ ]
|
|
423
|
-
- [ ] `CLMonitor`
|
|
442
|
+
- [ ] `NSLocationWhenInUseUsageDescription` is present and names a concrete benefit
|
|
443
|
+
- [ ] A denied user gets an explanation and a Settings deep link
|
|
444
|
+
- [ ] The `CLLocationUpdate` task is cancelled when not needed, to save battery
|
|
445
|
+
- [ ] Requested accuracy matches what the feature needs
|
|
446
|
+
- [ ] Annotation data is `Identifiable` with stable IDs
|
|
447
|
+
- [ ] Geocoding handles network failure and empty results
|
|
448
|
+
- [ ] Completer input is debounced
|
|
449
|
+
- [ ] `CLMonitor` stays at or under 20 conditions and the instance is kept alive
|
|
424
450
|
- [ ] Background location uses `CLBackgroundActivitySession`
|
|
425
|
-
- [ ]
|
|
426
|
-
- [ ]
|
|
451
|
+
- [ ] The map has been tried with VoiceOver
|
|
452
|
+
- [ ] Annotation models and location-driven UI state are `@MainActor`
|
|
427
453
|
|
|
428
454
|
## References
|
|
429
455
|
|
|
430
|
-
- [
|
|
431
|
-
|
|
456
|
+
- [Map patterns](references/mapkit-patterns.md): map setup,
|
|
457
|
+
annotations, camera, search, routes, dense maps and clustering, Look Around,
|
|
458
|
+
snapshots, iOS 26 APIs.
|
|
459
|
+
- [Location patterns](references/mapkit-corelocation-patterns.md):
|
|
460
|
+
`CLLocationUpdate`, `CLServiceSession`, `CLMonitor`, background location,
|
|
461
|
+
testing, privacy keys.
|