diff --git a/relax.offline.mp3.music.xcodeproj/project.pbxproj b/relax.offline.mp3.music.xcodeproj/project.pbxproj index 6e7bec8..20986a7 100644 --- a/relax.offline.mp3.music.xcodeproj/project.pbxproj +++ b/relax.offline.mp3.music.xcodeproj/project.pbxproj @@ -17,6 +17,10 @@ CB0968752C2121410045E55B /* GADTSmallTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = CB09686C2C2121410045E55B /* GADTSmallTemplateView.m */; }; CB0968762C2121410045E55B /* GADTSmallTemplateView.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB09686D2C2121410045E55B /* GADTSmallTemplateView.xib */; }; CB0968772C2121410045E55B /* GADTTemplateView.m in Sources */ = {isa = PBXBuildFile; fileRef = CB09686F2C2121410045E55B /* GADTTemplateView.m */; }; + CB0B368B2C65AE3A004036E2 /* Lottie in Frameworks */ = {isa = PBXBuildFile; productRef = CB0B368A2C65AE3A004036E2 /* Lottie */; }; + CB0B368D2C65AEEF004036E2 /* Wave_Animation.json in Resources */ = {isa = PBXBuildFile; fileRef = CB0B368C2C65AEEF004036E2 /* Wave_Animation.json */; }; + CB0B368F2C65B026004036E2 /* MP_WaveAnimationMaskView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0B368E2C65B026004036E2 /* MP_WaveAnimationMaskView.swift */; }; + CB0B36912C65EBFC004036E2 /* MPPositive_BaseShowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */; }; CB15B89B2C353B2400756E89 /* MP_GuideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB15B8992C353B2400756E89 /* MP_GuideViewController.swift */; }; CB15B89C2C353B2400756E89 /* MP_GuideViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB15B89A2C353B2400756E89 /* MP_GuideViewController.xib */; }; CB1E3B662C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */; }; @@ -274,6 +278,9 @@ CB09686E2C2121410045E55B /* GADTTemplateView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GADTTemplateView.h; sourceTree = ""; }; CB09686F2C2121410045E55B /* GADTTemplateView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GADTTemplateView.m; sourceTree = ""; }; CB09687E2C2126DD0045E55B /* Swift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Swift-Bridging-Header.h"; sourceTree = ""; }; + CB0B368C2C65AEEF004036E2 /* Wave_Animation.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = Wave_Animation.json; sourceTree = ""; }; + CB0B368E2C65B026004036E2 /* MP_WaveAnimationMaskView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_WaveAnimationMaskView.swift; sourceTree = ""; }; + CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_BaseShowView.swift; sourceTree = ""; }; CB15B8992C353B2400756E89 /* MP_GuideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_GuideViewController.swift; sourceTree = ""; }; CB15B89A2C353B2400756E89 /* MP_GuideViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MP_GuideViewController.xib; sourceTree = ""; }; CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CustomPlayListModel.swift; sourceTree = ""; }; @@ -521,6 +528,7 @@ CBAFCBAD2C0A10DA0054500E /* FirebaseCrashlytics in Frameworks */, CBD4570D2C2EC38400CE766D /* AppTrackingTransparency.framework in Frameworks */, CBAFCBAB2C0A10DA0054500E /* FirebaseAnalytics in Frameworks */, + CB0B368B2C65AE3A004036E2 /* Lottie in Frameworks */, CB6EEB8E2C5DFE6100AEC414 /* StoreKit.framework in Frameworks */, CBAFCBAF2C0A10DA0054500E /* FirebaseRemoteConfig in Frameworks */, CB7FC5462C2AA01F00292A43 /* FacebookCore in Frameworks */, @@ -582,6 +590,7 @@ isa = PBXGroup; children = ( CBAFC9F72C0A10500054500E /* MP_Lunch_ProgressView.swift */, + CB0B368E2C65B026004036E2 /* MP_WaveAnimationMaskView.swift */, ); path = Views; sourceTree = ""; @@ -680,6 +689,7 @@ CBAFCA122C0A10500054500E /* Sounds of appliances */, CBAFCA1C2C0A10500054500E /* Sounds of nature */, CBAFCA1D2C0A10500054500E /* Resource.plist */, + CB0B368C2C65AEEF004036E2 /* Wave_Animation.json */, ); path = "Resource(资源)"; sourceTree = ""; @@ -903,6 +913,7 @@ CBAFCA782C0A10500054500E /* MPPositive_BottomShowView.swift */, CBAFCA7C2C0A10500054500E /* MPPositive_MoreOperationDownLoadTableViewCell.swift */, CB0033F52C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift */, + CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */, ); path = Base; sourceTree = ""; @@ -1098,13 +1109,6 @@ path = ViewControllers; sourceTree = ""; }; - CBAFCACA2C0A10500054500E /* Add(新增资源) */ = { - isa = PBXGroup; - children = ( - ); - path = "Add(新增资源)"; - sourceTree = ""; - }; CBAFCAD12C0A10500054500E /* Base(基类-导航栏-标签栏) */ = { isa = PBXGroup; children = ( @@ -1149,10 +1153,9 @@ CBAFCAE22C0A10500054500E /* Views */ = { isa = PBXGroup; children = ( - CBAFCACA2C0A10500054500E /* Add(新增资源) */, CBAFCAD12C0A10500054500E /* Base(基类-导航栏-标签栏) */, - CBAFCAD62C0A10500054500E /* Center(个人资源) */, CBAFCAE12C0A10500054500E /* Home(音乐资源列表-播放器) */, + CBAFCAD62C0A10500054500E /* Center(个人资源) */, ); path = Views; sourceTree = ""; @@ -1238,6 +1241,7 @@ CB7FC5412C2AA01F00292A43 /* FacebookAEM */, CB7FC5432C2AA01F00292A43 /* FacebookBasics */, CB7FC5452C2AA01F00292A43 /* FacebookCore */, + CB0B368A2C65AE3A004036E2 /* Lottie */, ); productName = relax.offline.mp3.music; productReference = CBC2D6E82BFDF3D700E17703 /* relax.offline.mp3.music.app */; @@ -1270,6 +1274,7 @@ packageReferences = ( CBAFCBA92C0A10DA0054500E /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, CB7FC5402C2AA01F00292A43 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */, + CB0B36892C65AE3A004036E2 /* XCRemoteSwiftPackageReference "lottie-spm" */, ); productRefGroup = CBC2D6E92BFDF3D700E17703 /* Products */; projectDirPath = ""; @@ -1331,6 +1336,7 @@ CB15B89C2C353B2400756E89 /* MP_GuideViewController.xib in Resources */, CBAFCB002C0A10500054500E /* Chirping of Birds.mp3 in Resources */, CBAFCBA72C0A10500054500E /* MPSideA_Home_SecondListCollectionViewCell.xib in Resources */, + CB0B368D2C65AEEF004036E2 /* Wave_Animation.json in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1464,6 +1470,7 @@ CB2CAAD82C5A1AC500EF691D /* MP_IAPViewController.swift in Sources */, CBC1FB7E2C509BB400AC0633 /* MPPositive_LibraryListViewModel.swift in Sources */, CBAFCB992C0A10500054500E /* MPSideA_CustomTabBarView.swift in Sources */, + CB0B368F2C65B026004036E2 /* MP_WaveAnimationMaskView.swift in Sources */, CBAFCB342C0A10500054500E /* MPPositive_DownloadViewModel.swift in Sources */, CBAFCB1E2C0A10500054500E /* MPPositive_JsonRecommend.swift in Sources */, CB7FC5482C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift in Sources */, @@ -1472,6 +1479,7 @@ CBAFCB402C0A10500054500E /* MPPositive_SearchResultsLoadViewModel.swift in Sources */, CBAFCB132C0A10500054500E /* MP_WebWork.swift in Sources */, CBAFCB3A2C0A10500054500E /* MPPositive_SearchSuggestionItemListModel.swift in Sources */, + CB0B36912C65EBFC004036E2 /* MPPositive_BaseShowView.swift in Sources */, CBAFCB122C0A10500054500E /* MP_PlayerSlider.swift in Sources */, CBAFCB082C0A10500054500E /* MP_AnalyticsManager.swift in Sources */, CBAFCB1C2C0A10500054500E /* MPPositive_JsonNext.swift in Sources */, @@ -1873,6 +1881,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + CB0B36892C65AE3A004036E2 /* XCRemoteSwiftPackageReference "lottie-spm" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/airbnb/lottie-spm.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 4.5.0; + }; + }; CB7FC5402C2AA01F00292A43 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/facebook/facebook-ios-sdk"; @@ -1892,6 +1908,11 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ + CB0B368A2C65AE3A004036E2 /* Lottie */ = { + isa = XCSwiftPackageProductDependency; + package = CB0B36892C65AE3A004036E2 /* XCRemoteSwiftPackageReference "lottie-spm" */; + productName = Lottie; + }; CB7FC5412C2AA01F00292A43 /* FacebookAEM */ = { isa = XCSwiftPackageProductDependency; package = CB7FC5402C2AA01F00292A43 /* XCRemoteSwiftPackageReference "facebook-ios-sdk" */; diff --git a/relax.offline.mp3.music.xcworkspace/xcshareddata/swiftpm/Package.resolved b/relax.offline.mp3.music.xcworkspace/xcshareddata/swiftpm/Package.resolved index 7376276..8f44fed 100644 --- a/relax.offline.mp3.music.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/relax.offline.mp3.music.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,5 @@ { - "originHash" : "356668427da72005d8cb60963e877385296f1863605fc5a20d1f75f2cec3b22c", + "originHash" : "faf6001fdda5daa8e1887ad5537209b76d1294d394c19dacdef18322dc72fcd3", "pins" : [ { "identity" : "abseil-cpp-binary", @@ -100,6 +100,15 @@ "version" : "1.22.5" } }, + { + "identity" : "lottie-spm", + "kind" : "remoteSourceControl", + "location" : "https://github.com/airbnb/lottie-spm.git", + "state" : { + "revision" : "b842598f1295f3ffa1475b1580672d1fe5b83580", + "version" : "4.5.0" + } + }, { "identity" : "nanopb", "kind" : "remoteSourceControl", diff --git a/relax.offline.mp3.music.xcworkspace/xcuserdata/zhou.xcuserdatad/UserInterfaceState.xcuserstate b/relax.offline.mp3.music.xcworkspace/xcuserdata/zhou.xcuserdatad/UserInterfaceState.xcuserstate index f4e37e8..1b245bd 100644 Binary files a/relax.offline.mp3.music.xcworkspace/xcuserdata/zhou.xcuserdatad/UserInterfaceState.xcuserstate and b/relax.offline.mp3.music.xcworkspace/xcuserdata/zhou.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/relax.offline.mp3.music/AppDelegate.swift b/relax.offline.mp3.music/AppDelegate.swift index 70aeb4c..e8500e1 100644 --- a/relax.offline.mp3.music/AppDelegate.swift +++ b/relax.offline.mp3.music/AppDelegate.swift @@ -222,7 +222,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } //MARK: - 当应用被用户关闭时 func applicationWillTerminate(_ application: UIApplication) { - MP_AnalyticsManager.shared.ad_session_total_valueAction() print("应用关闭了") //检索应用是否播放歌曲 guard let load = MP_PlayerManager.shared.loadPlayer, let videoId = load.currentVideoId, let songs = load.songVideos else {return} diff --git a/relax.offline.mp3.music/MP/Common/Base(公用基类)/Controllers/MP_LunchViewController.swift b/relax.offline.mp3.music/MP/Common/Base(公用基类)/Controllers/MP_LunchViewController.swift index bb75e72..d7d3a5b 100644 --- a/relax.offline.mp3.music/MP/Common/Base(公用基类)/Controllers/MP_LunchViewController.swift +++ b/relax.offline.mp3.music/MP/Common/Base(公用基类)/Controllers/MP_LunchViewController.swift @@ -344,15 +344,23 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { if ad === MP_AdMobManager.shared.appOpenAd || ad === MP_AdMobManager.shared.appInterstitialAd { if let openAd = MP_AdMobManager.shared.appOpenAd { print("当前展示的广告是开屏广告,广告ID--\(openAd.adUnitID)") - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } }else if let openAd = MP_AdMobManager.shared.appInterstitialAd { print("当前展示的广告是开屏广告,广告ID--\(openAd.adUnitID)") - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } } } diff --git a/relax.offline.mp3.music/MP/Common/Base(公用基类)/Views/MP_WaveAnimationMaskView.swift b/relax.offline.mp3.music/MP/Common/Base(公用基类)/Views/MP_WaveAnimationMaskView.swift new file mode 100644 index 0000000..400686a --- /dev/null +++ b/relax.offline.mp3.music/MP/Common/Base(公用基类)/Views/MP_WaveAnimationMaskView.swift @@ -0,0 +1,49 @@ +// +// MP_WaveAnimationMaskView.swift +// relax.offline.mp3.music +// +// Created by Mr.Zhou on 2024/8/9. +// + +import UIKit +import Lottie +class MP_WaveAnimationMaskView: UIView { + ///动画View + private lazy var lotView:LottieAnimationView = { + //获取动画View + let json = Bundle.main.path(forResource: "Wave_Animation", ofType: "json") + let animationView:LottieAnimationView = .init(filePath: json ?? "") + //无限循环 + animationView.loopMode = .loop + //填充 + animationView.contentMode = .scaleAspectFill + animationView.backgroundColor = .clear + return animationView + }() + init(frame: CGRect, cornerRadius:CGFloat) { + super.init(frame: frame) + backgroundColor = .init(hex: "#000000", alpha: 0.6) + layer.masksToBounds = true + layer.cornerRadius = cornerRadius + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + } + //配置 + func configure() { + addSubview(lotView) + lotView.snp.makeConstraints { make in + make.center.equalToSuperview() + make.width.height.equalToSuperview().multipliedBy(0.35) + } + } + //启动动画 + func startAnimation() { + lotView.play() + } + //暂停动画 + func stopAnimation() { + lotView.stop() + } +} diff --git a/relax.offline.mp3.music/MP/Common/Extension(扩展)/String.swift b/relax.offline.mp3.music/MP/Common/Extension(扩展)/String.swift index eb38543..ae96ddd 100644 --- a/relax.offline.mp3.music/MP/Common/Extension(扩展)/String.swift +++ b/relax.offline.mp3.music/MP/Common/Extension(扩展)/String.swift @@ -49,7 +49,7 @@ extension Range where Bound == String.Index { ///扩展UILabel extension UILabel { ///设置文本渐变色 - func setGradientTextColor(_ colors:[CGColor]) { + func setGradientTextColor(_ colors:[CGColor], alignmentMode:CATextLayerAlignmentMode = .center) { self.layoutIfNeeded() //设置一个渐变层 let gradientLayer = CAGradientLayer() @@ -63,7 +63,7 @@ extension UILabel { textLayer.string = self.attributedText textLayer.isWrapped = true textLayer.truncationMode = .end - textLayer.alignmentMode = .center + textLayer.alignmentMode = alignmentMode textLayer.contentsScale = UIScreen.main.scale gradientLayer.mask = textLayer //添加层级 diff --git a/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift b/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift index 0db53de..a5b8bb0 100644 --- a/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift +++ b/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift @@ -79,6 +79,8 @@ let serviceUrl:URL = .init(string: "https://musiclax.mystrikingly.com/terms")! let gradientTextColors:[CGColor] = [UIColor(red: 0, green: 0.863, blue: 1, alpha: 1).cgColor, UIColor(red: 0, green: 1, blue: 0.561, alpha: 1).cgColor, UIColor(red: 0.776, green: 1, blue: 0.639, alpha: 1).cgColor] +///常用文本颜色-绿色 +let greenTextColor:UIColor = .init(hex: "#80F988", alpha: 1.0) //MARK: - 全局变量与方法 //存储默认配置值 @@ -160,7 +162,8 @@ func coreDefaultValues() { if UserDefaults.standard.object(forKey: "LoadINSERTID") == nil { if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/4335559460", ad: "AdMob", type: .Insert), .init(level: 2, identifier: "ca-app-pub-1371732277241593/2398278378", ad: "AdMob", type: .Insert), - .init(level: 1, identifier: "ca-app-pub-1371732277241593/3107763383", ad: "AdMob", type: .Insert)]) { + .init(level: 1, identifier: "ca-app-pub-1371732277241593/7827517266", ad: "AdMob", type: .Insert), + .init(level: 0, identifier: "ca-app-pub-1371732277241593/3107763383", ad: "AdMob", type: .Insert)]) { //存入默认开屏热启动广告ID UserDefaults.standard.set(array, forKey: "LoadINSERTID") } @@ -190,7 +193,10 @@ func coreDefaultValues() { UserDefaults.standard.removeObject(forKey: "GlobalINSERTID") } if UserDefaults.standard.object(forKey: "GlobalINSERTID") == nil { - if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/9449223728", ad: "AdMob", type: .Insert)]) { + if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/2696862512", ad: "AdMob", type: .Insert), + .init(level: 2, identifier: "ca-app-pub-1371732277241593/2477370661", ad: "AdMob", type: .Insert), + .init(level: 1, identifier: "ca-app-pub-1371732277241593/3391529916", ad: "AdMob", type: .Insert), + .init(level: 0, identifier: "ca-app-pub-1371732277241593/9449223728", ad: "AdMob", type: .Insert)]) { //存入默认开屏热启动广告ID UserDefaults.standard.set(array, forKey: "GlobalINSERTID") } diff --git a/relax.offline.mp3.music/MP/Common/Resource(资源)/Wave_Animation.json b/relax.offline.mp3.music/MP/Common/Resource(资源)/Wave_Animation.json new file mode 100644 index 0000000..b4513f4 --- /dev/null +++ b/relax.offline.mp3.music/MP/Common/Resource(资源)/Wave_Animation.json @@ -0,0 +1 @@ +{"v":"4.8.0","meta":{"g":"LottieFiles AE ","a":"","k":"","d":"","tc":""},"fr":25,"ip":0,"op":24,"w":1080,"h":1080,"nm":"Comp 1","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 3","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[890,540,0],"ix":2},"a":{"a":0,"k":[-55.281,30.914,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":6,"s":[300,418]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":14,"s":[300,1018]},{"t":23,"s":[300,418]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":364,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false,"_render":true},{"ty":"fl","c":{"a":0,"k":[0.051,0.8745,0.1176,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[-55.281,30.914],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":750,"st":0,"bm":0,"completed":true},{"ddd":0,"ind":2,"ty":4,"nm":"Shape Layer 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[540,540,0],"ix":2},"a":{"a":0,"k":[-55.281,30.914,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[300,1018]},{"i":{"x":[0.833,0.833],"y":[1,1]},"o":{"x":[0.167,0.167],"y":[0,0]},"t":13,"s":[300,300]},{"t":24,"s":[300,1018]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":364,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false,"_render":true},{"ty":"fl","c":{"a":0,"k":[0.051,0.8745,0.1176,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[-55.281,30.914],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":750,"st":0,"bm":0,"completed":true},{"ddd":0,"ind":3,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[190,540,0],"ix":2},"a":{"a":0,"k":[-55.281,30.914,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":0,"s":[300,300]},{"i":{"x":[0.667,0.667],"y":[1,1]},"o":{"x":[0.333,0.333],"y":[0,0]},"t":11,"s":[300,1018]},{"t":22,"s":[300,300]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":364,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false,"_render":true},{"ty":"fl","c":{"a":0,"k":[0.051,0.8745,0.1176,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false,"_render":true},{"ty":"tr","p":{"a":0,"k":[-55.281,30.914],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform","_render":true}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false,"_render":true}],"ip":0,"op":750,"st":0,"bm":0,"completed":true}],"markers":[],"__complete":true} \ No newline at end of file diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift index 014c62b..5bfff39 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift @@ -8,8 +8,8 @@ import UIKit import AVFoundation import GoogleMobileAds -import AppLovinSDK import AppLovinAdapter +import AppLovinSDK import LiftoffMonetizeAdapter import VungleAdsSDK import PangleAdapter @@ -70,6 +70,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } private override init() { super.init() + NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_:)), notificationName: .net_switch_reachable) GADMobileAds.sharedInstance().audioVideoManager.delegate = self GADMobileAds.sharedInstance().audioVideoManager.audioSessionIsApplicationManaged = false reloadAdMobIDs() @@ -311,7 +312,16 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } } } + //网络可用时触发 + @objc private func netWorkReachableAction(_ sender:Notification) { + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + loadMoreAdMobs() + } + } deinit{ + NotificationCenter.default.removeObserver(self) displaySearchTimer?.invalidate() displaySearchTimer = nil displayLibraryTimer?.invalidate() @@ -414,6 +424,16 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont print("热启动广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.hot_ads_loadFailureAction("No Ads Fill") completion(false) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + [weak self] in + self?.loadOpenAd(.HOST, completion: { status in + if status { + print("重新加载热启动广告成功") + }else { + print("重新加载热启动广告失败") + } + }) + } return } item = OpenHOSTID[level] @@ -490,6 +510,16 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self.showOpenAdIfAvailable(type, completion: completion) } } + if type == .HOST { + //同步展示全屏广告 + showGlobalInterstitialAdIfAvailable { ad in + if let ad = ad { + if let block = completion { + block(ad, false) + } + } + } + } return } if type == .ICE { @@ -542,6 +572,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } } }else { + print("开屏广告展示失败") if type == .ICE { MP_AnalyticsManager.shared.cold_ads_showFailureAction("Ad loading failed") }else { @@ -674,9 +705,15 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard level < (SearchINSERTID.count) else { print("搜索插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.search_ads_loadFailureAction("No Ads Fill") - //开始加载全局插页 - loadGlobalInterstitialAd { status in - completion(status) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadSearchInterstitialAd { status in + if status { + print("重新加载搜索插页广告") + }else { + print("加载搜索插页广告失败") + } + } } return } @@ -728,6 +765,8 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self.showSearchInterstitialAdIfAvailable(completion: completion) } } + //展示全屏广告 + showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.search_ads_chanceAction() @@ -741,16 +780,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont interstitialSwitch = true ad.present(fromRootViewController: nil) } - }else if let ad = globalInterstitialAd { - //加载全局插页广告 - //传递加载完成事件 - if let block = completion { - block(ad) - }else { - isShowingGlobalInterstitialAd = true - interstitialSwitch = true - ad.present(fromRootViewController: nil) - } }else { MP_AnalyticsManager.shared.search_ads_showFailureAction("Ad loading failed") } @@ -796,9 +825,15 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard level < (PlayerINSERTID.count) else { print("播放插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.play_ads_loadFailureAction("No Ads Fill") - //开始加载全局插页 - loadGlobalInterstitialAd { status in - completion(status) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadPlayInterstitialAd { status in + if status { + print("重新加载播放插页广告") + }else { + print("加载播放插页广告失败") + } + } } return } @@ -826,17 +861,26 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } } ///播放插页广告展示 - func showPlayInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { + func showPlayInterstitialAdIfAvailable(completion:((GADInterstitialAd?) -> Void)?) { guard openAdStatus else { + completion?(nil) + return + } + guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { + completion?(nil) return } // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 - guard !interstitialSwitch, !isShowingPlayInterstitialAd else { return } + guard !interstitialSwitch, !isShowingPlayInterstitialAd else { + completion?(nil) + return + } //检索是否存在插页间隔时间 if let date = interstitialDate { if isShowInterstitialADAvailable(date) == false { //未超过插页间隔时长 print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") + completion?(nil) return } } @@ -844,8 +888,10 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont if !isPlayInterstitialAdAvailable() { loadPlayInterstitialAd{ [weak self] success in guard let self = self else { return } - if success { + if success { self.showPlayInterstitialAdIfAvailable(completion: completion) + }else { + completion?(nil) } } return @@ -861,18 +907,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont interstitialSwitch = true ad.present(fromRootViewController: nil) } - }else if let ad = globalInterstitialAd { - //加载全局插页广告 - //传递加载完成事件 - if let block = completion { - block(ad) - }else { - isShowingGlobalInterstitialAd = true - interstitialSwitch = true - ad.present(fromRootViewController: nil) - } }else { MP_AnalyticsManager.shared.play_ads_showFailureAction("Ad loading failed") + completion?(nil) } } //查询是否有播放插页广告 @@ -916,9 +953,15 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard level < (SwitchINSERTID.count) else { print("切歌插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.cut_ads_loadFailureAction("No Ads Fill") - //开始加载全局插页 - loadGlobalInterstitialAd { status in - completion(status) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadSwitchInterstitialAd { status in + if status { + print("重新加载切歌插页广告") + }else { + print("加载切歌插页广告失败") + } + } } return } @@ -968,6 +1011,8 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self.showSwitchInterstitialAdIfAvailable(completion: completion) } } + //展示全屏广告 + showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.cut_ads_chanceAction() @@ -981,16 +1026,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont interstitialSwitch = true ad.present(fromRootViewController: nil) } - }else if let ad = globalInterstitialAd { - //加载全局插页广告 - //传递加载完成事件 - if let block = completion { - block(ad) - }else { - isShowingGlobalInterstitialAd = true - interstitialSwitch = true - ad.present(fromRootViewController: nil) - } }else { MP_AnalyticsManager.shared.cut_ads_showFailureAction("Ad loading failed") } @@ -1035,9 +1070,15 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard level < (LoadINSERTID.count) else { print("下载插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.dl_ads_loadFailureAction("No Ads Fill") - //开始加载全局插页 - loadGlobalInterstitialAd { status in - completion(status) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadLoadInterstitialAd { status in + if status { + print("重新加载下载插页广告") + }else { + print("加载下载插页广告失败") + } + } } return } @@ -1087,6 +1128,8 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self.showLoadInterstitialAdIfAvailable(completion: completion) } } + //展示全屏广告 + showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.dl_ads_chanceAction() @@ -1100,16 +1143,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont interstitialSwitch = true ad.present(fromRootViewController: nil) } - }else if let ad = globalInterstitialAd { - //加载全局插页广告 - //传递加载完成事件 - if let block = completion { - block(ad) - }else { - isShowingGlobalInterstitialAd = true - interstitialSwitch = true - ad.present(fromRootViewController: nil) - } }else { MP_AnalyticsManager.shared.dl_ads_showFailureAction("Ad loading failed") } @@ -1133,25 +1166,25 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont private var loadLibraryInterstitialAdTime:Date? ///曲库广告处理闭包 var completeLibraryInterstitialAdBlock:(() -> Void)? - ///搜索原生广告加载器 + ///曲库原生广告加载器 var libraryAdLoader:GADAdLoader? - ///搜索原生广告 + ///曲库原生广告 var libraryNativeAds:[GADNativeAd]? - ///搜索原生广告视图一 + ///曲库原生广告视图一 var libraryNativeAdFirstView:GADNativeAdView? ///原生广告视图二 var libraryNativeAdSecondView:GADNativeAdView? - ///搜索原生存储时长 + ///曲库原生存储时长 var refreshLibraryTimes:TimeInterval = 3600 - ///搜索原生显示刷新计时器 + ///曲库原生显示刷新计时器 var displayLibraryTimer:Timer? - ///搜索原生加载时间 + ///曲库原生加载时间 var expirationLibraryDate:Date? - ///搜索控制器 + ///曲库控制器 var libraryViewController:UIViewController? - ///搜索原生回调闭包 + ///曲库原生回调闭包 var onLibraryNativeAdBlock:(() -> Void)? - ///配置搜索原生广告加载器 + ///配置曲库原生广告加载器 func configureLibraryNativeAd(rootController vc:UIViewController) { guard openAdStatus else { return @@ -1160,7 +1193,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont libraryViewController = vc } } - ///搜索原生广告加载 + ///曲库原生广告加载 func loadLibraryNativeAd() { guard openAdStatus else {return} guard let vc = libraryViewController, libraryNativeAds == nil else {return} @@ -1181,7 +1214,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont libraryNativeAds = [] } } - ///将加载的搜索原生广告添加到页面中 + ///将加载的曲库原生广告添加到页面中 func layoutLibraryNativeAd(in containerView: UIView, index:Int) { guard openAdStatus else {return} containerView.subviews.forEach { item in @@ -1254,7 +1287,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self?.loadLibraryNativeAd() } } - ///搜索原生存储时长 + ///曲库原生存储时长 private func refreshLibraryDate(_ date:Date?) -> Bool { guard let date = date else {return false} return Date().timeIntervalSince(date) < refreshLibraryTimes @@ -1281,9 +1314,15 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard level < (LibraryINSERTID.count) else { print("曲库插页广告组已经全部加载失败,停止继续加载") MP_AnalyticsManager.shared.listclk_ads_loadFailureAction("No Ads Fill") - //开始加载全局插页 - loadGlobalInterstitialAd { status in - completion(status) + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadLoadInterstitialAd { status in + if status { + print("重新加载曲库插页广告") + }else { + print("加载曲库插页广告失败") + } + } } return } @@ -1333,6 +1372,8 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont self.showLibraryInterstitialAdIfAvailable(completion: completion) } } + //展示全屏广告 + showGlobalInterstitialAdIfAvailable(completion: nil) return } MP_AnalyticsManager.shared.listclk_ads_chanceAction() @@ -1347,17 +1388,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont interstitialSwitch = true ad.present(fromRootViewController: nil) } - }else if let ad = globalInterstitialAd { - //加载全局插页广告 - - //传递加载完成事件 - if let block = completion { - block(ad) - }else { - isShowingGlobalInterstitialAd = true - interstitialSwitch = true - ad.present(fromRootViewController: nil) - } }else { MP_AnalyticsManager.shared.listclk_ads_showFailureAction("Ad loading failed") } @@ -1420,7 +1450,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } } ///全局插页广告展示 - func showGlobalInterstitialAdIfAvailable(completion:((GADInterstitialAd) -> Void)?) { + func showGlobalInterstitialAdIfAvailable(completion:((GADInterstitialAd?) -> Void)?) { guard openAdStatus else { return } @@ -1440,6 +1470,8 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont guard let self = self else { return } if success { self.showGlobalInterstitialAdIfAvailable(completion: completion) + }else { + completion?(nil) } } return @@ -1488,63 +1520,109 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont if OpenICEID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { //冷启动,检索是插页还是开屏 if let openAd = appOpenAd { - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } }else if let openAd = appInterstitialAd { - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.cold_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } } }else if OpenHOSTID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) { //热启动,检索是插页还是开屏 if let openAd = appOpenAd { - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } }else if let openAd = appInterstitialAd { - //上传广告收益 - openAd.paidEventHandler = { adValue in - MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + if MP_AnalyticsManager.shared.infoFromAdMobSource(openAd.responseInfo) { + //上传广告收益 + openAd.paidEventHandler = { adValue in + MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: adValue) + } + }else { + MP_AnalyticsManager.shared.hot_ads_showSuccessAction(openAd.responseInfo, adValue: .init()) } } } }else if ad === searchInterstitialAd {//搜索插页广告 print("当前展示的广告是搜索插页广告,广告ID--\(searchInterstitialAd?.adUnitID ?? "")") - searchInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(searchInterstitialAd?.responseInfo) { + searchInterstitialAd?.paidEventHandler = { adValue in + if let response = self.searchInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.search_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = self.searchInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.search_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.search_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === playInterstitialAd {//播放插页广告 print("当前展示的广告是播放插页广告,广告ID--\(playInterstitialAd?.adUnitID ?? "")") - playInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(playInterstitialAd?.responseInfo) { + playInterstitialAd?.paidEventHandler = { adValue in + if let response = self.playInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = self.playInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === switchInterstitialAd {//切歌插页广告 print("当前展示的广告是切歌插页广告,广告ID--\(switchInterstitialAd?.adUnitID ?? "")") - switchInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { + switchInterstitialAd?.paidEventHandler = { adValue in + if let response = self.switchInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.cut_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = self.switchInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.cut_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.cut_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === loadInterstitialAd {//下载插页广告 print("当前展示的广告是下载插页广告,广告ID--\(loadInterstitialAd?.adUnitID ?? "")") - loadInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { + loadInterstitialAd?.paidEventHandler = { adValue in + if let response = self.loadInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.dl_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = self.loadInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.dl_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.dl_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === libraryInterstitialAd {//曲库插页广告 print("当前展示的广告是曲库插页广告,广告ID--\(libraryInterstitialAd?.adUnitID ?? "")") - libraryInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(switchInterstitialAd?.responseInfo) { + libraryInterstitialAd?.paidEventHandler = { adValue in + if let response = self.libraryInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.listclk_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = self.libraryInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.listclk_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.listclk_ads_showSuccessAction(response, adValue: .init()) } } }else if ad === globalInterstitialAd {//全局插页广告 diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift index bc438a2..8103ca8 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift @@ -54,6 +54,8 @@ class MP_AnalyticsManager: NSObject { private let player_b_success_action = "player_b_success_action" //播放失败 private let player_b_failure_error = "player_b_failure_error" + //资源获取失败 + private let player_resource_failure = "player_resource_failure" //点击收藏 private let player_b_love_click = "player_b_love_click" //取消收藏 @@ -64,6 +66,7 @@ class MP_AnalyticsManager: NSObject { private let player_b_downloadsuccess_action = "player_b_downloadsuccess_action" //资源下载失败 private let player_b_downloadfailure_error = "player_b_downloadfailure_error" + //B面搜索曝光 private let search_pv = "search_pv" //如何进入搜索结果页 @@ -138,7 +141,7 @@ class MP_AnalyticsManager: NSObject { if array.isEmpty == false, let data = coreAdModelforJson(array) { UserDefaults.standard.removeObject(forKey: key) //重新更新内容 - print("Reload--\(key)") + print("\(key)---IDs:\(array.count)") UserDefaults.standard.set(data, forKey: key) } } @@ -339,6 +342,11 @@ class MP_AnalyticsManager: NSObject { "error":error ]) } + ///资源获取失败 + func player_resource_failureAction(_ code:String) { + Analytics.logEvent(player_resource_failure, parameters: ["area_code":code]) + } + ///点击收藏 /// - Parameters: /// - videoid: 音乐id @@ -540,20 +548,13 @@ class MP_AnalyticsManager: NSObject { "CS_CURRENCY":adValue.currencyCode, "CS_VALUE":priceString, "CS_STATUS":isOLD ? "Old":"New"] - //同时执行当前活跃会话的总价格和总次数更新 - if var totalPrices = UserDefaults.standard.array(forKey: "Session_TotalPrices") as? [Double] { - print("更新了当前活跃会话的广告总次数和总价值") - totalPrices.append(price) - UserDefaults.standard.set(totalPrices, forKey: "Session_TotalPrices") - }else { - print("更新了当前活跃会话的广告总次数和总价值") - //没有这个数据 - var array:[Double] = [] - array.append(price) - UserDefaults.standard.set(array, forKey: "Session_TotalPrices") - } return parameters } + ///检索广告来源 + func infoFromAdMobSource(_ responseInfo:GADResponseInfo?) -> Bool { + guard let responseInfo = responseInfo else {return false} + return (responseInfo.loadedAdNetworkResponseInfo?.adSourceInstanceName ?? "").contains("AdMob") + } //价格转化(全部转化为美元) private func valueToUSD(_ adValue:GADAdValue) -> Double { @@ -765,28 +766,6 @@ class MP_AnalyticsManager: NSObject { print("列表原生成功展示信息--\(parameters)") Analytics.logEvent(list_ads_show, parameters: parameters) } - ///对总价值的价格上报事件 - func ad_session_total_valueAction() { - //取出当前活跃次数总价值以及对应数据 - if let totalPrices = UserDefaults.standard.array(forKey: "Session_TotalPrices") as? [Double] { - //成功获取了总价值与总次数 - var totalPrice:Double = 0 - totalPrices.forEach { item in - totalPrice += item - } - let priceString = String(format: "%.5f", totalPrices) - let count = totalPrices.count - let currentTime = getCurrentLosAngelesTime() - let parameters:[String:Any] = ["session_currentTime":currentTime, - "session_totalPrice":priceString, - "session_totalNumber":count] - print("当前活跃会话总价值--\(parameters)") - //发布事件 - Analytics.logEvent(ad_session_total_value, parameters: parameters) - //清理当前活跃会话广告总价值 - UserDefaults.standard.removeObject(forKey: "Session_TotalPrices") - } - } //获取太平洋洛杉矶时间 func getCurrentLosAngelesTime() -> String { // 获取当前日期和时间 diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift index abeb877..ba7a184 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift @@ -285,7 +285,6 @@ extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver do { if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { - print("Receipt validation response: \(jsonResponse)") if let status = jsonResponse["status"] as? Int { if status == 0 { completion(true) @@ -339,8 +338,6 @@ extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver } do { if let jsonResponse = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] { - print("Sandbox receipt validation response: \(jsonResponse)") - if let status = jsonResponse["status"] as? Int, status == 0 { completion(true) } else { diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift index 96518e1..2e07b8c 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift @@ -2092,6 +2092,9 @@ extension MP_NetWorkManager { parsingAndroidPlayerStreamingData(streamingData){ videos,itags,mimeType in completion((videos,itags,mimeType),infos) } + }else { + MP_HUD.error("Failed to obtain resource, please try again later", delay: 1.0, completion: nil) + MP_AnalyticsManager.shared.player_resource_failureAction(locaton ?? "HK") } } diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift index 17f1d97..14038a1 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift @@ -143,7 +143,7 @@ class MP_PlayerManager:NSObject{ } } //是否因为广告原因延迟了播放(当广告加载时,延迟播放器状态切换) - var isAdLate:Bool?{ + var isAdLate:Bool? = false{ didSet{ DispatchQueue.main.asyncAfter(deadline: .now()) { [weak self] in @@ -370,6 +370,8 @@ class MP_PlayerManager:NSObject{ }else { player.play() } + }else { + } //暂停计时器,并获取延时值 suspendTimer() diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift index 401a1e7..59d05e8 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_BaseViewController.swift @@ -37,6 +37,7 @@ class MPPositive_BaseViewController: MP_BaseViewController, UIGestureRecognizerD override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) NotificationCenter.notificationKey.add(observer: self, selector: #selector(errorAction(_ :)), notificationName: .netWork_error_deal) + NotificationCenter.notificationKey.add(observer: self, selector: #selector(switchCurrentVideoAction(_ :)), notificationName: .positive_player_reload) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) @@ -161,5 +162,21 @@ class MPPositive_BaseViewController: MP_BaseViewController, UIGestureRecognizerD } return true } - + ///当用户切换了歌曲后 + @objc private func switchCurrentVideoAction(_ notification:Notification) { + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //检索当前View内部是否存在tableView + view.subviews.forEach { item in + if item is UITableView { + let tableView = item as? UITableView + tableView?.reloadData() + }else if item is UICollectionView { + let collectionView = item as? UICollectionView + collectionView?.reloadData() + } + } + } + } } diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_TabBarController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_TabBarController.swift index 2467546..4fcf6ec 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_TabBarController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_TabBarController.swift @@ -21,6 +21,7 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio } //是否Push private var isPush:Bool = false + var pushPlayerBlock:(() -> Void)? override func viewDidLoad() { super.viewDidLoad() self.setValue(customTabBar, forKey: "tabBar") @@ -94,28 +95,38 @@ extension MPPositive_TabBarController { @objc private func pupPlayerAction() { MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable { [weak self] ad in guard let self = self else {return} - //判断音乐播放器是否已经播放 - MP_AdMobManager.shared.isShowingPlayInterstitialAd = true - //播放器还未播放,可以弹出广告 - MP_AdMobManager.shared.setInterstitialSwitch(true) - ad.fullScreenContentDelegate = self - ad.present(fromRootViewController: self) + if let ad = ad { + //判断音乐播放器是否已经播放 + MP_AdMobManager.shared.isShowingPlayInterstitialAd = true + //播放器还未播放,可以弹出广告 + MP_AdMobManager.shared.setInterstitialSwitch(true) + ad.fullScreenContentDelegate = self + ad.present(fromRootViewController: self) + }else { + if let block = self.pushPlayerBlock { + block() + } + } } - //执行加载播放器页面 - DispatchQueue.main.async { + //赋予block任务块 + self.pushPlayerBlock = { [weak self] in - let playerVC = MPPositive_PlayerViewController() - playerVC.modalPresentationStyle = .fullScreen - playerVC.recommendBlock = { - let recommendVC = MPPositive_RecommendViewController(MP_PlayerManager.shared.loadPlayer?.currentVideo?.song.relatedID ?? "") - self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(recommendVC, animated: false) + //执行加载播放器页面 + DispatchQueue.main.async { + [weak self] in + let playerVC = MPPositive_PlayerViewController() + playerVC.modalPresentationStyle = .fullScreen + playerVC.recommendBlock = { + let recommendVC = MPPositive_RecommendViewController(MP_PlayerManager.shared.loadPlayer?.currentVideo?.song.relatedID ?? "") + self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(recommendVC, animated: false) + } + playerVC.searchBlock = { (text) in + MP_AnalyticsManager.shared.search_from_actionAction("player page") + let resultVC = MPPositive_SearchResultShowViewController(text, isShowAd: false) + self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(resultVC, animated: false) + } + self?.present(playerVC, animated: true) } - playerVC.searchBlock = { (text) in - MP_AnalyticsManager.shared.search_from_actionAction("player page") - let resultVC = MPPositive_SearchResultShowViewController(text, isShowAd: false) - self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(resultVC, animated: false) - } - self?.present(playerVC, animated: true) } } //切换底部音乐模块状态 @@ -167,9 +178,15 @@ extension MPPositive_TabBarController { // UIApplication.shared.isStatusBarHidden = true if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告 print("当前展示的广告是播放插页广告,广告ID--\(MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? "")") - MP_AdMobManager.shared.playInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(MP_AdMobManager.shared.playInterstitialAd?.responseInfo) { + MP_AdMobManager.shared.playInterstitialAd?.paidEventHandler = { adValue in + if let response = MP_AdMobManager.shared.playInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = MP_AdMobManager.shared.playInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: .init()) } } } @@ -185,16 +202,8 @@ extension MPPositive_TabBarController { if MP_AdMobManager.shared.completePlayInterstitialAdBlock != nil { MP_AdMobManager.shared.completePlayInterstitialAdBlock!() } - //执行加载播放器页面 - DispatchQueue.main.async { - [weak self] in - let playerVC = MPPositive_PlayerViewController() - playerVC.modalPresentationStyle = .fullScreen - playerVC.recommendBlock = { - let recommendVC = MPPositive_RecommendViewController(MP_PlayerManager.shared.loadPlayer.currentVideo.song.relatedID) - self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(recommendVC, animated: false) - } - self?.present(playerVC, animated: true) + if let block = self.pushPlayerBlock { + block() } } diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift index 7cb0d13..504e296 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_HomeViewController.swift @@ -102,6 +102,10 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro MP_HUD.loading() } MP_AdMobManager.shared.configureLibraryNativeAd(rootController: self) + MP_AdMobManager.shared.loadLibraryNativeAd() + //加载搜索原生广告 + MP_AdMobManager.shared.configureSreachNativeAd(rootController: self) + MP_AdMobManager.shared.loadSearchNativeAd() errorBlock = { [weak self] in guard let self = self else { @@ -454,102 +458,96 @@ extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDeleg } func numberOfSections(in tableView: UITableView) -> Int { - if MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty { - return 1 - }else { - return 2 - } + return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - if MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels.isEmpty { - return MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count - }else { - switch section { - case 0: - return 1 - default: - return MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count - } - } + return MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count + 1 } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - switch indexPath.section { - case 0: + switch indexPath.row { + case 1: let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeLibraryListstableViewCellID, for: indexPath) as! MPPositive_HomeLibraryListstableViewCell cell.libraryViewModels = MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels return cell default: - if let first = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row].items.first, first.browseItem.itemType == .single, (first.browseItem.pageType == "MUSIC_VIDEO_TYPE_ATV" || first.browseItem.pageType == "MUSIC_VIDEO_TYPE_UGC") { - //是单曲 - let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeSinglesTableViewCellID, for: indexPath) as! MPPositive_HomeSinglesTableViewCell - cell.browseViewModel = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row] - return cell - }else { - let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeShowTableViewCellID, for: indexPath) as! MPPositive_HomeShowTableViewCell - cell.browseViewModel = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row] - if let first = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row].items.first, first.browseItem.itemType == .single, first.browseItem.pageType == "MUSIC_VIDEO_TYPE_OMV" { - cell.showType = .Fifth + let row:Int = indexPath.row == 0 ? 0:(indexPath.row-1) + if row < MPPositive_BrowseLoadViewModel.shared.browseModuleLists.count { + if let first = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row].items.first, first.browseItem.itemType == .single, (first.browseItem.pageType == "MUSIC_VIDEO_TYPE_ATV" || first.browseItem.pageType == "MUSIC_VIDEO_TYPE_UGC") { + //是单曲 + let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeSinglesTableViewCellID, for: indexPath) as! MPPositive_HomeSinglesTableViewCell + cell.browseViewModel = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row] + return cell }else { - //判断是列表还是艺术家 - if MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row].items.first?.browseItem.pageType == "MUSIC_PAGE_TYPE_ARTIST" { - cell.showType = .Fourth + let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeShowTableViewCellID, for: indexPath) as! MPPositive_HomeShowTableViewCell + cell.browseViewModel = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row] + if let first = MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row].items.first, first.browseItem.itemType == .single, first.browseItem.pageType == "MUSIC_VIDEO_TYPE_OMV" { + cell.showType = .Fifth }else { - cell.showType = .Third - } - } - cell.requestNextBlock = { - [weak self] (item) in - guard let self = self else {return} - MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "") - switch item.browseItem.itemType { - case .single: - //单曲/视频跳转 - MPPositive_Debouncer.shared.call { - [weak self] in - guard let self = self else {return} - guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Weak connection.", delay: 2.0, completion: nil) - return - } - MP_AnalyticsManager.shared.song_clickAction("Home") - //优先清除数据 - MP_PlayerManager.shared.loadPlayer = nil - //弹出播放器 - NotificationCenter.notificationKey.post(notificationName: .pup_player_vc) - MP_AnalyticsManager.shared.player_b_impAction() - //触发next请求,优先获取列表全部单曲基础数据(不完善) - MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in - guard let self = self else {return} - //回掉的数据并不完善,生成一个playerloadViewModel - let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "") - lodaViewModel.improveData(item.browseItem.videoId ?? "") - //更改播放器播放类型 - MP_PlayerManager.shared.setPlayType(.normal) - MP_PlayerManager.shared.loadPlayer = lodaViewModel - MP_AnalyticsManager.shared.player_b_listAction() - } + //判断是列表还是艺术家 + if MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row].items.first?.browseItem.pageType == "MUSIC_PAGE_TYPE_ARTIST" { + cell.showType = .Fourth + }else { + cell.showType = .Third } - case .list: - isFirstAppearance = false - //列表专辑 - let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") - navigationController?.pushViewController(listVC, animated: true) - case .artist: - isFirstAppearance = false - //前往艺术家页面 - let artistVC = MPPositive_ArtistShowViewController(item.browseItem.artistId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") - navigationController?.pushViewController(artistVC, animated: true) - default: - break } + cell.requestNextBlock = { + [weak self] (item) in + guard let self = self else {return} + MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "") + switch item.browseItem.itemType { + case .single: + //单曲/视频跳转 + MPPositive_Debouncer.shared.call { + [weak self] in + guard let self = self else {return} + guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { + MP_HUD.text("Weak connection.", delay: 2.0, completion: nil) + return + } + MP_AnalyticsManager.shared.song_clickAction("Home") + //优先清除数据 + MP_PlayerManager.shared.loadPlayer = nil + //弹出播放器 + NotificationCenter.notificationKey.post(notificationName: .pup_player_vc) + MP_AnalyticsManager.shared.player_b_impAction() + //触发next请求,优先获取列表全部单曲基础数据(不完善) + MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams){ [weak self] listSongs in + guard let self = self else {return} + //回掉的数据并不完善,生成一个playerloadViewModel + let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "") + lodaViewModel.improveData(item.browseItem.videoId ?? "") + //更改播放器播放类型 + MP_PlayerManager.shared.setPlayType(.normal) + MP_PlayerManager.shared.loadPlayer = lodaViewModel + MP_AnalyticsManager.shared.player_b_listAction() + } + } + case .list: + isFirstAppearance = false + //列表专辑 + let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") + navigationController?.pushViewController(listVC, animated: true) + case .artist: + isFirstAppearance = false + //前往艺术家页面 + let artistVC = MPPositive_ArtistShowViewController(item.browseItem.artistId ?? "", clickTrackingParams: item.browseItem.clickTrackingParams ?? "") + navigationController?.pushViewController(artistVC, animated: true) + default: + break + } + } + cell.findMoreBlock = { + [weak self] in + guard let self = self else {return} + isFirstAppearance = false + let moreVC = MPPositive_MoreContentViewController(MPPositive_BrowseLoadViewModel.shared.browseModuleLists[row]) + navigationController?.pushViewController(moreVC, animated: true) + } + return cell } - cell.findMoreBlock = { - [weak self] in - guard let self = self else {return} - isFirstAppearance = false - let moreVC = MPPositive_MoreContentViewController(MPPositive_BrowseLoadViewModel.shared.browseModuleLists[indexPath.row]) - navigationController?.pushViewController(moreVC, animated: true) - } + }else { + let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeLibraryListstableViewCellID, for: indexPath) as! MPPositive_HomeLibraryListstableViewCell + cell.libraryViewModels = MPPositive_BrowseLoadViewModel.shared.libraryList.libraryViewModels return cell } } diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchResultShowViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchResultShowViewController.swift index 890c050..4c76a72 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchResultShowViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchResultShowViewController.swift @@ -212,6 +212,7 @@ class MPPositive_SearchResultShowViewController: MPPositive_BaseViewController, searchText = "" suggestionView.suggestions = nil resultsShowView.loadModel = nil + historyView.isHidden = false } //取消并返回上一页 @objc private func backPopClick(_ sender:UIButton) { @@ -235,6 +236,7 @@ extension MPPositive_SearchResultShowViewController:UITextFieldDelegate { if text.isEmpty { self.suggestionList = nil cancelDebounceTimer() + historyView.isHidden = false }else { //触发网络请求 loadSearchSuggestions(text) diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchViewController.swift index dcf2d3e..339b28e 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_SearchViewController.swift @@ -33,9 +33,6 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController { super.viewDidLoad() setTitle("") configure() - //加载搜索原生广告 - MP_AdMobManager.shared.configureSreachNativeAd(rootController: self) - MP_AdMobManager.shared.loadSearchNativeAd() NotificationCenter.notificationKey.add(observer: self, selector: #selector(grideReloadAction(_ :)), notificationName: .search_gride_reload) } override func viewWillAppear(_ animated: Bool) { diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_BaseShowView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_BaseShowView.swift new file mode 100644 index 0000000..7af6882 --- /dev/null +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_BaseShowView.swift @@ -0,0 +1,39 @@ +// +// MPPositive_BaseShowView.swift +// relax.offline.mp3.music +// +// Created by Mr.Zhou on 2024/8/9. +// + +import UIKit + +class MPPositive_BaseShowView: UIView { + + override init(frame: CGRect) { + super.init(frame: frame) + NotificationCenter.notificationKey.add(observer: self, selector: #selector(switchCurrentVideoAction(_ :)), notificationName: .positive_player_reload) + } + ///当用户切换了歌曲后 + @objc private func switchCurrentVideoAction(_ notification:Notification) { + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //检索当前View内部是否存在tableView + subviews.forEach { item in + if item is UITableView { + let tableView = item as? UITableView + tableView?.reloadData() + }else if item is UICollectionView { + let collectionView = item as? UICollectionView + collectionView?.reloadData() + } + } + } + } + required init?(coder: NSCoder) { + super.init(coder: coder) + } + deinit{ + NotificationCenter.default.removeObserver(self) + } +} diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowSongTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowSongTableViewCell.swift index fcbf548..46ffa62 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowSongTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowSongTableViewCell.swift @@ -15,6 +15,7 @@ class MPPositive_ArtistShowSongTableViewCell: UITableViewCell, PKDownloadButtonD imageView.layer.masksToBounds = true return imageView }() + private lazy var maskImageView:MP_WaveAnimationMaskView = .init(frame: .init(x: 0, y: 0, width: 24*width, height: 24*width), cornerRadius: 10*width) private lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left) private lazy var subtitleLabel:UILabel = createLabel(font: .systemFont(ofSize: 12*width, weight: .regular), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .left) ///更多按钮 @@ -54,6 +55,15 @@ class MPPositive_ArtistShowSongTableViewCell: UITableViewCell, PKDownloadButtonD titleLabel.text = itemView.title subtitleLabel.text = itemView.subtitle setProgress(itemView.browseItem.videoId ?? "") + if (itemView?.browseItem.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } @@ -102,6 +112,14 @@ class MPPositive_ArtistShowSongTableViewCell: UITableViewCell, PKDownloadButtonD make.bottom.equalToSuperview().offset(-8*width) make.left.equalToSuperview().offset(18*width) } + contentView.addSubview(maskImageView) + maskImageView.snp.makeConstraints { make in + make.width.height.equalTo(iconImageView) + make.center.equalTo(iconImageView) + } + maskImageView.configure() + maskImageView.isHidden = true + maskImageView.stopAnimation() contentView.addSubview(moreBtn) moreBtn.snp.makeConstraints { make in make.width.height.equalTo(24*width) diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSingleCollectionViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSingleCollectionViewCell.swift index 4b22e24..c3898cf 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSingleCollectionViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSingleCollectionViewCell.swift @@ -6,8 +6,8 @@ // import UIKit - -class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { +import DownloadButton +class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell, PKDownloadButtonDelegate { ///封面图片 private lazy var coverImageView:UIImageView = { let imageView:UIImageView = .init() @@ -16,6 +16,7 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { imageView.layer.cornerRadius = 10*width return imageView }() + private lazy var maskImageView:MP_WaveAnimationMaskView = .init(frame: .init(x: 0, y: 0, width: 24*width, height: 24*width), cornerRadius: 10*width) ///标题 private lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left) ///副标题 @@ -27,19 +28,62 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { btn.addTarget(self, action: #selector(moreActionClick(_ :)), for: .touchUpInside) return btn }() + ///下载按钮 + private lazy var dowloadBtn:PKDownloadButton = { + let btn:PKDownloadButton = .init() + //开始下载状态 + btn.startDownloadButton.cleanDefaultAppearance() + btn.startDownloadButton.setBackgroundImage(UIImage(named: "Song_Unload'logo"), for: .normal) + //下载结束状态 + btn.downloadedButton.setBackgroundImage(UIImage(named: "Song_Loaded'logo"), for: .normal) + btn.downloadedButton.setAttributedTitle(nil, for: .normal) + //停止下载状态 + btn.stopDownloadButton.stopButton.setImage(UIImage(named: "download"), for: .normal) + btn.stopDownloadButton.tintColor = UIColor(hex: "#80F988") + btn.stopDownloadButton.stopButtonWidth = 2 + btn.stopDownloadButton.filledLineWidth = 3*width + btn.stopDownloadButton.filledLineStyleOuter = true + + //加载状态设置 + btn.pendingView.tintColor = UIColor(hex: "#80F988") + btn.pendingView.radius = 12*width + btn.pendingView.emptyLineRadians = 2*width + btn.pendingView.spinTime = 3 + btn.delegate = self + return btn + }() var moreBlock:(() -> Void)? + //删除 + var deleteBlock:(() -> Void)? + //取消 + var cancelBlock:(() -> Void)? var itemViewModel:MPPositive_BrowseItemViewModel!{ didSet{ - itemViewModel.setUrltoImage(coverImageView) - titleLabel.text = itemViewModel.title - subtitleLabel.text = itemViewModel.subtitle + itemViewModel?.setUrltoImage(coverImageView) + titleLabel.text = itemViewModel?.title + subtitleLabel.text = itemViewModel?.subtitle + setProgress(itemViewModel?.browseItem.videoId ?? "") + if (itemViewModel?.browseItem.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } override init(frame: CGRect) { super.init(frame: frame) + //注册通知 + NotificationCenter.notificationKey.add(observer: self, selector: #selector(downloadProgressAction(_ :)), notificationName: .download_progress_source) + NotificationCenter.notificationKey.add(observer: self, selector: #selector(downloadEndAction(_ :)), notificationName: .dowload_end_source) confirgue() } - + deinit { + NotificationCenter.default.removeObserver(self) + } required init?(coder: NSCoder) { super.init(coder: coder) } @@ -53,17 +97,31 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { make.left.equalToSuperview().offset(18*width) make.centerY.equalToSuperview() } + addSubview(maskImageView) + maskImageView.snp.makeConstraints { make in + make.width.height.equalTo(coverImageView) + make.center.equalTo(coverImageView) + } + maskImageView.configure() + maskImageView.isHidden = true + maskImageView.stopAnimation() addSubview(moreBtn) moreBtn.snp.makeConstraints { make in make.width.height.equalTo(24*width) make.centerY.equalTo(coverImageView.snp.centerY) make.right.equalToSuperview().offset(-5*width) } + addSubview(dowloadBtn) + dowloadBtn.snp.makeConstraints { make in + make.width.height.equalTo(24*width) + make.centerY.equalTo(moreBtn.snp.centerY) + make.right.equalTo(moreBtn.snp.left).offset(-8*width) + } addSubview(titleLabel) titleLabel.snp.makeConstraints { make in make.top.equalTo(coverImageView.snp.top).offset(10*width) make.left.equalTo(coverImageView.snp.right).offset(12*width) - make.right.equalTo(moreBtn.snp.left).offset(-12*width) + make.right.equalTo(dowloadBtn.snp.left).offset(-12*width) } addSubview(subtitleLabel) subtitleLabel.snp.makeConstraints { make in @@ -71,6 +129,19 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { make.left.right.equalTo(titleLabel) } } + //收到progress加载 + @objc private func downloadProgressAction(_ sender:Notification) { + if let dict = sender.object as? [String:String], let videoId = dict["videoId"], let currentVideoId = itemViewModel?.browseItem.videoId, videoId == currentVideoId { + //比较当前videoId + setProgress(videoId) + } + } + //收到下载结束 + @objc private func downloadEndAction(_ sender:Notification) { + if let dict = sender.object as? [String:String], let videoId = dict["videoId"], let currentVideoId = itemViewModel?.browseItem.videoId, videoId == currentVideoId { + setProgress(videoId) + } + } //点击更多 @objc private func moreActionClick(_ sender:UIButton) { guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { @@ -82,4 +153,122 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell { } moreBlock!() } + //根据输入videoId检索是否下载 + func setProgress(_ videoId:String) { + guard videoId.isEmpty == false, videoId == itemViewModel?.browseItem.videoId else { + DispatchQueue.main.async { + //未加入下载队列 + self.dowloadBtn.state = .startDownload + } + return + } + MP_DownloadManager.shared.loadQueue.async { + [weak self] in + guard let self = self else {return} + //判断是否下载完成 + MP_DownloadManager.shared.isDownloadedFileDocuments(videoId) { statu in + if statu == false { + //未下载,判断是否加入了下载队列 + if MP_DownloadManager.shared.isTasksQueue(for: videoId) { + //加入下载队列,确定是否活跃下中 + if MP_DownloadManager.shared.isActiveTask(for: videoId) { + DispatchQueue.main.async { + self.dowloadBtn.state = .downloading + } + //活跃中,获取下载值 + if let progress = MP_DownloadManager.shared.getProgress(for: videoId) { + //下载中 + DispatchQueue.main.async { + self.dowloadBtn.stopDownloadButton.progress = progress + } + } + }else { + //处于队列中,还未开始下载 + DispatchQueue.main.async { + //未加入下载队列 + self.dowloadBtn.state = .pending + } + } + }else { + //未加入下载队列 + DispatchQueue.main.async { + //未加入下载队列 + self.dowloadBtn.state = .startDownload + } + } + }else { + DispatchQueue.main.async { + //已经完成下载 + self.dowloadBtn.state = .downloaded + } + } + } + } + } + //下载按钮代理 + func downloadButtonTapped(_ downloadButton: PKDownloadButton!, currentState state: PKDownloadButtonState) { + var video:MPPositive_SongItemModel! + //根据当前按钮状态确定进度 + switch state { + case .startDownload://开始状态,点击后进入下载状态 + //检索当前网络状态 + guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { + MP_HUD.text("Weak connection.", delay: 2.0, completion: nil) + return + } + //检索当前歌曲是否下载过 + guard let videoId = itemViewModel.browseItem.videoId else { + return + } + //切换为准备状态 + downloadButton.state = .pending + //通过网络请求获取当前预览项资源(转为Song) + MP_NetWorkManager.shared.requestNextList("", videoId: videoId, clickTrackingParams: nil){ + [weak self] listSongs in + guard let self = self, let first = listSongs.first else { + //获取资源失败 + self?.setProgress(videoId) + return + } + let group = DispatchGroup() + group.enter() + improveDataforLycirsAndRelated(first) {(result) in + first.lyricsID = result.0 + first.relatedID = result.1 + group.leave() + } + group.enter() + //补全资源路径组和封面路径组 + improveDataforResouceAndCover(first) {(resourceUrls, coverUrls) in + if let resourceUrls = resourceUrls { + first.resourceUrls = resourceUrls.0 + first.itags = resourceUrls.1 + first.mimeTypes = resourceUrls.2 + } + first.coverUrls = coverUrls + group.leave() + } + group.notify(queue: .main, execute: { + [weak self] in + guard let self = self else { + self?.setProgress(videoId) + return + } + video = first + //事件打点 + MP_AnalyticsManager.shared.player_b_download_clickAction(video.videoId, videoname: video.title ?? "", artistname: video.shortBylineText ?? "") + //补全了数据,执行下载 + MP_DownloadManager.shared.prepareVideoDownloadTask(from: video) + }) + } + case .downloaded://已下载 + if let block = deleteBlock { + block() + } + default: + if let block = cancelBlock { + block() + } + } + } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift index 2466855..22a6728 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeSinglesTableViewCell.swift @@ -74,7 +74,7 @@ class MPPositive_HomeSinglesTableViewCell: UITableViewCell, UIViewControllerTran collectionView.snp.makeConstraints { make in make.top.equalTo(titleLabel.snp.bottom) make.left.right.equalToSuperview() - make.bottom.equalToSuperview().offset(-32*width).priority(999) + make.bottom.equalToSuperview().offset(-20*width).priority(999) } } //经过计算设置tableViewCell真实高度 @@ -98,8 +98,7 @@ extension MPPositive_HomeSinglesTableViewCell:UICollectionViewDataSource, UIColl cell.itemViewModel = browseViewModel.items[indexPath.row] cell.moreBlock = { [weak self] in - guard let self = self else {return} - let itemView = self.browseViewModel.items[indexPath.row] + guard let self = self, let itemView = self.browseViewModel?.items[indexPath.row] else {return} MPPositive_Debouncer.shared.call { MPPositive_ModalType = .MoreOperations let moreVC = MPPositive_MoreSongOperationsViewController(itemView) @@ -113,6 +112,44 @@ extension MPPositive_HomeSinglesTableViewCell:UICollectionViewDataSource, UIColl self.parentController()?.present(moreVC, animated: true) } } + cell.deleteBlock = { + [weak self] in + guard let self = self else {return} + //点击删除下载 + let alertController = UIAlertController(title: "Delete This Song", message: "Are you sure you want to delete the offline resources of this song?", preferredStyle: .alert) + let cancel = UIAlertAction(title: "Cancel", style: .cancel) + alertController.addAction(cancel) + let sure = UIAlertAction(title: "Sure", style: .destructive) {(action) in + guard let videoId = self.browseViewModel?.items[indexPath.row].browseItem.videoId else {return} + //确定删除 + MP_DownloadManager.shared.deleteFileDocuments(videoId) { videoId in + MP_HUD.progress("Loading...", delay: 0.5) { + MP_HUD.text("Removed", delay: 1.0, completion: nil) + collectionView.reloadData() + } + } + } + alertController.addAction(sure) + self.parentController()?.present(alertController, animated: true) + } + cell.cancelBlock = { + [weak self] in + guard let self = self else {return} + //点击取消下载 + let alertController = UIAlertController(title: "Cancel Song Download Task", message: "Are you sure you want to cancel the download task of this song?", preferredStyle: .alert) + let cancel = UIAlertAction(title: "Cancel", style: .cancel) + alertController.addAction(cancel) + let sure = UIAlertAction(title: "Sure", style: .destructive) {(action) in + guard let videoId = self.browseViewModel?.items[indexPath.row].browseItem.videoId else {return} + //确定取消 + MP_DownloadManager.shared.cancelDownloadTask(videoId) { videoId in + MP_HUD.text("Canceled", delay: 1.0, completion: nil) + collectionView.reloadData() + } + } + alertController.addAction(sure) + self.parentController()?.present(alertController, animated: true) + } return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_MusicItemShowTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_MusicItemShowTableViewCell.swift index 1e35533..d8bde46 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_MusicItemShowTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_MusicItemShowTableViewCell.swift @@ -17,6 +17,7 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe imageView.layer.cornerRadius = 10*width return imageView }() + private lazy var maskImageView:MP_WaveAnimationMaskView = .init(frame: .init(x: 0, y: 0, width: 24*width, height: 24*width), cornerRadius: 10*width) ///标题 private lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left) ///副标题 @@ -63,6 +64,15 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe subtitleLabel.text = itemView.subtitle rankLabel.isHidden = (itemView.coverUrl != nil) setProgress(itemView.browseItem.videoId ?? "") + if (itemView?.browseItem.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } var rank:Int = 0 { @@ -180,6 +190,14 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe make.top.equalToSuperview().offset(8*width).priority(999) make.bottom.equalToSuperview().offset(-8*width).priority(999) } + contentView.addSubview(maskImageView) + maskImageView.snp.makeConstraints { make in + make.width.height.equalTo(coverImageView) + make.center.equalTo(coverImageView) + } + maskImageView.configure() + maskImageView.isHidden = true + maskImageView.stopAnimation() contentView.addSubview(rankLabel) rankLabel.snp.makeConstraints { make in make.center.equalTo(coverImageView) @@ -235,8 +253,6 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe guard let videoId = itemView.browseItem.videoId else { return } - //未下载 -// MP_AdMobManager.shared.showLoadInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //通过网络请求获取当前预览项资源(转为Song) diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_RecommendShowTypeView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_RecommendShowTypeView.swift index 674ec5a..aa31d39 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_RecommendShowTypeView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_RecommendShowTypeView.swift @@ -7,7 +7,7 @@ import UIKit import MJRefresh -class MPPositive_RecommendShowTypeView: UIView, JXSegmentedListContainerViewListDelegate { +class MPPositive_RecommendShowTypeView: MPPositive_BaseShowView, JXSegmentedListContainerViewListDelegate { //tableView private lazy var tableView:UITableView = { let tableView = UITableView() diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchHistoryView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchHistoryView.swift index dba098d..733a6b7 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchHistoryView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchHistoryView.swift @@ -108,8 +108,12 @@ extension MPPositive_SearchHistoryView: UICollectionViewDataSource, UICollection return cell } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - if let text = historys[indexPath.row].text, let block = selectedTagBlock { - block(text) + MPPositive_Debouncer.shared.call { + [weak self] in + guard let self = self else {return} + if let text = historys[indexPath.row].text, let block = selectedTagBlock { + block(text) + } } } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultPreviewShowView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultPreviewShowView.swift index 8869699..5bad970 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultPreviewShowView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultPreviewShowView.swift @@ -7,7 +7,7 @@ import UIKit ///对搜索预览结果展示 -class MPPositive_SearchResultPreviewShowView: UIView, JXSegmentedListContainerViewListDelegate { +class MPPositive_SearchResultPreviewShowView: MPPositive_BaseShowView, JXSegmentedListContainerViewListDelegate { //tableView private lazy var tableView:UITableView = { let tableView = UITableView() diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultShowTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultShowTableViewCell.swift index 51166e8..e20cf46 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultShowTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultShowTableViewCell.swift @@ -17,6 +17,7 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto imageView.layer.cornerRadius = 10*width return imageView }() + private lazy var maskImageView:MP_WaveAnimationMaskView = .init(frame: .init(x: 0, y: 0, width: 24*width, height: 24*width), cornerRadius: 10*width) private lazy var titleLabel:UILabel = createLabel(font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left) private lazy var subtitleLabel:UILabel = createLabel(font: .systemFont(ofSize: 12*width, weight: .regular), textColor: .init(hex: "#FFFFFF", alpha: 0.6), textAlignment: .left) ///更多按钮 @@ -72,6 +73,15 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto titleLabel.text = songViewModel.title subtitleLabel.text = songViewModel.subtitle setProgress(songViewModel.collectionSong.videoId ?? "") + if (songViewModel?.collectionSong.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } var loadViewModel:MPPositive_DownloadViewModel!{ @@ -80,6 +90,15 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto titleLabel.text = loadViewModel.title subtitleLabel.text = loadViewModel.subtitle setProgress(loadViewModel.loadItem.videoId ?? "") + if (loadViewModel?.loadItem.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } var videoModel:MPPositive_CustomVideoModel!{ @@ -88,6 +107,15 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto titleLabel.text = videoModel.title subtitleLabel.text = videoModel.subtitle setProgress(videoModel.videoId ?? "") + if (videoModel?.videoId == MP_PlayerManager.shared.loadPlayer?.currentVideo?.song?.videoId) { + titleLabel.textColor = greenTextColor + maskImageView.isHidden = false + maskImageView.startAnimation() + }else { + titleLabel.textColor = .white + maskImageView.isHidden = true + maskImageView.stopAnimation() + } } } @@ -193,6 +221,14 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto make.bottom.equalToSuperview().offset(-8*width) make.left.equalToSuperview().offset(18*width) } + contentView.addSubview(maskImageView) + maskImageView.snp.makeConstraints { make in + make.width.height.equalTo(iconImageView) + make.center.equalTo(iconImageView) + } + maskImageView.configure() + maskImageView.isHidden = true + maskImageView.stopAnimation() contentView.addSubview(moreBtn) moreBtn.snp.makeConstraints { make in make.width.height.equalTo(24*width) diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultTypeShowView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultTypeShowView.swift index a46abf1..d60bc11 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultTypeShowView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultTypeShowView.swift @@ -8,7 +8,7 @@ import UIKit import MJRefresh ///对搜索结果进行分类详情展示 -class MPPositive_SearchResultTypeShowView: UIView, JXSegmentedListContainerViewListDelegate, UIViewControllerTransitioningDelegate { +class MPPositive_SearchResultTypeShowView: MPPositive_BaseShowView, JXSegmentedListContainerViewListDelegate, UIViewControllerTransitioningDelegate { //tableView private lazy var tableView:UITableView = { let tableView = UITableView() diff --git a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Base(基类-导航栏-标签栏-计时器-播放器)/MPSideA_TabBarController.swift b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Base(基类-导航栏-标签栏-计时器-播放器)/MPSideA_TabBarController.swift index 1ae63bf..f5b02ff 100644 --- a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Base(基类-导航栏-标签栏-计时器-播放器)/MPSideA_TabBarController.swift +++ b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Base(基类-导航栏-标签栏-计时器-播放器)/MPSideA_TabBarController.swift @@ -12,6 +12,7 @@ class MPSideA_TabBarController: UITabBarController, GADFullScreenContentDelegate private lazy var customTabBar:MPSideA_CustomTabBar = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 72*width)) //底部音乐展示View(默认隐藏) private lazy var bottomView:MPSideA_BottomShowView = .instanceFromNib() + var pushPlayerBlock:(() -> Void)? //底部bottomShowView的展示状态 private var isbottomShow:Bool = false{ willSet{ @@ -154,19 +155,28 @@ extension MPSideA_TabBarController: UIViewControllerTransitioningDelegate { print("Go to player") MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable { [weak self] ad in guard let self = self else {return} - //判断音乐播放器是否已经播放 - MP_AdMobManager.shared.isShowingPlayInterstitialAd = true - //播放器还未播放,可以弹出广告 - MP_AdMobManager.shared.setInterstitialSwitch(true) - ad.fullScreenContentDelegate = self - ad.present(fromRootViewController: self) + if let ad = ad { + //判断音乐播放器是否已经播放 + MP_AdMobManager.shared.isShowingPlayInterstitialAd = true + //播放器还未播放,可以弹出广告 + MP_AdMobManager.shared.setInterstitialSwitch(true) + ad.fullScreenContentDelegate = self + ad.present(fromRootViewController: self) + }else { + if let block = self.pushPlayerBlock { + block() + } + } } - //执行加载播放器页面 - DispatchQueue.main.async { + self.pushPlayerBlock = { [weak self] in - //模态弹出 - let playerVC = MPSideA_PlayerViewController() - self?.present(playerVC, animated: true) + //执行加载播放器页面 + DispatchQueue.main.async { + [weak self] in + //模态弹出 + let playerVC = MPSideA_PlayerViewController() + self?.present(playerVC, animated: true) + } } } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { @@ -261,9 +271,15 @@ extension MPSideA_TabBarController { func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) { if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告 print("当前展示的广告是播放插页广告,广告ID--\(MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? "")") - MP_AdMobManager.shared.playInterstitialAd?.paidEventHandler = { adValue in + if MP_AnalyticsManager.shared.infoFromAdMobSource(MP_AdMobManager.shared.playInterstitialAd?.responseInfo) { + MP_AdMobManager.shared.playInterstitialAd?.paidEventHandler = { adValue in + if let response = MP_AdMobManager.shared.playInterstitialAd?.responseInfo { + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + } + } + }else { if let response = MP_AdMobManager.shared.playInterstitialAd?.responseInfo { - MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: adValue) + MP_AnalyticsManager.shared.play_ads_showSuccessAction(response, adValue: .init()) } } } @@ -279,11 +295,8 @@ extension MPSideA_TabBarController { MP_AdMobManager.shared.completePlayInterstitialAdBlock!() } //执行加载播放器页面 - DispatchQueue.main.async { - [weak self] in - //模态弹出 - let playerVC = MPSideA_PlayerViewController() - self?.present(playerVC, animated: true) + if let block = self.pushPlayerBlock { + block() } } diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.swift b/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.swift index 9895a0d..b5719a4 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.swift @@ -11,6 +11,11 @@ class MPSideA_CenterTableViewCell: UITableViewCell { @IBOutlet weak var coverImageView: UIImageView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var durationLabel: UILabel! + @IBOutlet weak var maskAnimationView: MP_WaveAnimationMaskView!{ + didSet{ + maskAnimationView.configure() + } + } var musicView:MPSideA_MusicViewModel!{ didSet{ coverImageView.image = musicView.cover @@ -21,11 +26,15 @@ class MPSideA_CenterTableViewCell: UITableViewCell { //展示未播放状态 titleLabel.textColor = .init(hex: "#FFFFFF") durationLabel.textColor = .init(hex: "#FFFFFF") + maskAnimationView.isHidden = true + maskAnimationView.stopAnimation() return } //展示播放状态 titleLabel.textColor = .init(hex: "#80F988") durationLabel.textColor = .init(hex: "#80F988") + maskAnimationView.isHidden = false + maskAnimationView.startAnimation() } } var moreBlock:((UIButton) -> Void)? diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.xib b/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.xib index b6c29d7..0dd72a2 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.xib +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Center(个人资源)/MPSideA_CenterTableViewCell.xib @@ -10,7 +10,7 @@ - + @@ -81,8 +81,18 @@ + + @@ -106,6 +116,9 @@ + + + @@ -124,6 +137,7 @@ + diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.swift b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.swift index 10a7194..abe2159 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.swift +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.swift @@ -12,6 +12,11 @@ class MPSideA_Home_FirstListCollectionViewCell: UICollectionViewCell { @IBOutlet weak var stateBtn: UIButton! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var subtitleLabel: UILabel! + @IBOutlet weak var maskAnimationView: MP_WaveAnimationMaskView!{ + didSet{ + maskAnimationView.configure() + } + } var musicView:MPSideA_MusicViewModel!{ didSet{ coverImageView.image = musicView.cover @@ -23,12 +28,16 @@ class MPSideA_Home_FirstListCollectionViewCell: UICollectionViewCell { titleLabel.textColor = .init(hex: "#FFFFFF") subtitleLabel.textColor = .init(hex: "#FFFFFF") stateBtn.isSelected = false + maskAnimationView.isHidden = true + maskAnimationView.stopAnimation() return } //展示播放状态 titleLabel.textColor = .init(hex: "#80F988") subtitleLabel.textColor = .init(hex: "#80F988") stateBtn.isSelected = true + maskAnimationView.isHidden = false + maskAnimationView.startAnimation() } } override func awakeFromNib() { diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.xib b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.xib index 28a838f..a79e6ce 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.xib +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FirstListCollectionViewCell.xib @@ -10,7 +10,7 @@ - + @@ -20,6 +20,10 @@ + @@ -86,10 +90,14 @@ + + + + @@ -102,6 +110,7 @@ + diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.swift b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.swift index 81ffd48..7314edd 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.swift +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.swift @@ -11,7 +11,11 @@ class MPSideA_Home_FourthListCollectionViewCell: UICollectionViewCell { @IBOutlet weak var coverImageView: UIImageView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var subtitleLabel: UILabel! - @IBOutlet weak var shieldView: UIView! + @IBOutlet weak var maskAnimationView: MP_WaveAnimationMaskView!{ + didSet{ + maskAnimationView.configure() + } + } @IBOutlet weak var stateBtn: UIButton! var musicView:MPSideA_MusicViewModel!{ didSet{ @@ -24,14 +28,16 @@ class MPSideA_Home_FourthListCollectionViewCell: UICollectionViewCell { titleLabel.textColor = .init(hex: "#FFFFFF") subtitleLabel.textColor = .init(hex: "#FFFFFF") stateBtn.isSelected = false - shieldView.isHidden = true + maskAnimationView.isHidden = true + maskAnimationView.stopAnimation() return } //展示播放状态 titleLabel.textColor = .init(hex: "#80F988") subtitleLabel.textColor = .init(hex: "#80F988") stateBtn.isSelected = true - shieldView.isHidden = false + maskAnimationView.isHidden = false + maskAnimationView.startAnimation() } } override func awakeFromNib() { diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.xib b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.xib index 05223cb..8796443 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.xib +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_FourthListCollectionViewCell.xib @@ -10,7 +10,7 @@ - + @@ -37,30 +37,9 @@ - - diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.swift b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.swift index 10aa0a2..eed1c57 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.swift +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.swift @@ -11,7 +11,11 @@ class MPSideA_Home_SecondListCollectionViewCell: UICollectionViewCell { @IBOutlet weak var coverImageView: UIImageView! @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var subtitleLabel: UILabel! - @IBOutlet weak var shieldView: UIView! + @IBOutlet weak var maskAnimationView: MP_WaveAnimationMaskView!{ + didSet{ + maskAnimationView.configure() + } + } var musicView:MPSideA_MusicViewModel!{ didSet{ coverImageView.image = musicView.cover @@ -22,13 +26,15 @@ class MPSideA_Home_SecondListCollectionViewCell: UICollectionViewCell { //展示未播放状态 titleLabel.textColor = .init(hex: "#FFFFFF") subtitleLabel.textColor = .init(hex: "#FFFFFF") - shieldView.isHidden = true + maskAnimationView.isHidden = true + maskAnimationView.stopAnimation() return } //展示播放状态 titleLabel.textColor = .init(hex: "#80F988") subtitleLabel.textColor = .init(hex: "#80F988") - shieldView.isHidden = false + maskAnimationView.isHidden = false + maskAnimationView.startAnimation() } } override func awakeFromNib() { diff --git a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.xib b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.xib index 17aaf80..36da860 100644 --- a/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.xib +++ b/relax.offline.mp3.music/MP/MPSideA/Views/Home(音乐资源列表-播放器)/MPSideA_Home_SecondListCollectionViewCell.xib @@ -10,7 +10,7 @@ - + @@ -25,30 +25,9 @@ - - + @@ -114,6 +93,5 @@ -