// // FlutterMethodChannelManager.swift // Runner // // Created by Destiny on 2025/5/8. // import Flutter import UIKit import StoreKit import AdServices class FlutterMethodChannelManager: NSObject { // 单例模式 static let shared = FlutterMethodChannelManager() // 方法通道 var keyboardChannel: FlutterMethodChannel? var retryCount = 0 // 私有初始化方法 private override init() { super.init() } // 设置方法通道 func setupMethodChannels(controller: FlutterViewController) { // 创建键盘相关的方法通道 keyboardChannel = FlutterMethodChannel( name: "keyboard_ios", binaryMessenger: controller.binaryMessenger) // 设置方法调用处理器 keyboardChannel?.setMethodCallHandler { [weak self] (call, result) in guard let self = self else { return } switch call.method { case "saveSystemKeyboardInfo": if let args = call.arguments as? [String: Any], let info = args["info"] as? String { KeyboardSharedDataManager.shared.saveSystemkeyboard(info) result(true) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } case "saveAuthToken": if let args = call.arguments as? [String: Any], let token = args["token"] as? String { KeyboardSharedDataManager.shared.saveToken(token) result(true) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } case "clearAuthToken": KeyboardSharedDataManager.shared.clearAuthToken() result(true) case "saveIDFV": if let args = call.arguments as? [String: Any], let idfv = args["idfv"] as? String { KeyboardSharedDataManager.shared.saveInitIDFV(idfv) result(true) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } case "saveIDFA": if let args = call.arguments as? [String: Any], let idfa = args["idfa"] as? String { KeyboardSharedDataManager.shared.saveInitIDFA(idfa) result(true) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } case "isKeyboardAdded": let isAdd = self.isKeyboardEnabled() result(isAdd) case "isDefaultKeyboard": let isDefault = self.isCustomKeybroad() result(isDefault) case "openKeyboardGuide": KeyboardSharedDataManager.shared.saveIsShowGuide() result(true) case "isHasDiscount": if let args = call.arguments as? [String: Any], let appleGoodId = args["appleGoodId"] as? String { self.checkProductDiscount(appleGoodId: appleGoodId, completion: { hasDiscount in result(hasDiscount) }) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } case "initAttr": self.initAttribution() case "addASAPayReport": if let args = call.arguments as? [String: Any], let price = args["price"] as? Double { AsaManager.shared.addEventAttribution(eventDict: ["event_name": "pay", "event_val": price]) } else { result(FlutterError(code: "INVALID_ARGUMENTS", message: "无效的参数", details: nil)) } default: result(FlutterMethodNotImplemented) } } } // 是否添加键盘 func isKeyboardEnabled() -> Bool { // 获取系统中已安装的键盘列表 let keyboards = UserDefaults.standard.dictionaryRepresentation() .filter { $0.key.contains("Keyboard") } if let keyboardList = keyboards["AppleKeyboards"] as? [String] { let keyboardBundleId = "com.qihuan.zhuiaijianpan.AiKeyboard" let isAdded = keyboardList.contains(keyboardBundleId) return isAdded } return false } // 是否为默认键盘 func isCustomKeybroad() -> Bool { let currentKeyboardName = (((UITextInputMode.activeInputModes as NSArray).filtered(using: NSPredicate(format: "isDisplayed = YES"))).last as? NSObject)?.value(forKey: "extendedDisplayName") as? String let infoDictionary = Bundle.main.infoDictionary! let appDisplayName = infoDictionary["CFBundleDisplayName"] as? String return currentKeyboardName == appDisplayName } } extension FlutterMethodChannelManager { func initAttribution() { if #available(iOS 14.3, *) { do { let appleAttributionToken = try AAAttribution.attributionToken() // 尝试获取归因信息 getASA(token: appleAttributionToken) } catch let error { print("Error fetching attribution token: \(error.localizedDescription)") } } } // 开始获取归因结果 func getASA(token: String) { guard retryCount < 3 else { return } let configuration = URLSessionConfiguration.default let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: nil) let asaUrl = URL(string: "https://api-adservices.apple.com/api/v1/")! var request = URLRequest(url: asaUrl) request.httpMethod = "POST" request.addValue("application/json", forHTTPHeaderField: "Content-Type") request.httpBody = token.data(using: .utf8) let task = session.dataTask(with: request) { data, response, error in if let error = error { print("sendASAToken error = \(error)") // 5秒后重试 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { self.getASA(token: token) } return } guard let data = data, let payloadDic = try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any] else { print("sendASAToken error payload = nil") // 5秒后重试 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { self.getASA(token: token) } return } print("sendASAToken payload = \(payloadDic)") if let attribution = payloadDic["attribution"] { UserDefaults.standard.set(payloadDic, forKey: "ASA_ATTRIBUTION_PAYLOAD") UserDefaults.standard.synchronize() // 调用奇异果数据上报接口 let appSaManager = AsaManager.shared appSaManager.addAttributionReport { isSuccess in print("asaReportWithCompletion = ", isSuccess) if isSuccess { let isRegister = UserDefaults.standard.bool(forKey: "isRegisterKey") if !isRegister { AsaManager.shared.addEventAttribution(eventDict: ["event_name": "active", "event_val": 1]) AsaManager.shared.addEventAttribution(eventDict: ["event_name": "register", "event_val": 1]) UserDefaults.standard.setValue(true, forKey: "isRegisterKey") } } } } } task.resume() retryCount += 1 } } extension FlutterMethodChannelManager { private func checkProductDiscount(appleGoodId: String, completion: @escaping (Bool) -> Void) { if #available(iOS 15.0, *) { Task { do { // print("开始请求产品信息 (StoreKit 2)") let products = try await Product.products(for: [appleGoodId]) print("成功获取产品信息: \(products.count) 个产品") if let product = products.first { // 检查是否有优惠 var hasDiscount = await product.subscription?.isEligibleForIntroOffer ?? false DispatchQueue.main.async { completion(hasDiscount) } } else { print("未找到产品") DispatchQueue.main.async { completion(false) } } } catch { print("获取产品失败 (StoreKit 2): \(error)") DispatchQueue.main.async { completion(false) } } } } // // 使用StoreKit查询商品信息 // let request = SKProductsRequest(productIdentifiers: [appleGoodId]) // request.delegate = ProductRequestDelegate(completion: { product in // if let product = product { // // iOS 12.2及以上版本支持促销优惠 // if #available(iOS 12.2, *) { // // 检查商品是否有促销优惠 // let hasDiscount = product.discounts.count > 0 // completion(hasDiscount) // } else { // completion(false) // } // } else { // completion(false) // } // }) // request.start() } } // 处理StoreKit产品请求的代理 class ProductRequestDelegate: NSObject, SKProductsRequestDelegate { private let completion: (SKProduct?) -> Void init(completion: @escaping (SKProduct?) -> Void) { self.completion = completion super.init() } func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { if let product = response.products.first { completion(product) } else { completion(nil) } } func request(_ request: SKRequest, didFailWithError error: Error) { print("商品请求失败: \(error.localizedDescription)") completion(nil) } }