如何在ShieldActionExtension中使用completionHandler(.defer)实现应用访问授权通知?
实现Screen Time屏蔽界面的访问许可信号发送
从WWDC关于Screen Time API的视频中了解到:
“屏蔽响应可以是关闭被屏蔽应用,或是延迟操作并重绘屏蔽配置。”
“屏蔽的延迟操作功能非常强大,因为它能让屏蔽界面在等待后续操作信号的同时更新外观。例如,当孩子点击‘请求访问’时,可用于显示屏蔽界面正在等待监护人操作。”
我的需求是:引导用户从屏蔽配置界面跳转至我的应用,通过按钮向等待状态的屏蔽界面发送访问许可信号,允许用户访问目标应用。
实现方案
由于屏蔽动作扩展(Shield Action Extension)与主应用属于不同进程,需通过App Group实现跨进程通信,步骤如下:
配置App Group
在Xcode中为主应用和屏蔽动作扩展添加相同的App Group标识符(如group.com.yourdomain.yourapp),并确保两者的Info.plist均包含该配置。修改屏蔽动作扩展代码
触发延迟响应后,监听主应用发送的许可信号并完成授权:
import ManagedSettings import Combine class MyShieldActionExtension: ShieldActionHandler { private var cancellables = Set<AnyCancellable>() // 共享UserDefaults用于跨进程通信 private let sharedDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp")! override func handle( action: ShieldAction, for application: Application, completionHandler: @escaping (ShieldActionResponse) -> Void ) { switch action { case .primaryButtonPressed: // 发送延迟响应,让屏蔽界面保持等待状态 completionHandler(.defer) // 监听主应用的许可信号 sharedDefaults.publisher(for: \.allowAccess) .filter { $0 } .first() .sink { [weak self] _ in // 收到许可后关闭屏蔽界面,允许访问目标应用 completionHandler(.close) // 重置信号状态 self?.sharedDefaults.set(false, forKey: "allowAccess") } .store(in: &cancellables) // 跳转至主应用(需提前配置URL Scheme) if let url = URL(string: "yourapp://grant-access?bundleID=\(application.bundleID)") { open(url) } case .secondaryButtonPressed: completionHandler(.close) @unknown default: fatalError() } } }
- 主应用中实现许可按钮逻辑
在按钮点击事件中通过共享UserDefaults发送许可信号:
import UIKit class GrantAccessViewController: UIViewController { private let sharedDefaults = UserDefaults(suiteName: "group.com.yourdomain.yourapp")! var targetBundleID: String? @IBAction func allowAccessTapped(_ sender: UIButton) { // 设置许可信号 sharedDefaults.set(true, forKey: "allowAccess") // 关闭页面返回屏蔽界面 dismiss(animated: true) } }
- 配置URL Scheme
在主应用的Info.plist中添加自定义URL Scheme(如yourapp),并在SceneDelegate或AppDelegate中处理URL跳转,解析目标应用的Bundle ID并展示授权页面。
内容的提问来源于stack exchange,提问作者David Johansen
相关产品推荐
相关产品推荐

