@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,490 +1,356 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: passkit-wallet
|
|
3
|
-
description: "
|
|
3
|
+
description: "Apple Pay and Wallet passes with PassKit: Apple Pay buttons, payment requests, authorization flow, merchant capabilities, shipping and contact fields, adding and distributing passes (PKPaymentRequest, PKPaymentButton, PKPaymentAuthorizationController, PKPass, AddPassToWalletButton, PKPassLibrary, PKAddPassesViewController). Use when building Apple Pay checkout for physical goods, real-world services, donations or eligible recurring payments, or adding and updating Wallet passes. Not for digital goods or subscriptions (storekit) or FinanceKit."
|
|
4
4
|
metadata:
|
|
5
|
-
source:
|
|
5
|
+
source: multi-agent-pipeline
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# PassKit
|
|
8
|
+
# PassKit: Apple Pay and Wallet
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
PassKit covers two things: taking Apple Pay payments and putting passes
|
|
11
|
+
(tickets, cards, coupons) into Wallet. Apple Pay is meant for tangible
|
|
12
|
+
products, in-person or real-world services, donations and eligible recurring
|
|
13
|
+
charges.
|
|
14
|
+
Examples assume Swift 6.3 and iOS 26.
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
advanced
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
## Contents
|
|
21
|
-
|
|
22
|
-
- [Setup](#setup)
|
|
23
|
-
- [Displaying the Apple Pay Button](#displaying-the-apple-pay-button)
|
|
24
|
-
- [Creating a Payment Request](#creating-a-payment-request)
|
|
25
|
-
- [Presenting the Payment Sheet](#presenting-the-payment-sheet)
|
|
26
|
-
- [Handling Payment Authorization](#handling-payment-authorization)
|
|
27
|
-
- [Wallet Passes](#wallet-passes)
|
|
28
|
-
- [Checking Pass Library](#checking-pass-library)
|
|
29
|
-
- [Common Mistakes](#common-mistakes)
|
|
30
|
-
- [Review Checklist](#review-checklist)
|
|
31
|
-
- [References](#references)
|
|
16
|
+
One rule shapes advanced checkouts: a single `PKPaymentRequest` may carry at
|
|
17
|
+
most one optional advanced type. The candidates are a recurring request, an
|
|
18
|
+
automatic-reload request, a deferred request, the Apple Pay Later setting, and
|
|
19
|
+
multi-token contexts. When a flow
|
|
20
|
+
needs two of them, build two requests.
|
|
32
21
|
|
|
33
22
|
## Setup
|
|
34
23
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
4.
|
|
24
|
+
1. Add the **Apple Pay** capability to the target.
|
|
25
|
+
2. Register a Merchant ID in the developer portal, in the form
|
|
26
|
+
`merchant.com.yourcompany.store`.
|
|
27
|
+
3. Create the Payment Processing Certificate for that Merchant ID and hand it
|
|
28
|
+
to your processor or server.
|
|
29
|
+
4. Make sure the Merchant ID is listed in the app's entitlements.
|
|
41
30
|
|
|
42
|
-
###
|
|
31
|
+
### Can this device pay?
|
|
43
32
|
|
|
44
|
-
|
|
45
|
-
check for an active card with `canMakePayments(usingNetworks:capabilities:)`,
|
|
46
|
-
Apple's HIG expects Apple Pay to be a primary, prominent payment option wherever
|
|
47
|
-
you use that check.
|
|
33
|
+
Check before any Apple Pay UI appears, in two steps:
|
|
48
34
|
|
|
49
35
|
```swift
|
|
50
36
|
import PassKit
|
|
51
37
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
38
|
+
enum Checkout {
|
|
39
|
+
static let merchantID = "merchant.com.yourcompany.store"
|
|
40
|
+
static let country = "US"
|
|
41
|
+
static let currency = "USD"
|
|
42
|
+
static let networks: [PKPaymentNetwork] = [.visa, .masterCard, .amex, .discover]
|
|
43
|
+
|
|
44
|
+
static var deviceSupportsApplePay: Bool {
|
|
45
|
+
PKPaymentAuthorizationController.canMakePayments()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
static var walletHasUsableCard: Bool {
|
|
49
|
+
PKPaymentAuthorizationController.canMakePayments(
|
|
50
|
+
usingNetworks: networks,
|
|
51
|
+
capabilities: .threeDSecure
|
|
52
|
+
)
|
|
56
53
|
}
|
|
57
|
-
// Check user has cards for the networks you support
|
|
58
|
-
return PKPaymentAuthorizationController.canMakePayments(
|
|
59
|
-
usingNetworks: [.visa, .masterCard, .amex, .discover],
|
|
60
|
-
capabilities: .threeDSecure
|
|
61
|
-
)
|
|
62
54
|
}
|
|
63
55
|
```
|
|
64
56
|
|
|
65
|
-
|
|
57
|
+
The first call asks whether the hardware and region support Apple Pay; the
|
|
58
|
+
second whether the user has a card on one of your networks. Keeping merchant
|
|
59
|
+
ID, country, currency and networks in one type also avoids scattering the
|
|
60
|
+
Merchant ID string through the codebase.
|
|
61
|
+
|
|
62
|
+
The Human Interface Guidelines attach a condition to the second call: an app
|
|
63
|
+
that asks whether the user holds an active card must then present Apple Pay
|
|
64
|
+
as a primary, prominent way to pay.
|
|
66
65
|
|
|
67
|
-
|
|
66
|
+
## The Apple Pay button
|
|
68
67
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
the Apple Pay logo or "Apple Pay" text.
|
|
68
|
+
Anything labelled Apple Pay must be Apple's own button. A custom control may
|
|
69
|
+
not show the Apple Pay mark or the words "Apple Pay".
|
|
72
70
|
|
|
73
71
|
```swift
|
|
74
|
-
|
|
75
|
-
|
|
72
|
+
struct BasketFooter: View {
|
|
73
|
+
let startPayment: () -> Void
|
|
76
74
|
|
|
77
|
-
struct CheckoutView: View {
|
|
78
75
|
var body: some View {
|
|
79
|
-
PayWithApplePayButton(.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
.payWithApplePayButtonStyle(.black)
|
|
83
|
-
.frame(height: 48)
|
|
84
|
-
.padding()
|
|
76
|
+
PayWithApplePayButton(.checkout, action: startPayment)
|
|
77
|
+
.payWithApplePayButtonStyle(.black)
|
|
78
|
+
.frame(height: 50)
|
|
85
79
|
}
|
|
86
80
|
}
|
|
87
81
|
```
|
|
88
82
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Use `PKPaymentButton` for UIKit-based interfaces.
|
|
83
|
+
UIKit uses `PKPaymentButton`:
|
|
92
84
|
|
|
93
85
|
```swift
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
)
|
|
98
|
-
button.cornerRadius = 12
|
|
99
|
-
button.addTarget(self, action: #selector(startPayment), for: .touchUpInside)
|
|
86
|
+
let payButton = PKPaymentButton(paymentButtonType: .checkout, paymentButtonStyle: .black)
|
|
87
|
+
payButton.cornerRadius = 10
|
|
88
|
+
payButton.addTarget(self, action: #selector(payTapped), for: .primaryActionTriggered)
|
|
100
89
|
```
|
|
101
90
|
|
|
102
|
-
|
|
103
|
-
`.checkout`, `.continue`, `.book`, `.subscribe`, `.reload`, `.addMoney`,
|
|
104
|
-
`.topUp`, `.order`, `.rent`, `.support`, `.contribute`, `.tip`
|
|
91
|
+
Pick the `PKPaymentButtonType` whose wording fits the action:
|
|
105
92
|
|
|
106
|
-
|
|
93
|
+
| Purpose | Types |
|
|
94
|
+
|---------|-------|
|
|
95
|
+
| Generic or purchase | `.plain`, `.buy`, `.checkout`, `.continue`, `.order` |
|
|
96
|
+
| Setup and in-store | `.setUp`, `.inStore` |
|
|
97
|
+
| Giving | `.donate`, `.contribute`, `.support`, `.tip` |
|
|
98
|
+
| Bookings and plans | `.book`, `.rent`, `.subscribe` |
|
|
99
|
+
| Balances | `.reload`, `.addMoney`, `.topUp` |
|
|
107
100
|
|
|
108
|
-
|
|
109
|
-
PassKit amount APIs take `NSDecimalNumber`, not `Double`.
|
|
101
|
+
## Building the request
|
|
110
102
|
|
|
111
103
|
```swift
|
|
112
|
-
func
|
|
113
|
-
let
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
PKPaymentSummaryItem(
|
|
126
|
-
label: "Shipping",
|
|
127
|
-
amount: NSDecimalNumber(string: "4.99")
|
|
128
|
-
),
|
|
129
|
-
PKPaymentSummaryItem(
|
|
130
|
-
label: "My Store",
|
|
131
|
-
amount: NSDecimalNumber(string: "14.98")
|
|
132
|
-
) // Total
|
|
133
|
-
]
|
|
134
|
-
|
|
135
|
-
return request
|
|
104
|
+
func makeRequest(for basket: Basket) -> PKPaymentRequest {
|
|
105
|
+
let order = PKPaymentRequest()
|
|
106
|
+
order.merchantIdentifier = Checkout.merchantID
|
|
107
|
+
order.countryCode = Checkout.country
|
|
108
|
+
order.currencyCode = Checkout.currency
|
|
109
|
+
order.supportedNetworks = Checkout.networks
|
|
110
|
+
order.merchantCapabilities = .threeDSecure
|
|
111
|
+
|
|
112
|
+
let goods = PKPaymentSummaryItem(label: "Ceramic Mugs (2)", amount: NSDecimalNumber(string: "36.00"))
|
|
113
|
+
let tax = PKPaymentSummaryItem(label: "Sales Tax", amount: NSDecimalNumber(string: "2.97"))
|
|
114
|
+
let total = PKPaymentSummaryItem(label: "Clayworks Studio", amount: goods.amount.adding(tax.amount))
|
|
115
|
+
order.paymentSummaryItems = [goods, tax, total]
|
|
116
|
+
return order
|
|
136
117
|
}
|
|
137
118
|
```
|
|
138
119
|
|
|
139
|
-
|
|
140
|
-
|
|
120
|
+
- Money is `NSDecimalNumber`, built from a string or integer parts. A `Double`
|
|
121
|
+
literal such as `36.1` is already imprecise before it reaches PassKit.
|
|
122
|
+
- The last summary item is the total. Its label, your business name, is what
|
|
123
|
+
appears on the Pay line. Leave it out and the sheet shows your last line
|
|
124
|
+
item there instead.
|
|
141
125
|
|
|
142
|
-
###
|
|
126
|
+
### Shipping and contact details
|
|
143
127
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
collect them accurately.
|
|
128
|
+
Ask only for what you need to price, fulfil or legally process the order.
|
|
129
|
+
Anything the sheet cannot collect well (product options, notes, gifts shipped
|
|
130
|
+
to several addresses, a pickup store) belongs on your own screen before the
|
|
131
|
+
Apple Pay button.
|
|
149
132
|
|
|
150
133
|
```swift
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
label:
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
express.detail = "1-2 business days"
|
|
167
|
-
|
|
168
|
-
request.shippingMethods = [standard, express]
|
|
169
|
-
|
|
170
|
-
request.shippingType = .shipping // .delivery, .storePickup, .servicePickup
|
|
134
|
+
order.requiredShippingContactFields = [.postalAddress, .name, .phoneNumber]
|
|
135
|
+
order.requiredBillingContactFields = [.postalAddress]
|
|
136
|
+
|
|
137
|
+
func delivery(_ id: String, _ title: String, _ price: String, _ eta: String) -> PKShippingMethod {
|
|
138
|
+
let method = PKShippingMethod(label: title, amount: NSDecimalNumber(string: price))
|
|
139
|
+
method.identifier = id
|
|
140
|
+
method.detail = eta
|
|
141
|
+
return method
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
order.shippingMethods = [
|
|
145
|
+
delivery("ground", "Ground", "4.50", "Arrives in 3 to 5 days"),
|
|
146
|
+
delivery("overnight", "Overnight", "12.00", "Arrives tomorrow"),
|
|
147
|
+
]
|
|
148
|
+
order.shippingType = .shipping
|
|
171
149
|
```
|
|
172
150
|
|
|
173
|
-
|
|
151
|
+
`shippingType` can be `.shipping`, `.delivery`, `.storePickup` or
|
|
152
|
+
`.servicePickup`.
|
|
174
153
|
|
|
175
|
-
|
|
176
|
-
|---|---|
|
|
177
|
-
| Visa | `.visa` |
|
|
178
|
-
| Mastercard | `.masterCard` |
|
|
179
|
-
| American Express | `.amex` |
|
|
180
|
-
| Discover | `.discover` |
|
|
181
|
-
| China UnionPay | `.chinaUnionPay` |
|
|
182
|
-
| JCB | `.JCB` |
|
|
183
|
-
| Maestro | `.maestro` |
|
|
184
|
-
| Electron | `.electron` |
|
|
185
|
-
| Interac | `.interac` |
|
|
154
|
+
### Networks
|
|
186
155
|
|
|
187
|
-
|
|
156
|
+
`PKPaymentNetwork` constants include `.visa`, `.masterCard`, `.amex`,
|
|
157
|
+
`.discover`, `.chinaUnionPay`, `.JCB`, `.maestro`, `.electron` and `.interac`.
|
|
158
|
+
`PKPaymentRequest.availableNetworks()` reports what the device supports at
|
|
159
|
+
run time.
|
|
188
160
|
|
|
189
|
-
## Presenting the
|
|
161
|
+
## Presenting the sheet and authorizing
|
|
190
162
|
|
|
191
|
-
|
|
163
|
+
`PKPaymentAuthorizationController` works from SwiftUI and UIKit alike and
|
|
164
|
+
needs no view controller. Because the delegate property is weak, store the
|
|
165
|
+
controller in a property until the sheet has gone. The SDK marks every
|
|
166
|
+
delegate callback as main-actor, so the methods below are plain members of
|
|
167
|
+
the `@MainActor` coordinator. Marking them `nonisolated` would force the
|
|
168
|
+
non-`Sendable` `reply` handlers and shipping methods across actors, which
|
|
169
|
+
Swift 6 rejects.
|
|
192
170
|
|
|
193
171
|
```swift
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
if !presented {
|
|
206
|
-
self?.paymentController = nil
|
|
207
|
-
}
|
|
172
|
+
@MainActor
|
|
173
|
+
final class PaymentCoordinator: NSObject, PKPaymentAuthorizationControllerDelegate {
|
|
174
|
+
private var controller: PKPaymentAuthorizationController?
|
|
175
|
+
private var basket = Basket()
|
|
176
|
+
|
|
177
|
+
func pay() {
|
|
178
|
+
let sheet = PKPaymentAuthorizationController(paymentRequest: makeRequest(for: basket))
|
|
179
|
+
sheet.delegate = self
|
|
180
|
+
controller = sheet
|
|
181
|
+
Task {
|
|
182
|
+
if await !sheet.present() { controller = nil }
|
|
208
183
|
}
|
|
209
184
|
}
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
## Handling Payment Authorization
|
|
214
|
-
|
|
215
|
-
Implement `PKPaymentAuthorizationControllerDelegate` to process the payment token.
|
|
216
185
|
|
|
217
|
-
```swift
|
|
218
|
-
extension CheckoutCoordinator: PKPaymentAuthorizationControllerDelegate {
|
|
219
186
|
func paymentAuthorizationController(
|
|
220
|
-
_
|
|
187
|
+
_ sheet: PKPaymentAuthorizationController,
|
|
221
188
|
didAuthorizePayment payment: PKPayment,
|
|
222
|
-
handler
|
|
189
|
+
handler reply: @escaping (PKPaymentAuthorizationResult) -> Void
|
|
223
190
|
) {
|
|
224
|
-
|
|
191
|
+
let token = payment.token.paymentData
|
|
225
192
|
Task {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} catch {
|
|
230
|
-
completion(PKPaymentAuthorizationResult(status: .failure, errors: [error]))
|
|
231
|
-
}
|
|
193
|
+
let failure = await OrderAPI.charge(token)
|
|
194
|
+
let status: PKPaymentAuthorizationStatus = failure == nil ? .success : .failure
|
|
195
|
+
reply(PKPaymentAuthorizationResult(status: status, errors: failure.map { [$0] }))
|
|
232
196
|
}
|
|
233
197
|
}
|
|
234
198
|
|
|
235
|
-
func paymentAuthorizationControllerDidFinish(
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
controller.dismiss { [weak self] in
|
|
239
|
-
self?.paymentController = nil
|
|
199
|
+
func paymentAuthorizationControllerDidFinish(_ sheet: PKPaymentAuthorizationController) {
|
|
200
|
+
sheet.dismiss { [weak self] in
|
|
201
|
+
Task { @MainActor in self?.controller = nil }
|
|
240
202
|
}
|
|
241
203
|
}
|
|
242
|
-
}
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
### Handling Shipping Changes
|
|
246
204
|
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
205
|
+
func paymentAuthorizationController(
|
|
206
|
+
_ sheet: PKPaymentAuthorizationController,
|
|
207
|
+
didSelectShippingMethod method: PKShippingMethod,
|
|
208
|
+
handler reply: @escaping (PKPaymentRequestShippingMethodUpdate) -> Void
|
|
209
|
+
) {
|
|
210
|
+
basket.shipping = method
|
|
211
|
+
let items = makeRequest(for: basket).paymentSummaryItems
|
|
212
|
+
reply(PKPaymentRequestShippingMethodUpdate(paymentSummaryItems: items))
|
|
213
|
+
}
|
|
256
214
|
}
|
|
257
215
|
```
|
|
258
216
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
217
|
+
- The payment token goes to your server or processor as opaque data. Never
|
|
218
|
+
decode it in the app.
|
|
219
|
+
- Report declines and network failures through the result's status and
|
|
220
|
+
errors so the sheet can show them.
|
|
221
|
+
- Dismiss only in `paymentAuthorizationControllerDidFinish(_:)`. Dismissing
|
|
222
|
+
from `didAuthorizePayment` leaves a blank sheet.
|
|
223
|
+
- Every shipping-method change recalculates the summary items, total included.
|
|
262
224
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
adding it. `PKPass(data:)` expects signed pass data and can throw invalid-data
|
|
266
|
-
or invalid-signature errors. Name `invalid-data` and `invalid-signature`
|
|
267
|
-
failures explicitly instead of hiding them behind a bare `try?` in review
|
|
268
|
-
guidance.
|
|
225
|
+
Recurring, deferred, coupon and multi-merchant requests, plus a full SwiftUI
|
|
226
|
+
checkout screen, are in the [Wallet and advanced payments reference](references/wallet-passes.md).
|
|
269
227
|
|
|
270
|
-
|
|
271
|
-
func addPassToWallet(data: Data) {
|
|
272
|
-
guard PKAddPassesViewController.canAddPasses() else {
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
do {
|
|
277
|
-
let pass = try PKPass(data: data)
|
|
278
|
-
guard let addController = PKAddPassesViewController(pass: pass) else {
|
|
279
|
-
return
|
|
280
|
-
}
|
|
281
|
-
addController.delegate = self
|
|
282
|
-
present(addController, animated: true)
|
|
283
|
-
} catch {
|
|
284
|
-
// Signed pass data is invalid or the signature cannot be validated.
|
|
285
|
-
showRecoverablePassError(error)
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
```
|
|
228
|
+
## Wallet passes
|
|
289
229
|
|
|
290
|
-
###
|
|
230
|
+
### Adding a pass
|
|
291
231
|
|
|
292
|
-
|
|
232
|
+
Passes arrive as signed `.pkpass` data, usually from your server.
|
|
233
|
+
`PKPass(data:)` throws when the data is not a valid pass or when its signature
|
|
234
|
+
does not verify. Name those two failures in your error handling and show the
|
|
235
|
+
user something recoverable; a bare `try?` hides both.
|
|
293
236
|
|
|
294
237
|
```swift
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
addedToWallet = added
|
|
307
|
-
}
|
|
308
|
-
.addPassToWalletButtonStyle(.blackOutline)
|
|
309
|
-
.frame(width: 250, height: 50)
|
|
238
|
+
@MainActor
|
|
239
|
+
func offerPass(_ data: Data, from presenter: UIViewController) throws {
|
|
240
|
+
guard PKAddPassesViewController.canAddPasses() else { throw WalletError.addingUnavailable }
|
|
241
|
+
let pass: PKPass
|
|
242
|
+
do {
|
|
243
|
+
pass = try PKPass(data: data)
|
|
244
|
+
} catch let error as PKPassKitError {
|
|
245
|
+
switch error.code {
|
|
246
|
+
case .invalidSignature: throw WalletError.badSignature
|
|
247
|
+
case .invalidDataError: throw WalletError.invalidPass
|
|
248
|
+
default: throw WalletError.unknown(error)
|
|
310
249
|
}
|
|
311
250
|
}
|
|
251
|
+
guard let sheet = PKAddPassesViewController(pass: pass) else { throw WalletError.invalidPass }
|
|
252
|
+
sheet.delegate = presenter as? PKAddPassesViewControllerDelegate
|
|
253
|
+
presenter.present(sheet, animated: true)
|
|
312
254
|
}
|
|
313
255
|
```
|
|
314
256
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
Use `PKPassLibrary` to inspect and manage passes the user already has. Check
|
|
318
|
-
`PKPassLibrary.isPassLibraryAvailable()` before pass-library operations, but use
|
|
319
|
-
`PKAddPassesViewController.canAddPasses()` to decide whether the device can add
|
|
320
|
-
passes. `passes()` only returns passes your app can access through its
|
|
321
|
-
entitlements. When replacing an existing pass, check the Boolean result from
|
|
322
|
-
`replacePass(with:)` and handle failure. For signed pass bundle construction,
|
|
323
|
-
update web services, and `replacePass(with:)`, read
|
|
324
|
-
[references/wallet-passes.md](references/wallet-passes.md).
|
|
325
|
-
|
|
326
|
-
```swift
|
|
327
|
-
let library = PKPassLibrary()
|
|
328
|
-
|
|
329
|
-
// Check if a specific pass is already in Wallet
|
|
330
|
-
let hasPass = library.containsPass(pass)
|
|
331
|
-
|
|
332
|
-
// Retrieve passes your app can access
|
|
333
|
-
let passes = library.passes()
|
|
334
|
-
|
|
335
|
-
// Check if pass library is available
|
|
336
|
-
guard PKPassLibrary.isPassLibraryAvailable() else { return }
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
## Common Mistakes
|
|
340
|
-
|
|
341
|
-
### DON'T: Use StoreKit for physical goods
|
|
342
|
-
|
|
343
|
-
Apple Pay (PassKit) is for **physical goods, real-world services, donations, and
|
|
344
|
-
eligible recurring payments**. StoreKit is for virtual goods, app features, and
|
|
345
|
-
digital-content subscriptions. Using the wrong framework leads to App Review
|
|
346
|
-
rejection.
|
|
257
|
+
`PKAddPassesViewController` shows the pass so the user can confirm it first.
|
|
347
258
|
|
|
348
|
-
|
|
349
|
-
// WRONG: Using StoreKit to sell a physical product
|
|
350
|
-
let product = try await Product.products(for: ["com.example.tshirt"])
|
|
351
|
-
|
|
352
|
-
// CORRECT: Use Apple Pay for physical goods
|
|
353
|
-
let request = PKPaymentRequest()
|
|
354
|
-
request.paymentSummaryItems = [
|
|
355
|
-
PKPaymentSummaryItem(label: "T-Shirt", amount: NSDecimalNumber(string: "29.99")),
|
|
356
|
-
PKPaymentSummaryItem(label: "My Store", amount: NSDecimalNumber(string: "29.99"))
|
|
357
|
-
]
|
|
358
|
-
```
|
|
259
|
+
### SwiftUI button
|
|
359
260
|
|
|
360
|
-
|
|
261
|
+
`AddPassToWalletButton` is the SwiftUI version of `PKAddPassButton`. Show it
|
|
262
|
+
only when `canAddPasses()` is true and the pass parsed:
|
|
361
263
|
|
|
362
264
|
```swift
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
// CORRECT: Centralize configuration
|
|
371
|
-
enum PaymentConfig {
|
|
372
|
-
static let merchantIdentifier = "merchant.com.example.app"
|
|
373
|
-
static let countryCode = "US"
|
|
374
|
-
static let currencyCode = "USD"
|
|
375
|
-
static let supportedNetworks: [PKPaymentNetwork] = [.visa, .masterCard, .amex]
|
|
265
|
+
if PKAddPassesViewController.canAddPasses(), let ticket = parsedTicket {
|
|
266
|
+
AddPassToWalletButton([ticket]) { added in
|
|
267
|
+
ticketSaved = added
|
|
268
|
+
}
|
|
269
|
+
.addPassToWalletButtonStyle(.blackOutline)
|
|
270
|
+
.frame(width: 260, height: 50)
|
|
376
271
|
}
|
|
377
272
|
```
|
|
378
273
|
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
The last item in `paymentSummaryItems` is the total row. If you only list line
|
|
382
|
-
items, the payment sheet uses the final line item as the Pay line instead of
|
|
383
|
-
your business name.
|
|
384
|
-
|
|
385
|
-
```swift
|
|
386
|
-
// WRONG: No total item
|
|
387
|
-
request.paymentSummaryItems = [
|
|
388
|
-
PKPaymentSummaryItem(label: "Widget", amount: NSDecimalNumber(string: "9.99"))
|
|
389
|
-
]
|
|
390
|
-
|
|
391
|
-
// CORRECT: Last item is the total with your merchant name
|
|
392
|
-
request.paymentSummaryItems = [
|
|
393
|
-
PKPaymentSummaryItem(label: "Widget", amount: NSDecimalNumber(string: "9.99")),
|
|
394
|
-
PKPaymentSummaryItem(
|
|
395
|
-
label: "My Store",
|
|
396
|
-
amount: NSDecimalNumber(string: "9.99")
|
|
397
|
-
) // Total
|
|
398
|
-
]
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### DON'T: Use binary floating-point values for money
|
|
402
|
-
|
|
403
|
-
```swift
|
|
404
|
-
// WRONG: PassKit amounts are NSDecimalNumber values
|
|
405
|
-
PKPaymentSummaryItem(label: "Widget", amount: 9.99)
|
|
406
|
-
|
|
407
|
-
// CORRECT: Construct decimal amounts explicitly
|
|
408
|
-
PKPaymentSummaryItem(label: "Widget", amount: NSDecimalNumber(string: "9.99"))
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
### DON'T: Skip the canMakePayments check
|
|
412
|
-
|
|
413
|
-
```swift
|
|
414
|
-
// WRONG: Show Apple Pay button without checking
|
|
415
|
-
PayWithApplePayButton(.buy) { startPayment() }
|
|
416
|
-
|
|
417
|
-
// CORRECT: Only show when available
|
|
418
|
-
if PKPaymentAuthorizationController.canMakePayments(
|
|
419
|
-
usingNetworks: PaymentConfig.supportedNetworks
|
|
420
|
-
) {
|
|
421
|
-
PayWithApplePayButton(.buy) { startPayment() }
|
|
422
|
-
} else {
|
|
423
|
-
// Show alternative checkout or setup button
|
|
424
|
-
Button("Set Up Apple Pay") { /* guide user */ }
|
|
425
|
-
}
|
|
426
|
-
```
|
|
274
|
+
`parsedTicket` is a `PKPass?` produced by the throwing parse above, which has
|
|
275
|
+
already reported any invalid-data or signature error.
|
|
427
276
|
|
|
428
|
-
###
|
|
277
|
+
### The pass library
|
|
429
278
|
|
|
430
|
-
|
|
431
|
-
property is weak. Dismiss only after the sheet finishes.
|
|
279
|
+
`PKPassLibrary` looks at, and manages, passes the user already has.
|
|
432
280
|
|
|
433
281
|
```swift
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
) {
|
|
440
|
-
controller.dismiss() // Too early -- causes blank sheet
|
|
441
|
-
completion(.init(status: .success, errors: nil))
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
// CORRECT: Dismiss only in paymentAuthorizationControllerDidFinish
|
|
445
|
-
func paymentAuthorizationControllerDidFinish(
|
|
446
|
-
_ controller: PKPaymentAuthorizationController
|
|
447
|
-
) {
|
|
448
|
-
controller.dismiss { [weak self] in
|
|
449
|
-
self?.paymentController = nil
|
|
282
|
+
guard PKPassLibrary.isPassLibraryAvailable() else { return }
|
|
283
|
+
let library = PKPassLibrary()
|
|
284
|
+
if library.containsPass(updated) {
|
|
285
|
+
if !library.replacePass(with: updated) {
|
|
286
|
+
showRetryableWalletError()
|
|
450
287
|
}
|
|
451
288
|
}
|
|
452
289
|
```
|
|
453
290
|
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
-
|
|
458
|
-
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
-
|
|
470
|
-
|
|
471
|
-
-
|
|
472
|
-
|
|
473
|
-
-
|
|
474
|
-
|
|
475
|
-
-
|
|
291
|
+
- `isPassLibraryAvailable()` gates library operations. Whether a pass can be
|
|
292
|
+
added is a different question, answered by `canAddPasses()`. Do not use one
|
|
293
|
+
for the other.
|
|
294
|
+
- `passes()` returns only passes your entitlements give you access to.
|
|
295
|
+
- `replacePass(with:)` returns a `Bool`; handle `false`.
|
|
296
|
+
|
|
297
|
+
Pass bundle contents, the update web service and replacement flow are in the
|
|
298
|
+
[reference](references/wallet-passes.md).
|
|
299
|
+
|
|
300
|
+
## Common mistakes
|
|
301
|
+
|
|
302
|
+
- **StoreKit for physical goods, or PassKit for digital ones.** Tangible
|
|
303
|
+
products, services delivered outside the app, donations and qualifying
|
|
304
|
+
recurring charges use Apple Pay. In-app currency, unlocked features and
|
|
305
|
+
subscriptions to digital content use StoreKit. Mixing them up gets the app rejected.
|
|
306
|
+
- **Merchant ID copied everywhere.** Keep it, with country, currency and
|
|
307
|
+
networks, in one configuration type.
|
|
308
|
+
- **No total line.** The Pay line then shows the last item rather than your
|
|
309
|
+
business name.
|
|
310
|
+
- **`Double` amounts.** `amount: 9.99` is binary floating point; construct
|
|
311
|
+
`NSDecimalNumber` explicitly.
|
|
312
|
+
- **Skipping `canMakePayments`.** Show the button only when it can work, and
|
|
313
|
+
otherwise offer another checkout or a "Set Up Apple Pay" button.
|
|
314
|
+
- **Dismissing too early.** Keep the controller retained and dismiss only in
|
|
315
|
+
`paymentAuthorizationControllerDidFinish(_:)`.
|
|
316
|
+
|
|
317
|
+
## Review checklist
|
|
318
|
+
|
|
319
|
+
- [ ] Apple Pay capability and Merchant ID configured
|
|
320
|
+
- [ ] Payment Processing Certificate created and installed
|
|
321
|
+
- [ ] `canMakePayments(usingNetworks:capabilities:)` checked before the button shows
|
|
322
|
+
- [ ] Apple Pay is prominent wherever the active-card check is used
|
|
323
|
+
- [ ] Product choices, extra details and complex shipping collected before the sheet
|
|
324
|
+
- [ ] Last summary item is the total, labelled with the merchant name
|
|
325
|
+
- [ ] Summary and token-context amounts are `NSDecimalNumber`
|
|
326
|
+
- [ ] Payment token goes to the server and is never decoded on device
|
|
327
|
+
- [ ] Controller retained while presented and released after finish
|
|
328
|
+
- [ ] `paymentAuthorizationControllerDidFinish` dismisses the sheet
|
|
329
|
+
- [ ] Shipping-method changes recalculate the totals
|
|
330
|
+
- [ ] StoreKit and Apple Pay responsibilities kept apart
|
|
331
|
+
- [ ] Every pass is a signed `.pkpass` bundle
|
|
332
|
+
- [ ] The user hears about a pass that fails to parse, whether the data or the signature is bad
|
|
333
|
+
- [ ] `isPassLibraryAvailable()` used for library work, not for add capability
|
|
334
|
+
- [ ] `canAddPasses()` checked before any add-pass UI
|
|
335
|
+
- [ ] `replacePass(with:)` result checked
|
|
336
|
+
- [ ] System buttons only: `PKPaymentButton` or `PayWithApplePayButton`
|
|
337
|
+
- [ ] Adding to Wallet uses `PKAddPassButton`, `AddPassToWalletButton` or `PKAddPassesViewController`
|
|
338
|
+
- [ ] Authorization results carry errors for declines and network failures
|
|
476
339
|
|
|
477
340
|
## References
|
|
478
341
|
|
|
479
|
-
-
|
|
480
|
-
-
|
|
481
|
-
|
|
482
|
-
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
-
|
|
489
|
-
|
|
490
|
-
-
|
|
342
|
+
- [Wallet and advanced payments](references/wallet-passes.md): recurring,
|
|
343
|
+
coupon, multi-merchant and deferred requests; pass bundles; pass updates;
|
|
344
|
+
SwiftUI checkout
|
|
345
|
+
- Apple documentation:
|
|
346
|
+
[PassKit](https://developer.apple.com/documentation/passkit),
|
|
347
|
+
[payment request](https://developer.apple.com/documentation/passkit/pkpaymentrequest),
|
|
348
|
+
[authorization controller](https://developer.apple.com/documentation/passkit/pkpaymentauthorizationcontroller),
|
|
349
|
+
[UIKit pay button](https://developer.apple.com/documentation/passkit/pkpaymentbutton),
|
|
350
|
+
[SwiftUI pay button](https://developer.apple.com/documentation/passkit/paywithapplepaybutton),
|
|
351
|
+
[SwiftUI add-pass button](https://developer.apple.com/documentation/passkit/addpasstowalletbutton),
|
|
352
|
+
[pass](https://developer.apple.com/documentation/passkit/pkpass),
|
|
353
|
+
[add-passes controller](https://developer.apple.com/documentation/passkit/pkaddpassesviewcontroller),
|
|
354
|
+
[pass library](https://developer.apple.com/documentation/passkit/pkpasslibrary),
|
|
355
|
+
[payment networks](https://developer.apple.com/documentation/passkit/pkpaymentnetwork)
|
|
356
|
+
- [HIG page for Apple Pay](https://developer.apple.com/design/human-interface-guidelines/apple-pay)
|