diff --git a/Podfile b/Podfile index c21c7be..33e2481 100644 --- a/Podfile +++ b/Podfile @@ -29,6 +29,8 @@ pod "DownloadButton" pod 'Tiercel' #文本跑马灯 pod 'MarqueeLabel' + + #广告组 pod 'GoogleUserMessagingPlatform', '2.4.0' pod 'Google-Mobile-Ads-SDK', '11.4.0' diff --git a/Podfile.lock b/Podfile.lock index 89fc32a..06dc06b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -179,6 +179,6 @@ SPEC CHECKSUMS: Tiercel: c0a73f876a72800333b15f4e7e48791f4ad21e90 VungleAds: 4823f53e691ba140ff21e3a3a6897af789832a36 -PODFILE CHECKSUM: 6a95ca6014572e024266fe6dd05d870b42d7be49 +PODFILE CHECKSUM: 5af34d4e7dc09fde7b668a4368b6fc382756eebd COCOAPODS: 1.15.2 diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index 89fc32a..06dc06b 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -179,6 +179,6 @@ SPEC CHECKSUMS: Tiercel: c0a73f876a72800333b15f4e7e48791f4ad21e90 VungleAds: 4823f53e691ba140ff21e3a3a6897af789832a36 -PODFILE CHECKSUM: 6a95ca6014572e024266fe6dd05d870b42d7be49 +PODFILE CHECKSUM: 5af34d4e7dc09fde7b668a4368b6fc382756eebd COCOAPODS: 1.15.2 diff --git a/relax.offline.mp3.music.xcodeproj/project.pbxproj b/relax.offline.mp3.music.xcodeproj/project.pbxproj index 8b1fbf5..6af9251 100644 --- a/relax.offline.mp3.music.xcodeproj/project.pbxproj +++ b/relax.offline.mp3.music.xcodeproj/project.pbxproj @@ -22,6 +22,7 @@ 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 */; }; + CB0D07BB2C9AACD2005B9768 /* MP_AppLovinManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0D07BA2C9AACD2005B9768 /* MP_AppLovinManager.swift */; }; CB0D33972C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0D33962C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift */; }; CB0D339B2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0D339A2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift */; }; CB108C872C901A5E0017C40F /* MP_LuxServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB108C862C901A5E0017C40F /* MP_LuxServerManager.swift */; }; @@ -32,6 +33,7 @@ CB20A0702C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB20A06F2C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift */; }; CB2CAAD42C59DC1100EF691D /* MPPositive_TrashListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2CAAD32C59DC1100EF691D /* MPPositive_TrashListModel.swift */; }; CB2CAAD82C5A1AC500EF691D /* MP_IAPViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB2CAAD52C5A1AC500EF691D /* MP_IAPViewController.swift */; }; + CB51340E2C9C1E4800833AD5 /* MP_ADSimpleManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB51340D2C9C1E4800833AD5 /* MP_ADSimpleManager.swift */; }; CB6EEB8E2C5DFE6100AEC414 /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB6EEB8D2C5DFE6100AEC414 /* StoreKit.framework */; }; CB7FC5422C2AA01F00292A43 /* FacebookAEM in Frameworks */ = {isa = PBXBuildFile; productRef = CB7FC5412C2AA01F00292A43 /* FacebookAEM */; }; CB7FC5442C2AA01F00292A43 /* FacebookBasics in Frameworks */ = {isa = PBXBuildFile; productRef = CB7FC5432C2AA01F00292A43 /* FacebookBasics */; }; @@ -250,7 +252,7 @@ CBC2D6F82BFDF3D800E17703 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D6F72BFDF3D800E17703 /* Assets.xcassets */; }; CBC2D6FB2BFDF3D800E17703 /* Base in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D6FA2BFDF3D800E17703 /* Base */; }; CBC2D7D42BFDF4B900E17703 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = CBC2D7792BFDF4B900E17703 /* PrivacyInfo.xcprivacy */; }; - CBC3F2B22C3E76160075DC74 /* MPPositive_AdModelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */; }; + CBC3F2B22C3E76160075DC74 /* MPPositive_AdItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC3F2B12C3E76160075DC74 /* MPPositive_AdItemModel.swift */; }; CBC5E51D2C7D82A200336746 /* MPPositive_RecentlyModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC5E51C2C7D82A200336746 /* MPPositive_RecentlyModel.swift */; }; CBC5E51F2C7DAB8600336746 /* MPPositive_RecentlyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC5E51E2C7DAB8600336746 /* MPPositive_RecentlyViewModel.swift */; }; CBC81FBA2C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */; }; @@ -269,6 +271,7 @@ CBDBDDF62C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */; }; CBDC4A292C61B88300960649 /* relax.offline.mp3.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = CBDC4A272C61B88300960649 /* relax.offline.mp3.xcdatamodeld */; }; CBF3AEDA2C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF3AED92C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift */; }; + CBF769992C95678A00EF9B45 /* Devices.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF769982C95678A00EF9B45 /* Devices.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -298,6 +301,7 @@ 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 = ""; }; + CB0D07BA2C9AACD2005B9768 /* MP_AppLovinManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_AppLovinManager.swift; sourceTree = ""; }; CB0D33962C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PersonalListViewModel.swift; sourceTree = ""; }; CB0D339A2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PersonalisedRecommendationsTableViewCell.swift; sourceTree = ""; }; CB108C862C901A5E0017C40F /* MP_LuxServerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_LuxServerManager.swift; sourceTree = ""; }; @@ -308,6 +312,7 @@ CB20A06F2C53BDBF00FC5AFC /* MP_WebVisitorDataManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_WebVisitorDataManager.swift; sourceTree = ""; }; CB2CAAD32C59DC1100EF691D /* MPPositive_TrashListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_TrashListModel.swift; sourceTree = ""; }; CB2CAAD52C5A1AC500EF691D /* MP_IAPViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_IAPViewController.swift; sourceTree = ""; }; + CB51340D2C9C1E4800833AD5 /* MP_ADSimpleManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_ADSimpleManager.swift; sourceTree = ""; }; CB6EEB8D2C5DFE6100AEC414 /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; }; CB7FC5472C2AC25C00292A43 /* MPPositive_CenterListSearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CenterListSearchView.swift; sourceTree = ""; }; CBAFC9F22C0A10500054500E /* MP_BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MP_BaseViewController.swift; sourceTree = ""; }; @@ -543,7 +548,7 @@ CBC2D6FA2BFDF3D800E17703 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; CBC2D6FC2BFDF3D800E17703 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CBC2D7792BFDF4B900E17703 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_AdModelModel.swift; sourceTree = ""; }; + CBC3F2B12C3E76160075DC74 /* MPPositive_AdItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_AdItemModel.swift; sourceTree = ""; }; CBC5E51C2C7D82A200336746 /* MPPositive_RecentlyModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_RecentlyModel.swift; sourceTree = ""; }; CBC5E51E2C7DAB8600336746 /* MPPositive_RecentlyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_RecentlyViewModel.swift; sourceTree = ""; }; CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_HomeSinglesTableViewCell.swift; sourceTree = ""; }; @@ -562,6 +567,7 @@ CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_GrideMoodViewController.swift; sourceTree = ""; }; CBDC4A282C61B88300960649 /* MusicPlayer.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = MusicPlayer.xcdatamodel; sourceTree = ""; }; CBF3AED92C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PlayListsShowTypeView.swift; sourceTree = ""; }; + CBF769982C95678A00EF9B45 /* Devices.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Devices.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -679,6 +685,7 @@ CBAFCA012C0A10500054500E /* Notification.swift */, CBAFCA032C0A10500054500E /* TableView.swift */, CBB75FDC2C4F7AA60041665D /* UIImageView.swift */, + CBF769982C95678A00EF9B45 /* Devices.swift */, ); path = "Extension(扩展)"; sourceTree = ""; @@ -757,7 +764,9 @@ CBAFCA282C0A10500054500E /* MP_PlayerManager.swift */, CBAFCA202C0A10500054500E /* MP_AVURLAsset.swift */, CBAFCA1F2C0A10500054500E /* MP_AnalyticsManager.swift */, + CB51340D2C9C1E4800833AD5 /* MP_ADSimpleManager.swift */, CBB6372B2C1C17C300F1DEC9 /* MP_AdMobManager.swift */, + CB0D07BA2C9AACD2005B9768 /* MP_AppLovinManager.swift */, CBAFCA212C0A10500054500E /* MP_CacheManager.swift */, CBAFCA232C0A10500054500E /* MP_CoreDataHandlerManager.swift */, CBAFCA242C0A10500054500E /* MP_DownloadManager.swift */, @@ -815,7 +824,7 @@ isa = PBXGroup; children = ( CBAFCA3D2C0A10500054500E /* MPPositive_ArtistHeaderModel.swift */, - CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */, + CBC3F2B12C3E76160075DC74 /* MPPositive_AdItemModel.swift */, CBAFCA3E2C0A10500054500E /* MPPositive_BrowseItemModel.swift */, CBC5E51C2C7D82A200336746 /* MPPositive_RecentlyModel.swift */, CBC1FB792C50999800AC0633 /* MPPositive_LibraryItemModel.swift */, @@ -969,8 +978,8 @@ isa = PBXGroup; children = ( CBAFCA792C0A10500054500E /* MPPositive_CustomTabBar.swift */, - CBAFCA7A2C0A10500054500E /* MPPositive_CustomTabBarItem.swift */, CBAFCA7B2C0A10500054500E /* MPPositive_CustomTabBarView.swift */, + CBAFCA7A2C0A10500054500E /* MPPositive_CustomTabBarItem.swift */, CBAFCA782C0A10500054500E /* MPPositive_BottomShowView.swift */, CBAFCA7C2C0A10500054500E /* MPPositive_MoreOperationDownLoadTableViewCell.swift */, CB0033F52C295E3100B18FD3 /* MPPositive_MoreOperationShowTableViewCell.swift */, @@ -1637,7 +1646,7 @@ CBAFCB442C0A10500054500E /* MPPositive_PresentationController.swift in Sources */, CB0968752C2121410045E55B /* GADTSmallTemplateView.m in Sources */, CBAFCB9B2C0A10500054500E /* MPSideA_CenterTableViewCell.swift in Sources */, - CBC3F2B22C3E76160075DC74 /* MPPositive_AdModelModel.swift in Sources */, + CBC3F2B22C3E76160075DC74 /* MPPositive_AdItemModel.swift in Sources */, CBAFCB412C0A10500054500E /* MPPositive_BaseViewController.swift in Sources */, CBCBA7D92C6DFD93004E5BEF /* MPPositive_SortTypeViewController.swift in Sources */, CBAFCB4E2C0A10500054500E /* MPPositive_PlayerListShowViewController.swift in Sources */, @@ -1685,17 +1694,20 @@ CBC1FB802C50E59C00AC0633 /* MPPositive_HomeLibraryListstableViewCell.swift in Sources */, CBAFCB792C0A10500054500E /* MPSideA_AddViewController.swift in Sources */, CBAFCB5A2C0A10500054500E /* MPPositive_ArtistDescriptionTableViewCell.swift in Sources */, + CB51340E2C9C1E4800833AD5 /* MP_ADSimpleManager.swift in Sources */, CBAFCB272C0A10500054500E /* MPPositive_CollectionSongModel.swift in Sources */, CBAFCB562C0A10500054500E /* MPPositive_CustomTabBarView.swift in Sources */, CBAFCB6C2C0A10500054500E /* MPPositive_PlayerSilder.swift in Sources */, CBAFCB332C0A10500054500E /* MPPositive_CollectionSongViewModel.swift in Sources */, CBAFCB762C0A10500054500E /* MPSideA_LoadDataMusic.swift in Sources */, CBAFCB172C0A10500054500E /* MPPositive_JsonArtist.swift in Sources */, + CBF769992C95678A00EF9B45 /* Devices.swift in Sources */, CBAFCB1A2C0A10500054500E /* MPPositive_JsonListAlbum.swift in Sources */, CBAFCB1F2C0A10500054500E /* MPPositive_JsonSearchResults.swift in Sources */, CBAFCB362C0A10500054500E /* MPPositive_ListHeaderViewModel.swift in Sources */, CBAFCB0F2C0A10500054500E /* MP_LocationManager.swift in Sources */, CBAFCB5E2C0A10500054500E /* MPPositive_ArtistShowListCollectionViewCell.swift in Sources */, + CB0D07BB2C9AACD2005B9768 /* MP_AppLovinManager.swift in Sources */, CBAFCB6D2C0A10500054500E /* MPPositive_RecommendMemberCollectionViewCell.swift in Sources */, CB0D339B2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift in Sources */, CBAFCB2B2C0A10500054500E /* MPPositive_SearchTagModel.swift in Sources */, @@ -1899,7 +1911,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1.2.0.1; + CURRENT_PROJECT_VERSION = 1.2.1.1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH; @@ -1920,11 +1932,11 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.2.1; PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_Development; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_15ProDevelopment; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; @@ -1945,7 +1957,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1.2.0.1; + CURRENT_PROJECT_VERSION = 1.2.1.1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = ""; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH; @@ -1966,11 +1978,11 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.2.0; + MARKETING_VERSION = 1.2.1; PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_Development; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = Musiclax_15ProDevelopment; SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; SUPPORTS_MACCATALYST = NO; SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; 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 7099c58..3a90a4d 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 4a572eb..6d97d9e 100644 --- a/relax.offline.mp3.music/AppDelegate.swift +++ b/relax.offline.mp3.music/AppDelegate.swift @@ -16,6 +16,7 @@ import FacebookCore import StoreKit import UserMessagingPlatform + @_exported import IQKeyboardManagerSwift @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { @@ -47,8 +48,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { ActiveDaysCalculation() //FireBase初始化 FirebaseApp.configure() - //广告初始化 - MP_AdMobManager.shared.start() + //AdMob广告初始化 + MP_ADSimpleManager.shared.start() //启动前销毁所有的下载任务 MP_DownloadManager.shared.cancelAllTasksIfNeeded() setAudioSupport() @@ -195,9 +196,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { //算出与后台时间节点的差值 let duration = currentDate.timeIntervalSince(backDate) //获取插页间隔时长 - let times = MP_AdMobManager.shared.getOpenAppDuration() + let times = MP_ADSimpleManager.shared.platform ? MP_AppLovinManager.shared.getOpenAppDuration():MP_AdMobManager.shared.getOpenAppDuration() if duration >= times { - MP_AdMobManager.shared.showOpenAdIfAvailable(.HOST, completion: nil) + MP_ADSimpleManager.shared.showOpenAdIfAvailable(.HOST, completion: nil) //超过间隔时长,进行热启动广告展示 print("返回前台,并展示了热启动广告") }else { diff --git a/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/Contents.json b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/Contents.json new file mode 100644 index 0000000..4f9ec51 --- /dev/null +++ b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg 1.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg 1.png b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg 1.png new file mode 100644 index 0000000..657b662 Binary files /dev/null and b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg 1.png differ diff --git a/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg.png b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg.png new file mode 100644 index 0000000..657b662 Binary files /dev/null and b/relax.offline.mp3.music/Assets.xcassets/Positive/Player/Click_Download'logo.imageset/img_v3_02em_7d9ebc7f-0fde-40e7-ab5d-5b1c24a8ddbg.png differ 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 9b49e36..33e90c2 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 @@ -7,8 +7,9 @@ import UIKit import GoogleMobileAds +import AppLovinSDK ///启动页 -class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { +class MP_LunchViewController: UIViewController { @IBOutlet weak var progressView: MP_Lunch_ProgressView!{ didSet{ progressView.layer.masksToBounds = true @@ -131,13 +132,13 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { MPPositive_BrowseLoadViewModel.shared.reloadBrowseLists() } } - MP_AdMobManager.shared.loadMoreAdMobs() - MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad, isOpen) in + MP_ADSimpleManager.shared.loadMoreAds() + MP_ADSimpleManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad, isOpen, platform) in guard let self = self else {return} addValue = 3 //将广告事件传递闭包赋值 adShowBlock = { - self.adPresent(ad: ad, isOpen: isOpen) + self.adPresent(ad: ad, isOpen: isOpen, platform: platform) } } //进入过B面 @@ -170,13 +171,13 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { guard let self = self else {return} if open { //开关检测为通过,以下发ID刷新广告 - MP_AdMobManager.shared.loadMoreAdMobs() - MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad,isOpen) in + MP_ADSimpleManager.shared.loadMoreAds() + MP_ADSimpleManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad, isOpen, platform) in guard let self = self else {return} addValue = 3 //将广告事件传递闭包赋值 adShowBlock = { - self.adPresent(ad: ad, isOpen: isOpen) + self.adPresent(ad: ad, isOpen: isOpen, platform: platform) } } //根据ip值确定进入那个页面 @@ -258,13 +259,13 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { } }else { //开关检测未通过,以默认ID刷新广告 - MP_AdMobManager.shared.loadMoreAdMobs() - MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad,isOpen) in + MP_ADSimpleManager.shared.loadMoreAds() + MP_ADSimpleManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad, isOpen, platform) in guard let self = self else {return} addValue = 3 //将广告事件传递闭包赋值 adShowBlock = { - self.adPresent(ad: ad, isOpen: isOpen) + self.adPresent(ad: ad, isOpen: isOpen, platform: platform) } } print("ALog") @@ -299,43 +300,94 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate { } } //广告弹出 - private func adPresent(ad: GADFullScreenPresentingAd, isOpen:Bool) { + private func adPresent(ad: AnyObject, isOpen:Bool, platform:Bool) { DispatchQueue.main.async { - //printCallStack() - //修改插页总开关状态 - MP_AdMobManager.shared.setInterstitialSwitch(true) - MP_AdMobManager.shared.isShowingOpenAd = true - if isOpen { - let new = ad as? GADAppOpenAd - //覆盖并实现代理 - new?.fullScreenContentDelegate = self - do{ - try new?.canPresent(fromRootViewController: self) - new?.present(fromRootViewController: self) - }catch{ - print("开屏广告展示失败,失败原因:\(error)") - if MP_AdMobManager.shared.completeOpenAdBlock != nil { - MP_AdMobManager.shared.completeOpenAdBlock!() - } - - } + if platform { + //修改插页总开关状态 + MP_AppLovinManager.shared.setInterstitialSwitch(true) + MP_AppLovinManager.shared.isShowingOpenAd = true + //展示广告 + let new = ad as? MAInterstitialAd + new?.delegate = self + new?.show() }else { - let new = ad as? GADInterstitialAd - //覆盖并实现代理 - new?.fullScreenContentDelegate = self - do{ - try new?.canPresent(fromRootViewController: self) - new?.present(fromRootViewController: self) - }catch{ - print("开屏广告展示失败,失败原因:\(error)") - if MP_AdMobManager.shared.completeOpenAdBlock != nil { - MP_AdMobManager.shared.completeOpenAdBlock!() - } + //修改插页总开关状态 + MP_AdMobManager.shared.setInterstitialSwitch(true) + MP_AdMobManager.shared.isShowingOpenAd = true + if isOpen { + let new = ad as? GADAppOpenAd + //覆盖并实现代理 + new?.fullScreenContentDelegate = self + do{ + try new?.canPresent(fromRootViewController: self) + new?.present(fromRootViewController: self) + }catch{ + print("开屏广告展示失败,失败原因:\(error)") + if MP_AdMobManager.shared.completeOpenAdBlock != nil { + MP_AdMobManager.shared.completeOpenAdBlock!() + } + } + }else { + let new = ad as? GADInterstitialAd + //覆盖并实现代理 + new?.fullScreenContentDelegate = self + do{ + try new?.canPresent(fromRootViewController: self) + new?.present(fromRootViewController: self) + }catch{ + print("开屏广告展示失败,失败原因:\(error)") + if MP_AdMobManager.shared.completeOpenAdBlock != nil { + MP_AdMobManager.shared.completeOpenAdBlock!() + } + + } } } } } +} +extension MP_LunchViewController: GADFullScreenContentDelegate, MAAdDelegate{ + func didLoad(_ ad: MAAd) { + } + + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + } + + func didDisplay(_ ad: MAAd) { + if ad.adUnitIdentifier == MP_AppLovinManager.shared.appOpenAd?.adUnitIdentifier { + print("当前展示的广告是开屏广告,广告ID--\(ad.adUnitIdentifier)") + //上传成功事件 + MP_AnalyticsManager.shared.max_lunch_showSuccessAction() + } + } + + func didHide(_ ad: MAAd) { + //当前启动页,展示广告一定是开屏广告 + if switchBlock != nil { + switchBlock!() + } + if MP_AppLovinManager.shared.completeOpenAdBlock != nil { + MP_AppLovinManager.shared.completeOpenAdBlock!() + } + print("冷启动广告关闭") + MP_AnalyticsManager.shared.cold_ads_closeAction() + } + + func didClick(_ ad: MAAd) { + } + + func didFail(toDisplay ad: MAAd, withError error: MAError) { + //当前启动页,展示广告一定是开屏广告 + if switchBlock != nil { + switchBlock!() + } + MP_AnalyticsManager.shared.max_lunch_showFailureAction(error.message) + if MP_AppLovinManager.shared.completeOpenAdBlock != nil { + MP_AppLovinManager.shared.completeOpenAdBlock!() + } + } + //MARK: - 覆盖型广告代理 GADFullScreenContentDelegate //覆盖型广告将要将要展示 func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) { diff --git a/relax.offline.mp3.music/MP/Common/Extension(扩展)/Devices.swift b/relax.offline.mp3.music/MP/Common/Extension(扩展)/Devices.swift new file mode 100644 index 0000000..4c84cee --- /dev/null +++ b/relax.offline.mp3.music/MP/Common/Extension(扩展)/Devices.swift @@ -0,0 +1,116 @@ +// +// Devices.swift +// relax.offline.mp3.music +// +// Created by Mr.Zhou on 2024/9/14. +// + +import UIKit + +extension UIDevice { + var modelName: String { + var systemInfo = utsname() + uname(&systemInfo) + let machineMirror = Mirror(reflecting: systemInfo.machine) + let identifier = machineMirror.children.reduce("") { identifier, element in + guard let value = element.value as? Int8, value != 0 else { return identifier } + return identifier + String(UnicodeScalar(UInt8(value))) + } + + return mapToDevice(identifier: identifier) + } + + private func mapToDevice(identifier: String) -> String { + #if os(iOS) + switch identifier { + case "iPhone1,1": return "iPhone" + case "iPhone1,2": return "iPhone 3G" + case "iPhone2,1": return "iPhone 3GS" + case "iPhone3,1", "iPhone3,2", "iPhone3,3": return "iPhone 4" + case "iPhone4,1", "iPhone4,2", "iPhone4,3": return "iPhone 4S" + case "iPhone5,1", "iPhone5,2": return "iPhone 5" + case "iPhone5,3", "iPhone5,4": return "iPhone 5C" + case "iPhone6,1", "iPhone6,2": return "iPhone 5S" + case "iPhone7,2": return "iPhone 6" + case "iPhone7,1": return "iPhone 6 Plus" + case "iPhone8,1": return "iPhone 6S" + case "iPhone8,2": return "iPhone 6S Plus" + case "iPhone8,4": return "iPhone SE" + case "iPhone9,1", "iPhone9,3": return "iPhone 7" + case "iPhone9,2", "iPhone9,4": return "iPhone 7 Plus" + case "iPhone10,1", "iPhone10,4": return "iPhone 8" + case "iPhone10,2", "iPhone10,5": return "iPhone 8 Plus" + case "iPhone10,3", "iPhone10,6": return "iPhone X" + case "iPhone11,2": return "iPhone Xs" + case "iPhone11,4", "iPhone11,6": return "iPhone Xs Max" + case "iPhone11,8": return "iPhone Xʀ" + case "iPhone12,1": return "iPhone 11" + case "iPhone12,3": return "iPhone 11 Pro" + case "iPhone12,5": return "iPhone 11 Pro Max" + case "iPhone12,8": return "iPhone SE 2" + case "iPhone13,1": return "iPhone 12 mini" + case "iPhone13,2": return "iPhone 12" + case "iPhone13,3": return "iPhone 12 Pro" + case "iPhone13,4": return "iPhone 12 Pro Max" + case "iPhone14,4": return "iPhone 13 mini" + case "iPhone14,5": return "iPhone 13" + case "iPhone14,2": return "iPhone 13 Pro" + case "iPhone14,3": return "iPhone 13 Pro Max" + case "iPhone14,6": return "iPhone SE 3" + case "iPhone14,7": return "iPhone 14" + case "iPhone14,8": return "iPhone 14 Plus" + case "iPhone15,2": return "iPhone 14 Pro" + case "iPhone15,3": return "iPhone 14 Pro Max" + case "iPhone15,4": return "iPhone 15" + case "iPhone15,5": return "iPhone 15 Plus" + case "iPhone16,1": return "iPhone 15 Pro" + case "iPhone16,2": return "iPhone 15 Pro Max" + case "iPhone17,3": return "iPhone 16" + case "iPhone17,4": return "iPhone 16 Plus" + case "iPhone17,1": return "iPhone 16 Pro" + case "iPhone17,2": return "iPhone 16 Pro Max" + // iPad + case "iPad1,1": return "iPad" + case "iPad2,1", "iPad2,2", "iPad2,3", "iPad2,4": return "iPad 2" + case "iPad3,1", "iPad3,2", "iPad3,3": return "iPad (3rd generation)" + case "iPad3,4", "iPad3,5", "iPad3,6": return "iPad (4th generation)" + case "iPad6,11", "iPad6,12": return "iPad (5th generation)" + case "iPad7,5", "iPad7,6": return "iPad (6th generation)" + case "iPad7,11", "iPad7,12": return "iPad (7th generation)" + case "iPad11,6", "iPad11,7": return "iPad (8th generation)" + case "iPad12,1", "iPad12,2": return "iPad (9th generation)" + case "iPad13,18", "iPad13,19": return "iPad (10th generation)" + // iPad Air + case "iPad4,1", "iPad4,2", "iPad4,3": return "iPad Air" + case "iPad5,3", "iPad5,4": return "iPad Air 2" + case "iPad11,3", "iPad11,4": return "iPad Air (3rd generation)" + case "iPad13,1", "iPad13,2": return "iPad Air (4th generation)" + case "iPad13,16", "iPad13,17": return "iPad Air (5th generation)" + // iPad mini + case "iPad2,5", "iPad2,6", "iPad2,7": return "iPad mini" + case "iPad4,4", "iPad4,5", "iPad4,6": return "iPad mini 2" + case "iPad4,7", "iPad4,8", "iPad4,9": return "iPad mini 3" + case "iPad5,1", "iPad5,2": return "iPad mini 4" + case "iPad11,1", "iPad11,2": return "iPad mini (5th generation)" + case "iPad14,1", "iPad14,2": return "iPad mini (6th generation)" + // iPad Pro + case "iPad6,7", "iPad6,8": return "iPad Pro (12.9-inch)" + case "iPad6,3", "iPad6,4": return "iPad Pro (9.7-inch)" + case "iPad7,1", "iPad7,2": return "iPad Pro (12.9-inch, 2nd generation)" + case "iPad7,3", "iPad7,4": return "iPad Pro (10.5-inch)" + case "iPad8,1", "iPad8,2", "iPad8,3", "iPad8,4": return "iPad Pro (11-inch, 1st generation)" + case "iPad8,5", "iPad8,6", "iPad8,7", "iPad8,8": return "iPad Pro (12.9-inch, 3rd generation)" + case "iPad8,9", "iPad8,10": return "iPad Pro (11-inch, 2nd generation)" + case "iPad8,11", "iPad8,12": return "iPad Pro (12.9-inch, 4th generation)" + case "iPad13,4", "iPad13,5", "iPad13,6", "iPad13,7": return "iPad Pro (11-inch, 3rd generation)" + case "iPad13,8", "iPad13,9", "iPad13,10", "iPad13,11": return "iPad Pro (12.9-inch, 5th generation)" + case "iPad14,3", "iPad14,4": return "iPad Pro (11-inch, 4th generation)" + case "iPad14,5", "iPad14,6": return "iPad Pro (12.9-inch, 6th generation)" + // Add more cases here as needed + default: return identifier + } + #else + return identifier + #endif + } +} diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/ar.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/ar.lproj/Localizable.strings index eca63db..d2db4b7 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/ar.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/ar.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "ليس الآن"; ///更新提醒 "Update available" = "تحديث متاح"; +///切换至离线歌单 +"You are in offline mode" = "أنت في وضع عدم الاتصال بالإنترنت"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "تم نسخ عنوان البريد الإلكتروني بنجاح إلى الحافظة"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/de.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/de.lproj/Localizable.strings index 37cd695..903907e 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/de.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/de.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Nicht jetzt"; ///更新提醒 "Update available" = "Aktualisierung verfügbar"; +///切换至离线歌单 +"You are in offline mode" = "Sie befinden sich im Offline-Modus"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "E-Mail-Adresse erfolgreich in die Zwischenablage kopiert"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/en.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/en.lproj/Localizable.strings index 65927ef..49341a5 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/en.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/en.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Not now"; ///更新提醒 "Update available" = "Update available"; +///切换至离线歌单 +"You are in offline mode" = "You are in offline mode"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Successfully copied the e-mail address to the clipboard"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/es-419.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/es-419.lproj/Localizable.strings index cefa3c2..87a908e 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/es-419.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/es-419.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Ahora no"; ///更新提醒 "Update available" = "Actualización disponible"; +///切换至离线歌单 +"You are in offline mode" = "Estás en modo fuera de línea"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Dirección de correo electrónico copiada correctamente al portapapeles"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/fr.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/fr.lproj/Localizable.strings index e4b6100..fff4495 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/fr.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/fr.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Pas maintenant"; ///更新提醒 "Update available" = "Mise à jour disponible"; +///切换至离线歌单 +"You are in offline mode" = "Vous êtes en mode hors ligne"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Adresse e-mail copiée avec succès dans le presse-papiers"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/it.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/it.lproj/Localizable.strings index 9d5318c..2cb2976 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/it.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/it.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Non ora"; ///更新提醒 "Update available" = "Aggiornamento disponibile"; +///切换至离线歌单 +"You are in offline mode" = "Sei in modalità offline"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Indirizzo email copiato con successo negli appunti"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/pt-BR.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/pt-BR.lproj/Localizable.strings index 16ca6f1..0deec33 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/pt-BR.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/pt-BR.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Não agora"; ///更新提醒 "Update available" = "Atualização disponível"; +///切换至离线歌单 +"You are in offline mode" = "Você está no modo offline"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Endereço de e-mail copiado com sucesso para a área de transferência"; diff --git a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/tr.lproj/Localizable.strings b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/tr.lproj/Localizable.strings index 4ce08d3..511b72f 100644 --- a/relax.offline.mp3.music/MP/Common/Localizable(本地化)/tr.lproj/Localizable.strings +++ b/relax.offline.mp3.music/MP/Common/Localizable(本地化)/tr.lproj/Localizable.strings @@ -142,6 +142,8 @@ "Not now" = "Şimdi değil"; ///更新提醒 "Update available" = "Güncelleme mevcut"; +///切换至离线歌单 +"You are in offline mode" = "Çevrimdışı moddasınız"; //MARK: - HUD文本 ///已成功将电子邮件地址复制到剪贴板 "Successfully copied the e-mail address to the clipboard" = "Herhangi bir yorumunuz veya öneriniz varsa lütfen aşağıdaki e-posta adresinden bizimle iletişime geçin."; diff --git a/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift b/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift index 95dcfbe..e99a362 100644 --- a/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift +++ b/relax.offline.mp3.music/MP/Common/Macro(宏定义与全局量)/Macro.swift @@ -174,6 +174,34 @@ func coreDefaultValues() { UserDefaults.standard.set(array, forKey: "LibraryNATIVEID") } } + if UserDefaults.standard.object(forKey: "Max_OpenICEIDs") == nil { + if let array = coreAdModelforJson([.init(level: 3, identifier: "1dd2cf325a0eb64d", ad: "AppLovin", type: .Insert)]) { + //存入默认开屏热启动广告ID + UserDefaults.standard.set(array, forKey: "Max_OpenICEIDs") + } + } + if UserDefaults.standard.object(forKey: "Max_SearchINSERTIDs") == nil { + if let array = coreAdModelforJson([.init(level: 3, identifier: "43414b9a63224bc6", ad: "AppLovin", type: .Insert)]) { + //存入默认开屏热启动广告ID + UserDefaults.standard.set(array, forKey: "Max_SearchINSERTIDs") + } + } + if UserDefaults.standard.object(forKey: "Max_PlayerINSERTIDs") == nil { + if let array = coreAdModelforJson([.init(level: 3, identifier: "e13ab66866fd6bf8", ad: "AppLovin", type: .Insert)]) { + //存入默认开屏热启动广告ID + UserDefaults.standard.set(array, forKey: "Max_PlayerINSERTIDs") + } + } + if UserDefaults.standard.object(forKey: "Max_LibraryNATIVEIDs") == nil { + if let array = coreAdModelforJson([.init(level: 3, identifier: "4f3858556dc405ee", ad: "AppLovin", type: .Insert)]) { + //存入默认开屏热启动广告ID + UserDefaults.standard.set(array, forKey: "Max_LibraryNATIVEIDs") + } + } + if UserDefaults.standard.object(forKey: "platform") == nil { + UserDefaults.standard.set(false, forKey: "platform") + } + //更多内容操作 if UserDefaults.standard.string(forKey: "ClientVersion") == nil { UserDefaults.standard.set("1.20240618.01.00", forKey: "ClientVersion") @@ -205,7 +233,7 @@ func coreDefaultValues() { } } ///将广告模型组转为Data -func coreAdModelforJson(_ array:[MPPositive_AdModelModel]) -> Data? { +func coreAdModelforJson(_ array:[MPPositive_AdItemModel]) -> Data? { guard array.isEmpty != true else {return nil} do{ let jsonData = try JSONEncoder().encode(array) @@ -217,9 +245,9 @@ func coreAdModelforJson(_ array:[MPPositive_AdModelModel]) -> Data? { } } ///将data转为广告模型组 -func jsonforCoreAdModel(_ data:Data) -> [MPPositive_AdModelModel]? { +func jsonforCoreAdModel(_ data:Data) -> [MPPositive_AdItemModel]? { do{ - let array:[MPPositive_AdModelModel] = try JSONDecoder().decode([MPPositive_AdModelModel].self, from: data) + let array:[MPPositive_AdItemModel] = try JSONDecoder().decode([MPPositive_AdItemModel].self, from: data) return array }catch{ //编译失败 @@ -265,10 +293,12 @@ func improveDataforLycirsAndRelated(_ song:MPPositive_SongItemModel, completion: } } ///调用player对资源路径和封面路径补全 -func improveDataforResouceAndCover(_ song:MPPositive_SongItemModel, completion:@escaping((([String],[Int],[String])?, [String]?) -> Void)) { +func improveDataforResouceAndCover(_ song:MPPositive_SongItemModel, completion:@escaping((([String],[Int],[String])?, [String]?) -> Void), failure: ((Bool) -> Void)? = nil) { //单曲补全需要调用player接口 MP_NetWorkManager.shared.requestAndroidPlayer(song.videoId ?? "", playlistId: "", clickTrackingParams: song.clickTrackingParams ?? "") { resourceUrls, coverUrls in completion(resourceUrls,coverUrls) + } failure: {statu in + failure?(statu) } } ///转时分值 @@ -535,3 +565,43 @@ func postUpdateReminder(_ observe:UIViewController) { MP_AnalyticsManager.shared.update_reminder_showAction() observe.present(alter, animated: true) } +///从离线第一首开始播放 +func playOfflineSongs() { + if MPPositive_LoadCoreModel.shared.loadViewModels.isEmpty == false { + MP_HUD.text("You are in offline mode".localizableString(), delay: 2.0, completion: nil) + //获取离线的歌曲 + MP_AnalyticsManager.shared.song_clickAction("Offline Song") + //优先清除数据 + MP_PlayerManager.shared.loadPlayer = nil + //弹出播放器 + NotificationCenter.notificationKey.post(notificationName: .pup_player_vc) + MP_AnalyticsManager.shared.player_b_impAction() + //将当前下载音乐放入列表中 + var array:[MPPositive_SongItemModel] = [] + for (index, song) in MPPositive_LoadCoreModel.shared.loadViewModels.enumerated() { + let item = MPPositive_SongItemModel() + item.index = index + item.coverUrls = [song.loadItem.coverImage ?? ""] + item.reviewUrls = [song.loadItem.reviewImage ?? ""] + item.title = song.loadItem.title + item.longBylineText = song.loadItem.longBylineText + item.lengthText = song.loadItem.lengthText + item.shortBylineText = song.loadItem.shortBylineText + item.lyricsID = song.loadItem.lyricsID + item.lyrics = song.loadItem.lyrics + item.videoId = song.loadItem.videoId + item.relatedID = song.loadItem.relatedID + array.append(item) + } + if let currentVideo = MPPositive_LoadCoreModel.shared.loadViewModels.first { + let lodaViewModel = MPPositive_PlayerLoadViewModel(array, currentVideoId: currentVideo.loadItem.videoId ?? "") + lodaViewModel.improveData(currentVideo.loadItem.videoId ?? "") + //更改播放器播放类型 + MP_PlayerManager.shared.setPlayType(.normal) + MP_PlayerManager.shared.loadPlayer = lodaViewModel + MP_AnalyticsManager.shared.player_b_listAction() + } + }else { + MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + } +} diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift index 507c3a7..e0690fc 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MPPositive_Debouncer.swift @@ -11,12 +11,16 @@ class MPPositive_Debouncer: NSObject { static let shared = MPPositive_Debouncer() //计时器 private var timer: Timer? + //播放器计时器 + private var playerTimer:Timer? private override init() { super.init() } deinit { timer?.invalidate() timer = nil + playerTimer?.invalidate() + playerTimer = nil } func call(_ delay:TimeInterval = 0.15, action:@escaping (() -> Void)) { // 取消之前的延迟调用 @@ -27,4 +31,11 @@ class MPPositive_Debouncer: NSObject { action() } } + func playCall(_ action:@escaping (() -> Void)) { + playerTimer?.invalidate() + playerTimer = nil + playerTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { _ in + action() + } + } } diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_ADSimpleManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_ADSimpleManager.swift new file mode 100644 index 0000000..95e9c6f --- /dev/null +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_ADSimpleManager.swift @@ -0,0 +1,198 @@ +// +// MP_ADSimpleManager.swift +// relax.offline.mp3.music +// +// Created by Mr.Zhou on 2024/9/19. +// + +import UIKit +import AVFoundation +import GoogleMobileAds +import AppLovinAdapter +import AppLovinSDK +import LiftoffMonetizeAdapter +import VungleAdsSDK +import PangleAdapter +import PAGAdSDK +import IronSourceAdapter +import IronSource +import MintegralAdapter +import MTGSDK +import ChartboostSDK +import ChartboostAdapter +//开屏广告类型 +enum OpenType:Int { + //冷启动 + case ICE = 0 + //热启动 + case HOST = 1 + var title:String{ + switch self { + case .ICE: + return "是冷启动开屏广告" + case .HOST: + return "是热启动开屏广告" + } + } +} +///广告中央管理器 +class MP_ADSimpleManager: NSObject { + static let shared = MP_ADSimpleManager() + //调用的广告平台, false为AdMob,ture为AppLovin + var platform:Bool{ + if let newValue = UserDefaults.standard.object(forKey: "platform") as? Bool { + return newValue + }else { + return false + } + } + ///广告总开关 + var openAdStatus:Bool = true + ///内部使用广告开光 + var internalAdStatus:Bool = true + ///设置广告总开关 + func setOpenAdStatus(_ bool:Bool) { + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + openAdStatus = bool + } + } + ///插页广告总开关 + private var interstitialSwitch:Bool { + get { + if platform { + return MP_AppLovinManager.shared.getInterstitialSwitch() + }else { + return MP_AdMobManager.shared.getInterstitialSwitch() + } + } + } + ///获得插页开关的状态 + func getInterstitialSwitch() -> Bool { + return interstitialSwitch + } + override init() { + super.init() + NotificationCenter.notificationKey.add(observer: self, selector: #selector(netWorkReachableAction(_:)), notificationName: .net_switch_reachable) + } + deinit{ + NotificationCenter.default.removeObserver(self) + } + //启动广告初始化 + func start() { + MP_AdMobManager.shared.start() + MP_AppLovinManager.shared.startConfig() + } + + //网络可用时触发 + @objc private func netWorkReachableAction(_ sender:Notification) { + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + guard openAdStatus, internalAdStatus else {return} + if platform { + MP_AppLovinManager.shared.loadMoreAds() + }else { + MP_AdMobManager.shared.loadMoreAdMobs() + } + } + } + //加载更多广告 + func loadMoreAds() { + guard openAdStatus, internalAdStatus else {return} + if platform { + MP_AppLovinManager.shared.loadMoreAds() + }else { + MP_AdMobManager.shared.loadMoreAdMobs() + } + } + ///展示开屏广告 + func showOpenAdIfAvailable(_ type:OpenType, completion:((_ ad:AnyObject, _ isOpen:Bool, _ platform:Bool) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + if platform { + if let block = completion { + MP_AppLovinManager.shared.showOpenAdIfAvailable {[weak self] ad in + guard let self = self else {return} + block(ad, false, true) + } + }else { + MP_AppLovinManager.shared.showOpenAdIfAvailable(nil) + } + }else { + if let block = completion { + MP_AdMobManager.shared.showOpenAdIfAvailable(type) { [weak self] ad, isOpen in + guard let self = self else {return} + block(ad, isOpen, false) + } + }else { + MP_AdMobManager.shared.showOpenAdIfAvailable(type, completion: nil) + } + } + } + ///展示搜索广告 + func showSearchInterstitialAdIfAvailable(completion:((AnyObject, Bool) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + if platform { + if let block = completion { + MP_AppLovinManager.shared.showSearchInterstitialAdIfAvailable { ad in + block(ad, true) + } + }else { + MP_AppLovinManager.shared.showSearchInterstitialAdIfAvailable(nil) + } + }else { + if let block = completion { + MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable { ad in + block(ad, false) + } + }else { + MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable(completion: nil) + } + } + } + ///展示播放广告 + func showPlayInterstitialAdIfAvailable(_ completion:((AnyObject?, Bool) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + if platform { + if let block = completion { + MP_AppLovinManager.shared.showPlayInterstitialAdIfAvailable { ad in + block(ad, true) + } + }else { + MP_AppLovinManager.shared.showPlayInterstitialAdIfAvailable(nil) + } + }else { + if let block = completion { + MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable { ad in + block(ad, false) + } + }else { + MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable(completion: nil) + } + } + } + ///展示曲库广告 + func showLibraryInterstitialAdIfAvailable(completion:((AnyObject) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + if platform { + if let block = completion { + MP_AppLovinManager.shared.showLibraryInterstitialAdIfAvailable { ad in + block(ad) + } + }else { + MP_AppLovinManager.shared.showLibraryInterstitialAdIfAvailable(nil) + } + }else { + if let block = completion { + MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable { ad in + block(ad) + } + }else { + MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + } + } + } +} + + 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 be6ce59..a6b36ce 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AdMobManager.swift @@ -21,23 +21,15 @@ import MTGSDK import ChartboostSDK import ChartboostAdapter -///广告管理器 +///AdMob广告管理器 class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenContentDelegate, GADNativeAdLoaderDelegate, GADNativeAdDelegate, GADVideoControllerDelegate { static let shared = MP_AdMobManager() - private let sharedInstance = GADMobileAds.sharedInstance() ///广告总开关 - private var openAdStatus:Bool = true + private var openAdStatus:Bool = MP_ADSimpleManager.shared.openAdStatus ///内部使用广告开光 - private var internalAdStatus:Bool = true + private var internalAdStatus:Bool = MP_ADSimpleManager.shared.internalAdStatus - ///设置广告总开关 - func setOpenAdStatus(_ bool:Bool) { - DispatchQueue.main.async { - [weak self] in - guard let self = self else {return} - openAdStatus = bool - } - } + private let sharedInstance = GADMobileAds.sharedInstance() ///广告过期时间(50分钟) private let expirationTime:TimeInterval = 3000 @@ -53,7 +45,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont didSet{ DispatchQueue.main.async { [weak self] in -// MP_PlayerManager.shared.isAdLate = self?.interstitialSwitch MPSideA_MediaCenterManager.shared.isAdLate = self?.interstitialSwitch } } @@ -326,7 +317,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } ///加载更多广告 func loadMoreAdMobs() { - guard openAdStatus, internalAdStatus else {return} loadPlayInterstitialAd{status in if status { print("成功加载播放插页广告") @@ -341,13 +331,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont print("搜索插页广告加载失败") } } -// loadSwitchInterstitialAd { status in -// if status { -// print("成功加载切歌插页广告") -// }else { -// print("切歌插页广告加载失败") -// } -// } loadLibraryInterstitialAd { status in if status { print("成功加载曲库插页广告") @@ -356,20 +339,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } } -// loadGlobalInterstitialAd { status in -// if status { -// print("成功加载全局插页广告") -// }else { -// print("全局插页广告加载失败") -// } -// } -// loadLoadInterstitialAd { status in -// if status { -// print("成功加载下载插页广告") -// }else { -// print("下载插页广告加载失败") -// } -// } } //网络可用时触发 @objc private func netWorkReachableAction(_ sender:Notification) { @@ -411,24 +380,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } //MARK: - 开屏 //开屏冷启动广告ID - private var OpenICEID:[MPPositive_AdModelModel] = [] + private var OpenICEID:[MPPositive_AdItemModel] = [] //开屏热启动广告ID - private var OpenHOSTID:[MPPositive_AdModelModel] = [] - //开屏广告类型 - enum OpenType:Int { - //冷启动 - case ICE = 0 - //热启动 - case HOST = 1 - var title:String{ - switch self { - case .ICE: - return "是冷启动开屏广告" - case .HOST: - return "是热启动开屏广告" - } - } - } + private var OpenHOSTID:[MPPositive_AdItemModel] = [] //应用开屏广告实例 var appOpenAd:GADAppOpenAd? //应用插页广告实例 @@ -439,7 +393,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont var isShowingOpenAd:Bool = false //开屏广告加载时间 private var loadOpenAdTime:Date? - //开屏广告时间间隔(默认5秒) + //开屏广告时间间隔(默认10秒) private var openAppDuration:TimeInterval{ get{ if let times = UserDefaults.standard.object(forKey: "OpenAppDuration") as? TimeInterval { @@ -470,7 +424,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont return } //检索是否超过了对应的id组的阶级数量 - var item:MPPositive_AdModelModel + var item:MPPositive_AdItemModel switch type { case .ICE: guard OpenICEID.isEmpty == false else { @@ -517,13 +471,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } isLoadingOpenAd = true let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //判断需要生成什么广告 if item.type == .Open { @@ -673,9 +620,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont //MARK: - 搜索 //搜索插页广告ID - private var SearchINSERTID:[MPPositive_AdModelModel] = [] + private var SearchINSERTID:[MPPositive_AdItemModel] = [] //搜索原生广告ID - private var SearchNATIVEID:[MPPositive_AdModelModel] = [] + private var SearchNATIVEID:[MPPositive_AdItemModel] = [] ///搜索插页广告 private var searchInterstitialAd:GADInterstitialAd? ///是否正在加载搜索插页广告 @@ -725,13 +672,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont searchAdLoader = GADAdLoader(adUnitID: first.identifier, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions, imageAdOptions, videoAdOptions]) searchAdLoader?.delegate = self let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) searchAdLoader?.load(request) } } @@ -814,13 +754,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont isLoadingSearchInterstitialAd = true let item = SearchINSERTID[level] let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //加载搜索插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in @@ -889,7 +822,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont //MARK: - 播放 //播放插页广告ID - private var PlayerINSERTID:[MPPositive_AdModelModel] = [] + private var PlayerINSERTID:[MPPositive_AdItemModel] = [] ///播放插页广告 var playInterstitialAd:GADInterstitialAd? ///是否正在加载播放插页广告 @@ -938,13 +871,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont isLoadingPlayInterstitialAd = true let item = PlayerINSERTID[level] let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //加载播放插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in @@ -1025,7 +951,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont //MARK: - 切歌 //切歌插页广告ID - private var SwitchINSERTID:[MPPositive_AdModelModel] = [] + private var SwitchINSERTID:[MPPositive_AdItemModel] = [] ///切歌插页广告 var switchInterstitialAd:GADInterstitialAd? ///是否正在加载切歌插页广告 @@ -1073,13 +999,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont isLoadingSwitchInterstitialAd = true let item = SwitchINSERTID[level] let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //加载播放插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in @@ -1150,7 +1069,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont //MARK: - 下载 //下载插页广告ID - private var LoadINSERTID:[MPPositive_AdModelModel] = [] + private var LoadINSERTID:[MPPositive_AdItemModel] = [] ///下载插页广告 var loadInterstitialAd:GADInterstitialAd? ///是否正在加载下载插页广告 @@ -1198,13 +1117,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont isLoadingLoadInterstitialAd = true let item = LoadINSERTID[level] let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //加载下载插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in @@ -1274,9 +1186,9 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont } //MARK: - 曲库 //曲库插页ID - private var LibraryINSERTID:[MPPositive_AdModelModel] = [] + private var LibraryINSERTID:[MPPositive_AdItemModel] = [] //曲库原生ID - private var LibraryNATIVEID:[MPPositive_AdModelModel] = [] + private var LibraryNATIVEID:[MPPositive_AdItemModel] = [] ///曲库插页广告 private var libraryInterstitialAd:GADInterstitialAd? ///是否正在加载曲库插页广告 @@ -1333,12 +1245,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont libraryAdLoader?.delegate = self let request = GADRequest() //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) libraryAdLoader?.load(request) libraryNativeAds = [] } @@ -1446,7 +1352,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont MP_AnalyticsManager.shared.listclk_ads_loadFailureAction("No Ads Fill") DispatchQueue.main.asyncAfter(deadline: .now() + 10) { [weak self] in - self?.loadLoadInterstitialAd { status in + self?.loadLibraryInterstitialAd { status in if status { print("重新加载曲库插页广告") }else { @@ -1459,13 +1365,6 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont isLoadingLibraryInterstitialAd = true let item = LibraryINSERTID[level] let request = GADRequest() - //设置不同广告中介器限制-Mintegral,Pangle,Liftoff,ironsource静音 -// let mintegralExtra = GADMAdapterMintegralExtras() -// mintegralExtra.muteVideoAudio = true -// let appLovinExtra = GADMAdapterAppLovinExtras() -// appLovinExtra.muteAudio = true -// request.register(appLovinExtra) -// request.register(mintegralExtra) //加载曲库插页广告 GADInterstitialAd.load(withAdUnitID: item.identifier, request: request) { ad, error in DispatchQueue.main.async { [weak self] in @@ -1538,7 +1437,7 @@ class MP_AdMobManager: NSObject, GADAudioVideoManagerDelegate, GADFullScreenCont //MARK: - 全局 //全局备用插页ID - private var GlobalINSERTID:[MPPositive_AdModelModel] = [] + private var GlobalINSERTID:[MPPositive_AdItemModel] = [] ///全局插页广告 private var globalInterstitialAd:GADInterstitialAd? ///是否正在加载全局插页广告 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 efac51c..bc336ba 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AnalyticsManager.swift @@ -190,6 +190,10 @@ class MP_AnalyticsManager: NSObject { //更新通知 scheduleDailyNotifications() } + //更新启用的广告平台 + let platform = self.remoteConfig.configValue(forKey: "platform").boolValue + print("广告平台为\(platform ? "AppLovin":"AdMob")") + UserDefaults.standard.set(platform, forKey: "platform") //是否需要弹出更新弹窗 if let updateReminder = self.remoteConfig.configValue(forKey: "updateReminder").jsonValue as? [String:Any] { //检索是否需要更新 @@ -229,11 +233,13 @@ class MP_AnalyticsManager: NSObject { if open { //更新广告ID设置-正式版 self.reloadAdMobIDs("adMobNewLevelIDs") + self.reloadAdMobIDs("maxAdLevelIDs") //进入b面 completion(true) }else { //更新广告ID设置-测试版 self.reloadAdMobIDs("lowPriceAdModIDs") + self.reloadAdMobIDs("maxAdLevelIDs") //进入a面 completion(false) } @@ -241,6 +247,7 @@ class MP_AnalyticsManager: NSObject { //不是同一个版本,直接进入B面 //更新广告ID设置-正式版 self.reloadAdMobIDs("adMobNewLevelIDs") + self.reloadAdMobIDs("maxAdLevelIDs") completion(true) } } @@ -272,14 +279,14 @@ class MP_AnalyticsManager: NSObject { } } } - ///更新广告配置 + ///更新AdMob广告配置 private func reloadAdMobIDs(_ adMob:String) { //根据传入的键值决定使用什么版本的广告ID组 //更新广告ID设置 if let adTextIDs = self.remoteConfig.configValue(forKey: adMob).jsonValue as? [String:[[String:Any]]] { //对所有广告ID组进行更新 for (key, values) in adTextIDs { - var array:[MPPositive_AdModelModel] = [] + var array:[MPPositive_AdItemModel] = [] values.forEach { value in if let level = value["level"] as? Int, let identifier = value["identifier"] as? String, let ad = value["ad"] as? String, let item = value["type"] as? String, let type = MPPositive_AdModelType(rawValue: item) { array.append(.init(level: level, identifier: identifier, ad: ad, type: type)) @@ -631,6 +638,43 @@ class MP_AnalyticsManager: NSObject { //总价值上报 private let ad_session_total_value:String = "ad_session_total_value" + //AppLovin广告上报 + //启动位展示机会 + private let max_lunch_chance:String = "max_lunch_chance" + //启动位加载失败 + private let max_lunch_loadFailure:String = "max_lunch_loadFailure" + //启动位展示成果 + private let max_lunch_showSuccess:String = "max_lunch_showSuccess" + //启动位展示失败 + private let max_lunch_showFailure:String = "max_lunch_showFailure" + + //搜索位展示机会 + private let max_search_chance:String = "max_search_chance" + //搜索位加载失败 + private let max_search_loadFailure:String = "max_search_loadFailure" + //搜索位展示成功 + private let max_search_showSuccess:String = "max_search_showSuccess" + //搜索位展示失败 + private let max_search_showFailure:String = "max_search_showFailure" + + //播放位展示机会 + private let max_play_chance:String = "max_play_chance" + //播放位加载失败 + private let max_play_loadFailure:String = "max_play_loadFailure" + //播放位展示成功 + private let max_play_showSuccess:String = "max_play_showSuccess" + //播放位展示失败 + private let max_play_showFailure:String = "max_play_showFailure" + + //曲库位展示机会 + private let max_library_chance:String = "max_library_chance" + //曲库位加载失败 + private let max_library_loadFailure:String = "max_library_loadFailure" + //曲库位展示成功 + private let max_library_showSuccess:String = "max_library_showSuccess" + //曲库位展示失败 + private let max_library_showFailure:String = "max_library_showFailure" + //插页广告内容值转化 private func infoToParameters(_ responseInfo:GADResponseInfo, adValue:GADAdValue) -> [String:Any] { var mediation = "Unknown" @@ -888,5 +932,78 @@ class MP_AnalyticsManager: NSObject { let losAngelesTimeString = dateFormatter.string(from: now) return losAngelesTimeString } + + ///AppLovin开屏广告展示机会 + func max_lunch_chanceAction() { + Analytics.logEvent(max_lunch_chance, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin开屏广告加载失败 + func max_lunch_loadFailureAction(_ error:String) { + Analytics.logEvent(max_lunch_loadFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin开屏广告展示成功 + func max_lunch_showSuccessAction() { + Analytics.logEvent(max_lunch_showSuccess, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin开屏广告展示失败 + func max_lunch_showFailureAction(_ error:String) { + Analytics.logEvent(max_lunch_showFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin搜索广告展示机会 + func max_search_chanceAction() { + Analytics.logEvent(max_search_chance, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin搜索广告加载失败 + func max_search_loadFailureAction(_ error:String) { + Analytics.logEvent(max_search_loadFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin搜索广告展示成功 + func max_search_showSuccessAction() { + Analytics.logEvent(max_search_showSuccess, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin搜索广告展示失败 + func max_search_showFailureAction(_ error:String) { + Analytics.logEvent(max_search_showFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin播放广告展示机会 + func max_play_chanceACtion() { + Analytics.logEvent(max_play_chance, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin播放广告加载失败 + func max_play_loadFailureAction(_ error:String) { + Analytics.logEvent(max_play_loadFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin播放广告展示成功 + func max_play_showSuccessAction() { + Analytics.logEvent(max_play_showSuccess, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin播放广告展示失败 + func max_play_showFailureAction(_ error:String) { + Analytics.logEvent(max_play_showFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin曲库广告展示机会 + func max_library_chanceAction() { + Analytics.logEvent(max_library_chance, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin曲库广告加载失败 + func max_library_loadFailureAction(_ error:String) { + Analytics.logEvent(max_library_loadFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } + ///AppLovin曲库广告展示成功 + func max_library_showSuccessAction() { + Analytics.logEvent(max_library_showSuccess, parameters: ["CS_STATUS":isOLD ? "Old":"New"]) + } + ///AppLovin曲库广告展示失败 + func max_library_showFailureAction(_ error:String) { + Analytics.logEvent(max_library_showFailure, parameters: ["CS_STATUS":isOLD ? "Old":"New", + "CS_ERROR":error]) + } } diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AppLovinManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AppLovinManager.swift new file mode 100644 index 0000000..2a21093 --- /dev/null +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_AppLovinManager.swift @@ -0,0 +1,874 @@ +// +// MP_AppLovinManager.swift +// relax.offline.mp3.music +// +// Created by Mr.Zhou on 2024/9/18. +// + +import UIKit +import AppLovinSDK +///AppLovin管理器 +class MP_AppLovinManager: NSObject { + static let shared = MP_AppLovinManager() + ///广告总开关 + private var openAdStatus:Bool = MP_ADSimpleManager.shared.openAdStatus + ///内部使用广告开光 + private var internalAdStatus:Bool = MP_ADSimpleManager.shared.internalAdStatus + //AppLovin的SDk密钥 + private var SDKKey:String { + return "1z4AGzagANHydAtmbNQmAcrt1O5_HtPpt4iNTNW5Bb0RQhaXVByUEQTq5cMcR0l9NnfDtuobQqhSQE0kfEWwAC" + } + ///广告过期时间(50分钟) + private let expirationTime:TimeInterval = 3000 + + //检测广告是否过期 + private func wasAdexpirationTime(_ date:Date?) -> Bool { + guard let loadTime = date else { return false } + // Check if ad was loaded more than four hours ago. + return Date().timeIntervalSince(loadTime) < expirationTime + } + //MARK: - 插页广告总设置 + ///插页广告总开关 + private var interstitialSwitch:Bool = false{ + didSet{ + DispatchQueue.main.async { + [weak self] in + MPSideA_MediaCenterManager.shared.isAdLate = self?.interstitialSwitch + } + } + } + ///插页广告显示时间 + var interstitialDate:Date? + ///插页广告间隔秒数(默认40秒) + private var interstitialDuration:TimeInterval{ + get{ + if let times = UserDefaults.standard.object(forKey: "InterstitialDuration") as? TimeInterval { + return times + }else { + return 40 + } + } + } + ///中介间隔秒数 + private var intermediaryDuration:TimeInterval{ + get{ + if let times = UserDefaults.standard.object(forKey: "IntermediaryDuration") as? TimeInterval { + return times + }else { + return 40 + } + } + } + ///设置插页总开关 + func setInterstitialSwitch(_ status:Bool) { + interstitialSwitch = status + } + ///获得插页开关的状态 + func getInterstitialSwitch() -> Bool { + return interstitialSwitch + } + ///开屏中介记录时间值 + private var intermediaryOpenShowTime:Date? + ///插页中介记录时间值 + private var intermediaryInterstitialShowTime:Date? + ///检索与插页广告之间的中介间隔时长是否达标 + private func retrieveIntermediaryInterstitial() -> Bool { + //判断插页中介记录时间值是否存在 + guard let date = intermediaryInterstitialShowTime else {return true} + return Date().timeIntervalSince(date) > intermediaryDuration + } + ///检索与开屏广告之间的中介间隔时长是否达标 + private func retrieveIntermediaryOpen() -> Bool { + //判断插页中介记录时间值是否存在 + guard let date = intermediaryOpenShowTime else {return true} + return Date().timeIntervalSince(date) > intermediaryDuration + } + ///是否达到插页间隔时长(达到即可继续展示插页广告) + private func isShowInterstitialADAvailable(_ date:Date) -> Bool { + return Date().timeIntervalSince(date) > interstitialDuration + } + override init() { + super.init() + reloadAppLovinIDs() + //对开屏广告完成处理闭包 + completeOpenAdBlock = { + [weak self] in + guard let self = self, interstitialSwitch == true else {return} + //销毁现在的开屏广告实例 + appOpenAd = nil + isShowingOpenAd = false + loadOpenAdTime = nil + //关闭插页广告开关 + interstitialSwitch = false + //更新开屏广告中介间隔时间 + intermediaryOpenShowTime = Date() + //重新加载后续的开屏广告 + DispatchQueue.main.asyncAfter(deadline: .now() + 4) { + [weak self] in + self?.loadOpenAd{ status in + if status == true { + print("新的开屏广告加载成功") + }else { + print("开屏广告加载失败了") + } + } + } + } + //搜索插页广告完成处理闭包 + completeSearchInterstitialAdBlock = { + [weak self] in + guard let self = self, interstitialSwitch == true else {return} + //销毁现在的搜索插页广告实例 + searchInterstitialAd = nil + isShowingSearchInterstitialAd = false + loadSearchInterstitialAdTime = nil + //关闭插页广告开关 + interstitialSwitch = false + //更新插页广告中介间隔时长 + intermediaryInterstitialShowTime = Date() + //重新加载后续的搜索插页广告 + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadSearchInterstitialAd { status in + if status { + print("成功加载搜索插页广告") + }else { + print("搜索插页广告加载失败") + } + } + } + } + //播放插页广告完成处理闭包 + completePlayInterstitialAdBlock = { + [weak self] in + guard let self = self, interstitialSwitch == true else {return} + //销毁现在的播放插页广告实例 + playInterstitialAd = nil + isShowingPlayInterstitialAd = false + loadPlayInterstitialAdTime = nil + //关闭插页广告开关 + interstitialSwitch = false + //更新插页广告中介间隔时长 + intermediaryInterstitialShowTime = Date() + //重新加载后续的播放插页广告 + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadPlayInterstitialAd { status in + if status { + print("成功加载播放插页广告") + }else { + print("播放插页广告加载失败") + } + } + } + } + //曲库插页广告完成处理闭包 + completeLibraryInterstitialAdBlock = { + [weak self] in + guard let self = self, interstitialSwitch == true else {return} + //销毁现在的曲库插页广告实例 + libraryInterstitialAd = nil + isShowingLibraryInterstitialAd = false + loadLibraryInterstitialAdTime = nil + //关闭插页广告开关 + interstitialSwitch = false + //更新插页广告中介间隔时长 + intermediaryInterstitialShowTime = Date() + //重新加载后续的曲库插页广告 + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadLibraryInterstitialAd { status in + if status { + print("成功加载曲库插页广告") + }else { + print("曲库插页广告加载失败") + } + } + } + } + } + ///初始化 + func startConfig() { + //AppLovin初始化配置 + let initConfig = ALSdkInitializationConfiguration(sdkKey: SDKKey) { builder in + builder.mediationProvider = ALMediationProviderMAX + } + //AppLovin初始化 + ALSdk.shared().initialize(with: initConfig) { sdkConfig in + //开始加载AppLovin广告 + } + //设置全部静音 + ALSdk.shared().settings.isMuted = true + } + ///更新广告ID + func reloadAppLovinIDs() { + //更新要用到的广告信息 + if let data = UserDefaults.standard.object(forKey: "Max_OpenICEIDs") as? Data, let array = jsonforCoreAdModel(data) { + print("成功提取ID") + OpenIDs = array.sorted(by: {$0.level > $1.level}) + } + if let data = UserDefaults.standard.object(forKey: "Max_SearchINSERTIDs") as? Data, let array = jsonforCoreAdModel(data) { + SearchINSERTIDs = array.sorted(by: {$0.level > $1.level}) + } + if let data = UserDefaults.standard.object(forKey: "Max_PlayerINSERTIDs") as? Data, let array = jsonforCoreAdModel(data) { + PlayerINSERTIDs = array.sorted(by: {$0.level > $1.level}) + } + if let data = UserDefaults.standard.object(forKey: "Max_LibraryNATIVEIDs") as? Data, let array = jsonforCoreAdModel(data) { + LibraryINSERTIDs = array.sorted(by: {$0.level > $1.level}) + } + } + ///加载广告 + func loadMoreAds(){ + loadPlayInterstitialAd{status in + if status { + print("成功加载播放插页广告") + }else { + print("播放插页广告加载失败") + } + } + loadSearchInterstitialAd { status in + if status { + print("成功加载搜索插页广告") + }else { + print("搜索插页广告加载失败") + } + } + loadLibraryInterstitialAd { status in + if status { + print("成功加载曲库插页广告") + }else { + print("曲库插页广告加载失败") + } + + } + } + + //MARK: - 开屏广告 + ///开屏广告ID组 + private var OpenIDs:[MPPositive_AdItemModel] = [] + ///开屏广告 + var appOpenAd:MAInterstitialAd? + ///是否正在加载开屏广告 + private var isLoadingOpenAd:Bool = false + ///是否正在展示开屏广告 + var isShowingOpenAd:Bool = false + //开屏广告加载时间 + private var loadOpenAdTime:Date? + //开屏广告回调传值闭包 + private var loadStatuOpenAdBlock:((Bool) -> Void)? + //开屏广告加载完成处理闭包 + var completeOpenAdBlock:(() -> Void)? + //当前加载的ID数组Level阶级(从0开始,越低等级越高) + private var openLevel:Int = 0 + //开屏广告时间间隔(默认10秒) + private var openAppDuration:TimeInterval{ + get{ + if let times = UserDefaults.standard.object(forKey: "OpenAppDuration") as? TimeInterval { + return times + }else { + return 10 + } + } + } + //设置开屏广告时间间隔 + func setOpenAppDuration(_ duration:TimeInterval) { + UserDefaults.standard.set(duration, forKey: "OpenAppDuration") + } + //获取开屏广告时间间隔 + func getOpenAppDuration() -> TimeInterval { + return self.openAppDuration + } + ///加载开屏广告 + func loadOpenAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { + guard openAdStatus, internalAdStatus else {return} + // 检测当前是否有广告或者有广告正在加载 + if isLoadingOpenAd || isOpenAdAvailable() { + // 有广告或有广告在加载 + completion(false) + return + } + //检索是否超过了对应的id组的阶级数量 + guard OpenIDs.isEmpty == false else { + //冷启动无数据 + MP_AnalyticsManager.shared.max_lunch_showFailureAction("No IDs") + //重新获取数据 + reloadAppLovinIDs() + completion(false) + return + } + guard level < (OpenIDs.count) else { + print("开屏广告组已经全部加载失败,停止继续加载") + MP_AnalyticsManager.shared.max_lunch_loadFailureAction("No Ads Fill") + completion(false) + DispatchQueue.main.asyncAfter(deadline: .now() + 3) { + [weak self] in + self?.loadOpenAd( completion: { status in + if status { + print("重新加载启动广告成功") + }else { + print("重新加载启动广告失败") + } + }) + } + return + } + let item = OpenIDs[level] + openLevel = level + //重置闭包导向 + loadStatuOpenAdBlock = completion + //根据ID生成广告 + appOpenAd = MAInterstitialAd(adUnitIdentifier: item.identifier) + appOpenAd?.delegate = self + //加载开屏广告 + appOpenAd?.load() + } + ///展示加载广告 + func showOpenAdIfAvailable(_ completion:((_ T:MAInterstitialAd) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 + guard !interstitialSwitch, !isShowingOpenAd, retrieveIntermediaryInterstitial() else { return } + // 如果应用开屏广告尚不可用但应该显示,则加载新广告。 + if !isOpenAdAvailable() { + loadOpenAd{ [weak self] success in + guard let self = self else { return } + if success { + self.showOpenAdIfAvailable(completion) + } + } + return + } + MP_AnalyticsManager.shared.max_lunch_chanceAction() + if let ad = appOpenAd, ad.isReady { + //传递加载完成事件 + if let block = completion { + block(ad) + }else { + isShowingOpenAd = true + interstitialSwitch = true + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //可以展示 + ad.show() + } + } + }else { + print("开屏广告展示失败") + MP_AnalyticsManager.shared.max_lunch_showFailureAction("Ad loading failed") + } + } + ///查询是否有开屏广告 + func isOpenAdAvailable() -> Bool { + return (appOpenAd != nil) && wasAdexpirationTime(loadOpenAdTime) + } + //MARK: - 搜索 + ///搜索插页广告ID + private var SearchINSERTIDs:[MPPositive_AdItemModel] = [] + ///搜索插页广告 + private var searchInterstitialAd:MAInterstitialAd? + ///是否正在加载搜索插页广告 + private var isLoadingSearchInterstitialAd:Bool = false + ///是否正在展示搜索插页广告 + var isShowingSearchInterstitialAd:Bool = false + ///搜索插页加载时间 + private var loadSearchInterstitialAdTime:Date? + ///搜索广告处理闭包 + var completeSearchInterstitialAdBlock:(() -> Void)? + //开屏广告回调传值闭包 + private var loadStatuSearchAdBlock:((Bool) -> Void)? + //当前加载的ID数组Level阶级(从0开始,越低等级越高) + private var searchLevel:Int = 0 + //异步加载搜索插页广告 + func loadSearchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { + guard openAdStatus, internalAdStatus else {return} + if isLoadingSearchInterstitialAd || isSearchInterstitialAdAvailable() { + // 有广告或有广告在加载 + completion(false) + return + } + guard SearchINSERTIDs.isEmpty == false else { + MP_AnalyticsManager.shared.max_search_showFailureAction("No IDs") + //重新获取数据 + reloadAppLovinIDs() + completion(false) + return + } + guard level < (SearchINSERTIDs.count) else { + print("搜索插页广告组已经全部加载失败,停止继续加载") + MP_AnalyticsManager.shared.max_search_loadFailureAction("No Ads Fill") + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadSearchInterstitialAd { status in + if status { + print("重新加载搜索插页广告") + }else { + print("加载搜索插页广告失败") + } + } + } + return + } + isLoadingSearchInterstitialAd = true + searchLevel = level + //重置闭包导向 + loadStatuSearchAdBlock = completion + let item = SearchINSERTIDs[level] + //根据ID生成广告 + searchInterstitialAd = MAInterstitialAd(adUnitIdentifier: item.identifier) + searchInterstitialAd?.delegate = self + //加载开屏广告 + searchInterstitialAd?.load() + } + ///搜索插页广告展示 + func showSearchInterstitialAdIfAvailable(_ completion:((MAInterstitialAd) -> Void)?) { + guard openAdStatus, internalAdStatus else {return} + // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 + guard !interstitialSwitch, !isShowingSearchInterstitialAd, retrieveIntermediaryOpen() else { return } + //检索是否存在插页间隔时间 + if let date = interstitialDate { + if isShowInterstitialADAvailable(date) == false { + //未超过插页间隔时长 + print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") + return + } + } + // 如果搜索广告尚不可用但应该显示,则加载新广告。 + if !isSearchInterstitialAdAvailable() { + loadSearchInterstitialAd { [weak self] success in + guard let self = self else { return } + if success { + self.showSearchInterstitialAdIfAvailable(completion) + } + } + return + } + MP_AnalyticsManager.shared.max_search_chanceAction() + //当搜索插页广告确定有值后展示 + if let ad = searchInterstitialAd, ad.isReady { + //传递加载完成事件 + if let block = completion { + block(ad) + }else { + isShowingSearchInterstitialAd = true + interstitialSwitch = true + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //可以展示 + ad.show() + } + } + }else { + MP_AnalyticsManager.shared.max_search_showFailureAction("Ad loading failed") + } + } + //查询是否有搜索插页广告 + func isSearchInterstitialAdAvailable() -> Bool { + return searchInterstitialAd != nil && wasAdexpirationTime(loadSearchInterstitialAdTime) + } + //MARK: - 播放/切割插页广告位 + ///播放插页广告ID + private var PlayerINSERTIDs:[MPPositive_AdItemModel] = [] + ///播放插页广告 + var playInterstitialAd:MAInterstitialAd? + ///是否正在加载播放插页广告 + private var isLoadingPlayInterstitialAd:Bool = false + ///是否正在展示播放插页广告 + var isShowingPlayInterstitialAd:Bool = false + ///播放插页加载时间 + private var loadPlayInterstitialAdTime:Date? + ///播放广告处理闭包 + var completePlayInterstitialAdBlock:(() -> Void)? + //开屏广告回调传值闭包 + private var loadStatuPlayAdBlock:((Bool) -> Void)? + //当前加载的ID数组Level阶级(从0开始,越低等级越高) + private var playLevel:Int = 0 + //异步加载播放插页广告 + func loadPlayInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { + guard openAdStatus, internalAdStatus else { + completion(false) + return + } + // 检测当前是否有广告或者有广告正在加载 + if isLoadingPlayInterstitialAd || isPlayInterstitialAdAvailable() { + // 有广告或有广告在加载 + completion(false) + return + } + guard PlayerINSERTIDs.isEmpty == false else { + MP_AnalyticsManager.shared.max_play_showFailureAction("No IDs") + //重新获取数据 + reloadAppLovinIDs() + completion(false) + return + } + + guard level < (PlayerINSERTIDs.count) else { + print("播放插页广告组已经全部加载失败,停止继续加载") + MP_AnalyticsManager.shared.max_play_loadFailureAction("No Ads Fill") + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadPlayInterstitialAd { status in + if status { + print("重新加载播放插页广告") + }else { + print("加载播放插页广告失败") + } + } + } + return + } + isLoadingPlayInterstitialAd = true + playLevel = level + //重置闭包导向 + loadStatuPlayAdBlock = completion + let item = PlayerINSERTIDs[level] + //根据ID生成广告 + playInterstitialAd = MAInterstitialAd(adUnitIdentifier: item.identifier) + playInterstitialAd?.delegate = self + //加载开屏广告 + playInterstitialAd?.load() + } + ///播放插页广告展示 + func showPlayInterstitialAdIfAvailable(_ completion:((MAInterstitialAd?) -> Void)?) { + guard openAdStatus, internalAdStatus else { + completion?(nil) + return + } + guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { + completion?(nil) + return + } + // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 + guard !interstitialSwitch, !isShowingPlayInterstitialAd, retrieveIntermediaryOpen() else { + completion?(nil) + return + } + //检索是否存在插页间隔时间 + if let date = interstitialDate { + if isShowInterstitialADAvailable(date) == false { + //未超过插页间隔时长 + print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") + completion?(nil) + return + } + } + // 如果播放插页广告尚不可用但应该显示,则加载新广告。 + if !isPlayInterstitialAdAvailable() { + loadPlayInterstitialAd{ [weak self] success in + guard let self = self else { return } + if success { + print("播放广告已加载") + } + } + completion?(nil) + return + } + MP_AnalyticsManager.shared.max_play_chanceACtion() + //当播放插页广告确定有值后展示 + if let ad = playInterstitialAd, ad.isReady { + //传递加载完成事件 + if let block = completion { + block(ad) + }else { + isShowingPlayInterstitialAd = true + interstitialSwitch = true + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //可以展示 + ad.show() + } + } + }else { + MP_AnalyticsManager.shared.max_play_showFailureAction("Ad loading failed") + completion?(nil) + } + } + //查询是否有播放插页广告 + func isPlayInterstitialAdAvailable() -> Bool { + return playInterstitialAd != nil && wasAdexpirationTime(loadPlayInterstitialAdTime) + } + //MARK: - 曲库/下载插页广告位 + ///曲库插页ID + private var LibraryINSERTIDs:[MPPositive_AdItemModel] = [] + ///曲库插页广告 + private var libraryInterstitialAd:MAInterstitialAd? + ///是否正在加载曲库插页广告 + private var isLoadingLibraryInterstitialAd:Bool = false + ///是否正在展示曲库插页广告 + var isShowingLibraryInterstitialAd:Bool = false + ///曲库插页加载时间 + private var loadLibraryInterstitialAdTime:Date? + ///曲库广告处理闭包 + var completeLibraryInterstitialAdBlock:(() -> Void)? + //开屏广告回调传值闭包 + private var loadStatuLibraryAdBlock:((Bool) -> Void)? + //当前加载的ID数组Level阶级(从0开始,越低等级越高) + private var libraryLevel:Int = 0 + //异步加载曲库插页广告 + func loadLibraryInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) { + guard openAdStatus, internalAdStatus else { + completion(false) + return + } + // 检测当前是否有广告或者有广告正在加载 + if isLoadingLibraryInterstitialAd || isLibraryInterstitialAdAvailable() { + // 有广告或有广告在加载 + completion(false) + return + } + guard LibraryINSERTIDs.isEmpty == false else { + MP_AnalyticsManager.shared.max_library_showFailureAction("No IDs") + //重新获取数据 + reloadAppLovinIDs() + completion(false) + return + } + guard level < (LibraryINSERTIDs.count) else { + print("曲库插页广告组已经全部加载失败,停止继续加载") + MP_AnalyticsManager.shared.max_library_loadFailureAction("No Ads Fill") + DispatchQueue.main.asyncAfter(deadline: .now() + 10) { + [weak self] in + self?.loadLibraryInterstitialAd { status in + if status { + print("重新加载曲库插页广告") + }else { + print("加载曲库插页广告失败") + } + } + } + return + } + isLoadingLibraryInterstitialAd = true + libraryLevel = level + //重置闭包导向 + loadStatuLibraryAdBlock = completion + let item = LibraryINSERTIDs[level] + //根据ID生成广告 + libraryInterstitialAd = MAInterstitialAd(adUnitIdentifier: item.identifier) + libraryInterstitialAd?.delegate = self + //加载开屏广告 + libraryInterstitialAd?.load() + } + ///曲库插页广告展示 + func showLibraryInterstitialAdIfAvailable(_ completion:((MAInterstitialAd) -> Void)?) { + // 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。 + guard !interstitialSwitch, !isShowingLibraryInterstitialAd, retrieveIntermediaryOpen() else { return } + //检索是否存在插页间隔时间 + if let date = interstitialDate { + if isShowInterstitialADAvailable(date) == false { + //未超过插页间隔时长 + print("距上一次展示插页广告时长未超过要求,此次插页广告展示滞后") + return + } + } + // 如果曲库广告尚不可用但应该显示,则加载新广告。 + if !isLibraryInterstitialAdAvailable() { + loadLibraryInterstitialAd { [weak self] success in + guard let self = self else { return } + if success { + self.showLibraryInterstitialAdIfAvailable(completion) + } + } + return + } + MP_AnalyticsManager.shared.max_library_chanceAction() + //当曲库插页广告确定有值后展示 + if let ad = libraryInterstitialAd, ad.isReady { + //传递加载完成事件 + if let block = completion { + block(ad) + }else { + isShowingPlayInterstitialAd = true + interstitialSwitch = true + DispatchQueue.main.async { + [weak self] in + guard let self = self else {return} + //可以展示 + ad.show() + } + } + }else { + MP_AnalyticsManager.shared.max_library_showFailureAction("Ad loading failed") + } + } + //查询是否有曲库插页广告 + func isLibraryInterstitialAdAvailable() -> Bool { + return libraryInterstitialAd != nil && wasAdexpirationTime(loadLibraryInterstitialAdTime) + } +} +//MARK: - 插页广告代理实现 +extension MP_AppLovinManager: MAAdDelegate { + //广告加载成功 + func didLoad(_ ad: MAAd) { + let adUnitIdentifier = ad.adUnitIdentifier + //判断广告位 + if adUnitIdentifier == appOpenAd?.adUnitIdentifier { + //是开屏广告,调整加载状态 + isLoadingOpenAd = false + //更新开屏广告加载时间 + loadOpenAdTime = Date() + //实现开屏广告回调闭包 + if let block = loadStatuOpenAdBlock { + block(true) + } + }else if adUnitIdentifier == searchInterstitialAd?.adUnitIdentifier { + //是搜索插页广告,调整加载状态 + isLoadingSearchInterstitialAd = false + //更新搜索插页广告加载时间 + loadSearchInterstitialAdTime = Date() + //实现搜索插页广告回调闭包 + if let block = loadStatuSearchAdBlock { + block(true) + } + }else if adUnitIdentifier == playInterstitialAd?.adUnitIdentifier { + //是播放插页广告 + isLoadingPlayInterstitialAd = false + //更新播放插页广告加载时间 + loadPlayInterstitialAdTime = Date() + //实现播放插页广告回调闭包 + if let block = loadStatuPlayAdBlock { + block(true) + } + }else if adUnitIdentifier == libraryInterstitialAd?.adUnitIdentifier { + //是曲库插页广告 + isLoadingLibraryInterstitialAd = false + //更新曲库插页广告加载时间 + loadLibraryInterstitialAdTime = Date() + //实现曲库插页广告回调 + if let block = loadStatuLibraryAdBlock { + block(true) + } + } + } + //广告加载失败 + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + //判断广告位 + if adUnitIdentifier == appOpenAd?.adUnitIdentifier { + //是开屏广告,调整加载状态 + isLoadingOpenAd = false + //开屏广告加载失败,销毁广告 + appOpenAd = nil + MP_AnalyticsManager.shared.max_lunch_loadFailureAction(error.message) + if let block = loadStatuOpenAdBlock { + //重新加载广告 + loadOpenAd(openLevel + 1, completion: block) + } + }else if adUnitIdentifier == searchInterstitialAd?.adUnitIdentifier { + //是搜索插页广告,调整加载状态 + isLoadingSearchInterstitialAd = false + searchInterstitialAd = nil + MP_AnalyticsManager.shared.max_search_loadFailureAction(error.message) + if let block = loadStatuSearchAdBlock { + loadSearchInterstitialAd(searchLevel + 1, completion: block) + } + }else if adUnitIdentifier == playInterstitialAd?.adUnitIdentifier { + //是播放插页广告 + isLoadingPlayInterstitialAd = false + playInterstitialAd = nil + MP_AnalyticsManager.shared.max_play_loadFailureAction(error.message) + if let block = loadStatuPlayAdBlock { + loadPlayInterstitialAd(playLevel + 1, completion: block) + } + }else if adUnitIdentifier == libraryInterstitialAd?.adUnitIdentifier { + //是曲库插页广告 + isLoadingLibraryInterstitialAd = false + libraryInterstitialAd = nil + MP_AnalyticsManager.shared.max_library_loadFailureAction(error.message) + if let block = loadStatuLibraryAdBlock { + loadLibraryInterstitialAd(libraryLevel + 1, completion: block) + } + } + } + //广告展示 + func didDisplay(_ ad: MAAd) { + let adUnitIdentifier = ad.adUnitIdentifier + //检索广告位 + if adUnitIdentifier == appOpenAd?.adUnitIdentifier { + //开屏广告 + print("当前展示的广告是开屏广告,广告ID--\(ad.adUnitIdentifier)") + //上传广告事件 + }else if adUnitIdentifier == searchInterstitialAd?.adUnitIdentifier { + //搜索广告位 + print("当前展示的广告是搜索插页广告,广告ID--\(ad.adUnitIdentifier)") + //上传广告事件 + }else if adUnitIdentifier == playInterstitialAd?.adUnitIdentifier { + //播放广告位 + print("当前展示的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + }else if adUnitIdentifier == libraryInterstitialAd?.adUnitIdentifier { + //曲库广告位 + print("当前展示的广告是曲库插页广告,广告ID--\(ad.adUnitIdentifier)") + } + } + //广告关闭 + func didHide(_ ad: MAAd) { + let adUnitIdentifier = ad.adUnitIdentifier + //更新插页广告展示时间 + interstitialDate = Date() + if adUnitIdentifier == appOpenAd?.adUnitIdentifier { + print("当前消失的广告是开屏广告,广告ID--\(ad.adUnitIdentifier)") + if let block = completeOpenAdBlock { + block() + } + }else if adUnitIdentifier == searchInterstitialAd?.adUnitIdentifier { + //搜索广告位 + print("当前消失的广告是搜索插页广告,广告ID--\(ad.adUnitIdentifier)") + if let block = completeSearchInterstitialAdBlock { + block() + } + }else if adUnitIdentifier == playInterstitialAd?.adUnitIdentifier { + //播放广告位 + print("当前消失的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + if let block = completePlayInterstitialAdBlock { + block() + } + }else if adUnitIdentifier == libraryInterstitialAd?.adUnitIdentifier { + //曲库广告位 + print("当前消失的广告是曲库插页广告,广告ID--\(ad.adUnitIdentifier)") + if let block = completeLibraryInterstitialAdBlock { + block() + } + } + } + //广告点击 + func didClick(_ ad: MAAd) { + + } + //广告展示失败 + func didFail(toDisplay ad: MAAd, withError error: MAError) { + let adUnitIdentifier = ad.adUnitIdentifier + //更新插页广告展示时间 + interstitialDate = Date() + if adUnitIdentifier == appOpenAd?.adUnitIdentifier { + print("开屏广告展示时出错,广告ID--\(ad.adUnitIdentifier),具体错误原因:\(error.message)") + MP_AnalyticsManager.shared.max_lunch_showFailureAction(error.message) + if let block = completeOpenAdBlock { + block() + } + }else if adUnitIdentifier == searchInterstitialAd?.adUnitIdentifier { + //搜索广告位 + print("搜索插页广告展示时出错,广告ID--\(ad.adUnitIdentifier),具体错误原因:\(error.message)") + MP_AnalyticsManager.shared.max_search_showFailureAction(error.message) + if let block = completeSearchInterstitialAdBlock { + block() + } + }else if adUnitIdentifier == playInterstitialAd?.adUnitIdentifier { + //播放广告位 + print("播放插页广告展示时出错,广告ID--\(ad.adUnitIdentifier),具体错误原因:\(error.message)") + MP_AnalyticsManager.shared.max_play_showFailureAction(error.message) + if let block = completePlayInterstitialAdBlock { + block() + } + }else if adUnitIdentifier == libraryInterstitialAd?.adUnitIdentifier { + //曲库广告位 + print("曲库插页广告展示时出错,广告ID--\(ad.adUnitIdentifier),具体错误原因:\(error.message)") + MP_AnalyticsManager.shared.max_library_showFailureAction(error.message) + if let block = completeLibraryInterstitialAdBlock { + block() + } + } + } + + +} diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_DownloadManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_DownloadManager.swift index 37380df..1061052 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_DownloadManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_DownloadManager.swift @@ -114,6 +114,8 @@ class MP_DownloadManager: NSObject { } first.coverUrls = coverUrls group.leave() + }failure: { statu in + group.leave() } group.notify(queue: .main, execute: { [weak self] in diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_HUD.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_HUD.swift index c58eb50..2b9a653 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_HUD.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_HUD.swift @@ -31,7 +31,7 @@ class MP_HUD: NSObject { SVProgressHUD.setBackgroundColor(.init(hex: "#80F988", alpha: 0.15)) SVProgressHUD.setForegroundColor(.init(hex: "#80F988")) SVProgressHUD.setOffsetFromCenter(.init(horizontal: 0, vertical: 0)) - if MP_AdMobManager.shared.getInterstitialSwitch() { + if MP_ADSimpleManager.shared.getInterstitialSwitch() { //当前正在展示插页 }else { @@ -46,7 +46,7 @@ class MP_HUD: NSObject { SVProgressHUD.setBackgroundColor(.init(hex: "#80F988", alpha: 0.15)) SVProgressHUD.setForegroundColor(.init(hex: "#80F988")) SVProgressHUD.setOffsetFromCenter(.init(horizontal: 0, vertical: 0)) - if MP_AdMobManager.shared.getInterstitialSwitch() { + if MP_ADSimpleManager.shared.getInterstitialSwitch() { //当前正在展示插页 guard let completion = completion else{ return @@ -104,7 +104,7 @@ class MP_HUD: NSObject { SVProgressHUD.setBackgroundColor(.init(hex: "#80F988", alpha: 0.15)) SVProgressHUD.setForegroundColor(.init(hex: "#80F988")) SVProgressHUD.setOffsetFromCenter(.init(horizontal: 0, vertical: 0)) - if MP_AdMobManager.shared.getInterstitialSwitch() { + if MP_ADSimpleManager.shared.getInterstitialSwitch() { //当前正在展示插页 guard let completion = completion else{ return 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 1ecf10b..8be6127 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_IAPManager.swift @@ -76,7 +76,7 @@ class MP_IAPManager: NSObject { // 收据不存在 print("没有收据,广告默认开") //不能调用AppStore,默认使用广告 - MP_AdMobManager.shared.setOpenAdStatus(true) + MP_ADSimpleManager.shared.setOpenAdStatus(true) return } //收据,重置交易记录 @@ -90,7 +90,7 @@ class MP_IAPManager: NSObject { // 收据不存在 print("没有收据,广告默认开") //不能调用AppStore,默认使用广告 - MP_AdMobManager.shared.setOpenAdStatus(true) + MP_ADSimpleManager.shared.setOpenAdStatus(true) return } //有收据 @@ -102,9 +102,9 @@ class MP_IAPManager: NSObject { //更新广告开关状态 if isProductPurchased(productId: productIdentifiers[0]) || isProductPurchased(productId: productIdentifiers[1]) || isProductPurchased(productId: productIdentifiers[2]){ //设置广告开关为关 - MP_AdMobManager.shared.setOpenAdStatus(false) + MP_ADSimpleManager.shared.setOpenAdStatus(false) }else { - MP_AdMobManager.shared.setOpenAdStatus(true) + MP_ADSimpleManager.shared.setOpenAdStatus(true) } } @@ -162,7 +162,7 @@ extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver productIdentifiers.forEach { item in cleanPurchase(productId: item) } - MP_AdMobManager.shared.setOpenAdStatus(true) + MP_ADSimpleManager.shared.setOpenAdStatus(true) } } func paymentQueue(_ queue: SKPaymentQueue, restoreCompletedTransactionsFailedWithError error: any Error) { @@ -172,7 +172,7 @@ extension MP_IAPManager: SKProductsRequestDelegate, SKPaymentTransactionObserver productIdentifiers.forEach { item in cleanPurchase(productId: item) } - MP_AdMobManager.shared.setOpenAdStatus(true) + MP_ADSimpleManager.shared.setOpenAdStatus(true) } //存入交易信息值 private func storePurchase(productId: String) { diff --git a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_LuxServerManager.swift b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_LuxServerManager.swift index ee7f58c..dc5ef34 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_LuxServerManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_LuxServerManager.swift @@ -9,6 +9,7 @@ import UIKit import Alamofire import Security import AdSupport + ///自家后台管理器 class MP_LuxServerManager: NSObject { //单例工具 @@ -60,7 +61,7 @@ class MP_LuxServerManager: NSObject { } /// 设备类型 private var deviceVersion: String { - return UIDevice.current.name + return UIDevice.current.modelName } ///系统版本 private var osVersion:String { 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 7c7e8bb..80f6467 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_NetWorkManager.swift @@ -973,7 +973,7 @@ extension MP_NetWorkManager { //MARK: - 请求player播放资源 /// 请求Player(单曲/视频)播放资源 /// - Parameter item: 请求的预览实体 - func requestAndroidPlayer(_ videoId: String, playlistId: String, clickTrackingParams: String?, completion:@escaping ((([String],[Int],[String])?, [String]?) -> Void)){ + func requestAndroidPlayer(_ videoId: String, playlistId: String, clickTrackingParams: String?, completion:@escaping ((([String],[Int],[String])?, [String]?) -> Void), failure: ((Bool) -> Void)? = nil){ guard netWorkStatu != .notReachable else { completion(nil,nil) return @@ -1006,9 +1006,11 @@ extension MP_NetWorkManager { //guard netWorkStatu != .notReachable else {return} requestAndroidPostPlayer(url, videoId: videoId, parameters: parameters){ resourceUlrs, coverUrls in completion(resourceUlrs, coverUrls) + } failure: { statu in + failure?(statu) } } - private func requestAndroidPostPlayer(_ url:URL, videoId:String, parameters:Parameters, completion:@escaping((([String],[Int],[String])?, [String]?) -> Void)) { + private func requestAndroidPostPlayer(_ url:URL, videoId:String, parameters:Parameters, completion:@escaping((([String],[Int],[String])?, [String]?) -> Void), failure:((Bool) -> Void)? = nil) { //发送post请求 let request = PlayerSeesion.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseDecodable(of: JsonAndroidPlayer.self) { [weak self] (response) in guard let self = self else {return} @@ -1016,11 +1018,16 @@ extension MP_NetWorkManager { switch response.result { case .success(let value): parsingAndroidPlayer(value) { resourceUlrs, coverUrls in + //成功获得资源 completion(resourceUlrs, coverUrls) + } failure: { statu in + //失败 + failure?(statu) } + case .failure(let error): //当前无数据 - completion(nil,nil) + failure?(false) // 请求失败,处理错误 handleError(url, error: error, status: false) } @@ -2034,17 +2041,20 @@ extension MP_NetWorkManager { // } // } // } - private func parsingAndroidPlayer(_ player:JsonAndroidPlayer,completion:@escaping((([String],[Int],[String]), [String]?) -> Void)){ + private func parsingAndroidPlayer(_ player:JsonAndroidPlayer,completion:@escaping((([String],[Int],[String]), [String]?) -> Void), failure:((Bool) -> Void)? = nil){ var infos:[String]? //解析player,获取资源库和信息库 if let videoDetails = player.videoDetails { infos = parsingAndroidPlayerVideoDetails(videoDetails) } if let streamingData = player.streamingData { + //存在资源 parsingAndroidPlayerStreamingData(streamingData){ videos,itags,mimeType in completion((videos,itags,mimeType),infos) } }else { + //不存在资源(通常是IP被拉黑了) + failure?(true) 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 c20f202..5bbd59a 100644 --- a/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift +++ b/relax.offline.mp3.music/MP/Common/Tool(工具封装)/MP_PlayerManager.swift @@ -232,6 +232,8 @@ class MP_PlayerManager:NSObject{ private var playbackLikelyToKeepUpObservation:NSKeyValueObservation? ///播放实例报错的监听器 private var errorObservation:NSKeyValueObservation? + ///播放实例播放资格监听器 + private var playEntitlementObservation:NSKeyValueObservation? private override init() { super.init() //初始化计时器 @@ -314,6 +316,14 @@ class MP_PlayerManager:NSObject{ if startAction != nil { startActionBlock = startAction } + //检索是否具备播放资格 + guard loadPlayer?.currentVideo?.isPlayEntitlement != false else { + //明确不可播放, 执行下一首 + if MP_NetWorkManager.shared.netWorkStatu == .reachable { + nextEvent() + } + return + } if let currentVideo = loadPlayer?.currentVideo { //覆盖播放器原有的playerItem player.replaceCurrentItem(with: currentVideo.resourcePlayerItem) @@ -412,6 +422,15 @@ class MP_PlayerManager:NSObject{ MP_AnalyticsManager.shared.player_b_failure_errorAction(currentVideo.song.videoId ?? "", videoname: currentVideo.title ?? "", artistname: currentVideo.song.shortBylineText ?? "", error: nsError.localizedDescription) } }) + //播放资格 + playEntitlementObservation?.invalidate() + playEntitlementObservation = currentVideo.observe(\.isPlayEntitlement, options: [.old,.new], changeHandler: { [weak self] item, change in + guard let self = self, MP_NetWorkManager.shared.netWorkStatu == .reachable else {return} + if change.newValue == 0 { + //当前音乐不具备播放资格,直接下一首 + nextEvent() + } + }) currentVideo.isKVO = true //将进度回归为0 player.seek(to: .zero) @@ -485,7 +504,17 @@ class MP_PlayerManager:NSObject{ } } } - + //确定播放器播放后限时状态 + func playerStatuTimerAction() { + MPPositive_Debouncer.shared.playCall { + [weak self] in + guard let self = self else {return} + //10秒后检索播放器是否在播放 + if playState != .Playing { + MP_HUD.text("Failed to obtain resource, please try again later".localizableString(), delay: 2.0, completion: nil) + } + } + } //获取缓冲值 private func cacheLoadTimes() { //获取当前播放Item的缓冲值组 diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdModelModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdItemModel.swift similarity index 88% rename from relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdModelModel.swift rename to relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdItemModel.swift index a70707e..e1f2168 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdModelModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_AdItemModel.swift @@ -1,5 +1,5 @@ // -// MPPositive_AdModelModel.swift +// MPPositive_AdItemModel.swift // relax.offline.mp3.music // // Created by Mr.Zhou on 2024/7/10. @@ -7,7 +7,7 @@ import UIKit ///广告模型 -class MPPositive_AdModelModel: NSObject, Codable { +class MPPositive_AdItemModel: NSObject, Codable { ///阶级(从高到低) var level:Int ///id内容 diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_LibraryItemModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_LibraryItemModel.swift index 437c0fa..6291f7e 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_LibraryItemModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/Models/MPPositive_LibraryItemModel.swift @@ -16,12 +16,15 @@ class MPPositive_LibraryItemModel: NSObject { var title:String ///唯一标识符 var identifier:String? + ///数量组 + var count:Int - init(libraryType: LibraryType, coverUrl: URL?, title: String, identifier: String? = nil) { + init(libraryType: LibraryType, coverUrl: URL?, title: String, identifier: String? = nil, count:Int) { self.libraryType = libraryType self.coverUrl = coverUrl self.title = title self.identifier = identifier + self.count = count } } ///Library指向类型 diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_LibraryListViewModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_LibraryListViewModel.swift index 76c3d77..88ce030 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_LibraryListViewModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_LibraryListViewModel.swift @@ -56,30 +56,30 @@ class MPPositive_LibraryListViewModel: NSObject { } if songs.isEmpty == false, let lastUrl = songs.first?.coverURL { //获取收藏歌曲 - let item = MPPositive_LibraryViewModel(.init(libraryType: .love_songs, coverUrl: lastUrl, title: "Love Songs".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .love_songs, coverUrl: lastUrl, title: "Love Songs".localizableString(), count: songs.count)) array.append(item) }else { - let item = MPPositive_LibraryViewModel(.init(libraryType: .love_songs, coverUrl: nil, title: "Love Songs".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .love_songs, coverUrl: nil, title: "Love Songs".localizableString(), count: 0)) array.append(item) } if artists.isEmpty == false, let lastUrl = artists.first?.coverURL { - let item = MPPositive_LibraryViewModel(.init(libraryType: .love_aritists, coverUrl: lastUrl, title: "Love Artists".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .love_aritists, coverUrl: lastUrl, title: "Love Artists".localizableString(), count: artists.count)) array.append(item) }else { - let item = MPPositive_LibraryViewModel(.init(libraryType: .love_aritists, coverUrl: nil, title: "Love Artists".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .love_aritists, coverUrl: nil, title: "Love Artists".localizableString(), count: 0)) array.append(item) } if offlines.isEmpty == false, let lastUrl = offlines.first?.reviewURL { - let item = MPPositive_LibraryViewModel(.init(libraryType: .offline_songs, coverUrl: lastUrl, title: "Offline Songs".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .offline_songs, coverUrl: lastUrl, title: "Offline Songs".localizableString(), count: offlines.count)) array.append(item) }else { - let item = MPPositive_LibraryViewModel(.init(libraryType: .offline_songs, coverUrl: nil, title: "Offline Songs".localizableString())) + let item = MPPositive_LibraryViewModel(.init(libraryType: .offline_songs, coverUrl: nil, title: "Offline Songs".localizableString(), count: 0)) array.append(item) } //对自定义列表进行添加 MPPositive_LoadCoreModel.shared.playLists.forEach { list in if list.playList.videosArray.isEmpty == false, let lastUrl = list.coverImageURL, let title = list.title, let identifier = list.playList.playListId { - let item = MPPositive_LibraryViewModel(.init(libraryType: .custom_playlist, coverUrl: lastUrl, title: title, identifier: identifier)) + let item = MPPositive_LibraryViewModel(.init(libraryType: .custom_playlist, coverUrl: lastUrl, title: title, identifier: identifier, count: 0)) array.append(item) } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_SongViewModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_SongViewModel.swift index 866011a..81081fa 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_SongViewModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/ListViewModels/MPPositive_SongViewModel.swift @@ -36,6 +36,11 @@ class MPPositive_SongViewModel: NSObject { var isKVO:Bool = false ///是否完成了预加载 var isPreload:Bool = false + ///是否无数据 + var isEmptyResource:Bool = false + ///是否可以播放(会因为各种问题导致这首歌并不能播放) + @objc dynamic var isPlayEntitlement:NSNumber? + ///音乐实体 var song:MPPositive_SongItemModel! init(_ song:MPPositive_SongItemModel) { @@ -80,7 +85,10 @@ class MPPositive_SongViewModel: NSObject { if song.lyricsID == nil || song.relatedID == nil { //需要网络请求补全数据 improveDataforLycirsAndRelated(song) {[weak self] (result) in - guard let self = self else {return} + guard let self = self else { + group.leave() + return + } if let resultID = result.0 { song.lyricsID = resultID } @@ -104,13 +112,31 @@ class MPPositive_SongViewModel: NSObject { //没有下载过 //调用网络请求补全数据 improveDataforResouceAndCover(song) { [weak self] resourceUrls, coverUrls in - guard let self = self else {return} + guard let self = self else { + group.leave() + return + } if let resourceUrls = resourceUrls { song.resourceUrls = resourceUrls.0 song.itags = resourceUrls.1 song.mimeTypes = resourceUrls.2 } song.coverUrls = coverUrls + isEmptyResource = false + isPlayEntitlement = true + group.leave() + }failure: { [weak self] statu in + guard let self = self else { + group.leave() + return + } + //statu为false的情况下,是网络请求错误,为true则是网络正常,但是没有获取到数据 + if statu == false { + isEmptyResource = false + }else { + //无数据 + isEmptyResource = true + } group.leave() } } @@ -120,9 +146,9 @@ class MPPositive_SongViewModel: NSObject { guard let self = self else {return} //更新播放资源 if let first = song.resourceUrls?.first { + //具备资源,可以播放 resourcePlayerURL = .init(string:first) if isDlownd == true { - //下载了 resourcePlayerAsset = .init(LocalURL: resourcePlayerURL!, videoId: song.videoId ?? "", title: title ?? "") }else { @@ -130,6 +156,11 @@ class MPPositive_SongViewModel: NSObject { resourcePlayerAsset = .init(resourcePlayerURL!, videoId: song.videoId ?? "", title: title ?? "") } resourcePlayerItem = .init(asset: resourcePlayerAsset) + }else { + //不具备资源,不可以播放 + if isEmptyResource == false { + isPlayEntitlement = false + } } //更新歌词 if song.lyrics != nil { diff --git a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/LoadViewModels/MPPositive_PlayerLoadViewModel.swift b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/LoadViewModels/MPPositive_PlayerLoadViewModel.swift index 6d5776c..43ff120 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/LoadViewModels/MPPositive_PlayerLoadViewModel.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Models/ViewModels/LoadViewModels/MPPositive_PlayerLoadViewModel.swift @@ -140,6 +140,7 @@ class MPPositive_PlayerLoadViewModel: NSObject { self.currentVideo = self.listViewVideos.first(where: {$0.song.videoId == targetVideoId}) //只保留最后7首 self.listViewVideos = self.listViewVideos.suffix(7) + MP_PlayerManager.shared.playerStatuTimerAction() } ///重新获取指定歌曲资源 func remakeImproveData(_ completion:@escaping (() -> Void)) { diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_MoreSongOperationsViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_MoreSongOperationsViewController.swift index cbdabf1..427e1e2 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_MoreSongOperationsViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Base(基类,导航栏,标签栏)/MPPositive_MoreSongOperationsViewController.swift @@ -111,6 +111,8 @@ class MPPositive_MoreSongOperationsViewController: UIViewController, UIViewContr } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in @@ -149,6 +151,8 @@ class MPPositive_MoreSongOperationsViewController: UIViewController, UIViewContr } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in @@ -187,6 +191,8 @@ class MPPositive_MoreSongOperationsViewController: UIViewController, UIViewContr } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in @@ -226,6 +232,8 @@ class MPPositive_MoreSongOperationsViewController: UIViewController, UIViewContr } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in 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 2f868ef..85f3192 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 @@ -6,8 +6,9 @@ // import UIKit +import AppLovinSDK ///b面tabBar控制器 -class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitioningDelegate, GADFullScreenContentDelegate { +class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitioningDelegate, GADFullScreenContentDelegate, MAAdDelegate { //自定义tabBar private lazy var customTabBar:MPPositive_CustomTabBar = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 72*width)) private lazy var bottomView:MPPositive_BottomShowView = .init(frame: .init(x: 0, y: 0, width: 351, height: 82)) @@ -62,6 +63,13 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio addNotification() //触发更新弹窗 updateVersionEvent() + + //判断当前的网络,当网络处于不可用状态时,进入离线模式(展示曲库页) + guard MP_NetWorkManager.shared.netWorkStatu != .reachable else { + return + } + //离线模式 + selectedIndex = 2 } //监听通知 private func addNotification() { @@ -129,18 +137,32 @@ extension MPPositive_TabBarController { self?.present(playerVC, animated: true) } } - MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable { [weak self] ad in + MP_ADSimpleManager.shared.showPlayInterstitialAdIfAvailable { [weak self] (ad, platform) in guard let self = self else {return} - if let ad = ad { - //判断音乐播放器是否已经播放 - MP_AdMobManager.shared.isShowingPlayInterstitialAd = true - //播放器还未播放,可以弹出广告 - MP_AdMobManager.shared.setInterstitialSwitch(true) - ad.fullScreenContentDelegate = self - ad.present(fromRootViewController: self) + if platform { + if let ad = ad as? MAInterstitialAd { + //修改插页总开关状态 + MP_AppLovinManager.shared.setInterstitialSwitch(true) + MP_AppLovinManager.shared.isShowingPlayInterstitialAd = true + ad.delegate = self + ad.show() + }else { + if let block = self.pushPlayerBlock { + block() + } + } }else { - if let block = self.pushPlayerBlock { - block() + if let ad = ad as? GADInterstitialAd { + //判断音乐播放器是否已经播放 + MP_AdMobManager.shared.isShowingPlayInterstitialAd = true + //播放器还未播放,可以弹出广告 + MP_AdMobManager.shared.setInterstitialSwitch(true) + ad.fullScreenContentDelegate = self + ad.present(fromRootViewController: self) + }else { + if let block = self.pushPlayerBlock { + block() + } } } } @@ -236,18 +258,58 @@ 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) -// } } } + //MARK: - AppLovin + func didLoad(_ ad: MAAd) { + + } + + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + + } + + func didDisplay(_ ad: MAAd) { + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + print("当前展示的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + MP_AnalyticsManager.shared.max_play_showSuccessAction() + } + } + + func didHide(_ ad: MAAd) { + MP_AppLovinManager.shared.interstitialDate = Date() + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + print("当前消失的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + //执行播放插页广告完成事件包 + if MP_AppLovinManager.shared.completePlayInterstitialAdBlock != nil { + MP_AppLovinManager.shared.completePlayInterstitialAdBlock!() + } + if let block = self.pushPlayerBlock { + block() + } + } + } + + func didClick(_ ad: MAAd) { + + } + + func didFail(toDisplay ad: MAAd, withError error: MAError) { + MP_AppLovinManager.shared.interstitialDate = Date() + + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + + print("播放插页广告展示时出错,广告ID--\(ad.adUnitIdentifier)") + MP_AnalyticsManager.shared.max_play_showFailureAction(error.message) + //执行播放插页广告完成事件包 + if MP_AppLovinManager.shared.completePlayInterstitialAdBlock != nil { + MP_AppLovinManager.shared.completePlayInterstitialAdBlock!() + } + if let block = self.pushPlayerBlock { + block() + } + } + } + } diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Center(个人曲库页)/MPPositive_LibraryViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Center(个人曲库页)/MPPositive_LibraryViewController.swift index cc0c6cd..d1b887d 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Center(个人曲库页)/MPPositive_LibraryViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Center(个人曲库页)/MPPositive_LibraryViewController.swift @@ -243,7 +243,7 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon let offlineVC = MPPositive_OfflineSongsViewController() navigationController?.pushViewController(offlineVC, animated: true) } - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) } } //MARK: - JXSegmentedTitleDataSource @@ -289,7 +289,7 @@ extension MPPositive_LibraryViewController:JXSegmentedListContainerViewDataSourc //展示歌单详情 let playListVC = MPPositive_CustomPlayListViewController(item.playList) navigationController?.pushViewController(playListVC, animated: true) - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) } return showView default://收藏歌单 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 f26f115..094f2b8 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 @@ -280,7 +280,11 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro } //上拉加载更多 @objc private func footerRefreshContinuationData() { - guard MP_NetWorkManager.shared.continuationAndItct != nil else { + guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { + tableView.mj_footer?.endRefreshing() + return + } + guard (MP_NetWorkManager.shared.continuationAndItct != nil) || (MPPositive_BrowseLoadViewModel.shared.browseModuleLists.isEmpty == true) else { tableView.mj_footer?.endRefreshing() return } @@ -588,7 +592,7 @@ extension MPPositive_HomeViewController: UITableViewDataSource, UITableViewDeleg [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("Home") diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_ListShowViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_ListShowViewController.swift index 5f8e8b5..6bdfbf0 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_ListShowViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_ListShowViewController.swift @@ -249,7 +249,7 @@ class MPPositive_ListShowViewController: MPPositive_BaseViewController, UIViewCo [weak self] in guard let self = self, let item = listOrAlbum.items.first else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("List") @@ -277,7 +277,7 @@ class MPPositive_ListShowViewController: MPPositive_BaseViewController, UIViewCo [weak self] in guard let self = self, let item = listOrAlbum.items.randomElement() else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("List") @@ -396,7 +396,7 @@ extension MPPositive_ListShowViewController: UITableViewDataSource, UITableViewD [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("List") diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift index 40663f4..837cfbd 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Home(首页,各项列表页,艺术家页)/MPPositive_MoreContentViewController.swift @@ -139,7 +139,7 @@ extension MPPositive_MoreContentViewController: UICollectionViewDataSource, UICo [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("MoreContent") diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Player(播放器)/MPPositive_PlayerViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Player(播放器)/MPPositive_PlayerViewController.swift index c0f9f12..2435469 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Player(播放器)/MPPositive_PlayerViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Player(播放器)/MPPositive_PlayerViewController.swift @@ -154,6 +154,26 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont activityIndicator.color = .black return activityIndicator }() + //下载引导层 + private lazy var leadMaskView:UIView = { + let maskView = UIView(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height)) + maskView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(maskMissClick(_ :)))) + maskView.isUserInteractionEnabled = true + maskView.backgroundColor = .init(hex: "#000000", alpha: 0.6) + return maskView + }() + //下载提示层 + private lazy var leadNoticeView:UIView = { + let noticeView:UIView = .init(frame: .init(x: 0, y: 0, width: 120*width, height: 43*width)) + noticeView.backgroundColor = .clear + //添加一个提示弹窗 + let noticeImageView = UIImageView(image: .init(named: "Click_Download'logo")) + noticeView.addSubview(noticeImageView) + noticeImageView.snp.makeConstraints { make in + make.left.top.right.bottom.equalToSuperview() + } + return noticeView + }() //封面View(封面,标题,副标题,收藏,下载,进度条View) private lazy var coverView:MPPositive_PlayerCoverView = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 480*width)) //歌词View @@ -274,6 +294,12 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont // print("视频Layer移除") // MP_PlayerManager.shared.videoLayer.removeFromSuperlayer() } + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + if leadMaskView.superview != nil { + setMaskLayer() + } + } //视图配置 private func configure() { //导航View内容配置 @@ -347,6 +373,11 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont make.height.equalTo(42*width) } maskNotReachableView.isHidden = (MP_NetWorkManager.shared.netWorkStatu == .reachable) + guard UserDefaults.standard.bool(forKey: "isFristPlayer") != true else { + return + } + UserDefaults.standard.set(true, forKey: "isFristPlayer") + view.addSubview(leadMaskView) } //生成一个单选按钮组View private func createSwitchActionView() -> UIView { @@ -436,6 +467,30 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont } return bottomView } + //设置阴影层 + private func setMaskLayer() { + // 创建一个遮罩层 + let maskLayer = CAShapeLayer() + // 创建全屏路径 + let path = UIBezierPath(rect: leadMaskView.bounds) + // 获取下载按钮的 frame,并计算出要突出显示的圆形区域 + let buttonFrame = self.coverView.downloadButton.convert(self.coverView.downloadButton.bounds, to: leadMaskView) + let circlePath = UIBezierPath(ovalIn: buttonFrame.insetBy(dx: -15, dy: -15)) // 圆形区域比按钮稍大 + // 将圆形路径添加到全屏路径中(注意使用 `.byReversingPath()` 反转路径,这样圆圈内是透明的) + path.append(circlePath.reversing()) + // 将路径赋值给遮罩层 + maskLayer.path = path.cgPath + // 将遮罩层应用到遮罩视图上 + leadMaskView.layer.mask = maskLayer + view.addSubview(leadNoticeView) + leadNoticeView.snp.makeConstraints { make in + make.right.equalTo(self.coverView.downloadButton.snp.centerX).offset(43.5*width) + make.centerY.equalTo(self.coverView.downloadButton.snp.centerY).offset(-60*width) + make.width.equalTo(180*width) + make.height.equalTo(64.5*width) + } + } + //MARK: - 页面渲染 private func uploadUI() { DispatchQueue.main.async { @@ -557,6 +612,13 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont @objc private func disMissClick(_ sender:UIButton) { dismiss(animated: true) } + //引导遮罩层事件 + @objc private func maskMissClick(_ sender:UITapGestureRecognizer) { + view.endEditing(true) + sender.view?.removeFromSuperview() + leadNoticeView.removeFromSuperview() + } + //切换页面显示内容(单曲封面|歌词)按钮组 @objc private func switchActionClick(_ sender:UIButton) { guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { @@ -694,7 +756,7 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont } //切歌广告 if MP_NetWorkManager.shared.netWorkStatu == .reachable { - MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showPlayInterstitialAdIfAvailable(nil) } MPPositive_Debouncer.shared.call { [weak self] in @@ -712,7 +774,7 @@ class MPPositive_PlayerViewController: MPPositive_BaseViewController, UIViewCont } //切歌广告 if MP_NetWorkManager.shared.netWorkStatu == .reachable { - MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showPlayInterstitialAdIfAvailable(nil) } MPPositive_Debouncer.shared.call { [weak self] in diff --git a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_GrideMoodViewController.swift b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_GrideMoodViewController.swift index 4bcd11e..57bcb1a 100644 --- a/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_GrideMoodViewController.swift +++ b/relax.offline.mp3.music/MP/MPPositive/ViewControllers/Search(搜索页)/MPPositive_GrideMoodViewController.swift @@ -144,7 +144,7 @@ extension MPPositive_GrideMoodViewController: UITableViewDataSource, UITableView [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("Mood") 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 a4bca1e..ca5cda7 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 @@ -125,7 +125,7 @@ extension MPPositive_SearchViewController: UICollectionViewDataSource, UICollect MP_AnalyticsManager.shared.grid_mood_clickAction(item.title ?? "") let moodVC = MPPositive_GrideMoodViewController(item.grid.browseId, params: item.grid.params, title: item.title ?? "") navigationController?.pushViewController(moodVC, animated: false) - MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showSearchInterstitialAdIfAvailable(completion: nil) } } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_CustomTabBarView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_CustomTabBarView.swift index eebd8b3..b231862 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_CustomTabBarView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Base/MPPositive_CustomTabBarView.swift @@ -61,8 +61,16 @@ class MPPositive_CustomTabBarView: UIView { make.centerX.equalToSuperview().multipliedBy(0.45 + 0.55*Double(item.tag)) } } - //默认首位item处于选中状态 - tabBarItems[0].isSelected = true + //判断是否处于离线模式 + guard MP_NetWorkManager.shared.netWorkStatu != .reachable else { + //默认首位item处于选中状态 + tabBarItems.first?.isSelected = true + selectedItemIndex = 0 + return + } + //离线模式 + tabBarItems.last?.isSelected = true + selectedItemIndex = 2 } //点击事件 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 8cce910..1861dcb 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 @@ -249,7 +249,7 @@ class MPPositive_ArtistShowSongTableViewCell: UITableViewCell, PKDownloadButtonD return } //未下载 - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //通过网络请求获取当前预览项资源(转为Song) @@ -277,6 +277,8 @@ class MPPositive_ArtistShowSongTableViewCell: UITableViewCell, PKDownloadButtonD } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowTypeView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowTypeView.swift index acb4a31..5cf1cf2 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowTypeView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_ArtistShowTypeView.swift @@ -278,7 +278,7 @@ extension MPPositive_ArtistShowTypeView:UITableViewDataSource, UITableViewDelega [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("Artist") diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListCollectionViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListCollectionViewCell.swift index ae9f8ff..4146735 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListCollectionViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListCollectionViewCell.swift @@ -18,14 +18,19 @@ class MPPositive_HomeLibraryListCollectionViewCell: UICollectionViewCell { }() //标题Label private lazy var titleLabel:UILabel = createLabel("Title", font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left) + //数量Label + private lazy var countsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 25*width, weight: .bold), textColor: .white, textAlignment: .left) var library:MPPositive_LibraryViewModel!{ didSet{ switch library.library.libraryType { case .custom_playlist: coverImageView.kf.setImage(with: library.cover, placeholder: library.library.libraryType.image) + countsLabel.isHidden = true default: coverImageView.image = library.library.libraryType.image + countsLabel.isHidden = false } + countsLabel.text = "\(library.library.count)" titleLabel.text = library.title } } @@ -51,5 +56,11 @@ class MPPositive_HomeLibraryListCollectionViewCell: UICollectionViewCell { make.top.equalTo(coverImageView.snp.bottom).offset(9*width) make.left.right.equalToSuperview() } + addSubview(countsLabel) + countsLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(8*width) + make.right.equalToSuperview().offset(-8*width) + make.top.equalToSuperview().offset(8*width) + } } } diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListstableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListstableViewCell.swift index daf9c05..0d2423e 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListstableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_HomeLibraryListstableViewCell.swift @@ -121,6 +121,6 @@ extension MPPositive_HomeLibraryListstableViewCell:UICollectionViewDataSource, U } } } - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) } } 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 4ec7467..3ee59c0 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 @@ -240,7 +240,7 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell, PKDownloadB guard let videoId = itemViewModel.browseItem.videoId else { return } - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //通过网络请求获取当前预览项资源(转为Song) @@ -268,6 +268,8 @@ class MPPositive_HomeSingleCollectionViewCell: UICollectionViewCell, PKDownloadB } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in 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 a50c267..c243c82 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 @@ -167,7 +167,7 @@ extension MPPositive_HomeSinglesTableViewCell:UICollectionViewDataSource, UIColl [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } guard let item = (self.browseViewModel?.items[indexPath.row] ?? self.personlViewModel?.items[indexPath.row]) else { 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 947171d..aa6821c 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 @@ -273,7 +273,7 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe guard let videoId = itemView.browseItem.videoId else { return } - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //通过网络请求获取当前预览项资源(转为Song) @@ -301,6 +301,8 @@ class MPPositive_MusicItemShowTableViewCell: UITableViewCell, PKDownloadButtonDe } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_PersonalisedRecommendationsTableViewCell.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_PersonalisedRecommendationsTableViewCell.swift index b76d205..942f609 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_PersonalisedRecommendationsTableViewCell.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Home/MPPositive_PersonalisedRecommendationsTableViewCell.swift @@ -197,7 +197,7 @@ class MPPositive_PersonalisedRecommendationsTableViewCell: UITableViewCell, UIVi [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.home_b_module_clickAction(titleLabel.text ?? "") @@ -328,7 +328,7 @@ extension MPPositive_PersonalisedRecommendationsTableViewCell:UICollectionViewDa [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.home_b_module_clickAction(item.browseItem.pageType ?? "") diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_PlayerCoverView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_PlayerCoverView.swift index d5e7f79..35c96af 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_PlayerCoverView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Player/MPPositive_PlayerCoverView.swift @@ -347,7 +347,7 @@ class MPPositive_PlayerCoverView: UIView, PKDownloadButtonDelegate { MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) return } - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //当开始下载时 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 aa72a6e..8398d30 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 @@ -94,7 +94,7 @@ class MPPositive_SearchResultPreviewShowView: MPPositive_BaseShowView, JXSegment [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("Search") 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 1f2242e..5de739e 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 @@ -314,7 +314,7 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto return } //未下载 - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) //切换为准备状态 downloadButton.state = .pending //通过网络请求获取当前预览项资源(转为Song) @@ -342,6 +342,8 @@ class MPPositive_SearchResultShowTableViewCell: UITableViewCell, PKDownloadButto } first.coverUrls = coverUrls group.leave() + } failure: {_ in + group.leave() } group.notify(queue: .main, execute: { [weak self] in 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 301c64b..6d7928a 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 @@ -123,7 +123,7 @@ class MPPositive_SearchResultTypeShowView: MPPositive_BaseShowView, JXSegmentedL [weak self] in guard let self = self else {return} guard MP_NetWorkManager.shared.netWorkStatu == .reachable else { - MP_HUD.text("Bad connection~".localizableString(), delay: 2.0, completion: nil) + playOfflineSongs() return } MP_AnalyticsManager.shared.song_clickAction("Search") diff --git a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultsShowView.swift b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultsShowView.swift index 594e442..20a924c 100644 --- a/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultsShowView.swift +++ b/relax.offline.mp3.music/MP/MPPositive/Views/Search/MPPositive_SearchResultsShowView.swift @@ -6,7 +6,7 @@ // import UIKit - +import AppLovinSDK class MPPositive_SearchResultsShowView: UIView { ///搜索结果管理模型 var loadModel:MPPositive_SearchResultsLoadViewModel!{ @@ -18,17 +18,32 @@ class MPPositive_SearchResultsShowView: UIView { emptyImageView.isHidden = false }else { if isShowAd == true { - MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable { [weak self] ad in + MP_ADSimpleManager.shared.showSearchInterstitialAdIfAvailable { [weak self] ad, platform in guard let self = self else {return} //判断数据是否有值 if loadModel?.sectionLists?.count != nil { - //有值,不在展示 - MP_AdMobManager.shared.setInterstitialSwitch(false) + if platform { + MP_AppLovinManager.shared.setInterstitialSwitch(false) + }else { + //有值,不在展示 + MP_AdMobManager.shared.setInterstitialSwitch(false) + } }else { - MP_AdMobManager.shared.isShowingSearchInterstitialAd = true - //没有值,展示 - MP_AdMobManager.shared.setInterstitialSwitch(true) - ad.present(fromRootViewController: nil) + if platform { + if let new = ad as? MAInterstitialAd { + MP_AppLovinManager.shared.isShowingSearchInterstitialAd = true + //没有值,展示 + MP_AppLovinManager.shared.setInterstitialSwitch(true) + new.show() + } + }else { + if let new = ad as? GADInterstitialAd { + MP_AdMobManager.shared.isShowingSearchInterstitialAd = true + //没有值,展示 + MP_AdMobManager.shared.setInterstitialSwitch(true) + new.present(fromRootViewController: nil) + } + } } } } 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 8f4ee8b..935f0d7 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 @@ -6,8 +6,9 @@ // import UIKit +import AppLovinSDK ///A面通用标签栏 -class MPSideA_TabBarController: UITabBarController, GADFullScreenContentDelegate { +class MPSideA_TabBarController: UITabBarController, GADFullScreenContentDelegate, MAAdDelegate { //自定义tabBar private lazy var customTabBar:MPSideA_CustomTabBar = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: 72*width)) //底部音乐展示View(默认隐藏) @@ -169,21 +170,6 @@ extension MPSideA_TabBarController: UIViewControllerTransitioningDelegate { //前往播放器 private func pushPlayer() { print("Go to player") - MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable { [weak self] ad in - guard let self = self else {return} - 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() - } - } - } self.pushPlayerBlock = { [weak self] in //执行加载播放器页面 @@ -194,6 +180,35 @@ extension MPSideA_TabBarController: UIViewControllerTransitioningDelegate { self?.present(playerVC, animated: true) } } + MP_ADSimpleManager.shared.showPlayInterstitialAdIfAvailable { [weak self] (ad, platform) in + guard let self = self else {return} + if platform { + if let ad = ad as? MAInterstitialAd { + //修改插页总开关状态 + MP_AppLovinManager.shared.setInterstitialSwitch(true) + MP_AppLovinManager.shared.isShowingPlayInterstitialAd = true + ad.delegate = self + ad.show() + }else { + if let block = self.pushPlayerBlock { + block() + } + } + }else { + if let ad = ad as? GADInterstitialAd { + //判断音乐播放器是否已经播放 + MP_AdMobManager.shared.isShowingPlayInterstitialAd = true + //播放器还未播放,可以弹出广告 + MP_AdMobManager.shared.setInterstitialSwitch(true) + ad.fullScreenContentDelegate = self + ad.present(fromRootViewController: self) + }else { + if let block = self.pushPlayerBlock { + block() + } + } + } + } } func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? { return MPSideA_PresentationController(presentedViewController: presented, presenting: presenting) @@ -325,18 +340,60 @@ extension MPSideA_TabBarController { print("播放插页广告展示时出错,广告ID--\(UUID),具体错误原因:\(error.localizedDescription)") MP_AnalyticsManager.shared.play_ads_showFailureAction(error.localizedDescription) //执行播放插页广告完成事件包 - //执行播放插页广告完成事件包 if MP_AdMobManager.shared.completePlayInterstitialAdBlock != nil { MP_AdMobManager.shared.completePlayInterstitialAdBlock!() } - //执行加载播放器页面 -// DispatchQueue.main.async { -// [weak self] in -// //模态弹出 -// let playerVC = MPSideA_PlayerViewController() -// self?.present(playerVC, animated: true) -// } } } + //MARK: - AppLovin + func didLoad(_ ad: MAAd) { + + } + + func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) { + + } + + func didDisplay(_ ad: MAAd) { + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + print("当前展示的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + MP_AnalyticsManager.shared.max_play_showSuccessAction() + } + } + + func didHide(_ ad: MAAd) { + MP_AppLovinManager.shared.interstitialDate = Date() + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + print("当前消失的广告是播放插页广告,广告ID--\(ad.adUnitIdentifier)") + + //执行播放插页广告完成事件包 + if MP_AppLovinManager.shared.completePlayInterstitialAdBlock != nil { + MP_AppLovinManager.shared.completePlayInterstitialAdBlock!() + } + if let block = self.pushPlayerBlock { + block() + } + } + } + + func didClick(_ ad: MAAd) { + + } + + func didFail(toDisplay ad: MAAd, withError error: MAError) { + MP_AppLovinManager.shared.interstitialDate = Date() + + if ad.adUnitIdentifier == MP_AppLovinManager.shared.playInterstitialAd?.adUnitIdentifier { + print("播放插页广告展示时出错,广告ID--\(ad.adUnitIdentifier)") + MP_AnalyticsManager.shared.max_play_showFailureAction(error.message) + //执行播放插页广告完成事件包 + if MP_AppLovinManager.shared.completePlayInterstitialAdBlock != nil { + MP_AppLovinManager.shared.completePlayInterstitialAdBlock!() + } + if let block = self.pushPlayerBlock { + block() + } + } + } } diff --git a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Center(个人资源)/MPSideA_CenterViewController.swift b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Center(个人资源)/MPSideA_CenterViewController.swift index 4995d9a..6fc9935 100644 --- a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Center(个人资源)/MPSideA_CenterViewController.swift +++ b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Center(个人资源)/MPSideA_CenterViewController.swift @@ -115,7 +115,7 @@ class MPSideA_CenterViewController: MPSideA_BaseViewController { [weak self] in DispatchQueue.main.asyncAfter(wallDeadline: .now() + 0.3) { [weak self] in - MP_AdMobManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showLibraryInterstitialAdIfAvailable(completion: nil) } } navigationController?.pushViewController(setVC, animated: true) diff --git a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Home(音乐资源列表)/MPSideA_PlayerViewController.swift b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Home(音乐资源列表)/MPSideA_PlayerViewController.swift index 1c965e3..2948a7d 100644 --- a/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Home(音乐资源列表)/MPSideA_PlayerViewController.swift +++ b/relax.offline.mp3.music/MP/MPSideA/ViewControllers/Home(音乐资源列表)/MPSideA_PlayerViewController.swift @@ -254,7 +254,7 @@ extension MPSideA_PlayerViewController { //关闭麦克风监听器 MPSideA_MediaCenterManager.shared.stopMonitor() //弹出切割广告 - MP_AdMobManager.shared.showPlayInterstitialAdIfAvailable(completion: nil) + MP_ADSimpleManager.shared.showPlayInterstitialAdIfAvailable(nil) guard let music = MPSideA_MediaCenterManager.shared.getMusic() else { //播放器未能持有音乐实体 print("No Data Music")