$npx -y skills add dpearson2699/swift-ios-skills --skill permissionkitCreate child communication safety experiences using PermissionKit to request parental permission for children. Use when building apps that involve child-to-contact communication, need to check communication limits, request parent/guardian approval, or handle permission responses
| 1 | # PermissionKit |
| 2 | |
| 3 | Request permission from a parent or guardian to modify a child's communication |
| 4 | rules. PermissionKit creates communication safety experiences that let children ask for exceptions to communication limits set by their parents. |
| 5 | |
| 6 | PermissionKit communication experiences are available only through iMessage. |
| 7 | Use it for parent/guardian approval flows, not as a general in-app contact |
| 8 | permission, moderation, or chat-safety framework. |
| 9 | |
| 10 | ## Contents |
| 11 | |
| 12 | - [Availability and Setup](#availability-and-setup) |
| 13 | - [Core Concepts](#core-concepts) |
| 14 | - [Checking Communication Limits](#checking-communication-limits) |
| 15 | - [Creating Permission Questions](#creating-permission-questions) |
| 16 | - [Requesting Permission with AskCenter](#requesting-permission-with-askcenter) |
| 17 | - [SwiftUI Integration with PermissionButton](#swiftui-integration-with-permissionbutton) |
| 18 | - [Handling Responses](#handling-responses) |
| 19 | - [Significant App Update Topic](#significant-app-update-topic) |
| 20 | - [Common Mistakes](#common-mistakes) |
| 21 | - [Review Checklist](#review-checklist) |
| 22 | - [References](#references) |
| 23 | |
| 24 | ## Availability and Setup |
| 25 | |
| 26 | Import `PermissionKit`. Do not invent PermissionKit entitlement keys; verify |
| 27 | current Apple documentation and Xcode capabilities before adding signing |
| 28 | requirements. |
| 29 | |
| 30 | ```swift |
| 31 | import PermissionKit |
| 32 | ``` |
| 33 | |
| 34 | Use this centralized version matrix and verify it against the current SDK: |
| 35 | |
| 36 | | Tier | APIs | iOS/iPadOS/Mac Catalyst/macOS/visionOS | |
| 37 | |---|---|---| |
| 38 | | Core | Topics, handles, questions, responses, choices, `CommunicationLimits` | 26.0+ | |
| 39 | | Errors | `AskError` | 26.1+ | |
| 40 | | Presentation | `AskCenter`, ask/response sequences, `PermissionButton`, significant-update topics | 26.2+ | |
| 41 | |
| 42 | ## Core Concepts |
| 43 | |
| 44 | PermissionKit manages a flow where: |
| 45 | |
| 46 | 1. A child encounters a communication limit in your app |
| 47 | 2. Your app creates a `PermissionQuestion` describing the request |
| 48 | 3. The system presents the question to the child for them to send to their parent |
| 49 | 4. The parent reviews and approves or denies the request |
| 50 | 5. Your app receives a `PermissionResponse` with the parent's decision |
| 51 | |
| 52 | ### Key Types |
| 53 | |
| 54 | | Type | Role | |
| 55 | |---|---| |
| 56 | | `AskCenter` | Singleton that manages permission requests and responses | |
| 57 | | `PermissionQuestion` | Describes the permission being requested | |
| 58 | | `PermissionResponse` | The parent's decision (approval or denial) | |
| 59 | | `PermissionChoice` | The specific answer (approve/decline) | |
| 60 | | `PermissionButton` | SwiftUI button that triggers the permission flow | |
| 61 | | `CommunicationTopic` | Topic for communication-related permission requests | |
| 62 | | `CommunicationHandle` | A phone number, email, or custom identifier | |
| 63 | | `CommunicationLimits` | Checks which communication handles are known to the system | |
| 64 | | `SignificantAppUpdateTopic` | Topic for significant app update permission requests | |
| 65 | |
| 66 | ## Checking Communication Limits |
| 67 | |
| 68 | Use `CommunicationLimits.current` to check whether the system already knows a |
| 69 | communication handle for your app. This is not an "are communication limits |
| 70 | enabled?" probe. If limits are not enabled, `AskCenter.shared.ask(_:in:)` |
| 71 | throws `AskError.communicationLimitsNotEnabled`; handle that path when asking. |
| 72 | |
| 73 | `knownHandles(in:)` also requires the calling app to have a non-nil, nonempty |
| 74 | bundle identifier. Corrected code should guard `Bundle.main.bundleIdentifier` |
| 75 | before calling it. |
| 76 | |
| 77 | ```swift |
| 78 | import PermissionKit |
| 79 | |
| 80 | func needsPermissionPrompt(for handle: CommunicationHandle) async -> Bool { |
| 81 | let limits = CommunicationLimits.current |
| 82 | let isKnown = await limits.isKnownHandle(handle) |
| 83 | return !isKnown |
| 84 | } |
| 85 | |
| 86 | // Check multiple handles at once. |
| 87 | func filterKnownHandles(_ handles: Set<CommunicationHandle>) async -> Set<CommunicationHandle> { |
| 88 | guard Bundle.main.bundleIdentifier?.isEmpty == false else { return [] } |
| 89 | |
| 90 | let limits = CommunicationLimits.current |
| 91 | return await limits.knownHandles(in: handles) |
| 92 | } |
| 93 | ``` |
| 94 | |
| 95 | ### Creating Communication Handles |
| 96 | |
| 97 | ```swift |
| 98 | let phoneHandle = CommunicationHandle( |
| 99 | value: "+1234567890", |
| 100 | kind: .phoneNumber |
| 101 | ) |
| 102 | |
| 103 | let emailHandle = CommunicationHandle( |
| 104 | value: "friend@example.com", |
| 105 | kind: .emailAddress |
| 106 | ) |
| 107 | |
| 108 | let customHandle = CommunicationHandle( |
| 109 | value: "user123", |
| 110 | kind: .custom |
| 111 | ) |
| 112 | ``` |
| 113 | |
| 114 | ## Creating Permission Questions |
| 115 | |
| 116 | Build a `PermissionQuestion` with the contact information and communication |
| 117 | action type. |
| 118 | |
| 119 | ```swift |
| 120 | // Question for a single contact |
| 121 | let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber) |
| 122 | let question = PermissionQuestion<CommunicationTopic>(handle: handle) |
| 123 | |
| 124 | // Question for multiple contacts |
| 125 | let handles = [ |
| 126 | CommunicationHandle(value: "+1234567890", kind: .phoneNumber), |
| 127 | CommunicationHandle(value: "friend@example.com", kind: .emailAddress) |
| 128 | ] |
| 129 | let mult |