SwiftUI之AppDelegate

在 SwiftUI 中,传统的 AppDelegate 已被简化的生命周期模型替代,但如果你需要访问应用级事件(如推送通知、生命周期回调等),可以通过以下方式集成 AppDelegate


1. SwiftUI 中启用 AppDelegate 的步骤

a. 创建自定义 AppDelegate

import UIKit

class CustomAppDelegate: NSObject, UIApplicationDelegate {
    // 实现需要的 AppDelegate 方法
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print("App 启动完成")
        return true
    }
    
    // 示例:处理推送通知注册
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        print("设备 Token: \(deviceToken)")
    }
}

b. 在 SwiftUI App 中注入 AppDelegate

import SwiftUI

@main
struct MyApp: App {
    // 通过 @UIApplicationDelegateAdaptor 注入 AppDelegate
    @UIApplicationDelegateAdaptor(CustomAppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

2. 关键点解析

a. @UIApplicationDelegateAdaptor

  • 作用:将 UIKit 的 UIApplicationDelegate 桥接到 SwiftUI 应用生命周期。
  • 限制:一个应用只能有一个 AppDelegate

b. NSObject 和协议继承

  • CustomAppDelegate 必须继承 NSObject(UIKit 要求)。
  • 实现 UIApplicationDelegate 协议中的方法。

3. 常见使用场景

a. 处理应用生命周期事件

// 应用进入后台
func applicationDidEnterBackground(_ application: UIApplication) {
    print("应用进入后台")
}

// 应用即将终止
func applicationWillTerminate(_ application: UIApplication) {
    print("应用即将终止")
}

b. 配置第三方服务

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
    // 初始化 Firebase
    FirebaseApp.configure()
    
    // 配置推送通知
    UNUserNotificationCenter.current().delegate = self
    return true
}

c. 处理深层链接 (URL Schemes)

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    print("接收到 URL: \(url.absoluteString)")
    return true
}

4. 混合生命周期注意事项

a. 与 SwiftUI 生命周期的共存

  • SwiftUI 的 ScenePhase 可以监听应用状态,但与 AppDelegate 不冲突:
    @Environment(\.scenePhase) var scenePhase
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .onChange(of: scenePhase) { newPhase in
            if newPhase == .background {
                print("SwiftUI 检测到进入后台")
            }
        }
    }
    

b. Info.plist 配置

  • 如果遇到 AppDelegate 未被调用,检查 Info.plist 是否包含 Principal class
    <key>NSPrincipalClass</key>
    <string>$(PRODUCT_MODULE_NAME).CustomAppDelegate</string>
    

5. 完整代码示例

CustomAppDelegate.swift

import UIKit
import UserNotifications

class CustomAppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        // 请求推送通知权限
        UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, _ in
            if granted {
                DispatchQueue.main.async {
                    application.registerForRemoteNotifications()
                }
            }
        }
        return true
    }

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
        print("设备 Token: \(token)")
    }
}

MyApp.swift

import SwiftUI

@main
struct MyApp: App {
    @UIApplicationDelegateAdaptor(CustomAppDelegate.self) var appDelegate
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

6. 迁移旧项目到 SwiftUI

若从 UIKit 迁移到 SwiftUI 并保留 AppDelegate

  1. 保留原有的 AppDelegate 类。
  2. 在 SwiftUI 入口文件中通过 @UIApplicationDelegateAdaptor 注入。
  3. 移除 AppDelegate 中与 SwiftUI 冲突的逻辑(如 window 管理)。

总结

在 SwiftUI 中集成 AppDelegate 的关键是通过 @UIApplicationDelegateAdaptor 桥接 UIKit 的生命周期,适用于需要处理系统级事件或兼容旧代码的场景。确保遵循 UIKit 的协议要求,并在 Info.plist 中正确配置,即可无缝混合使用 SwiftUI 和传统 AppDelegate 功能。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容