permissionkit
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePermissionKit
PermissionKit
Note: PermissionKit is new in iOS 26. Method signatures should be verified against the latest Xcode 26 beta SDK.
Request permission from a parent or guardian to modify a child's communication
rules. PermissionKit creates communication safety experiences that let children
ask for exceptions to communication limits set by their parents. Targets
Swift 6.2 / iOS 26+.
注意: PermissionKit是iOS 26中的新功能。方法签名请对照最新的Xcode 26 beta SDK进行验证。
向家长或监护人请求权限以修改儿童的通信规则。PermissionKit可创建通信安全体验,让儿童能够请求放宽家长设置的通信限制。支持Swift 6.2 / iOS 26+。
Contents
目录
Setup
设置
Import . No special entitlements are required.
PermissionKitswift
import PermissionKitPlatform availability: iOS 26+, iPadOS 26+, macOS 26+.
导入,无需特殊权限。
PermissionKitswift
import PermissionKit平台支持: iOS 26+, iPadOS 26+, macOS 26+。
Core Concepts
核心概念
PermissionKit manages a flow where:
- A child encounters a communication limit in your app
- Your app creates a describing the request
PermissionQuestion - The system presents the question to the child for them to send to their parent
- The parent reviews and approves or denies the request
- Your app receives a with the parent's decision
PermissionResponse
PermissionKit管理以下流程:
- 儿童在应用中遇到通信限制
- 应用创建一个来描述请求
PermissionQuestion - 系统向儿童展示该问题,由其发送给家长
- 家长审核并批准或拒绝请求
- 应用收到包含家长决定的
PermissionResponse
Key Types
关键类型
| Type | Role |
|---|---|
| Singleton that manages permission requests and responses |
| Describes the permission being requested |
| The parent's decision (approval or denial) |
| The specific answer (approve/decline) |
| SwiftUI button that triggers the permission flow |
| Topic for communication-related permission requests |
| A phone number, email, or custom identifier |
| Checks whether communication limits apply |
| Topic for significant app update permission requests |
| 类型 | 作用 |
|---|---|
| 管理权限请求与响应的单例类 |
| 描述所请求的权限内容 |
| 家长的决定(批准或拒绝) |
| 具体的答复结果(批准/拒绝) |
| 触发权限请求流程的SwiftUI按钮 |
| 与通信相关的权限请求主题 |
| 电话号码、邮箱或自定义标识符 |
| 检查是否应用了通信限制 |
| 与重大应用更新相关的权限请求主题 |
Checking Communication Limits
检查通信限制
Before presenting a permission request, check if communication limits are
enabled and whether the handle is known.
swift
import PermissionKit
func checkCommunicationStatus(for handle: CommunicationHandle) async -> Bool {
let limits = CommunicationLimits.current
let isKnown = await limits.isKnownHandle(handle)
return isKnown
}
// Check multiple handles at once
func filterKnownHandles(_ handles: Set<CommunicationHandle>) async -> Set<CommunicationHandle> {
let limits = CommunicationLimits.current
return await limits.knownHandles(in: handles)
}在发起权限请求前,先检查是否启用了通信限制,以及联系人标识符是否已被识别。
swift
import PermissionKit
func checkCommunicationStatus(for handle: CommunicationHandle) async -> Bool {
let limits = CommunicationLimits.current
let isKnown = await limits.isKnownHandle(handle)
return isKnown
}
// 批量检查多个联系人标识符
func filterKnownHandles(_ handles: Set<CommunicationHandle>) async -> Set<CommunicationHandle> {
let limits = CommunicationLimits.current
return await limits.knownHandles(in: handles)
}Creating Communication Handles
创建通信标识符
swift
let phoneHandle = CommunicationHandle(
value: "+1234567890",
kind: .phoneNumber
)
let emailHandle = CommunicationHandle(
value: "friend@example.com",
kind: .emailAddress
)
let customHandle = CommunicationHandle(
value: "user123",
kind: .custom
)swift
let phoneHandle = CommunicationHandle(
value: "+1234567890",
kind: .phoneNumber
)
let emailHandle = CommunicationHandle(
value: "friend@example.com",
kind: .emailAddress
)
let customHandle = CommunicationHandle(
value: "user123",
kind: .custom
)Creating Permission Questions
创建权限请求问题
Build a with the contact information and communication
action type.
PermissionQuestionswift
// Question for a single contact
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
let question = PermissionQuestion<CommunicationTopic>(handle: handle)
// Question for multiple contacts
let handles = [
CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
CommunicationHandle(value: "friend@example.com", kind: .emailAddress)
]
let multiQuestion = PermissionQuestion<CommunicationTopic>(handles: handles)结合联系人信息和通信操作类型构建。
PermissionQuestionswift
// 单个联系人的请求问题
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
let question = PermissionQuestion<CommunicationTopic>(handle: handle)
// 多个联系人的请求问题
let handles = [
CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
CommunicationHandle(value: "friend@example.com", kind: .emailAddress)
]
let multiQuestion = PermissionQuestion<CommunicationTopic>(handles: handles)Using CommunicationTopic with Person Information
结合个人信息使用CommunicationTopic
Provide display names and avatars for a richer permission prompt.
swift
let personInfo = CommunicationTopic.PersonInformation(
handle: CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
nameComponents: {
var name = PersonNameComponents()
name.givenName = "Alex"
name.familyName = "Smith"
return name
}(),
avatarImage: nil
)
let topic = CommunicationTopic(
personInformation: [personInfo],
actions: [.message, .audioCall]
)
let question = PermissionQuestion<CommunicationTopic>(communicationTopic: topic)提供显示名称和头像,让权限请求提示更清晰。
swift
let personInfo = CommunicationTopic.PersonInformation(
handle: CommunicationHandle(value: "+1234567890", kind: .phoneNumber),
nameComponents: {
var name = PersonNameComponents()
name.givenName = "Alex"
name.familyName = "Smith"
return name
}(),
avatarImage: nil
)
let topic = CommunicationTopic(
personInformation: [personInfo],
actions: [.message, .audioCall]
)
let question = PermissionQuestion<CommunicationTopic>(communicationTopic: topic)Communication Actions
通信操作类型
| Action | Description |
|---|---|
| Text messaging |
| Voice call |
| Video call |
| Generic call |
| Chat communication |
| Follow a user |
| Allow being followed |
| Friend request |
| Connection request |
| Generic communication |
| 操作类型 | 描述 |
|---|---|
| 短信通信 |
| 语音通话 |
| 视频通话 |
| 通用通话 |
| 聊天通信 |
| 关注用户 |
| 允许被关注 |
| 好友请求 |
| 连接请求 |
| 通用通信 |
Requesting Permission with AskCenter
通过AskCenter请求权限
Use to present the permission request to the child.
AskCenter.sharedswift
import PermissionKit
func requestPermission(
for question: PermissionQuestion<CommunicationTopic>,
in viewController: UIViewController
) async {
do {
try await AskCenter.shared.ask(question, in: viewController)
// Question was presented to the child
} catch let error as AskError {
switch error {
case .communicationLimitsNotEnabled:
// Communication limits not active -- no permission needed
break
case .contactSyncNotSetup:
// Contact sync not configured
break
case .invalidQuestion:
// Question is malformed
break
case .notAvailable:
// PermissionKit not available on this device
break
case .systemError(let underlying):
print("System error: \(underlying)")
case .unknown:
break
@unknown default:
break
}
}
}使用向儿童展示权限请求。
AskCenter.sharedswift
import PermissionKit
func requestPermission(
for question: PermissionQuestion<CommunicationTopic>,
in viewController: UIViewController
) async {
do {
try await AskCenter.shared.ask(question, in: viewController)
// 请求问题已展示给儿童
} catch let error as AskError {
switch error {
case .communicationLimitsNotEnabled:
// 未启用通信限制——无需申请权限
break
case .contactSyncNotSetup:
// 未配置联系人同步
break
case .invalidQuestion:
// 请求问题格式错误
break
case .notAvailable:
// 当前设备不支持PermissionKit
break
case .systemError(let underlying):
print("系统错误: \(underlying)")
case .unknown:
break
@unknown default:
break
}
}
}SwiftUI Integration with PermissionButton
通过PermissionButton集成SwiftUI
PermissionButtonswift
import SwiftUI
import PermissionKit
struct ContactPermissionView: View {
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
var body: some View {
let question = PermissionQuestion<CommunicationTopic>(handle: handle)
PermissionButton(question: question) {
Label("Ask to Message", systemImage: "message")
}
}
}PermissionButtonswift
import SwiftUI
import PermissionKit
struct ContactPermissionView: View {
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
var body: some View {
let question = PermissionQuestion<CommunicationTopic>(handle: handle)
PermissionButton(question: question) {
Label("申请发送消息权限", systemImage: "message")
}
}
}PermissionButton with Custom Topic
自定义主题的PermissionButton
swift
struct CustomPermissionView: View {
var body: some View {
let personInfo = CommunicationTopic.PersonInformation(
handle: CommunicationHandle(value: "user456", kind: .custom),
nameComponents: nil,
avatarImage: nil
)
let topic = CommunicationTopic(
personInformation: [personInfo],
actions: [.follow]
)
let question = PermissionQuestion<CommunicationTopic>(
communicationTopic: topic
)
PermissionButton(question: question) {
Text("Ask to Follow")
}
}
}swift
struct CustomPermissionView: View {
var body: some View {
let personInfo = CommunicationTopic.PersonInformation(
handle: CommunicationHandle(value: "user456", kind: .custom),
nameComponents: nil,
avatarImage: nil
)
let topic = CommunicationTopic(
personInformation: [personInfo],
actions: [.follow]
)
let question = PermissionQuestion<CommunicationTopic>(
communicationTopic: topic
)
PermissionButton(question: question) {
Text("申请关注权限")
}
}
}Handling Responses
处理权限响应
Listen for permission responses asynchronously.
swift
func observeResponses() async {
let responses = AskCenter.shared.responses(for: CommunicationTopic.self)
for await response in responses {
let choice = response.choice
let question = response.question
switch choice.answer {
case .approval:
// Parent approved -- enable communication
print("Approved for topic: \(question.topic)")
case .denial:
// Parent denied -- keep restriction
print("Denied")
@unknown default:
break
}
}
}异步监听权限响应结果。
swift
func observeResponses() async {
let responses = AskCenter.shared.responses(for: CommunicationTopic.self)
for await response in responses {
let choice = response.choice
let question = response.question
switch choice.answer {
case .approval:
// 家长已批准——启用通信功能
print("已批准主题: \(question.topic)")
case .denial:
// 家长已拒绝——保持限制
print("已拒绝")
@unknown default:
break
}
}
}PermissionChoice Properties
PermissionChoice属性
swift
let choice: PermissionChoice = response.choice
print("Answer: \(choice.answer)") // .approval or .denial
print("Choice ID: \(choice.id)")
print("Title: \(choice.title)")
// Convenience statics
let approved = PermissionChoice.approve
let declined = PermissionChoice.declineswift
let choice: PermissionChoice = response.choice
print("答复结果: \(choice.answer)") // .approval 或 .denial
print("选择ID: \(choice.id)")
print("标题: \(choice.title)")
// 便捷静态属性
let approved = PermissionChoice.approve
let declined = PermissionChoice.declineSignificant App Update Topic
重大应用更新主题
Request permission for significant app updates that require parental approval.
swift
let updateTopic = SignificantAppUpdateTopic(
description: "This update adds multiplayer chat features"
)
let question = PermissionQuestion<SignificantAppUpdateTopic>(
significantAppUpdateTopic: updateTopic
)
// Present the question
try await AskCenter.shared.ask(question, in: viewController)
// Listen for responses
for await response in AskCenter.shared.responses(for: SignificantAppUpdateTopic.self) {
switch response.choice.answer {
case .approval:
// Proceed with update
break
case .denial:
// Skip update
break
@unknown default:
break
}
}当应用有重大更新需要家长批准时,可发起权限请求。
swift
let updateTopic = SignificantAppUpdateTopic(
description: "本次更新新增多人聊天功能"
)
let question = PermissionQuestion<SignificantAppUpdateTopic>(
significantAppUpdateTopic: updateTopic
)
// 展示请求问题
try await AskCenter.shared.ask(question, in: viewController)
// 监听响应结果
for await response in AskCenter.shared.responses(for: SignificantAppUpdateTopic.self) {
switch response.choice.answer {
case .approval:
// 继续执行更新
break
case .denial:
// 跳过更新
break
@unknown default:
break
}
}Common Mistakes
常见错误
DON'T: Skip checking if communication limits are enabled
错误做法:跳过检查通信限制是否启用
If communication limits are not enabled, calling throws
. Check first or handle the error.
ask.communicationLimitsNotEnabledswift
// WRONG: Assuming limits are always active
try await AskCenter.shared.ask(question, in: viewController)
// CORRECT: Handle the case where limits are not enabled
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch AskError.communicationLimitsNotEnabled {
// Communication limits not active -- allow communication directly
allowCommunication()
} catch {
handleError(error)
}如果未启用通信限制,调用方法会抛出错误。请提前检查或处理该错误。
ask.communicationLimitsNotEnabledswift
// 错误:假设通信限制始终处于启用状态
try await AskCenter.shared.ask(question, in: viewController)
// 正确:处理未启用通信限制的情况
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch AskError.communicationLimitsNotEnabled {
// 未启用通信限制——直接允许通信
allowCommunication()
} catch {
handleError(error)
}DON'T: Ignore AskError cases
错误做法:忽略AskError的具体类型
Each error case requires different handling.
swift
// WRONG: Catch-all with no user feedback
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch {
print(error)
}
// CORRECT: Handle each case
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch let error as AskError {
switch error {
case .communicationLimitsNotEnabled:
allowCommunication()
case .contactSyncNotSetup:
showContactSyncPrompt()
case .invalidQuestion:
showInvalidQuestionAlert()
case .notAvailable:
showUnavailableMessage()
case .systemError(let underlying):
showSystemError(underlying)
case .unknown:
showGenericError()
@unknown default:
break
}
}每种错误类型需要不同的处理方式。
swift
// 错误:统一捕获错误但不提供用户反馈
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch {
print(error)
}
// 正确:分别处理每种错误类型
do {
try await AskCenter.shared.ask(question, in: viewController)
} catch let error as AskError {
switch error {
case .communicationLimitsNotEnabled:
allowCommunication()
case .contactSyncNotSetup:
showContactSyncPrompt()
case .invalidQuestion:
showInvalidQuestionAlert()
case .notAvailable:
showUnavailableMessage()
case .systemError(let underlying):
showSystemError(underlying)
case .unknown:
showGenericError()
@unknown default:
break
}
}DON'T: Create questions with empty handles
错误做法:创建包含空联系人列表的请求问题
A question with no handles or person information is invalid.
swift
// WRONG: Empty handles array
let question = PermissionQuestion<CommunicationTopic>(handles: []) // Invalid
// CORRECT: Provide at least one handle
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
let question = PermissionQuestion<CommunicationTopic>(handle: handle)没有联系人标识符或个人信息的请求问题是无效的。
swift
// 错误:空联系人数组
let question = PermissionQuestion<CommunicationTopic>(handles: []) // 无效
// 正确:至少提供一个联系人标识符
let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)
let question = PermissionQuestion<CommunicationTopic>(handle: handle)DON'T: Forget to observe responses
错误做法:忘记监听响应结果
Presenting a question without listening for the response means you never
know if the parent approved.
swift
// WRONG: Fire and forget
try await AskCenter.shared.ask(question, in: viewController)
// CORRECT: Observe responses
Task {
for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
handleResponse(response)
}
}
try await AskCenter.shared.ask(question, in: viewController)发起请求但不监听响应,将无法得知家长是否批准。
swift
// 错误:发起请求后不再处理
try await AskCenter.shared.ask(question, in: viewController)
// 正确:监听响应结果
Task {
for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {
handleResponse(response)
}
}
try await AskCenter.shared.ask(question, in: viewController)DON'T: Use deprecated CommunicationLimitsButton
错误做法:使用已废弃的CommunicationLimitsButton
Use instead of the deprecated .
PermissionButtonCommunicationLimitsButtonswift
// WRONG: Deprecated
CommunicationLimitsButton(question: question) {
Text("Ask Permission")
}
// CORRECT: Use PermissionButton
PermissionButton(question: question) {
Text("Ask Permission")
}请使用替代已废弃的。
PermissionButtonCommunicationLimitsButtonswift
// 错误:使用已废弃的API
CommunicationLimitsButton(question: question) {
Text("申请权限")
}
// 正确:使用PermissionButton
PermissionButton(question: question) {
Text("申请权限")
}Review Checklist
审核清单
- handled to allow fallback
AskError.communicationLimitsNotEnabled - cases handled individually with appropriate user feedback
AskError - created with correct
CommunicationHandle(phone, email, custom)Kind - includes at least one handle or person information
PermissionQuestion - observed to receive parent decisions
AskCenter.shared.responses(for:) - used instead of deprecated
PermissionButtonCommunicationLimitsButton - Person information includes name components for a clear permission prompt
- Communication actions match the app's actual communication capabilities
- Response handling updates UI on the main actor
- Error states provide clear guidance to the user
- 已处理错误,提供回退方案
AskError.communicationLimitsNotEnabled - 已分别处理的每种错误类型,并提供合适的用户反馈
AskError - 创建时使用了正确的类型(电话、邮箱、自定义)
CommunicationHandle - 包含至少一个联系人标识符或个人信息
PermissionQuestion - 已通过监听家长的决定
AskCenter.shared.responses(for:) - 使用替代已废弃的
PermissionButtonCommunicationLimitsButton - 个人信息中包含姓名组件,让权限请求提示更清晰
- 通信操作类型与应用实际的通信能力匹配
- 响应处理逻辑在主线程更新UI
- 错误状态向用户提供清晰的指导
References
参考资料
- Extended patterns (response handling, multi-topic, UIKit):
references/permissionkit-patterns.md - PermissionKit framework
- AskCenter
- PermissionQuestion
- PermissionButton
- PermissionResponse
- CommunicationTopic
- CommunicationHandle
- CommunicationLimits
- SignificantAppUpdateTopic
- AskError
- Creating a communication experience
- 扩展模式(响应处理、多主题、UIKit):
references/permissionkit-patterns.md - PermissionKit框架文档
- AskCenter文档
- PermissionQuestion文档
- PermissionButton文档
- PermissionResponse文档
- CommunicationTopic文档
- CommunicationHandle文档
- CommunicationLimits文档
- SignificantAppUpdateTopic文档
- AskError文档
- 创建通信安全体验