iOS10:Today Extension打开宿主App时AppDelegate未触发及多操作需求
iOS 10下Today Extension打开宿主App并执行不同操作的解决方案
刚好之前处理过iOS10下Today Extension(Widget)和宿主App交互的问题,给你整理一套完整的解决方案,一步步来解决你的问题:
一、先给宿主App配置自定义URL Scheme
这是Widget能唤起宿主App的基础,必须配置正确:
- 打开宿主App的
Info.plist文件 - 添加
URL types数组项,在数组里新增一个字典 - 给字典添加
URL scheme字段,设置一个唯一的标识(比如myappcustomscheme,别和其他App重复) - 可选:添加
URL identifier字段,设置为你的App Bundle ID(比如com.yourcompany.yourapp)
二、在Today Extension中实现按钮唤起逻辑
在Widget的按钮点击事件里,通过带参数的URL唤起宿主App,用参数区分不同操作:
import UIKit import NotificationCenter class TodayViewController: UIViewController, NCWidgetProviding { override func viewDidLoad() { super.viewDidLoad() // 按钮1:触发刷新操作 let refreshBtn = UIButton(type: .system) refreshBtn.setTitle("刷新数据", for: .normal) refreshBtn.addTarget(self, action: #selector(refreshBtnTapped), for: .touchUpInside) refreshBtn.frame = CGRect(x: 20, y: 20, width: 200, height: 40) view.addSubview(refreshBtn) // 按钮2:触发展示详情操作 let detailBtn = UIButton(type: .system) detailBtn.setTitle("查看详情", for: .normal) detailBtn.addTarget(self, action: #selector(detailBtnTapped), for: .touchUpInside) detailBtn.frame = CGRect(x: 20, y: 80, width: 200, height: 40) view.addSubview(detailBtn) } @objc private func refreshBtnTapped() { // 构造带操作标识的URL guard let url = URL(string: "myappcustomscheme://action?type=refresh") else { return } // iOS10及以后用open(_:options:completionHandler:)方法 UIApplication.shared.open(url, options: [:], completionHandler: { success in if !success { print("唤起宿主App失败") } }) } @objc private func detailBtnTapped() { guard let url = URL(string: "myappcustomscheme://action?type=showDetail") else { return } UIApplication.shared.open(url, options: [:], completionHandler: nil) } func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) { completionHandler(NCUpdateResult.newData) } }
三、宿主App中处理唤起请求(iOS10适配关键)
你遇到的AppDelegate对应函数未被调用问题,大概率是用了iOS9及以前的旧方法。iOS10及以后,系统会调用新的回调方法,必须在AppDelegate中实现它:
import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // 初始化逻辑 return true } // iOS10及以后的URL唤起回调,必须实现这个! func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool { // 解析URL中的参数,区分不同操作 guard let components = URLComponents(url: url, resolvingAgainstBaseURL: true), let queryItems = components.queryItems else { return false } // 提取操作类型参数 if let typeItem = queryItems.first(where: { $0.name == "type" }), let operationType = typeItem.value { handleOperation(type: operationType) } return true } // 根据操作类型执行对应逻辑 private func handleOperation(type: String) { switch type { case "refresh": // 这里写刷新操作的逻辑,比如通知主页面刷新数据 print("执行刷新操作") NotificationCenter.default.post(name: NSNotification.Name(rawValue: "RefreshMainContent"), object: nil) case "showDetail": // 这里写跳转到详情页的逻辑 print("执行展示详情操作") guard let window = UIApplication.shared.keyWindow, let rootVC = window.rootViewController else { return } let detailVC = DetailViewController() // 替换成你的详情页VC rootVC.present(detailVC, animated: true) default: break } } }
注意:如果你的App支持iOS9及以下,可以同时保留旧方法application(_:open:sourceApplication:annotation:),但iOS10及以上系统会优先调用新方法。
四、常见问题排查
- 检查URL Scheme拼写:确保Widget里调用的URL Scheme和宿主App
Info.plist里配置的完全一致,大小写敏感! - 测试环境:必须在真机或模拟器上安装宿主App,Widget才能唤起它;模拟器测试时,先启动一次宿主App再测试Widget。
- URL格式合法性:如果参数里有特殊字符,需要用
addingPercentEncoding(withAllowedCharacters:)进行编码,避免URL无效。
内容的提问来源于stack exchange,提问作者Screwdriver92
相关产品推荐
相关产品推荐

