You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

iOS10:Today Extension打开宿主App时AppDelegate未触发及多操作需求

iOS 10下Today Extension打开宿主App并执行不同操作的解决方案

刚好之前处理过iOS10下Today Extension(Widget)和宿主App交互的问题,给你整理一套完整的解决方案,一步步来解决你的问题:

一、先给宿主App配置自定义URL Scheme

这是Widget能唤起宿主App的基础,必须配置正确:

  1. 打开宿主App的Info.plist文件
  2. 添加URL types数组项,在数组里新增一个字典
  3. 给字典添加URL scheme字段,设置一个唯一的标识(比如myappcustomscheme,别和其他App重复)
  4. 可选:添加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和宿主AppInfo.plist里配置的完全一致,大小写敏感!
  • 测试环境:必须在真机或模拟器上安装宿主App,Widget才能唤起它;模拟器测试时,先启动一次宿主App再测试Widget。
  • URL格式合法性:如果参数里有特殊字符,需要用addingPercentEncoding(withAllowedCharacters:)进行编码,避免URL无效。

内容的提问来源于stack exchange,提问作者Screwdriver92

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:45:20