// // KMAdvertisementManager.swift // KMAdvertisement // // Created by lizhe on 2022/11/23. // 广告管理 #if os(OSX) import AppKit public typealias UIImage = NSImage public typealias UIView = NSView public typealias UIButton = NSButton public typealias UIScrollView = NSScrollView public typealias UIColor = NSColor public typealias UIFont = NSFont public typealias UITextView = NSTextView public typealias UIImageView = NSImageView public typealias UIEvent = NSEvent public typealias UIBezierPath = NSBezierPath public typealias UITextField = NSTextField public typealias UIEdgeInsets = NSEdgeInsets #elseif os(iOS) import UIKit public typealias NSImage = UIImage public typealias NSView = UIView public typealias NSButton = UIButton public typealias NSScrollView = UIScrollView public typealias NSColor = UIColor public typealias NSFont = UIFont public typealias NSTextView = UITextView public typealias NSImageView = UIImageView public typealias NSEvent = UIEvent public typealias NSBezierPath = UIBezierPath public typealias NSTextField = UILabel public typealias NSEdgeInsets = UIEdgeInsets #endif @objcMembers open class KMAdvertisementManager: NSObject { //单例 @objc public static let manager = KMAdvertisementManager() @objc public var configuration: KMAdvertisementConfig = KMAdvertisementConfig() /** @abstract 测试模式,默认为false */ @objc public var debug: Bool = false /** @abstract 初始化数据 @param appID 产品名称 @param subscribeType 订阅状态,可单独在configuration设置 @param platform 平台 @return */ @objc public func initConfig(appName: KMAdvertisementAppNameType, subscribeType:KMAdvertisementSubscribeType, platform: KMAdvertisementPlatformType) { configuration.initParameters(appName: appName, subscribeType: subscribeType, platform: platform) } } extension KMAdvertisementManager { //MARK: request /** @abstract 获取数据 @param data 传入参数 类型为KMAdvertisementModel @return */ @objc public func fetchData(completion: @escaping (_ data: [KMAdvertisementModel]?, _ error:Error?) -> Void) -> Void { self.fetchDataWithResponseObject { data, responseObject, error in if completion != nil { completion(data, error) } } } @objc public func fetchDataWithResponseObject(completion:@escaping (_ data: [KMAdvertisementModel]?, _ responseObject: AnyObject? , _ error:Error?) -> Void) -> Void { print("开始获取数据") var version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString").debugDescription if (version.count == 0) { version = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion").debugDescription version = version.replacingOccurrences(of: ".", with: "") } let urlString = configuration.activityBaseURL() + "/api/advertise-new" let params: [String:Any] = ["app_name": configuration.appName.string(), "app_version": version] //先拿缓存数据 再请求新数据 let cacheData = KMAdvertisementCache.default.readData() if cacheData.count != 0 { self.parseData(data: cacheData, isNeedLocalComparison: false) { result in if result.count != 0 { completion(result, nil, nil) } } } unowned let weakSelf = self KMAdvertisementRequestServer.requestServer.request(urlString: urlString, method: "GET", params: params) { task, responseObject, error in print("正在获取数据") if (error == nil && responseObject != nil) { let array = responseObject?["list"] ?? [] if array != nil { //解析数据 print("开始解析数据") weakSelf.parseData(data: array as! [NSDictionary], isNeedLocalComparison: true) { data in print("数据处理完毕") if data.count != 0 { completion(data, responseObject, nil) } } } else { print("解析数据失败array") completion(nil, responseObject, error) } } else { print("解析数据失败数据不存在") completion(nil, responseObject, error) } } } } extension KMAdvertisementManager { //MARK: show /** @abstract 显示视图 @param type 显示类型 @param data 显示数据 @param superView 父视图 @return KMAdvertisementModel */ @objc public func show(type: KMAdvertisementShowType, data: KMAdvertisementModel?, superView: NSView?, _ action: KMAdvertisementActionCompletion?) -> NSView { return self.show(type: type, data: data, superView: superView, action, nil) } @objc public func show(type: KMAdvertisementShowType, data: KMAdvertisementModel?, superView: NSView?, _ action: KMAdvertisementActionCompletion?, _ loadCompletion: KMAdvertisementLoadCompletion?) -> NSView { if superView != nil { for item in superView!.subviews { item.removeFromSuperview() } } var view = KMAdvertisementBaseView() #if os(OSX) if data != nil { if type == .list { view = KMAdvertisementTableView.init(data: data!, superView: superView!) } else if type == .view { view = KMAdvertisementShowView.init(data: data!, superView: superView!) } } #else if data != nil { if type == .scroll { view = KMAdvertisementShowScroll_iOS.init(data: data!, superView: superView!) } else if type == .view { view = KMAdvertisementShowView_iOS.init(data: data!, superView: superView!) } } #endif if action == nil { view.actionCompletion = { tap, content in self.transitionAction(item: content) } } else { view.actionCompletion = action } if loadCompletion == nil { } else { view.loadCompletion = loadCompletion } return view } func transitionAction(item: KMAdvertisementModelItem) { if (item.actionType == .URL) { let string = item.linkURL?.en ?? "" #if os(iOS) if UIApplication.shared.canOpenURL(URL(string: string )!) { UIApplication.shared.open(URL(string: string )!, options: [:]) } #elseif os(OSX) if NSWorkspace.shared.open(URL.init(string: string)!) { NSWorkspace.shared.open(URL.init(string: string)!) } #endif print("链接" + string) } else if (item.actionType == .comparative) { print("比较表") } else { print("其他") } } } extension KMAdvertisementManager { //MARK: data /** @abstract 解析数据 @param data 传入参数 NSDictionary @param isNeedLocalComparison 是否需要对比本地版本,如果不一样将会刷新 @return KMAdvertisementModel */ public func parseData(data: [NSDictionary], isNeedLocalComparison: Bool ,completion:(_ result: [KMAdvertisementModel]) -> Void) -> Void { //获取缓存数据 var isNeedSave = false let cacheData = KMAdvertisementCache.default.readData() var resultArray:[KMAdvertisementModel] = [] for model in data { if (!(cacheData.contains(model) && isNeedLocalComparison)) { if (self.allowLoadData(data: model)) { let jsonString: String = (model["detail"] as? String) ?? "" let jsonData: Data = jsonString.data(using: .utf8)! let decoder = JSONDecoder() // decoder.dataDecodingStrategy = .base64 // decoder.keyDecodingStrategy = .convertFromSnakeCase //带下划线命名 decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+∞", negativeInfinity: "-∞", nan: "NaN") #if DEBUG //MARK: 测试使用 var advertisementModel = try! decoder.decode(KMAdvertisementModel.self, from: jsonData) if (self.allowLoadContentData(data: advertisementModel)) { resultArray.append(self.allowLoadItemData(advertisementModel)) isNeedSave = true } #else // MARK: 此处try 使用 ? ,如果数据出问题 advertisementModel将无参数, 测试时使用! var advertisementModel = try? decoder.decode(KMAdvertisementModel.self, from: jsonData) if (advertisementModel != nil) { if (self.allowLoadContentData(data: advertisementModel!)) { resultArray.append(self.allowLoadItemData(advertisementModel!)) isNeedSave = true } } #endif } } } if isNeedSave && isNeedLocalComparison { KMAdvertisementCache.default.saveData(data: data) print("已更新本地数据") } else { print("不需要更新本地数据") } completion(resultArray) } func allowLoadData(data: NSDictionary) -> Bool { var result = false let status = (data["status"] as? Int) ?? 0 let app_name: String = data["app_name"] as? String ?? "" if (status == 1 && app_name == configuration.appName.string()) { result = true } return result } func allowLoadContentData(data: KMAdvertisementModel) -> Bool { var result = false let time: NSInteger = NSInteger(KMAdvertisementTimeStampConversion.getCurrentTimeInterval())! let startTime: NSInteger = NSInteger(data.startTime!)! let endTime: NSInteger = NSInteger(data.endTime!)! let platform = configuration.platform let subscribeType = configuration.subscribeType let version = data.version ?? "1.0" let localVersion = self.getLocalVersion() let hidden = data.hidden ?? false if (time >= startTime && time <= endTime && platform == data.platform && self.compareVersion(nowVersion:localVersion, newVersion: version) && (subscribeType == data.subscribeType || data.subscribeType == .all) && !hidden) { result = true } return result } //过滤item是否显示 func allowLoadItemData(_ data: KMAdvertisementModel) -> KMAdvertisementModel { //获取缓存数据 if (UserDefaults.standard.object(forKey: "KMAdvertisementShowScroll_iOS") == nil) { UserDefaults.standard.set([], forKey: "KMAdvertisementShowScroll_iOS") } let cacheArray: [String] = UserDefaults.standard.object(forKey: "KMAdvertisementShowScroll_iOS") as! [String] let model = data var sections: [KMAdvertisementModelSection] = [] for section in data.content! { var items: [KMAdvertisementModelItem] = [] for item in section.content! { let timeString = KMAdvertisementTimeStampConversion.getCurrentTimeInterval() let time: NSInteger = NSInteger(timeString)! let startTime: NSInteger = NSInteger(item.startTime ?? timeString)! let endTime: NSInteger = NSInteger(item.endTime ?? timeString)! let hidden = item.hidden ?? false // print(hidden ? "隐藏" : "显示") if (!hidden && time >= startTime && time <= endTime && !cacheArray.contains(item.productID ?? "")) { items.append(item) } } section.content = items sections.append(section) } model.content = sections return model } //获取本地版本号 func getLocalVersion() -> String { var localVersion = "" if let v: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String { localVersion = v } return localVersion } func compareVersion(nowVersion: String, newVersion: String) -> Bool { let nowArray = nowVersion.split(separator: ".") let newArray = newVersion.split(separator: ".") let big = nowArray.count > newArray.count ? newArray.count : nowArray.count if big != 0 { for index in 0...big - 1 { let first = nowArray[index] let second = newArray[index] if Int(first)! < Int(second)! { return true } if index == big - 1 { if Int(first)! <= Int(second)! { return true } } } } else { return true } return false } } extension KMAdvertisementManager { // //MARK: image // public func dynamic_sdkBundle_image()-> NSImage? { // // class: 库里 任意class, dynamic bundle 和 mainBundle 不是同一个 // let bundle = Bundle(for: KMAdvertisementManager.self) //// let mainBundle = Bundle.main // let path = bundle.path(forResource: "KMAdvertisement", ofType: "bundle") // if let path = path { // let sdkBundle = Bundle(path: path) // let filePath = sdkBundle?.pathForImageResource("1") // let image = NSImage.init(contentsOfFile: filePath!) //// let image = NSImage(named: "1", in: sdkBundle, compatibleWith: nil) // return image // } // return nil // } // // public func staticSdk_image() -> NSImage? { // // class: 库里 任意class // let bundle = Bundle(for: KMAdvertisementManager.self) // let path = bundle.path(forResource: "KMAdvertisement", ofType: "framework") // if let path = path { // let sdkBundle = Bundle(path: path) // let filePath = sdkBundle?.pathForImageResource("1") // let image = NSImage.init(contentsOfFile: filePath!) // return image // } // return nil // } }