KMAdvertisementManager.swift 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. //
  2. // KMAdvertisementManager.swift
  3. // KMAdvertisement
  4. //
  5. // Created by lizhe on 2022/11/23.
  6. // 广告管理
  7. #if os(OSX)
  8. import AppKit
  9. public typealias UIImage = NSImage
  10. public typealias UIView = NSView
  11. public typealias UIButton = NSButton
  12. public typealias UIScrollView = NSScrollView
  13. public typealias UIColor = NSColor
  14. public typealias UIFont = NSFont
  15. public typealias UITextView = NSTextView
  16. public typealias UIImageView = NSImageView
  17. public typealias UIEvent = NSEvent
  18. public typealias UIBezierPath = NSBezierPath
  19. public typealias UITextField = NSTextField
  20. public typealias UIEdgeInsets = NSEdgeInsets
  21. #elseif os(iOS)
  22. import UIKit
  23. public typealias NSImage = UIImage
  24. public typealias NSView = UIView
  25. public typealias NSButton = UIButton
  26. public typealias NSScrollView = UIScrollView
  27. public typealias NSColor = UIColor
  28. public typealias NSFont = UIFont
  29. public typealias NSTextView = UITextView
  30. public typealias NSImageView = UIImageView
  31. public typealias NSEvent = UIEvent
  32. public typealias NSBezierPath = UIBezierPath
  33. public typealias NSTextField = UILabel
  34. public typealias NSEdgeInsets = UIEdgeInsets
  35. #endif
  36. @objcMembers open class KMAdvertisementManager: NSObject {
  37. //单例
  38. @objc public static let manager = KMAdvertisementManager()
  39. @objc public var configuration: KMAdvertisementConfig = KMAdvertisementConfig()
  40. /**
  41. @abstract 测试模式,默认为false
  42. */
  43. @objc public var debug: Bool = false
  44. /**
  45. @abstract 初始化数据
  46. @param appID 产品名称
  47. @param subscribeType 订阅状态,可单独在configuration设置
  48. @param platform 平台
  49. @return
  50. */
  51. @objc public func initConfig(appName: KMAdvertisementAppNameType,
  52. subscribeType:KMAdvertisementSubscribeType,
  53. platform: KMAdvertisementPlatformType) {
  54. configuration.initParameters(appName: appName, subscribeType: subscribeType, platform: platform)
  55. }
  56. }
  57. extension KMAdvertisementManager {
  58. //MARK: request
  59. /**
  60. @abstract 获取数据
  61. @param data 传入参数 类型为KMAdvertisementModel
  62. @return
  63. */
  64. @objc public func fetchData(completion: @escaping (_ data: [KMAdvertisementModel]?, _ error:Error?) -> Void) -> Void {
  65. self.fetchDataWithResponseObject { data, responseObject, error in
  66. if completion != nil {
  67. completion(data, error)
  68. }
  69. }
  70. }
  71. @objc public func fetchDataWithResponseObject(completion:@escaping (_ data: [KMAdvertisementModel]?, _ responseObject: AnyObject? , _ error:Error?) -> Void) -> Void {
  72. print("开始获取数据")
  73. var version: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString").debugDescription
  74. if (version.count == 0) {
  75. version = Bundle.main.object(forInfoDictionaryKey: "CFBundleVersion").debugDescription
  76. version = version.replacingOccurrences(of: ".", with: "")
  77. }
  78. let urlString = configuration.activityBaseURL() + "/api/advertise-new"
  79. let params: [String:Any] = ["app_name": configuration.appName.string(),
  80. "app_version": version]
  81. //先拿缓存数据 再请求新数据
  82. let cacheData = KMAdvertisementCache.default.readData()
  83. if cacheData.count != 0 {
  84. self.parseData(data: cacheData, isNeedLocalComparison: false) { result in
  85. if result.count != 0 {
  86. completion(result, nil, nil)
  87. }
  88. }
  89. }
  90. unowned let weakSelf = self
  91. KMAdvertisementRequestServer.requestServer.request(urlString: urlString, method: "GET", params: params) { task, responseObject, error in
  92. print("正在获取数据")
  93. if (error == nil && responseObject != nil) {
  94. let array = responseObject?["list"] ?? []
  95. if array != nil {
  96. //解析数据
  97. print("开始解析数据")
  98. weakSelf.parseData(data: array as! [NSDictionary], isNeedLocalComparison: true) { data in
  99. print("数据处理完毕")
  100. if data.count != 0 {
  101. completion(data, responseObject, nil)
  102. }
  103. }
  104. } else {
  105. print("解析数据失败array")
  106. completion(nil, responseObject, error)
  107. }
  108. } else {
  109. print("解析数据失败数据不存在")
  110. completion(nil, responseObject, error)
  111. }
  112. }
  113. }
  114. }
  115. extension KMAdvertisementManager {
  116. //MARK: show
  117. /**
  118. @abstract 显示视图
  119. @param type 显示类型 <KMAdvertisementShowType>
  120. @param data 显示数据 <KMAdvertisementModel>
  121. @param superView 父视图 <NSView>
  122. @return KMAdvertisementModel
  123. */
  124. @objc public func show(type: KMAdvertisementShowType, data: KMAdvertisementModel?, superView: NSView?, _ action: KMAdvertisementActionCompletion?) -> NSView {
  125. return self.show(type: type, data: data, superView: superView, action, nil)
  126. }
  127. @objc public func show(type: KMAdvertisementShowType, data: KMAdvertisementModel?, superView: NSView?, _ action: KMAdvertisementActionCompletion?, _ loadCompletion: KMAdvertisementLoadCompletion?) -> NSView {
  128. if superView != nil {
  129. for item in superView!.subviews {
  130. item.removeFromSuperview()
  131. }
  132. }
  133. var view = KMAdvertisementBaseView()
  134. #if os(OSX)
  135. if data != nil {
  136. if type == .list {
  137. view = KMAdvertisementTableView.init(data: data!, superView: superView!)
  138. } else if type == .view {
  139. view = KMAdvertisementShowView.init(data: data!, superView: superView!)
  140. }
  141. }
  142. #else
  143. if data != nil {
  144. if type == .scroll {
  145. view = KMAdvertisementShowScroll_iOS.init(data: data!, superView: superView!)
  146. } else if type == .view {
  147. view = KMAdvertisementShowView_iOS.init(data: data!, superView: superView!)
  148. }
  149. }
  150. #endif
  151. if action == nil {
  152. view.actionCompletion = { tap, content in
  153. self.transitionAction(item: content)
  154. }
  155. } else {
  156. view.actionCompletion = action
  157. }
  158. if loadCompletion == nil {
  159. } else {
  160. view.loadCompletion = loadCompletion
  161. }
  162. return view
  163. }
  164. func transitionAction(item: KMAdvertisementModelItem) {
  165. if (item.actionType == .URL) {
  166. let string = item.linkURL?.en ?? ""
  167. #if os(iOS)
  168. if UIApplication.shared.canOpenURL(URL(string: string )!) {
  169. UIApplication.shared.open(URL(string: string )!, options: [:])
  170. }
  171. #elseif os(OSX)
  172. if NSWorkspace.shared.open(URL.init(string: string)!) {
  173. NSWorkspace.shared.open(URL.init(string: string)!)
  174. }
  175. #endif
  176. print("链接" + string)
  177. } else if (item.actionType == .comparative) {
  178. print("比较表")
  179. } else {
  180. print("其他")
  181. }
  182. }
  183. }
  184. extension KMAdvertisementManager {
  185. //MARK: data
  186. /**
  187. @abstract 解析数据
  188. @param data 传入参数 NSDictionary
  189. @param isNeedLocalComparison 是否需要对比本地版本,如果不一样将会刷新
  190. @return KMAdvertisementModel
  191. */
  192. public func parseData(data: [NSDictionary], isNeedLocalComparison: Bool ,completion:(_ result: [KMAdvertisementModel]) -> Void) -> Void {
  193. //获取缓存数据
  194. var isNeedSave = false
  195. let cacheData = KMAdvertisementCache.default.readData()
  196. var resultArray:[KMAdvertisementModel] = []
  197. for model in data {
  198. if (!(cacheData.contains(model) && isNeedLocalComparison)) {
  199. if (self.allowLoadData(data: model)) {
  200. let jsonString: String = (model["detail"] as? String) ?? ""
  201. let jsonData: Data = jsonString.data(using: .utf8)!
  202. let decoder = JSONDecoder()
  203. // decoder.dataDecodingStrategy = .base64
  204. // decoder.keyDecodingStrategy = .convertFromSnakeCase //带下划线命名
  205. decoder.nonConformingFloatDecodingStrategy = .convertFromString(positiveInfinity: "+∞", negativeInfinity: "-∞", nan: "NaN")
  206. #if DEBUG
  207. //MARK: 测试使用
  208. var advertisementModel = try! decoder.decode(KMAdvertisementModel.self, from: jsonData)
  209. if (self.allowLoadContentData(data: advertisementModel)) {
  210. resultArray.append(self.allowLoadItemData(advertisementModel))
  211. isNeedSave = true
  212. }
  213. #else
  214. // MARK: 此处try 使用 ? ,如果数据出问题 advertisementModel将无参数, 测试时使用!
  215. var advertisementModel = try? decoder.decode(KMAdvertisementModel.self, from: jsonData)
  216. if (advertisementModel != nil) {
  217. if (self.allowLoadContentData(data: advertisementModel!)) {
  218. resultArray.append(self.allowLoadItemData(advertisementModel!))
  219. isNeedSave = true
  220. }
  221. }
  222. #endif
  223. }
  224. }
  225. }
  226. if isNeedSave && isNeedLocalComparison {
  227. KMAdvertisementCache.default.saveData(data: data)
  228. print("已更新本地数据")
  229. } else {
  230. print("不需要更新本地数据")
  231. }
  232. completion(resultArray)
  233. }
  234. func allowLoadData(data: NSDictionary) -> Bool {
  235. var result = false
  236. let status = (data["status"] as? Int) ?? 0
  237. let app_name: String = data["app_name"] as? String ?? ""
  238. if (status == 1 &&
  239. app_name == configuration.appName.string()) {
  240. result = true
  241. }
  242. return result
  243. }
  244. func allowLoadContentData(data: KMAdvertisementModel) -> Bool {
  245. var result = false
  246. let time: NSInteger = NSInteger(KMAdvertisementTimeStampConversion.getCurrentTimeInterval())!
  247. let startTime: NSInteger = NSInteger(data.startTime!)!
  248. let endTime: NSInteger = NSInteger(data.endTime!)!
  249. let platform = configuration.platform
  250. let subscribeType = configuration.subscribeType
  251. let version = data.version ?? "1.0"
  252. let localVersion = self.getLocalVersion()
  253. let hidden = data.hidden ?? false
  254. if (time >= startTime &&
  255. time <= endTime &&
  256. platform == data.platform &&
  257. self.compareVersion(nowVersion:localVersion, newVersion: version) &&
  258. (subscribeType == data.subscribeType || data.subscribeType == .all) &&
  259. !hidden) {
  260. result = true
  261. }
  262. return result
  263. }
  264. //过滤item是否显示
  265. func allowLoadItemData(_ data: KMAdvertisementModel) -> KMAdvertisementModel {
  266. //获取缓存数据
  267. if (UserDefaults.standard.object(forKey: "KMAdvertisementShowScroll_iOS") == nil) {
  268. UserDefaults.standard.set([], forKey: "KMAdvertisementShowScroll_iOS")
  269. }
  270. let cacheArray: [String] = UserDefaults.standard.object(forKey: "KMAdvertisementShowScroll_iOS") as! [String]
  271. let model = data
  272. var sections: [KMAdvertisementModelSection] = []
  273. for section in data.content! {
  274. var items: [KMAdvertisementModelItem] = []
  275. for item in section.content! {
  276. let timeString = KMAdvertisementTimeStampConversion.getCurrentTimeInterval()
  277. let time: NSInteger = NSInteger(timeString)!
  278. let startTime: NSInteger = NSInteger(item.startTime ?? timeString)!
  279. let endTime: NSInteger = NSInteger(item.endTime ?? timeString)!
  280. let hidden = item.hidden ?? false
  281. // print(hidden ? "隐藏" : "显示")
  282. if (!hidden &&
  283. time >= startTime &&
  284. time <= endTime &&
  285. !cacheArray.contains(item.productID ?? "")) {
  286. items.append(item)
  287. }
  288. }
  289. section.content = items
  290. sections.append(section)
  291. }
  292. model.content = sections
  293. return model
  294. }
  295. //获取本地版本号
  296. func getLocalVersion() -> String {
  297. var localVersion = ""
  298. if let v: String = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String {
  299. localVersion = v
  300. }
  301. return localVersion
  302. }
  303. func compareVersion(nowVersion: String, newVersion: String) -> Bool {
  304. let nowArray = nowVersion.split(separator: ".")
  305. let newArray = newVersion.split(separator: ".")
  306. let big = nowArray.count > newArray.count ? newArray.count : nowArray.count
  307. if big != 0 {
  308. for index in 0...big - 1 {
  309. let first = nowArray[index]
  310. let second = newArray[index]
  311. if Int(first)! < Int(second)! {
  312. return true
  313. }
  314. if index == big - 1 {
  315. if Int(first)! <= Int(second)! {
  316. return true
  317. }
  318. }
  319. }
  320. } else {
  321. return true
  322. }
  323. return false
  324. }
  325. }
  326. extension KMAdvertisementManager {
  327. // //MARK: image
  328. // public func dynamic_sdkBundle_image()-> NSImage? {
  329. // // class: 库里 任意class, dynamic bundle 和 mainBundle 不是同一个
  330. // let bundle = Bundle(for: KMAdvertisementManager.self)
  331. //// let mainBundle = Bundle.main
  332. // let path = bundle.path(forResource: "KMAdvertisement", ofType: "bundle")
  333. // if let path = path {
  334. // let sdkBundle = Bundle(path: path)
  335. // let filePath = sdkBundle?.pathForImageResource("1")
  336. // let image = NSImage.init(contentsOfFile: filePath!)
  337. //// let image = NSImage(named: "1", in: sdkBundle, compatibleWith: nil)
  338. // return image
  339. // }
  340. // return nil
  341. // }
  342. //
  343. // public func staticSdk_image() -> NSImage? {
  344. // // class: 库里 任意class
  345. // let bundle = Bundle(for: KMAdvertisementManager.self)
  346. // let path = bundle.path(forResource: "KMAdvertisement", ofType: "framework")
  347. // if let path = path {
  348. // let sdkBundle = Bundle(path: path)
  349. // let filePath = sdkBundle?.pathForImageResource("1")
  350. // let image = NSImage.init(contentsOfFile: filePath!)
  351. // return image
  352. // }
  353. // return nil
  354. // }
  355. }