AppDelegate.swift 5.66 KB
//
//  AppDelegate.swift
//  Runner
//
//  Created by 权海 on 2026/6/11.
//

import Foundation
import UIKit
import Flutter
import UserNotifications
import AppTrackingTransparency
import AdSupport

typealias FlutterBridgeMethod = ((_ params: Any?, _ result: FlutterResult) -> Void)


@Observable
class AppDelegate: NSObject, UIApplicationDelegate {
    
    /// UIApplicationDelegate 要求声明 window,
    /// image_cropper 等插件会通过 UIApplication.shared.delegate?.window 查找 keyWindow,
    /// 缺少此属性会导致 "unrecognized selector" 崩溃。
    var window: UIWindow?
    
    private(set) var enginInitError: String?
    
    enum FlutterBridgeMethodName: String{
        case verifyPayment
    }
    private var methods: [String: FlutterBridgeMethod] = [:]
    
    var flutterEngine: FlutterEngine?
    var channel: FlutterMethodChannel?
    private var isFlutterEngineReady = false

    func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        AppShared.shared.agent.genUA()
        AppShared.shared.payment.delegate = self
        _ = AppShared.shared.payment.listenForTransactions()
        
        UIApplication.shared.registerForRemoteNotifications()
        UNUserNotificationCenter.current().setBadgeCount(0)
        UNUserNotificationCenter.current().delegate = self
        requestIDFAAuthorization()

        WatchConnectivityService.shared.activate()
        HealthKitService.shared.startBackgroundObserversIfNeeded()
        return true
    }
    
    func warmUpFlutterEngineIfNeeded() {
        guard !isFlutterEngineReady else {
            enginInitError = nil
            return
        }
        flutterEngine = FlutterEngine(name: "main_flutter_engine")
        guard let flutterEngine else{
            enginInitError = "engin 初始化失败"
            return
        }
        isFlutterEngineReady = true
        flutterEngine.run()
        GeneratedPluginRegistrant.register(with: flutterEngine)
        NativePigeonRegistrar.register(binaryMessenger: flutterEngine.binaryMessenger)
        channel = FlutterMethodChannel(name: "doublefeel_flutter_main_channel", binaryMessenger: flutterEngine.binaryMessenger)
        methods = defaultMethods()
        
        enginInitError = nil
    }
    
    func application(_ application: UIApplication,
                     didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        let tokenParts = deviceToken.map { data in String(format: "%02.2hhx", data) }
        let token = tokenParts.joined()

        print("✅ Device Token: \(token)")
    }

    func application(_ application: UIApplication,
                     didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print("❌ Failed to register: \(error.localizedDescription)")
    }
}

extension AppDelegate{
    private func defaultMethods() -> [String: FlutterBridgeMethod]{
        var methods: [String: FlutterBridgeMethod] = [:]
        methods[FlutterBridgeMethodName.verifyPayment.rawValue] = { params, result in
            result(params)
        }
        
        return methods
    }
    
    func invoke(method: FlutterBridgeMethodName, arguments: Any?, result: @escaping FlutterResult){
        channel?.invokeMethod(method.rawValue, arguments: arguments, result: result)
    }
}

extension AppDelegate: UNUserNotificationCenterDelegate{
    func userNotificationCenter(_ center: UNUserNotificationCenter,
                                willPresent notification: UNNotification,
                                withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler([.banner, .sound, .badge])
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
        let userInfo = response.notification.request.content.userInfo
        
        // 从通知中获取 URL
        if let payload = userInfo["payload"] as? String,
           let data = payload.data(using: .utf8),
           let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
           let urlString = dict["url"] as? String,
           let url = URL(string: urlString) {
            
            // 通过 openURL 触发 onOpenURL 回调
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                if UIApplication.shared.canOpenURL(url) {
                    UIApplication.shared.open(url)
                }
            }
        }
        completionHandler()
    }
}

extension AppDelegate {
    private func requestIDFAAuthorization() {
        if ATTrackingManager.trackingAuthorizationStatus == .notDetermined {
            DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
                ATTrackingManager.requestTrackingAuthorization { status in
                    switch status {
                    case .authorized:
                        let idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
                        print("✅ IDFA: \(idfa)")
                    case .denied:
                        print("❌ 用户拒绝了IDFA授权")
                    case .restricted:
                        print("⚠️ IDFA受限制,无法获取")
                    case .notDetermined:
                        print("⏳ 用户尚未做出选择")
                    @unknown default:
                        print("未知的IDFA授权状态")
                    }
//                    ReyunUtil.initSDK()
                }
            }
        } else {
//            ReyunUtil.initSDK()
        }
    }
}