KMAdsWebView.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. import Cocoa
  2. import WebKit
  3. protocol AdsWebViewDelegate: AnyObject {
  4. func kmAdViewClicked(_ adView: KMAdsWebView)
  5. func kmAdViewClose(_ adView: KMAdsWebView)
  6. }
  7. enum KMADViewDirections: Int {
  8. case up
  9. case down
  10. }
  11. // Banner Ads Width,Height
  12. let kAD_View_Width = 728.0
  13. let kAD_View_Height = 90.0
  14. // Banner Ads refresh rate in second, 新广告会自动刷新,所以时间延长
  15. let kAD_Refresh_Rate = 6000.0
  16. class KMAdsWebView: NSView, WKNavigationDelegate, CAAnimationDelegate {
  17. weak var adDelegate: AdsWebViewDelegate?
  18. private var closeButton: NSButton!
  19. var clickButton: NSButton!
  20. private var timer: Timer?
  21. private var currentPage: Int = 0
  22. private var completionHandler: ((Int) -> Void)?
  23. var adsImageView: NSImageView!
  24. var adsInfo: KMAdsInfo!
  25. var adPosY: CGFloat = 30.0
  26. override init(frame frameRect: NSRect) {
  27. super.init(frame: frameRect)
  28. wantsLayer = true
  29. self.frame = NSRect(x: 0, y: 0, width: kAD_View_Width, height: kAD_View_Height)
  30. autoresizingMask = [.minXMargin, .maxXMargin]
  31. adsImageView = NSImageView.init(frame: self.bounds)
  32. adsImageView.autoresizingMask = [.width, .height]
  33. adsImageView.imageScaling = .scaleAxesIndependently
  34. addSubview(adsImageView)
  35. adPosY = 30.0
  36. clickButton = NSButton.init(frame: self.bounds)
  37. clickButton.isHidden = false
  38. clickButton.autoresizingMask = [.width, .height]
  39. clickButton.isBordered = false
  40. clickButton.title = ""
  41. clickButton.target = self
  42. clickButton.action = #selector(buttonItemClicked(_:))
  43. addSubview(clickButton)
  44. closeButton = NSButton.init(frame: NSRect(x: frameRect.size.width - 30, y: frameRect.size.height - 30, width: 30, height: 30))
  45. closeButton.isHidden = false
  46. closeButton.imagePosition = .imageOnly
  47. closeButton.imageScaling = .scaleProportionallyUpOrDown
  48. closeButton.autoresizingMask = [.maxXMargin, .minYMargin]
  49. closeButton.image = NSImage(named: "ad_cancel_button00")
  50. closeButton.isBordered = false
  51. closeButton.target = self
  52. closeButton.action = #selector(buttonItemClicked_Close(_:))
  53. addSubview(closeButton)
  54. NotificationCenter.default.addObserver(self, selector: #selector(handleUserHaveClickRateUsNotification(_:)), name: NSNotification.Name("kUserHaveClickRateUsNotification"), object: nil)
  55. NotificationCenter.default.addObserver(self, selector: #selector(adsWebView_Switch), name: NSNotification.Name("KMFirebaseRemateConfigRequestIsSuccessful"), object: nil)
  56. NotificationCenter.default.addObserver(self, selector: #selector(recommondInfoUpdateNoti), name: NSNotification.Name("KMRecommondInfoUpdateNoti"), object: nil)
  57. }
  58. required init?(coder: NSCoder) {
  59. fatalError("init(coder:) has not been implemented")
  60. }
  61. deinit {
  62. adDelegate = nil
  63. timer?.invalidate()
  64. timer = nil
  65. completionHandler = nil
  66. NotificationCenter.default.removeObserver(self)
  67. }
  68. var adsData: [String] {
  69. get {
  70. var data: [String] = []
  71. #if VERSION_DMG
  72. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  73. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_DMG_HouseAD_728x90"]
  74. } else {
  75. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_DMG_728x90"]
  76. }
  77. #else
  78. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  79. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_Store_HouseAD_728x90"]
  80. } else {
  81. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_Store_728x90"]
  82. }
  83. #endif
  84. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  85. data = [KMKdanRemoteConfig.remoteConfig.displayHouseAdsUrl()]
  86. } else {
  87. data = [KMKdanRemoteConfig.remoteConfig.displayAdsUrl()]
  88. }
  89. #if DEBUG
  90. #if VERSION_DMG
  91. data = ["http://test-pdf-pro.kdan.cn:3021/native?s=PDFReaderPro_Mac_DMG_HouseAD_728x90&testflag=on"]
  92. #else
  93. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_Store_728x90"]
  94. #endif
  95. #endif
  96. return data
  97. }
  98. set {
  99. }
  100. }
  101. func restoreDefaultAdPosY() {
  102. adPosY = 30.0
  103. }
  104. func sortAdsData() {
  105. return
  106. let tLength = self.adsData.count
  107. for _ in 0..<24 {
  108. let tIndex0 = Int(arc4random()) % tLength
  109. var tIndex1 = Int(arc4random()) % tLength
  110. if tIndex0 == tIndex1 {
  111. tIndex1 = (tIndex1 + 1) % tLength
  112. }
  113. self.adsData.swapAt(tIndex0, tIndex1)
  114. }
  115. }
  116. func startAdsDataRequest() {
  117. if adsData.count > 0 {
  118. KMAdsManager.defaultManager.refreshLoadingDate()
  119. }
  120. }
  121. func reloadData() {
  122. DispatchQueue.main.async {
  123. self.adsImageView.image = self.adsInfo?.adsImage
  124. }
  125. }
  126. func stopLoading() {
  127. if timer != nil {
  128. timer?.invalidate()
  129. timer = nil
  130. }
  131. }
  132. func resizeWithOldSuperviewSize(oldSize: NSSize) {
  133. var width = kAD_View_Width
  134. var height = kAD_View_Height
  135. if superview?.frame.size.width ?? 0 < width {
  136. let newWidth = (superview?.frame.size.width ?? 0) - 20
  137. height = height / width * newWidth
  138. width = newWidth
  139. }
  140. self.frame = NSRect(x: (superview?.frame.size.width ?? 0 - width) / 2.0, y: frame.origin.y, width: width, height: height)
  141. }
  142. func beginSheetModalForView(view: NSView, directions: KMADViewDirections, animated: Bool, completionHandler handler: ((Int) -> Void)?) {
  143. self.completionHandler = handler
  144. if adPosY < 0 {
  145. restoreDefaultAdPosY()
  146. }
  147. let tWidth = frame.size.width
  148. let tHeight = frame.size.height
  149. view.addSubview(self)
  150. if animated {
  151. switch directions {
  152. case .up:
  153. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: view.frame.size.height, width: tWidth, height: tHeight)
  154. animator().frame = NSRect(x: frame.origin.x, y: view.frame.size.height - tHeight - adPosY, width: tWidth, height: tHeight)
  155. case .down:
  156. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: -tHeight, width: tWidth, height: tHeight)
  157. animator().frame = NSRect(x: frame.origin.x, y: adPosY, width: tWidth, height: tHeight)
  158. default:
  159. frame = NSRect(x: 0, y: 0, width: tWidth, height: tHeight)
  160. }
  161. } else {
  162. switch directions {
  163. case .up:
  164. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: view.frame.size.height - tHeight - adPosY, width: tWidth, height: tHeight)
  165. case .down:
  166. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: adPosY, width: tWidth, height: tHeight)
  167. default:
  168. frame = NSRect(x: 0, y: 0, width: tWidth, height: tHeight)
  169. }
  170. }
  171. adsImageView.frame = bounds
  172. closeButton.frame = NSRect(x: self.bounds.size.width - 30, y: self.bounds.size.height - 30, width: 30, height: 30)
  173. currentPage = 0
  174. startAdsDataRequest()
  175. if timer != nil {
  176. timer?.invalidate()
  177. timer = nil
  178. }
  179. var interval = 0
  180. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  181. interval = KMKdanRemoteConfig.remoteConfig.refreshAdsDate()
  182. } else {
  183. interval = KMKdanRemoteConfig.remoteConfig.refreshAdsDateEvaluateAfter()
  184. }
  185. timer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(adsWebView_Switch), userInfo: nil, repeats: true
  186. )
  187. RunLoop.current.add(timer!, forMode: .common)
  188. }
  189. @objc func adsWebView_Switch() {
  190. DispatchQueue.main.async {
  191. if !KMKdanRemoteConfig.remoteConfig.isDisplayAds() || !KMAdsManager.defaultManager.checkTheDate() || !KMAdsManager.defaultManager.isValidLastShowAds() {
  192. self.removeFromSuperview()
  193. return
  194. }
  195. let transition = CATransition()
  196. transition.type = .moveIn
  197. let tRandomData = arc4random() % 100
  198. if tRandomData > 50 {
  199. transition.subtype = .fromBottom
  200. } else {
  201. transition.subtype = .fromTop
  202. }
  203. transition.duration = 0.6
  204. transition.delegate = self
  205. self.layer?.add(transition, forKey: "KMTransitionAnimation")
  206. self.currentPage += 1
  207. if self.currentPage >= self.adsData.count {
  208. self.currentPage = 0
  209. }
  210. let url = URL(string: self.adsData[self.currentPage])
  211. KMAdsManager.defaultManager.refreshLoadingDate()
  212. }
  213. }
  214. @objc func recommondInfoUpdateNoti() {
  215. DispatchQueue.main.async {
  216. self.reloadData()
  217. }
  218. }
  219. @objc func buttonItemClicked_Open(_ sender: Any) {
  220. guard let newURL = (sender as? NSURL) else {
  221. return
  222. }
  223. NSWorkspace.shared.open(newURL as URL)
  224. adDelegate?.kmAdViewClicked(self)
  225. if let completionHandler = self.completionHandler {
  226. completionHandler(currentPage + 1)
  227. }
  228. removeFromSuperview()
  229. }
  230. @objc func buttonItemClicked(_ sender: Any) {
  231. guard let string = self.adsInfo?.adsURLLink else {
  232. return
  233. }
  234. guard let type = self.adsInfo?.jumpType else {
  235. return
  236. }
  237. if type == .ComparisonSheet {
  238. KMProductCompareWC.shared.orientation = false
  239. KMProductCompareWC.shared.showWindow(nil)
  240. } else {
  241. let newURL = NSURL(string: string)
  242. NSWorkspace.shared.open(newURL! as URL)
  243. }
  244. if let completionHandler = self.completionHandler {
  245. completionHandler(currentPage + 1)
  246. }
  247. adDelegate?.kmAdViewClicked(self)
  248. guard let dict = self.adsInfo.infoDict else {
  249. return
  250. }
  251. guard let firebase = dict["firebase"] as? NSDictionary else {
  252. return
  253. }
  254. guard let firebaseEvent = firebase["event"] as? String else {
  255. return
  256. }
  257. guard let firebasepropertyKey = firebase["propertyKey"] as? String else {
  258. return
  259. }
  260. guard let firebasepropertyValue = firebase["propertyValue"] as? String else {
  261. return
  262. }
  263. FMTrackEventManager.defaultManager.trackEvent(event: firebaseEvent, withProperties: [firebasepropertyValue : firebasepropertyValue])
  264. }
  265. @objc func buttonItemClicked_Close(_ sender: Any) {
  266. adDelegate?.kmAdViewClose(self)
  267. if let completionHandler = self.completionHandler {
  268. completionHandler(0)
  269. }
  270. removeFromSuperview()
  271. }
  272. func animationDidStart(_ anim: CAAnimation) {
  273. if timer != nil {
  274. timer?.invalidate()
  275. }
  276. }
  277. func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
  278. if !flag {
  279. return
  280. }
  281. if timer != nil {
  282. timer?.invalidate()
  283. }
  284. var interval = 0
  285. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  286. interval = KMKdanRemoteConfig.remoteConfig.refreshAdsDate()
  287. } else {
  288. interval = KMKdanRemoteConfig.remoteConfig.refreshAdsDateEvaluateAfter()
  289. }
  290. timer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(adsWebView_Switch), userInfo: nil, repeats: true)
  291. RunLoop.current.add(timer!, forMode: .common)
  292. closeButton.alphaValue = 1.0
  293. adsImageView.frame = bounds
  294. }
  295. // MARK: - WKNavigationDelegate
  296. @objc func handleUserHaveClickRateUsNotification(_ notification: Notification) {
  297. adsWebView_Switch()
  298. }
  299. }