KMAdsWebView.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. private var timer: Timer?
  20. private var currentPage: Int = 0
  21. private var completionHandler: ((Int) -> Void)?
  22. private var adsWebView: WKWebView
  23. var adPosY: CGFloat = 30.0
  24. override init(frame frameRect: NSRect) {
  25. closeButton = NSButton(frame: NSRect(x: frameRect.size.width - 30, y: frameRect.size.height - 30, width: 30, height: 30))
  26. adsWebView = WKWebView(frame: frameRect)
  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. adsWebView.navigationDelegate = self
  32. adsWebView.autoresizingMask = [.width, .height]
  33. addSubview(adsWebView)
  34. adPosY = 30.0
  35. closeButton.isHidden = false
  36. closeButton.imagePosition = .imageOnly
  37. // closeButton.cell?.highlightsBy = .contentsCellMask
  38. closeButton.imageScaling = .scaleProportionallyUpOrDown
  39. closeButton.image = NSImage(named: "ad_cancel_button00")
  40. closeButton.isBordered = false
  41. closeButton.target = self
  42. closeButton.action = #selector(buttonItemClicked_Close(_:))
  43. addSubview(closeButton)
  44. NotificationCenter.default.addObserver(self, selector: #selector(handleUserHaveClickRateUsNotification(_:)), name: NSNotification.Name("kUserHaveClickRateUsNotification"), object: nil)
  45. NotificationCenter.default.addObserver(self, selector: #selector(adsWebView_Switch), name: NSNotification.Name("KMFirebaseRemateConfigRequestIsSuccessful"), object: nil)
  46. }
  47. required init?(coder: NSCoder) {
  48. fatalError("init(coder:) has not been implemented")
  49. }
  50. deinit {
  51. adDelegate = nil
  52. adsWebView.navigationDelegate = nil
  53. adsWebView.stopLoading()
  54. timer?.invalidate()
  55. timer = nil
  56. completionHandler = nil
  57. NotificationCenter.default.removeObserver(self)
  58. }
  59. var adsData: [String] {
  60. get {
  61. var data: [String] = []
  62. #if VERSION_DMG
  63. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  64. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_DMG_HouseAD_728x90"]
  65. } else {
  66. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_DMG_728x90"]
  67. }
  68. #else
  69. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  70. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_Store_HouseAD_728x90"]
  71. } else {
  72. data = ["https://test.sitemaji.com/native/pdfreaderpro.html?s=PDFReaderPro_Mac_Store_728x90"]
  73. }
  74. #endif
  75. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  76. data = [KMKdanRemoteConfig.remoteConfig().displayHouseAdsUrl()]
  77. } else {
  78. data = [KMKdanRemoteConfig.remoteConfig().displayAdsUrl()]
  79. }
  80. #if DEBUG
  81. #if VERSION_DMG
  82. data = ["http://test-pdf-pro.kdan.cn:3021/native?s=PDFReaderPro_Mac_DMG_HouseAD_728x90&testflag=on"]
  83. #else
  84. data = ["http://test-pdf-pro.kdan.cn:3021/native?s=PDFReaderPro_Mac_Store_HouseAD_728x90&testflag=on"]
  85. #endif
  86. #endif
  87. return data
  88. }
  89. set {
  90. }
  91. }
  92. func restoreDefaultAdPosY() {
  93. adPosY = 30.0
  94. }
  95. func sortAdsData() {
  96. return
  97. let tLength = self.adsData.count
  98. for _ in 0..<24 {
  99. let tIndex0 = Int(arc4random()) % tLength
  100. var tIndex1 = Int(arc4random()) % tLength
  101. if tIndex0 == tIndex1 {
  102. tIndex1 = (tIndex1 + 1) % tLength
  103. }
  104. self.adsData.swapAt(tIndex0, tIndex1)
  105. }
  106. }
  107. func startAdsDataRequest() {
  108. adsWebView.navigationDelegate = self
  109. if adsData.count > 0 {
  110. let url = URL(string: adsData[currentPage])
  111. adsWebView.load(URLRequest(url: url!))
  112. KMAdsManager.defaultManager.refreshLoadingDate()
  113. }
  114. }
  115. func stopLoading() {
  116. adsWebView.navigationDelegate = nil
  117. adsWebView.stopLoading()
  118. }
  119. func resizeWithOldSuperviewSize(oldSize: NSSize) {
  120. var width = kAD_View_Width
  121. var height = kAD_View_Height
  122. if superview?.frame.size.width ?? 0 < width {
  123. let newWidth = (superview?.frame.size.width ?? 0) - 20
  124. height = height / width * newWidth
  125. width = newWidth
  126. }
  127. self.frame = NSRect(x: (superview?.frame.size.width ?? 0 - width) / 2.0, y: frame.origin.y, width: width, height: height)
  128. adsWebView.frame = bounds
  129. }
  130. func beginSheetModalForView(view: NSView, directions: KMADViewDirections, animated: Bool, completionHandler handler: ((Int) -> Void)?) {
  131. self.completionHandler = handler
  132. if adPosY < 0 {
  133. restoreDefaultAdPosY()
  134. }
  135. let tWidth = frame.size.width
  136. let tHeight = frame.size.height
  137. view.addSubview(self)
  138. if animated {
  139. switch directions {
  140. case .up:
  141. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: view.frame.size.height, width: tWidth, height: tHeight)
  142. animator().frame = NSRect(x: frame.origin.x, y: view.frame.size.height - tHeight - adPosY, width: tWidth, height: tHeight)
  143. case .down:
  144. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: -tHeight, width: tWidth, height: tHeight)
  145. animator().frame = NSRect(x: frame.origin.x, y: adPosY, width: tWidth, height: tHeight)
  146. default:
  147. frame = NSRect(x: 0, y: 0, width: tWidth, height: tHeight)
  148. }
  149. } else {
  150. switch directions {
  151. case .up:
  152. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: view.frame.size.height - tHeight - adPosY, width: tWidth, height: tHeight)
  153. case .down:
  154. frame = NSRect(x: (view.frame.size.width - tWidth) / 2.0, y: adPosY, width: tWidth, height: tHeight)
  155. default:
  156. frame = NSRect(x: 0, y: 0, width: tWidth, height: tHeight)
  157. }
  158. }
  159. adsWebView.frame = bounds
  160. currentPage = 0
  161. startAdsDataRequest()
  162. if timer != nil {
  163. timer?.invalidate()
  164. timer = nil
  165. }
  166. var interval = 0
  167. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  168. interval = KMKdanRemoteConfig.remoteConfig().refreshAdsDate()
  169. } else {
  170. interval = KMKdanRemoteConfig.remoteConfig().refreshAdsDateEvaluateAfter()
  171. }
  172. timer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(adsWebView_Switch), userInfo: nil, repeats: true
  173. )
  174. RunLoop.current.add(timer!, forMode: .common)
  175. }
  176. @objc func adsWebView_Switch() {
  177. DispatchQueue.main.async {
  178. if !KMKdanRemoteConfig.remoteConfig().isDisplayAds() || !KMAdsManager.defaultManager.checkTheDate() || !KMAdsManager.defaultManager.isValidLastShowAds() {
  179. self.removeFromSuperview()
  180. return
  181. }
  182. let transition = CATransition()
  183. transition.type = .moveIn
  184. let tRandomData = arc4random() % 100
  185. if tRandomData > 50 {
  186. transition.subtype = .fromBottom
  187. } else {
  188. transition.subtype = .fromTop
  189. }
  190. transition.duration = 0.6
  191. transition.delegate = self
  192. self.layer?.add(transition, forKey: "KMTransitionAnimation")
  193. self.currentPage += 1
  194. if self.currentPage >= self.adsData.count {
  195. self.currentPage = 0
  196. }
  197. let url = URL(string: self.adsData[self.currentPage])
  198. self.adsWebView.load(URLRequest(url: url!))
  199. KMAdsManager.defaultManager.refreshLoadingDate()
  200. }
  201. }
  202. @objc func buttonItemClicked_Open(_ sender: Any) {
  203. guard let newURL = (sender as? NSURL) else {
  204. return
  205. }
  206. NSWorkspace.shared.open(newURL as URL)
  207. adDelegate?.kmAdViewClicked(self)
  208. if let completionHandler = self.completionHandler {
  209. completionHandler(currentPage + 1)
  210. self.completionHandler = nil
  211. }
  212. removeFromSuperview()
  213. }
  214. @objc func buttonItemClicked_Close(_ sender: Any) {
  215. adDelegate?.kmAdViewClose(self)
  216. if let completionHandler = self.completionHandler {
  217. completionHandler(0)
  218. self.completionHandler = nil
  219. }
  220. removeFromSuperview()
  221. }
  222. func animationDidStart(_ anim: CAAnimation) {
  223. if timer != nil {
  224. timer?.invalidate()
  225. }
  226. closeButton.alphaValue = 0
  227. }
  228. func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
  229. if !flag {
  230. return
  231. }
  232. if timer != nil {
  233. timer?.invalidate()
  234. }
  235. var interval = 0
  236. if !UserDefaults.standard.bool(forKey: "kUserHaveClickRateUsKey") {
  237. interval = KMKdanRemoteConfig.remoteConfig().refreshAdsDate()
  238. } else {
  239. interval = KMKdanRemoteConfig.remoteConfig().refreshAdsDateEvaluateAfter()
  240. }
  241. timer = Timer.scheduledTimer(timeInterval: TimeInterval(interval), target: self, selector: #selector(adsWebView_Switch), userInfo: nil, repeats: true)
  242. RunLoop.current.add(timer!, forMode: .common)
  243. closeButton.alphaValue = 1.0
  244. adsWebView.frame = bounds
  245. }
  246. // MARK: - WKNavigationDelegate
  247. func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
  248. if navigationAction.navigationType == .linkActivated {
  249. let tURL = navigationAction.request.url
  250. if tURL != nil {
  251. buttonItemClicked_Open(tURL as Any)
  252. decisionHandler(.cancel)
  253. return
  254. }
  255. }
  256. decisionHandler(.allow)
  257. }
  258. func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
  259. webView.evaluateJavaScript("document.body.scrollHeight") { [weak self] (result, error) in
  260. if let height = result as? CGFloat, height > 0 {
  261. let newHeight = min(height, kAD_View_Height)
  262. self?.adsWebView.frame = NSRect(x: 0, y: 0, width: (self?.adsWebView.frame.size.width)!, height: newHeight)
  263. self?.frame.size.height = newHeight
  264. self?.closeButton.frame = NSRect(x: (self?.frame.size.width)! - 30, y: (self?.frame.size.height)! - 30, width: 30, height: 30)
  265. }
  266. }
  267. }
  268. func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
  269. print(error)
  270. }
  271. @objc func handleUserHaveClickRateUsNotification(_ notification: Notification) {
  272. adsWebView_Switch()
  273. }
  274. }