B面1.1.1 优化以及功能扩展
This commit is contained in:
parent
130fefd189
commit
d3d3da4f6e
@ -232,11 +232,18 @@
|
||||
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 */; };
|
||||
CBC81FBA2C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */; };
|
||||
CBC81FBC2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC81FBB2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift */; };
|
||||
CBD344DA2C3FACB30095F18F /* MPPositive_JsonGenres.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD344D92C3FACB30095F18F /* MPPositive_JsonGenres.swift */; };
|
||||
CBD344DC2C3FCA270095F18F /* MPPositive_GridModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD344DB2C3FCA270095F18F /* MPPositive_GridModel.swift */; };
|
||||
CBD344DE2C3FD8230095F18F /* MPPositive_GridViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD344DD2C3FD8230095F18F /* MPPositive_GridViewModel.swift */; };
|
||||
CBD4570D2C2EC38400CE766D /* AppTrackingTransparency.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBD4570C2C2EC38400CE766D /* AppTrackingTransparency.framework */; };
|
||||
CBD5CAFD2C3BE9A90001E315 /* MP_MarQueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD5CAFC2C3BE9A90001E315 /* MP_MarQueeLabel.swift */; };
|
||||
CBDAC60E2C2BE1B6008B8D34 /* MPPositive_ChooseNewPlayListTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDAC60D2C2BE1B6008B8D34 /* MPPositive_ChooseNewPlayListTableViewCell.swift */; };
|
||||
CBDBDDF22C40C40900767F0B /* MPPositive_GridLoadViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF12C40C40900767F0B /* MPPositive_GridLoadViewModel.swift */; };
|
||||
CBDBDDF42C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF32C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift */; };
|
||||
CBDBDDF62C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */; };
|
||||
CBF3AEDA2C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF3AED92C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -465,11 +472,18 @@
|
||||
CBC2D6FA2BFDF3D800E17703 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
|
||||
CBC2D6FC2BFDF3D800E17703 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
CBC2D7792BFDF4B900E17703 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
|
||||
CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_AdModelModel.swift; sourceTree = "<group>"; };
|
||||
CBC81FB92C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_HomeSinglesTableViewCell.swift; sourceTree = "<group>"; };
|
||||
CBC81FBB2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_HomeSingleCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
CBD344D92C3FACB30095F18F /* MPPositive_JsonGenres.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_JsonGenres.swift; sourceTree = "<group>"; };
|
||||
CBD344DB2C3FCA270095F18F /* MPPositive_GridModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_GridModel.swift; sourceTree = "<group>"; };
|
||||
CBD344DD2C3FD8230095F18F /* MPPositive_GridViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_GridViewModel.swift; sourceTree = "<group>"; };
|
||||
CBD4570C2C2EC38400CE766D /* AppTrackingTransparency.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppTrackingTransparency.framework; path = System/Library/Frameworks/AppTrackingTransparency.framework; sourceTree = SDKROOT; };
|
||||
CBD5CAFC2C3BE9A90001E315 /* MP_MarQueeLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_MarQueeLabel.swift; sourceTree = "<group>"; };
|
||||
CBDAC60D2C2BE1B6008B8D34 /* MPPositive_ChooseNewPlayListTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_ChooseNewPlayListTableViewCell.swift; sourceTree = "<group>"; };
|
||||
CBDBDDF12C40C40900767F0B /* MPPositive_GridLoadViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_GridLoadViewModel.swift; sourceTree = "<group>"; };
|
||||
CBDBDDF32C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_SearchGrideCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_GrideMoodViewController.swift; sourceTree = "<group>"; };
|
||||
CBF3AED92C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PlayListsShowTypeView.swift; sourceTree = "<group>"; };
|
||||
EE70E1FE424F9A64CCD389DD /* Pods-relax.offline.mp3.music.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-relax.offline.mp3.music.debug.xcconfig"; path = "Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@ -686,6 +700,7 @@
|
||||
children = (
|
||||
CBAFCA322C0A10500054500E /* MPPositive_JsonBrowse.swift */,
|
||||
CBBAF8CC2C339CF200B3C838 /* MPPositive_JsonCharts.swift */,
|
||||
CBD344D92C3FACB30095F18F /* MPPositive_JsonGenres.swift */,
|
||||
CBAFCA302C0A10500054500E /* MPPositive_JsonArtist.swift */,
|
||||
CBAFCA312C0A10500054500E /* MPPositive_JsonArtistMore.swift */,
|
||||
CBAFCA332C0A10500054500E /* MPPositive_JsonListAlbum.swift */,
|
||||
@ -705,7 +720,9 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CBAFCA3D2C0A10500054500E /* MPPositive_ArtistHeaderModel.swift */,
|
||||
CBC3F2B12C3E76160075DC74 /* MPPositive_AdModelModel.swift */,
|
||||
CBAFCA3E2C0A10500054500E /* MPPositive_BrowseItemModel.swift */,
|
||||
CBD344DB2C3FCA270095F18F /* MPPositive_GridModel.swift */,
|
||||
CBAFCA3F2C0A10500054500E /* MPPositive_CollectionArtistModel.swift */,
|
||||
CBAFCA402C0A10500054500E /* MPPositive_CollectionListModel.swift */,
|
||||
CBAFCA412C0A10500054500E /* MPPositive_CollectionSongModel.swift */,
|
||||
@ -727,6 +744,7 @@
|
||||
CBAFCA492C0A10500054500E /* MPPositive_ArtistViewModel.swift */,
|
||||
CBAFCA4A2C0A10500054500E /* MPPositive_BrowseItemViewModel.swift */,
|
||||
CBAFCA4B2C0A10500054500E /* MPPositive_BrowseModuleListViewModel.swift */,
|
||||
CBD344DD2C3FD8230095F18F /* MPPositive_GridViewModel.swift */,
|
||||
CBAFCA4C2C0A10500054500E /* MPPositive_CollectionArtistViewModel.swift */,
|
||||
CBAFCA4D2C0A10500054500E /* MPPositive_CollectionListViewModel.swift */,
|
||||
CBAFCA4E2C0A10500054500E /* MPPositive_CollectionSongViewModel.swift */,
|
||||
@ -751,6 +769,7 @@
|
||||
CBAFCA5A2C0A10500054500E /* MPPositive_PlayerLoadViewModel.swift */,
|
||||
CBAFCA5B2C0A10500054500E /* MPPositive_RecommendLoadViewModel.swift */,
|
||||
CBAFCA5C2C0A10500054500E /* MPPositive_SearchResultsLoadViewModel.swift */,
|
||||
CBDBDDF12C40C40900767F0B /* MPPositive_GridLoadViewModel.swift */,
|
||||
);
|
||||
path = LoadViewModels;
|
||||
sourceTree = "<group>";
|
||||
@ -825,6 +844,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CBAFCA752C0A10500054500E /* MPPositive_SearchViewController.swift */,
|
||||
CBDBDDF52C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift */,
|
||||
CBAFCA742C0A10500054500E /* MPPositive_SearchResultShowViewController.swift */,
|
||||
);
|
||||
path = "Search(搜索页)";
|
||||
@ -909,6 +929,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CBAFCA9E2C0A10500054500E /* MPPositive_SearchTagCollectionViewCell.swift */,
|
||||
CBDBDDF32C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift */,
|
||||
CBAFCA9D2C0A10500054500E /* MPPositive_SearchSuggestionsView.swift */,
|
||||
CBAFCA9A2C0A10500054500E /* MPPositive_SearchResultsShowView.swift */,
|
||||
CBAFCA982C0A10500054500E /* MPPositive_SearchResultPreviewShowView.swift */,
|
||||
@ -1353,6 +1374,7 @@
|
||||
CBAFCB652C0A10500054500E /* MPPositive_HomeListThirdCollectionViewCell.swift in Sources */,
|
||||
CBAFCB472C0A10500054500E /* MPPositive_LoveArtistsViewController.swift in Sources */,
|
||||
CBAFCAF62C0A10500054500E /* InstanceFromNib.swift in Sources */,
|
||||
CBD344DE2C3FD8230095F18F /* MPPositive_GridViewModel.swift in Sources */,
|
||||
CBAFCB622C0A10500054500E /* MPPositive_HomeListFirstCollectionViewCell.swift in Sources */,
|
||||
CBAFCB112C0A10500054500E /* MP_PlayerManager.swift in Sources */,
|
||||
CBAFCB582C0A10500054500E /* MPPositive_LibraryTableViewCell.swift in Sources */,
|
||||
@ -1365,12 +1387,14 @@
|
||||
CBAFCB632C0A10500054500E /* MPPositive_HomeListFourthCollectionViewCell.swift in Sources */,
|
||||
CB1E3B682C23E09100071DEA /* MPPositive_CustomVideoModel.swift in Sources */,
|
||||
CBAFCB3E2C0A10500054500E /* MPPositive_PlayerLoadViewModel.swift in Sources */,
|
||||
CBD344DC2C3FCA270095F18F /* MPPositive_GridModel.swift in Sources */,
|
||||
CBC81FBA2C3694990028143B /* MPPositive_HomeSinglesTableViewCell.swift in Sources */,
|
||||
CBAFCB252C0A10500054500E /* MPPositive_CollectionArtistModel.swift in Sources */,
|
||||
CBAFCB702C0A10500054500E /* MPPositive_SearchResultShowTableViewCell.swift in Sources */,
|
||||
CBAFCB662C0A10500054500E /* MPPositive_HomeShowTableViewCell.swift in Sources */,
|
||||
CBAFCB352C0A10500054500E /* MPPositive_ListAlbumListViewModel.swift in Sources */,
|
||||
CBAFCB7C2C0A10500054500E /* MPSideA_NavigationController.swift in Sources */,
|
||||
CBDBDDF62C40FFC600767F0B /* MPPositive_GrideMoodViewController.swift in Sources */,
|
||||
CBAFCB932C0A10500054500E /* MPSideA_PlayerViewController.swift in Sources */,
|
||||
CBAFCB512C0A10500054500E /* MPPositive_SearchResultShowViewController.swift in Sources */,
|
||||
CBAFCB4C2C0A10500054500E /* MPPositive_ListShowViewController.swift in Sources */,
|
||||
@ -1441,12 +1465,14 @@
|
||||
CBAFCB832C0A10500054500E /* MPSideA_DeleteViewController.swift in Sources */,
|
||||
CBAFCAF22C0A10500054500E /* String.swift in Sources */,
|
||||
CBAFCB0E2C0A10500054500E /* MP_HUD.swift in Sources */,
|
||||
CBD344DA2C3FACB30095F18F /* MPPositive_JsonGenres.swift in Sources */,
|
||||
CB0033F02C290AC200B18FD3 /* MPPositive_CustomPlayListViewModel.swift in Sources */,
|
||||
CBAFCB4B2C0A10500054500E /* MPPositive_HomeViewController.swift in Sources */,
|
||||
CBAFCB2A2C0A10500054500E /* MPPositive_SearchSuggestionItemModel.swift in Sources */,
|
||||
CBAFCB372C0A10500054500E /* MPPositive_RecommendListViewModel.swift in Sources */,
|
||||
CBAFCB282C0A10500054500E /* MPPositive_DownloadItemModel.swift in Sources */,
|
||||
CBAFCB152C0A10500054500E /* MPSideA_MediaCenterManager.swift in Sources */,
|
||||
CBDBDDF22C40C40900767F0B /* MPPositive_GridLoadViewModel.swift in Sources */,
|
||||
CBAFCAEB2C0A10500054500E /* relax.offline.mp3.xcdatamodeld in Sources */,
|
||||
CBAFCB192C0A10500054500E /* MPPositive_JsonBrowse.swift in Sources */,
|
||||
CBAFCB912C0A10500054500E /* MPSideA_HomeViewController.swift in Sources */,
|
||||
@ -1468,6 +1494,7 @@
|
||||
CBAFCB442C0A10500054500E /* MPPositive_PresentationController.swift in Sources */,
|
||||
CB0968752C2121410045E55B /* GADTSmallTemplateView.m in Sources */,
|
||||
CBAFCB9B2C0A10500054500E /* MPSideA_CenterTableViewCell.swift in Sources */,
|
||||
CBC3F2B22C3E76160075DC74 /* MPPositive_AdModelModel.swift in Sources */,
|
||||
CBAFCB412C0A10500054500E /* MPPositive_BaseViewController.swift in Sources */,
|
||||
CBAFCB4E2C0A10500054500E /* MPPositive_PlayerListShowViewController.swift in Sources */,
|
||||
CBAFCB8B2C0A10500054500E /* MPSideA_ServiceViewController.swift in Sources */,
|
||||
@ -1499,6 +1526,7 @@
|
||||
CBAFCB532C0A10500054500E /* MPPositive_BottomShowView.swift in Sources */,
|
||||
CBF3AEDA2C255B1200947AFC /* MPPositive_PlayListsShowTypeView.swift in Sources */,
|
||||
CBC2D6EC2BFDF3D700E17703 /* AppDelegate.swift in Sources */,
|
||||
CBDBDDF42C40D03F00767F0B /* MPPositive_SearchGrideCollectionViewCell.swift in Sources */,
|
||||
CBAFCB322C0A10500054500E /* MPPositive_CollectionListViewModel.swift in Sources */,
|
||||
CBC81FBC2C3696230028143B /* MPPositive_HomeSingleCollectionViewCell.swift in Sources */,
|
||||
CBAFCB812C0A10500054500E /* MPSideA_CenterViewController.swift in Sources */,
|
||||
|
||||
@ -25,6 +25,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
private var backgroundEntryTime:Date?
|
||||
//B面
|
||||
private var positiceVC:MPPositive_TabBarController!
|
||||
//推送要求
|
||||
private let notificationHandler = NotificationHandler()
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
||||
//请求通知权限
|
||||
UNUserNotificationCenter.current()
|
||||
@ -34,8 +36,10 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
print("Users are not allowed to be notified of messages.")
|
||||
}
|
||||
}
|
||||
//切换通知代理
|
||||
UNUserNotificationCenter.current().delegate = notificationHandler
|
||||
//广告默认ID
|
||||
coreAdMosIDs()
|
||||
coreDefaultValues()
|
||||
ActiveDaysCalculation()
|
||||
//FireBase初始化
|
||||
FirebaseApp.configure()
|
||||
@ -82,56 +86,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
//响应后台控制
|
||||
UIApplication.shared.beginReceivingRemoteControlEvents()
|
||||
}
|
||||
//存储修改值
|
||||
func coreAdMosIDs() {
|
||||
if UserDefaults.standard.string(forKey: "OpenICEID") == nil {
|
||||
print("第一次启动,添加广告ID")
|
||||
//存入默认开屏冷启动广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/5575463023", forKey: "OpenICEID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "OpenHOSTID") == nil {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/5575463023", forKey: "OpenHOSTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "SearchINSERTID") == nil {
|
||||
//存入默认搜索插页广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "SearchINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "SearchNATIVEID") == nil {
|
||||
//存入默认搜索原生广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/3986624511", forKey: "SearchNATIVEID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "PlayerINSERTID") == nil {
|
||||
//存入默认播放插页广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "PlayerINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "SwitchINSERTID") == nil {
|
||||
//存入默认切歌插页广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "SwitchINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "LoadINSERTID") == nil {
|
||||
//存入默认下载插页广告ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "LoadINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "LibraryINSERTID") == nil {
|
||||
//存入默认曲库插页ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "LibraryINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "LibraryNATIVEID") == nil {
|
||||
//存入默认曲库原生ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/3986624511", forKey: "LibraryNATIVEID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "GlobalINSERTID") == nil {
|
||||
//存入默认全局备用插页ID
|
||||
UserDefaults.standard.set("ca-app-pub-3940256099942544/4411468910", forKey: "GlobalINSERTID")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "ClientVersion") == nil {
|
||||
UserDefaults.standard.set("1.20240618.01.00", forKey: "ClientVersion")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "PlayerVersion") == nil {
|
||||
UserDefaults.standard.set("6.18.1", forKey: "PlayerVersion")
|
||||
}
|
||||
}
|
||||
//活跃天数计算
|
||||
private func ActiveDaysCalculation() {
|
||||
//判断是否存在活跃天数组
|
||||
@ -279,6 +233,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
func adManagerDidShowInterstitial() {
|
||||
window?.rootViewController?.setNeedsStatusBarAppearanceUpdate()
|
||||
}
|
||||
}
|
||||
///访问appDelegate
|
||||
let accessAppdelegate = ( UIApplication.shared.delegate as! AppDelegate)
|
||||
///在应用内展示通知
|
||||
class NotificationHandler: NSObject, UNUserNotificationCenterDelegate {
|
||||
func userNotificationCenter(_ center: UNUserNotificationCenter,
|
||||
willPresent notification: UNNotification,
|
||||
withCompletionHandler completionHandler:
|
||||
@escaping (UNNotificationPresentationOptions) -> Void) {
|
||||
completionHandler([.alert, .sound, .badge])
|
||||
|
||||
// 如果不想显示某个通知,可以直接用空 options 调用 completionHandler:
|
||||
// completionHandler([])
|
||||
}
|
||||
}
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
<string>fetch</string>
|
||||
</array>
|
||||
<key>GADApplicationIdentifier</key>
|
||||
<string>ca-app-pub-3940256099942544~1458002511</string>
|
||||
<string>ca-app-pub-1371732277241593~3881310073</string>
|
||||
<key>SKAdNetworkItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
|
||||
@ -17,7 +17,7 @@ class MP_BaseViewController: UIViewController {
|
||||
// MP_NetWorkManager.shared.requestStatusToYouTube()
|
||||
// 注册应用从后台唤醒到前台的通知
|
||||
// NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForegroundAction), name:UIApplication.willEnterForegroundNotification, object: nil)
|
||||
|
||||
|
||||
}
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
@ -39,7 +39,7 @@ class MP_BaseViewController: UIViewController {
|
||||
UserDefaults.standard.set(true, forKey: "isNetWorkUsage")
|
||||
|
||||
}
|
||||
|
||||
|
||||
// private func triggerLocalNetworkPrivacyAlert() {
|
||||
// let sock4 = socket(AF_INET, SOCK_DGRAM, 0)
|
||||
// guard sock4 >= 0 else { return }
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Five-Star Review" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ChX-fu-2sj">
|
||||
<rect key="frame" x="59" y="90" width="164.5" height="24"/>
|
||||
<fontDescription key="fontDescription" type="system" weight="heavy" pointSize="20"/>
|
||||
<color key="textColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="lt'd be awesomeif you wrote us a 5 star review" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="2" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iz5-RV-Ild">
|
||||
|
||||
@ -102,6 +102,7 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
}else {
|
||||
//停止计时器
|
||||
timer.isPaused = true
|
||||
MP_AnalyticsManager.shared.launch_progress_endAction()
|
||||
//判断是否具备广告
|
||||
if adShowBlock != nil {
|
||||
adShowBlock!()
|
||||
@ -129,27 +130,11 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
}
|
||||
//拉取广告
|
||||
MP_AdMobManager.shared.loadMoreAdMobs()
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] ad in
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad, isOpen) in
|
||||
guard let self = self else {return}
|
||||
//将广告事件传递闭包赋值
|
||||
adShowBlock = {
|
||||
DispatchQueue.main.async {
|
||||
//修改插页总开关状态
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(true)
|
||||
MP_AdMobManager.shared.isShowingOpenAd = true
|
||||
//覆盖并实现代理
|
||||
ad.fullScreenContentDelegate = self
|
||||
do{
|
||||
try ad.canPresent(fromRootViewController: self)
|
||||
ad.present(fromRootViewController: self)
|
||||
}catch{
|
||||
print("开屏广告展示失败,失败原因:\(error)")
|
||||
if MP_AdMobManager.shared.completeOpenAdBlock != nil {
|
||||
MP_AdMobManager.shared.completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
self.adPresent(ad: ad, isOpen: isOpen)
|
||||
}
|
||||
}
|
||||
//进入过B面
|
||||
@ -180,27 +165,11 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
if open {
|
||||
//开关检测为通过,以下发ID刷新广告
|
||||
MP_AdMobManager.shared.loadMoreAdMobs()
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] ad in
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad,isOpen) in
|
||||
guard let self = self else {return}
|
||||
//将广告事件传递闭包赋值
|
||||
adShowBlock = {
|
||||
DispatchQueue.main.async {
|
||||
//修改插页总开关状态
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(true)
|
||||
MP_AdMobManager.shared.isShowingOpenAd = true
|
||||
//覆盖并实现代理
|
||||
ad.fullScreenContentDelegate = self
|
||||
do{
|
||||
try ad.canPresent(fromRootViewController: self)
|
||||
ad.present(fromRootViewController: self)
|
||||
}catch{
|
||||
print("开屏广告展示失败,失败原因:\(error)")
|
||||
if MP_AdMobManager.shared.completeOpenAdBlock != nil {
|
||||
MP_AdMobManager.shared.completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
self.adPresent(ad: ad, isOpen: isOpen)
|
||||
}
|
||||
}
|
||||
//根据ip值确定进入那个页面
|
||||
@ -278,27 +247,11 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
}else {
|
||||
//开关检测未通过,以默认ID刷新广告
|
||||
MP_AdMobManager.shared.loadMoreAdMobs()
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] ad in
|
||||
MP_AdMobManager.shared.showOpenAdIfAvailable(.ICE) { [weak self] (ad,isOpen) in
|
||||
guard let self = self else {return}
|
||||
//将广告事件传递闭包赋值
|
||||
adShowBlock = {
|
||||
DispatchQueue.main.async {
|
||||
//修改插页总开关状态
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(true)
|
||||
MP_AdMobManager.shared.isShowingOpenAd = true
|
||||
//覆盖并实现代理
|
||||
ad.fullScreenContentDelegate = self
|
||||
do{
|
||||
try ad.canPresent(fromRootViewController: self)
|
||||
ad.present(fromRootViewController: self)
|
||||
}catch{
|
||||
print("开屏广告展示失败,失败原因:\(error)")
|
||||
if MP_AdMobManager.shared.completeOpenAdBlock != nil {
|
||||
MP_AdMobManager.shared.completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
self.adPresent(ad: ad, isOpen: isOpen)
|
||||
}
|
||||
}
|
||||
print("ALog")
|
||||
@ -330,13 +283,52 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
//广告弹出
|
||||
private func adPresent(ad: GADFullScreenPresentingAd, isOpen:Bool) {
|
||||
DispatchQueue.main.async {
|
||||
//修改插页总开关状态
|
||||
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!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}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!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//MARK: - 覆盖型广告代理 GADFullScreenContentDelegate
|
||||
//覆盖型广告将要将要展示
|
||||
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = true
|
||||
MP_AnalyticsManager.shared.cold_ads_showSuccessAction()
|
||||
}
|
||||
//覆盖型广告已经消失
|
||||
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
//当前启动页,展示广告一定是开屏广告
|
||||
if switchBlock != nil {
|
||||
switchBlock!()
|
||||
@ -344,10 +336,15 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
if MP_AdMobManager.shared.completeOpenAdBlock != nil {
|
||||
MP_AdMobManager.shared.completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
//覆盖型广告加载出错
|
||||
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
MP_AnalyticsManager.shared.cold_ads_showFailureAction(error.localizedDescription)
|
||||
//当前启动页,展示广告一定是开屏广告
|
||||
if switchBlock != nil {
|
||||
@ -356,6 +353,10 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
if MP_AdMobManager.shared.completeOpenAdBlock != nil {
|
||||
MP_AdMobManager.shared.completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,6 +8,18 @@
|
||||
import Foundation
|
||||
//MARK: - Color扩展
|
||||
extension UIColor {
|
||||
convenience init?(string: UInt64, alpha: CGFloat = 1.0) {
|
||||
// 1. 将值转换为 8 位十六进制颜色值
|
||||
let hexValue = string >> 8
|
||||
// 2. 将 8 位十六进制值转换为 RGB 值
|
||||
let red = CGFloat((hexValue >> 16) & 0xFF) / 255.0
|
||||
let green = CGFloat((hexValue >> 8) & 0xFF) / 255.0
|
||||
let blue = CGFloat((hexValue) & 0xFF) / 255.0
|
||||
|
||||
// 3. 使用 UIColor 构造方法创建颜色对象
|
||||
self.init(red: red, green: green, blue: blue, alpha: alpha)
|
||||
}
|
||||
|
||||
/// String -> UIColor
|
||||
convenience init(hex: String,alpha:CGFloat? = 1) {
|
||||
let string = hex.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
|
||||
@ -113,6 +113,8 @@ extension NotificationCenter{
|
||||
case download_progress_source
|
||||
///b面歌曲下载结束
|
||||
case dowload_end_source
|
||||
///b面搜索页模块更新
|
||||
case search_gride_reload
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ import AppTrackingTransparency
|
||||
import AdSupport
|
||||
import MessageUI
|
||||
import MarqueeLabel
|
||||
import UserNotifications
|
||||
@_exported import JXSegmentedView
|
||||
@_exported import JXPagingView
|
||||
//给JXPagingListContainerView添加extension,表示遵从JXSegmentedViewListContainer的协议
|
||||
@ -70,6 +71,135 @@ let privacyUrl:URL = .init(string: "https://musiclax.mystrikingly.com/privacy")!
|
||||
let serviceUrl:URL = .init(string: "https://musiclax.mystrikingly.com/terms")!
|
||||
|
||||
//MARK: - 全局变量与方法
|
||||
//存储默认配置值
|
||||
func coreDefaultValues() {
|
||||
if UserDefaults.standard.object(forKey: "OpenICEID") == nil {
|
||||
print("第一次启动,添加广告ID")
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/2126815630", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/8500652294", ad: "AdMob", type: .Open),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/4561407280", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/1926543650", ad: "AdMob", type: .Open)]) {
|
||||
//存入默认开屏冷启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "OpenICEID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "OpenHOSTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/9262752398", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/6536516707", ad: "AdMob", type: .Open),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/9239018894", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/3299335073", ad: "AdMob", type: .Open)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "OpenHOSTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "SearchINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/5323507386", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/6877962328", ad: "AdMob", type: .Insert),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/4251798981", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/8622500865", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "SearchINSERTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "SearchNATIVEID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/5674216970", ad: "AdMob", type: .Native)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "SearchNATIVEID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "PlayerINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/9569874154", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/8256792481", ad: "AdMob", type: .Insert),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/8031261896", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/4182802216", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "PlayerINSERTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "SwitchINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/4990165586", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/5247485769", ad: "AdMob", type: .Insert),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/1050920574", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/8439981117", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "SwitchINSERTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "LoadINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/4335559460", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/2398278378", ad: "AdMob", type: .Insert),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/3107763383", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "LoadINSERTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "LibraryINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/4607022200", ad: "AdMob", type: .Insert),
|
||||
.init(level: 2, identifier: "ca-app-pub-1371732277241593/3104538158", ad: "AdMob", type: .Insert),
|
||||
.init(level: 1, identifier: "ca-app-pub-1371732277241593/8931897131", ad: "AdMob", type: .Insert),
|
||||
.init(level: 0, identifier: "ca-app-pub-1371732277241593/5298812459", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "LibraryINSERTID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "LibraryNATIVEID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/4683255855", ad: "AdMob", type: .Native)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "LibraryNATIVEID")
|
||||
}
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "GlobalINSERTID") == nil {
|
||||
if let array = coreAdModelforJson([.init(level: 3, identifier: "ca-app-pub-1371732277241593/9449223728", ad: "AdMob", type: .Insert)]) {
|
||||
//存入默认开屏热启动广告ID
|
||||
UserDefaults.standard.set(array, forKey: "GlobalINSERTID")
|
||||
}
|
||||
}
|
||||
//更多内容操作
|
||||
if UserDefaults.standard.string(forKey: "ClientVersion") == nil {
|
||||
UserDefaults.standard.set("1.20240618.01.00", forKey: "ClientVersion")
|
||||
}
|
||||
if UserDefaults.standard.string(forKey: "PlayerVersion") == nil {
|
||||
UserDefaults.standard.set("6.18.1", forKey: "PlayerVersion")
|
||||
}
|
||||
if UserDefaults.standard.object(forKey: "NotificationBodyTexts") == nil {
|
||||
UserDefaults.standard.set(["✅ Enjoy your favorite offline music.Your new playlist is ready! Enjoy your favorite offline music.",
|
||||
"🕛 Now is the time to enjoy non-stop music!",
|
||||
"🚀 Boost your day with new offline music selections!",
|
||||
"🎵 Ready for a music adventure? Download latest tracks for offline fun!",
|
||||
"❤️ Your favorite songs are available for offline playback now.",
|
||||
"😍 New recommendations tailored for you. Add them to your library.",
|
||||
"👉 Touch the music journey, start now!",
|
||||
"🔥 Summer hits ready for download. Enjoy offline!",
|
||||
"🙌 Your music, your way. 💎💎💎",
|
||||
"💡 Discover today's music,enjoy the moment!"
|
||||
], forKey: "NotificationBodyTexts")
|
||||
}
|
||||
}
|
||||
///将广告模型组转为Data
|
||||
func coreAdModelforJson(_ array:[MPPositive_AdModelModel]) -> Data? {
|
||||
guard array.isEmpty != true else {return nil}
|
||||
do{
|
||||
let jsonData = try JSONEncoder().encode(array)
|
||||
return jsonData
|
||||
}catch {
|
||||
//编译失败
|
||||
print("用户默认广告配置设置失败,失败原因:\(error.localizedDescription)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
///将data转为广告模型组
|
||||
func jsonforCoreAdModel(_ data:Data) -> [MPPositive_AdModelModel]? {
|
||||
do{
|
||||
let array:[MPPositive_AdModelModel] = try JSONDecoder().decode([MPPositive_AdModelModel].self, from: data)
|
||||
return array
|
||||
}catch{
|
||||
//编译失败
|
||||
print("用户默认广告配置设置失败,失败原因:\(error.localizedDescription)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///总事件闭包
|
||||
typealias ActionBlock = () -> Void?
|
||||
///A面全局模态弹出类型
|
||||
@ -246,7 +376,7 @@ func saveLoadVideoItem(_ song:MPPositive_SongItemModel, completion:(() -> Void)?
|
||||
item.videoId = song.videoId
|
||||
item.relatedID = song.relatedID
|
||||
//保存下载数据
|
||||
MPPositive_DownloadItemModel.save(true)
|
||||
MPPositive_DownloadItemModel.save()
|
||||
completion?()
|
||||
DispatchQueue.main.async {
|
||||
//更新数据库
|
||||
@ -257,3 +387,51 @@ func saveLoadVideoItem(_ song:MPPositive_SongItemModel, completion:(() -> Void)?
|
||||
}
|
||||
}
|
||||
}
|
||||
///发布通知
|
||||
func scheduleDailyNotifications() {
|
||||
UNUserNotificationCenter.current().getNotificationSettings {
|
||||
settings in
|
||||
switch settings.authorizationStatus {
|
||||
case .authorized:
|
||||
DispatchQueue.main.async {
|
||||
guard let texts = UserDefaults.standard.object(forKey: "NotificationBodyTexts") as? [String], texts.isEmpty != true else {return}
|
||||
// 获取通知中心
|
||||
let center = UNUserNotificationCenter.current()
|
||||
//创建通知内容,通知只具备body
|
||||
let firstContent = UNMutableNotificationContent()
|
||||
firstContent.title = ""
|
||||
firstContent.body = texts.randomElement() ?? ""
|
||||
firstContent.sound = UNNotificationSound.default
|
||||
//设置触发器-每日上午10点
|
||||
var firstDateComponents = DateComponents()
|
||||
firstDateComponents.hour = 10
|
||||
let firstTrigger = UNCalendarNotificationTrigger(dateMatching: firstDateComponents, repeats: true)
|
||||
//创建通知内容,通知只具备body
|
||||
let secondContent = UNMutableNotificationContent()
|
||||
secondContent.title = ""
|
||||
secondContent.body = texts.randomElement() ?? ""
|
||||
secondContent.sound = UNNotificationSound.default
|
||||
//设置触发器-每日下午2点
|
||||
var secondDateComponents = DateComponents()
|
||||
secondDateComponents.hour = 14
|
||||
let secondTrigger = UNCalendarNotificationTrigger(dateMatching: secondDateComponents, repeats: true)
|
||||
//创建通知请求
|
||||
let firstRequest = UNNotificationRequest(identifier: "relax.offline.mp3.morningNotification", content: firstContent, trigger: firstTrigger)
|
||||
let secondRequest = UNNotificationRequest(identifier: "relax.offline.mp3.afternoonNotification", content: secondContent, trigger: secondTrigger)
|
||||
// 将通知请求添加到通知中心
|
||||
center.add(firstRequest) { error in
|
||||
if let error = error {
|
||||
print("更新上午通知失败,失败原因: \(error)")
|
||||
}
|
||||
}
|
||||
center.add(secondRequest) { error in
|
||||
if let error = error {
|
||||
print("更新下午通知失败,失败原因: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,7 +79,22 @@ extension MP_CoreDataOperationDelegate {
|
||||
/// 查询全部实体 (异步)
|
||||
/// - Parameter completion: 查询完成后回调,在主线程执行
|
||||
static func fetchAll(completion: @escaping ([ManagedObject]) -> Void) {
|
||||
fetch(predicate: nil, completion: completion)
|
||||
let fetchRequest = ManagedObject.fetchRequest
|
||||
// 使用 perform 方法异步执行查询
|
||||
MP_CoreDataHandlerManager.shared.context.perform {
|
||||
do {
|
||||
let results = try MP_CoreDataHandlerManager.shared.context.fetch(fetchRequest)
|
||||
// 回到主线程调用 completion 闭包
|
||||
DispatchQueue.main.async {
|
||||
completion(results)
|
||||
}
|
||||
} catch {
|
||||
print("Failed to fetch \(ManagedObject.entityName): \(error)")
|
||||
DispatchQueue.main.async {
|
||||
completion([]) // 查询失败,返回空数组
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/// 从表删除实体
|
||||
/// - Parameter object: 指定的实体
|
||||
@ -93,6 +108,10 @@ extension MP_CoreDataOperationDelegate {
|
||||
|
||||
/// 表执行保存
|
||||
static func save(_ isBackTheard:Bool = false) {
|
||||
MP_CoreDataHandlerManager.shared.saveContext()
|
||||
if isBackTheard {
|
||||
MP_CoreDataHandlerManager.shared.saveContextInBackground()
|
||||
}else {
|
||||
MP_CoreDataHandlerManager.shared.saveContext()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
static let shared = MP_AdMobManager()
|
||||
private let sharedInstance = GADMobileAds.sharedInstance()
|
||||
///广告总开关
|
||||
private var openAdStatus:Bool = false
|
||||
private var openAdStatus:Bool = true
|
||||
///广告过期时间(50分钟)
|
||||
private let expirationTime:TimeInterval = 3000
|
||||
|
||||
@ -64,6 +64,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
guard let self = self, interstitialSwitch == true else {return}
|
||||
//销毁现在的开屏广告实例
|
||||
appOpenAd = nil
|
||||
appInterstitialAd = nil
|
||||
isShowingOpenAd = false
|
||||
loadOpenAdTime = nil
|
||||
//关闭插页广告开关
|
||||
@ -216,36 +217,36 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
///更新ID
|
||||
func reloadAdMobIDs() {
|
||||
//更新所有广告ID
|
||||
if let str = UserDefaults.standard.string(forKey: "OpenICEID") {
|
||||
if let data = UserDefaults.standard.object(forKey: "OpenICEID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
print("成功提取ID")
|
||||
OpenICEID = str
|
||||
OpenICEID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "OpenHOSTID") {
|
||||
OpenHOSTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "OpenHOSTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
OpenHOSTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "SearchINSERTID") {
|
||||
SearchINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "SearchINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
SearchINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "SearchNATIVEID") {
|
||||
SearchNATIVEID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "SearchNATIVEID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
SearchNATIVEID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "PlayerINSERTID") {
|
||||
PlayerINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "PlayerINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
PlayerINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "SwitchINSERTID") {
|
||||
SwitchINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "SwitchINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
SwitchINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "LoadINSERTID") {
|
||||
LoadINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "LoadINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
LoadINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "LibraryINSERTID") {
|
||||
LibraryINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "LibraryINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
LibraryINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "LibraryNATIVEID") {
|
||||
LibraryNATIVEID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "LibraryNATIVEID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
LibraryNATIVEID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
if let str = UserDefaults.standard.string(forKey: "GlobalINSERTID") {
|
||||
GlobalINSERTID = str
|
||||
if let data = UserDefaults.standard.object(forKey: "GlobalINSERTID") as? Data, let array = jsonforCoreAdModel(data) {
|
||||
GlobalINSERTID = array.sorted(by: {$0.level > $1.level})
|
||||
}
|
||||
}
|
||||
///加载更多广告
|
||||
@ -318,9 +319,9 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
|
||||
//MARK: - 开屏
|
||||
//开屏冷启动广告ID
|
||||
private var OpenICEID:String!
|
||||
private var OpenICEID:[MPPositive_AdModelModel] = []
|
||||
//开屏热启动广告ID
|
||||
private var OpenHOSTID:String!
|
||||
private var OpenHOSTID:[MPPositive_AdModelModel] = []
|
||||
//开屏广告类型
|
||||
enum OpenType:Int {
|
||||
//冷启动
|
||||
@ -336,8 +337,10 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
}
|
||||
}
|
||||
}
|
||||
//开屏广告实例
|
||||
//应用开屏广告实例
|
||||
private var appOpenAd:GADAppOpenAd?
|
||||
//应用插页广告实例
|
||||
private var appInterstitialAd:GADInterstitialAd?
|
||||
//是否正在加载广告
|
||||
private var isLoadingOpenAd:Bool = false
|
||||
//是否正在展示广告
|
||||
@ -358,8 +361,26 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
var completeOpenAdBlock:(() -> Void)?
|
||||
|
||||
///异步加载开屏广告
|
||||
func loadOpenAd(_ type:OpenType,completion: @escaping (Bool) -> Void) {
|
||||
func loadOpenAd(_ type:OpenType, level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
//检索是否超过了对应的id组的阶级数量
|
||||
var item:MPPositive_AdModelModel
|
||||
switch type {
|
||||
case .ICE:
|
||||
guard level <= (OpenICEID.count-1) else {
|
||||
print("冷启动广告组已经全部加载失败,停止继续加载")
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
item = OpenICEID[level]
|
||||
case .HOST:
|
||||
guard level <= (OpenHOSTID.count-1) else {
|
||||
print("热启动广告组已经全部加载失败,停止继续加载")
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
item = OpenHOSTID[level]
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingOpenAd || isOpenAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -367,35 +388,54 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingOpenAd = true
|
||||
var UUID:String
|
||||
switch type {
|
||||
case .ICE:
|
||||
UUID = OpenICEID
|
||||
case .HOST:
|
||||
UUID = OpenHOSTID
|
||||
}
|
||||
// 使用 GADAppOpenAd 的 load 方法和一个completion handler来加载广告
|
||||
GADAppOpenAd.load(withAdUnitID: UUID, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载开屏广告失败,失败原因: \(error.localizedDescription)")
|
||||
self.isLoadingOpenAd = false
|
||||
completion(false)
|
||||
} else {
|
||||
self.appOpenAd = ad
|
||||
self.isLoadingOpenAd = false
|
||||
//实现代理
|
||||
self.appOpenAd?.fullScreenContentDelegate = self
|
||||
//更新加载时间
|
||||
self.loadOpenAdTime = Date()
|
||||
completion(true)
|
||||
//判断需要生成什么广告
|
||||
if item.type == .Open {
|
||||
//生成开屏广告
|
||||
// 使用 GADAppOpenAd 的 load 方法和一个completion handler来加载广告
|
||||
GADAppOpenAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载开屏广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingOpenAd = false
|
||||
loadOpenAd(type, level: level+1, completion: completion)
|
||||
} else {
|
||||
self.appOpenAd = ad
|
||||
self.isLoadingOpenAd = false
|
||||
//实现代理
|
||||
self.appOpenAd?.fullScreenContentDelegate = self
|
||||
//更新加载时间
|
||||
self.loadOpenAdTime = Date()
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if item.type == .Insert {
|
||||
//生成插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载开屏广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingOpenAd = false
|
||||
loadOpenAd(type, level: level+1, completion: completion)
|
||||
} else {
|
||||
self.appInterstitialAd = ad
|
||||
self.isLoadingOpenAd = false
|
||||
//实现代理
|
||||
self.appInterstitialAd?.fullScreenContentDelegate = self
|
||||
//更新加载时间
|
||||
self.loadOpenAdTime = Date()
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}else {
|
||||
completion(false)
|
||||
}
|
||||
}
|
||||
///开屏广告展示
|
||||
func showOpenAdIfAvailable(_ type:OpenType, completion:((GADAppOpenAd) -> Void)?) {
|
||||
func showOpenAdIfAvailable(_ type:OpenType, completion:((_ T:GADFullScreenPresentingAd, _ isOpen:Bool) -> Void)?) {
|
||||
guard openAdStatus else {return}
|
||||
// 如果应用插页广告或者开屏广告已经正在展示,则不再展示该广告。
|
||||
guard !interstitialSwitch, !isShowingOpenAd else { return }
|
||||
@ -415,10 +455,33 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
MP_AnalyticsManager.shared.hot_ads_chanceAction()
|
||||
}
|
||||
//当开屏广告确定有值后展示
|
||||
if let ad = appOpenAd {
|
||||
if let ad = (appOpenAd) {
|
||||
//传递加载完成事件
|
||||
if let block = completion {
|
||||
block(ad)
|
||||
block(ad, true)
|
||||
}else {
|
||||
isShowingOpenAd = true
|
||||
interstitialSwitch = true
|
||||
DispatchQueue.main.async {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
do{
|
||||
try ad.canPresent(fromRootViewController: nil)
|
||||
ad.present(fromRootViewController: nil)
|
||||
|
||||
}catch{
|
||||
print("开屏广告展示失败,失败原因:\(error)")
|
||||
if completeOpenAdBlock != nil {
|
||||
completeOpenAdBlock!()
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
}
|
||||
}else if let ad = (appInterstitialAd) {
|
||||
//传递加载完成事件
|
||||
if let block = completion {
|
||||
block(ad, false)
|
||||
}else {
|
||||
isShowingOpenAd = true
|
||||
interstitialSwitch = true
|
||||
@ -447,14 +510,14 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
}
|
||||
///查询是否有开屏广告
|
||||
func isOpenAdAvailable() -> Bool {
|
||||
return appOpenAd != nil && wasAdexpirationTime(loadOpenAdTime)
|
||||
return (appOpenAd != nil || appInterstitialAd != nil) && wasAdexpirationTime(loadOpenAdTime)
|
||||
}
|
||||
|
||||
//MARK: - 搜索
|
||||
//搜索插页广告ID
|
||||
private var SearchINSERTID:String!
|
||||
private var SearchINSERTID:[MPPositive_AdModelModel] = []
|
||||
//搜索原生广告ID
|
||||
private var SearchNATIVEID:String!
|
||||
private var SearchNATIVEID:[MPPositive_AdModelModel] = []
|
||||
///搜索插页广告
|
||||
private var searchInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载搜索插页广告
|
||||
@ -492,9 +555,11 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
let multipleAdOptions = GADMultipleAdsAdLoaderOptions()
|
||||
//加载一条,每次即使结束后重新刷新数据
|
||||
multipleAdOptions.numberOfAds = 1
|
||||
searchAdLoader = GADAdLoader(adUnitID: SearchNATIVEID, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions])
|
||||
searchAdLoader?.delegate = self
|
||||
searchAdLoader?.load(GADRequest())
|
||||
if let first = SearchNATIVEID.first, first.type == .Native {
|
||||
searchAdLoader = GADAdLoader(adUnitID: first.identifier, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions])
|
||||
searchAdLoader?.delegate = self
|
||||
searchAdLoader?.load(GADRequest())
|
||||
}
|
||||
}
|
||||
///将加载的搜索原生广告添加到页面中
|
||||
func layoutSearchNativeAd(in containerView: UIView) {
|
||||
@ -541,8 +606,16 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
}
|
||||
|
||||
//异步加载搜索插页广告
|
||||
func loadSearchInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadSearchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (SearchINSERTID.count-1) else {
|
||||
print("搜索插页广告组已经全部加载失败,停止继续加载")
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingSearchInterstitialAd || isSearchInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -550,17 +623,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingSearchInterstitialAd = true
|
||||
let item = SearchINSERTID[level]
|
||||
//加载搜索插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: SearchINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载搜索插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载搜索插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingSearchInterstitialAd = false
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
loadSearchInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.searchInterstitialAd = ad
|
||||
self.isLoadingSearchInterstitialAd = false
|
||||
@ -628,7 +699,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
|
||||
//MARK: - 播放
|
||||
//播放插页广告ID
|
||||
private var PlayerINSERTID:String!
|
||||
private var PlayerINSERTID:[MPPositive_AdModelModel] = []
|
||||
///播放插页广告
|
||||
var playInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载播放插页广告
|
||||
@ -640,8 +711,16 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
///播放广告处理闭包
|
||||
var completePlayInterstitialAdBlock:(() -> Void)?
|
||||
//异步加载播放插页广告
|
||||
func loadPlayInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadPlayInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (PlayerINSERTID.count-1) else {
|
||||
print("播放插页广告组已经全部加载失败,停止继续加载")
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingPlayInterstitialAd || isPlayInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -649,16 +728,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingPlayInterstitialAd = true
|
||||
let item = PlayerINSERTID[level]
|
||||
//加载播放插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: PlayerINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载播放插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载播放插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingPlayInterstitialAd = false
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
loadPlayInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.playInterstitialAd = ad
|
||||
self.isLoadingPlayInterstitialAd = false
|
||||
@ -727,7 +805,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
|
||||
//MARK: - 切歌
|
||||
//切歌插页广告ID
|
||||
private var SwitchINSERTID:String!
|
||||
private var SwitchINSERTID:[MPPositive_AdModelModel] = []
|
||||
///切歌插页广告
|
||||
var switchInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载切歌插页广告
|
||||
@ -739,8 +817,16 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
///切歌广告处理闭包
|
||||
var completeSwitchInterstitialAdBlock:(() -> Void)?
|
||||
//异步加载切歌插页广告
|
||||
func loadSwitchInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadSwitchInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (SwitchINSERTID.count-1) else {
|
||||
print("切歌插页广告组已经全部加载失败,停止继续加载")
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingSwitchInterstitialAd || isSwitchInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -748,16 +834,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingSwitchInterstitialAd = true
|
||||
let item = SwitchINSERTID[level]
|
||||
//加载播放插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: SwitchINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载切歌插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载切歌插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingSwitchInterstitialAd = false
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
loadSwitchInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.switchInterstitialAd = ad
|
||||
self.isLoadingSwitchInterstitialAd = false
|
||||
@ -825,7 +910,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
|
||||
//MARK: - 下载
|
||||
//下载插页广告ID
|
||||
private var LoadINSERTID:String!
|
||||
private var LoadINSERTID:[MPPositive_AdModelModel] = []
|
||||
///下载插页广告
|
||||
var loadInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载下载插页广告
|
||||
@ -837,8 +922,16 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
///下载广告处理闭包
|
||||
var completeLoadInterstitialAdBlock:(() -> Void)?
|
||||
//异步加载下载插页广告
|
||||
func loadLoadInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadLoadInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (LoadINSERTID.count-1) else {
|
||||
print("下载插页广告组已经全部加载失败,停止继续加载")
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingLoadInterstitialAd || isLoadInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -846,16 +939,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingLoadInterstitialAd = true
|
||||
let item = LoadINSERTID[level]
|
||||
//加载下载插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: LoadINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载下载插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载下载插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingLoadInterstitialAd = false
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
loadLoadInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.loadInterstitialAd = ad
|
||||
self.isLoadingLoadInterstitialAd = false
|
||||
@ -922,9 +1014,9 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
}
|
||||
//MARK: - 曲库
|
||||
//曲库插页ID
|
||||
private var LibraryINSERTID:String!
|
||||
private var LibraryINSERTID:[MPPositive_AdModelModel] = []
|
||||
//曲库原生ID
|
||||
private var LibraryNATIVEID:String!
|
||||
private var LibraryNATIVEID:[MPPositive_AdModelModel] = []
|
||||
///曲库插页广告
|
||||
private var libraryInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载曲库插页广告
|
||||
@ -967,10 +1059,12 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
let multipleAdOptions = GADMultipleAdsAdLoaderOptions()
|
||||
//加载一条,每次即使结束后重新刷新数据
|
||||
multipleAdOptions.numberOfAds = 2
|
||||
libraryAdLoader = GADAdLoader(adUnitID: LibraryNATIVEID, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions])
|
||||
libraryAdLoader?.delegate = self
|
||||
libraryAdLoader?.load(GADRequest())
|
||||
libraryNativeAds = []
|
||||
if let first = LibraryNATIVEID.first, first.type == .Native {
|
||||
libraryAdLoader = GADAdLoader(adUnitID: first.identifier, rootViewController: vc, adTypes: [.native], options: [multipleAdOptions])
|
||||
libraryAdLoader?.delegate = self
|
||||
libraryAdLoader?.load(GADRequest())
|
||||
libraryNativeAds = []
|
||||
}
|
||||
}
|
||||
///将加载的搜索原生广告添加到页面中
|
||||
func layoutLibraryNativeAd(in containerView: UIView, index:Int) {
|
||||
@ -1047,8 +1141,16 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return Date().timeIntervalSince(date) < refreshLibraryTimes
|
||||
}
|
||||
//异步加载曲库插页广告
|
||||
func loadLibraryInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadLibraryInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (LibraryINSERTID.count-1) else {
|
||||
print("曲库插页广告组已经全部加载失败,停止继续加载")
|
||||
//开始加载全局插页
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingLibraryInterstitialAd || isLibraryInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -1056,16 +1158,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingLibraryInterstitialAd = true
|
||||
let item = LibraryINSERTID[level]
|
||||
//加载曲库插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: LibraryINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载曲库插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载曲库插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingLibraryInterstitialAd = false
|
||||
loadGlobalInterstitialAd { status in
|
||||
completion(status)
|
||||
}
|
||||
loadLibraryInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.libraryInterstitialAd = ad
|
||||
self.isLoadingLibraryInterstitialAd = false
|
||||
@ -1135,7 +1236,7 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
|
||||
//MARK: - 全局
|
||||
//全局备用插页ID
|
||||
private var GlobalINSERTID:String!
|
||||
private var GlobalINSERTID:[MPPositive_AdModelModel] = []
|
||||
///全局插页广告
|
||||
private var globalInterstitialAd:GADInterstitialAd?
|
||||
///是否正在加载全局插页广告
|
||||
@ -1147,8 +1248,13 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
///全局广告处理闭包
|
||||
var completeGlobalInterstitialAdBlock:(() -> Void)?
|
||||
//异步加载全局插页广告
|
||||
func loadGlobalInterstitialAd(completion: @escaping (Bool) -> Void) {
|
||||
func loadGlobalInterstitialAd(_ level:Int = 0, completion: @escaping (Bool) -> Void) {
|
||||
guard openAdStatus else {return}
|
||||
guard level <= (GlobalINSERTID.count-1) else {
|
||||
print("全局插页广告组已经全部加载失败,停止继续加载")
|
||||
completion(false)
|
||||
return
|
||||
}
|
||||
// 检测当前是否有广告或者有广告正在加载
|
||||
if isLoadingGlobalInterstitialAd || isGlobalInterstitialAdAvailable() {
|
||||
// 有广告或有广告在加载
|
||||
@ -1156,14 +1262,15 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
return
|
||||
}
|
||||
isLoadingGlobalInterstitialAd = true
|
||||
let item = GlobalINSERTID[level]
|
||||
//加载全局插页广告
|
||||
GADInterstitialAd.load(withAdUnitID: GlobalINSERTID, request: GADRequest()) { ad, error in
|
||||
GADInterstitialAd.load(withAdUnitID: item.identifier, request: GADRequest()) { ad, error in
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let error = error {
|
||||
print("加载全局插页广告失败,失败原因: \(error.localizedDescription)")
|
||||
print("加载全局插页广告失败,失败原因: \(error.localizedDescription),已下调广告ID等级,重新加载")
|
||||
self.isLoadingGlobalInterstitialAd = false
|
||||
completion(false)
|
||||
loadGlobalInterstitialAd(level+1, completion: completion)
|
||||
} else {
|
||||
self.globalInterstitialAd = ad
|
||||
self.isLoadingGlobalInterstitialAd = false
|
||||
@ -1220,12 +1327,13 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
//MARK: - 覆盖型广告代理 GADFullScreenContentDelegate
|
||||
//覆盖型广告将要将要展示
|
||||
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
if ad === appOpenAd {//开屏广告
|
||||
print("当前展示的广告是开屏广告,广告ID--\(appOpenAd?.adUnitID ?? "")")
|
||||
// UIApplication.shared.isStatusBarHidden = true
|
||||
if ad === appOpenAd || ad === appInterstitialAd {//开屏广告
|
||||
print("当前展示的广告是开屏广告,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? ""))")
|
||||
//判断是冷启动还是热启动
|
||||
if appOpenAd?.adUnitID == OpenICEID {
|
||||
if OpenICEID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) {
|
||||
MP_AnalyticsManager.shared.cold_ads_showSuccessAction()
|
||||
}else if appOpenAd?.adUnitID == OpenHOSTID {
|
||||
}else if OpenHOSTID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) {
|
||||
MP_AnalyticsManager.shared.hot_ads_showSuccessAction()
|
||||
}
|
||||
}else if ad === searchInterstitialAd {//搜索插页广告
|
||||
@ -1249,10 +1357,11 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
}
|
||||
//覆盖型广告已经消失
|
||||
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
//更新插页广告展示时间
|
||||
interstitialDate = Date()
|
||||
if ad === appOpenAd {//开屏广告
|
||||
print("当前消失的广告是开屏广告,广告ID--\(appOpenAd?.adUnitID ?? "")")
|
||||
if ad === appOpenAd || ad === appInterstitialAd {//开屏广告
|
||||
print("当前消失的广告是开屏广告,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? ""))")
|
||||
//执行开屏广告完成事件包
|
||||
if completeOpenAdBlock != nil {
|
||||
completeOpenAdBlock!()
|
||||
@ -1294,18 +1403,23 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
completeGlobalInterstitialAdBlock!()
|
||||
}
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
//覆盖型广告加载出错
|
||||
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
//更新插页广告展示时间
|
||||
interstitialDate = Date()
|
||||
if ad === appOpenAd {//开屏广告
|
||||
print("开屏广告展示时出错,广告ID--\(appOpenAd?.adUnitID ?? ""),具体错误原因:\(error.localizedDescription)")
|
||||
if ad === appOpenAd || ad === appInterstitialAd {//应用开屏广告
|
||||
print("开屏广告展示时出错,广告ID--\(appOpenAd != nil ? (appOpenAd?.adUnitID ?? ""):(appInterstitialAd?.adUnitID ?? "")),具体错误原因:\(error.localizedDescription)")
|
||||
//判断是冷启动还是热启动
|
||||
if appOpenAd?.adUnitID == OpenICEID {
|
||||
if OpenICEID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) {
|
||||
MP_AnalyticsManager.shared.cold_ads_showFailureAction(error.localizedDescription)
|
||||
}else if appOpenAd?.adUnitID == OpenHOSTID {
|
||||
}else if OpenHOSTID.contains(where: {($0.identifier == (appOpenAd?.adUnitID ?? "") || $0.identifier == (appInterstitialAd?.adUnitID ?? ""))}) {
|
||||
MP_AnalyticsManager.shared.hot_ads_showFailureAction(error.localizedDescription)
|
||||
}
|
||||
if completeOpenAdBlock != nil {
|
||||
@ -1350,7 +1464,11 @@ class MP_AdMobManager: NSObject, GADFullScreenContentDelegate, GADNativeAdLoader
|
||||
completeGlobalInterstitialAdBlock!()
|
||||
}
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
//MARK: - GADNativeAdLoaderDelegate
|
||||
// 原生广告已展示。
|
||||
|
||||
@ -23,6 +23,8 @@ class MP_AnalyticsManager: NSObject {
|
||||
private let app_crash:String = "app_crash"
|
||||
//启动页曝光
|
||||
private let launch_pv:String = "launch_pv"
|
||||
//启动页计时结束点
|
||||
private let launch_progress_end:String = "launch_progress_end"
|
||||
//跳转页面动作
|
||||
private let jump_event:String = "jump_event"
|
||||
//A面首页曝光
|
||||
@ -63,6 +65,8 @@ class MP_AnalyticsManager: NSObject {
|
||||
private let player_b_downloadfailure_error = "player_b_downloadfailure_error"
|
||||
//B面搜索曝光
|
||||
private let search_pv = "search_pv"
|
||||
//B面搜索心情流派模块点击
|
||||
private let grid_mood_click = "grid_mood_click"
|
||||
//搜索SUG曝光
|
||||
private let search_sug_show = "search_sug_show"
|
||||
//点击sug结果
|
||||
@ -114,14 +118,23 @@ class MP_AnalyticsManager: NSObject {
|
||||
print("更新了插页广告时长间隔")
|
||||
}
|
||||
//更新广告ID设置
|
||||
// if let content = self.remoteConfig.configValue(forKey: "adMobIDs").jsonValue as? [String:String] {
|
||||
// //对所有广告ID进行更新
|
||||
// for (key, value) in content {
|
||||
// UserDefaults.standard.setValue(value, forKey: key)
|
||||
// }
|
||||
// print("更新了所有广告ID")
|
||||
// MP_AdMobManager.shared.reloadAdMobIDs()
|
||||
// }
|
||||
if let adTextIDs = self.remoteConfig.configValue(forKey: "adMobLevelIDs").jsonValue as? [String:[[String:Any]]] {
|
||||
//对所有广告ID组进行更新
|
||||
for (key, values) in adTextIDs {
|
||||
var array:[MPPositive_AdModelModel] = []
|
||||
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))
|
||||
}
|
||||
}
|
||||
//将array转为jsonData
|
||||
if let data = coreAdModelforJson(array) {
|
||||
UserDefaults.standard.set(data, forKey: key)
|
||||
}
|
||||
}
|
||||
print("更新了所有广告ID")
|
||||
MP_AdMobManager.shared.reloadAdMobIDs()
|
||||
}
|
||||
//更新版本数据设置
|
||||
if let versionData = self.remoteConfig.configValue(forKey: "dataVersion").jsonValue as? [String:String] {
|
||||
//对数据进行更新
|
||||
@ -131,6 +144,17 @@ class MP_AnalyticsManager: NSObject {
|
||||
print("更新了所有版本数据")
|
||||
MP_NetWorkManager.shared.reloadVersion()
|
||||
}
|
||||
//更新通知内容
|
||||
if let notificationBodyTexts = self.remoteConfig.configValue(forKey: "notificationBodyTexts").jsonValue as? [String:[String]] {
|
||||
//对数据进行更新
|
||||
for (key, value) in notificationBodyTexts {
|
||||
UserDefaults.standard.setValue(value, forKey: key)
|
||||
}
|
||||
print("更新了通知文本数据")
|
||||
//更新通知
|
||||
scheduleDailyNotifications()
|
||||
}
|
||||
|
||||
let js = self.remoteConfig.configValue(forKey: "openStatus").jsonValue as! [String:Any]
|
||||
let value = js["versionCode"] as! String
|
||||
if value == app_Version {
|
||||
@ -186,6 +210,10 @@ class MP_AnalyticsManager: NSObject {
|
||||
func launch_pvAction(){
|
||||
Analytics.logEvent(launch_pv, parameters: nil)
|
||||
}
|
||||
///启动页进度结束时间
|
||||
func launch_progress_endAction() {
|
||||
Analytics.logEvent(launch_progress_end, parameters: nil)
|
||||
}
|
||||
///跳转事件
|
||||
func jump_eventAction(_ side:String, reason:String) {
|
||||
Analytics.logEvent(jump_event, parameters: ["side":side,
|
||||
@ -339,6 +367,10 @@ class MP_AnalyticsManager: NSObject {
|
||||
func search_pvAction(){
|
||||
Analytics.logEvent(search_pv, parameters: nil)
|
||||
}
|
||||
///B面搜索心情流派模块点击
|
||||
func grid_mood_clickAction(_ mood:String) {
|
||||
Analytics.logEvent(grid_mood_click, parameters: ["mood":mood])
|
||||
}
|
||||
///搜索SUG曝光
|
||||
func search_sug_showAction(){
|
||||
Analytics.logEvent(search_sug_show, parameters: nil)
|
||||
|
||||
@ -27,14 +27,24 @@ class MP_CoreDataHandlerManager {
|
||||
}
|
||||
return container
|
||||
}()
|
||||
//托管(映射)对象空间
|
||||
//主线程托管(映射)对象空间
|
||||
var context: NSManagedObjectContext {
|
||||
return persistentContainer.viewContext
|
||||
}
|
||||
//后台托管对象空间
|
||||
var backgroundContext: NSManagedObjectContext {
|
||||
// 全局后台托管对象空间
|
||||
var backgroundContext: NSManagedObjectContext{
|
||||
return persistentContainer.newBackgroundContext()
|
||||
}
|
||||
private init() {
|
||||
// 在应用启动或合适的地方设置监听
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(mergeChangesFromBackgroundContext),
|
||||
name: .NSManagedObjectContextDidSave,
|
||||
object: nil)
|
||||
}
|
||||
deinit{
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
//主线程保存对象空间
|
||||
func saveContext() {
|
||||
//线程安全
|
||||
@ -47,41 +57,42 @@ class MP_CoreDataHandlerManager {
|
||||
try context.save()
|
||||
} catch {
|
||||
//保存失败
|
||||
let nserror = error as NSError
|
||||
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
|
||||
print("数据库更新失败,错误详情:\(error.localizedDescription)")
|
||||
}
|
||||
}
|
||||
}
|
||||
// //检索对象空间是否进行了更新
|
||||
// if context.hasChanges {
|
||||
// //线程安全
|
||||
// context.perform {
|
||||
// [weak self] in
|
||||
// guard let self = self else {return}
|
||||
// do {
|
||||
// //保存对象空间
|
||||
// try context.save()
|
||||
// } catch {
|
||||
// //保存失败
|
||||
// let nserror = error as NSError
|
||||
// fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
//后台保存
|
||||
///后台保存对象空间
|
||||
func saveContextInBackground() {
|
||||
|
||||
backgroundContext.perform {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
guard let self = self else { return }
|
||||
if backgroundContext.hasChanges {
|
||||
do {
|
||||
try backgroundContext.save()
|
||||
// 后台保存成功后发送通知
|
||||
NotificationCenter.default.post(name: .NSManagedObjectContextDidSave, object: backgroundContext)
|
||||
} catch {
|
||||
// 处理错误,比如记录错误日志
|
||||
print("后台保存失败: \(error), \(error.localizedDescription)")
|
||||
// 记录错误信息,而不是打印
|
||||
let nserror = error as NSError
|
||||
// 这里可以使用日志系统记录错误
|
||||
// 例如:self.logError(nserror)
|
||||
print("后台保存失败: \(nserror), \(nserror.userInfo)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@objc func mergeChangesFromBackgroundContext(notification: Notification) {
|
||||
DispatchQueue.main.async {
|
||||
// 从通知中获取上下文
|
||||
guard let backgroundContext = notification.object as? NSManagedObjectContext else {
|
||||
return
|
||||
}
|
||||
// 合并更改
|
||||
self.context.perform {
|
||||
self.context.mergeChanges(fromContextDidSave: notification)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,11 +68,11 @@ class MP_NetWorkManager: NSObject {
|
||||
private var playerVersion:String!
|
||||
///禁止接入IP信息组
|
||||
private let banIPs:[String] = [
|
||||
// "CN",
|
||||
// "HK",
|
||||
// "TW",
|
||||
// "JP",
|
||||
// "KR"
|
||||
"CN",
|
||||
"HK",
|
||||
"TW",
|
||||
"JP",
|
||||
"KR"
|
||||
]
|
||||
///允许访问的区域Code(对部分内容进行塞选)
|
||||
private let codes:[String] = [
|
||||
@ -657,6 +657,105 @@ extension MP_NetWorkManager {
|
||||
}
|
||||
}
|
||||
}
|
||||
///请求模块数据
|
||||
func requestGenres(_ completion:@escaping (([MPPositive_GridViewModel]) -> Void)) {
|
||||
//拼接出browse路径
|
||||
let path = header+point+browse
|
||||
//设置url
|
||||
guard let url = URL(string: path) else {
|
||||
print("Url is Incorrect")
|
||||
return
|
||||
}
|
||||
//设置参数
|
||||
let parameters:[String:Any] = [
|
||||
"browseId": "FEmusic_moods_and_genres",
|
||||
"prettyPrint":"false",
|
||||
"context":[
|
||||
"client":[
|
||||
//web端
|
||||
"clientName": "WEB_REMIX",
|
||||
//当前访问版本(日期值)
|
||||
"clientVersion": clientVersion,
|
||||
"platform":"MOBILE",
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
]
|
||||
]
|
||||
]
|
||||
requestPostGenres(url, parameters: parameters) { array in
|
||||
completion(array)
|
||||
}
|
||||
}
|
||||
///请求模块数据
|
||||
private func requestPostGenres(_ url:URL, parameters:Parameters, completion:@escaping (([MPPositive_GridViewModel]) -> Void)) {
|
||||
//发送post请求
|
||||
MPSession.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseDecodable(of: JsonGenres.self) { [weak self] (response) in
|
||||
guard let self = self else {return}
|
||||
switch response.result {
|
||||
case .success(let value):
|
||||
if let contents = value.contents?.singleColumnBrowseResultsRenderer?.tabs?.first?.tabRenderer?.content?.sectionListRenderer?.contents {
|
||||
let array = parsingGenres(contents)
|
||||
completion(array)
|
||||
}
|
||||
case .failure(let error):
|
||||
// 请求失败,处理错误
|
||||
handleError(url, error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
///请求模块详情数据
|
||||
func requestMoodDetails(_ browseId:String, params:String, completion:@escaping (([MPPositive_BrowseModuleListViewModel]) -> Void)) {
|
||||
//拼接出browse路径
|
||||
let path = header+point+browse
|
||||
//设置url
|
||||
guard let url = URL(string: path) else {
|
||||
print("Url is Incorrect")
|
||||
return
|
||||
}
|
||||
//设置参数
|
||||
let parameters:[String:Any] = [
|
||||
"browseId": browseId,
|
||||
"params":params,
|
||||
"prettyPrint":"false",
|
||||
"context":[
|
||||
"client":[
|
||||
//web端
|
||||
"clientName": "WEB_REMIX",
|
||||
//当前访问版本(日期值)
|
||||
"clientVersion": clientVersion,
|
||||
"platform":"MOBILE",
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
]
|
||||
]
|
||||
]
|
||||
requestPostMoodDetails(url, parameters: parameters) { array in
|
||||
completion(array)
|
||||
}
|
||||
}
|
||||
///请求模块详情数据
|
||||
private func requestPostMoodDetails(_ url:URL, parameters:Parameters, completion:@escaping (([MPPositive_BrowseModuleListViewModel]) -> Void)) {
|
||||
MPSession.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseDecodable(of: JsonBrowses.self) { [weak self] (response) in
|
||||
guard let self = self else {return}
|
||||
switch response.result {
|
||||
case .success(let value):
|
||||
//解析结构体
|
||||
let tab = value.contents?.singleColumnBrowseResultsRenderer?.tabs?[0]
|
||||
if let content = tab?.tabRenderer?.content {
|
||||
let array = parsingMoodDetails(content)
|
||||
completion(array)
|
||||
}
|
||||
case .failure(let error):
|
||||
print("Failed to parse browses content")
|
||||
// 请求失败,处理错误
|
||||
handleError(url, error: error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - 请求列表专辑下一部分
|
||||
///请求Next列表(优先于Player)
|
||||
@ -1673,7 +1772,64 @@ extension MP_NetWorkManager {
|
||||
return (nil,nil)
|
||||
}
|
||||
}
|
||||
|
||||
///解析模块数据_Genres
|
||||
private func parsingGenres(_ contents:[JsonGenres.Contents.SingleColumnBrowseResultsRenderer.Tab.TabRenderer.Content.SectionListRenderer.Content]) -> [MPPositive_GridViewModel] {
|
||||
var array:[MPPositive_GridViewModel] = []
|
||||
contents.forEach { content in
|
||||
if let items = content.gridRenderer?.items {
|
||||
items.forEach { item in
|
||||
if let text = item.musicNavigationButtonRenderer?.buttonText?.runs?.first?.text, let leftStripeColor = item.musicNavigationButtonRenderer?.solid?.leftStripeColor, let browseId = item.musicNavigationButtonRenderer?.clickCommand?.browseEndpoint?.browseId, let params = item.musicNavigationButtonRenderer?.clickCommand?.browseEndpoint?.params {
|
||||
let gride = MPPositive_GridModel(title: text, stringColor: leftStripeColor, browseId: browseId, params: params)
|
||||
array.append(.init(gride))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
///解析模块详情数据_Mood
|
||||
private func parsingMoodDetails(_ content:JsonBrowses.Contents.SingleColumnBrowseResultsRenderer.Tab.TabRenderer.Content) -> [MPPositive_BrowseModuleListViewModel] {
|
||||
//获取预览结构体中需要的数据(模块标题;歌曲信息:封面路径,音乐标题,歌手姓名,列表id和视频id)
|
||||
var browses:[MPPositive_BrowseModuleListViewModel] = []
|
||||
//循环获取音乐内容
|
||||
content.sectionListRenderer?.contents?.forEach({ content in
|
||||
//该循环获取预览模块内容,生成一个预览模型接收数据
|
||||
let browse = MPPositive_BrowseModuleListViewModel()
|
||||
if let musicCarouselShelfRenderer = content.musicCarouselShelfRenderer {
|
||||
browse.title = musicCarouselShelfRenderer.header?.musicCarouselShelfBasicHeaderRenderer?.title?.runs?.first?.text
|
||||
//循环音乐内容组
|
||||
musicCarouselShelfRenderer.contents?.forEach({ content in
|
||||
//设置标题、歌手、专辑/列表
|
||||
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer {
|
||||
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
|
||||
browse.items.append(.init(item))
|
||||
}
|
||||
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
|
||||
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
|
||||
}
|
||||
})
|
||||
if browse.items.isEmpty != true {
|
||||
browses.append(browse)
|
||||
}
|
||||
}else if let gridRenderer = content.gridRenderer {
|
||||
browse.title = gridRenderer.header?.gridHeaderRenderer?.title?.runs?.first?.text
|
||||
gridRenderer.items?.forEach({ content in
|
||||
//设置标题、歌手、专辑/列表
|
||||
if let musicResponsiveListItemRenderer = content.musicResponsiveListItemRenderer {
|
||||
if let item = parsingMusicResponsiveListItemRenderer(musicResponsiveListItemRenderer) {
|
||||
browse.items.append(.init(item))
|
||||
}
|
||||
}else if let musicTwoRowItemRenderer = content.musicTwoRowItemRenderer {
|
||||
browse.items.append(.init(parsingMusicTwoRowItemRenderer(musicTwoRowItemRenderer)))
|
||||
}
|
||||
})
|
||||
if browse.items.isEmpty != true {
|
||||
browses.append(browse)
|
||||
}
|
||||
}
|
||||
})
|
||||
return browses
|
||||
}
|
||||
/// 解析播放器_Player
|
||||
/// - Parameters:
|
||||
/// - player: player库
|
||||
|
||||
@ -310,15 +310,21 @@ class MP_PlayerManager:NSObject{
|
||||
print("当前音乐-\(loadPlayer?.currentVideo?.title ?? "") 已经准备好播放")
|
||||
}
|
||||
}else {
|
||||
print("当前音乐-\(loadPlayer?.currentVideo?.title ?? "") 未做好准备播放,失败原因是\(loadPlayer?.currentVideo?.resourcePlayerItem.error?.localizedDescription ?? "")")
|
||||
MP_AnalyticsManager.shared.player_b_failure_errorAction(loadPlayer?.currentVideo?.song.videoId ?? "", videoname: loadPlayer?.currentVideo?.title ?? "", artistname: loadPlayer?.currentVideo?.song.shortBylineText ?? "", error: loadPlayer?.currentVideo?.resourcePlayerItem.error?.localizedDescription ?? "Failed to buffer data")
|
||||
if loadPlayer?.currentVideo?.isKVO == true {
|
||||
suspendTimer()
|
||||
loadPlayer?.currentVideo?.isKVO = false
|
||||
//重新配置数据
|
||||
loadPlayer?.remakeImproveData {
|
||||
[weak self] in
|
||||
self?.play()
|
||||
if let currentVideo = loadPlayer?.currentVideo {
|
||||
print("当前音乐-\(currentVideo.title ?? "") 未做好准备播放,失败原因是\(currentVideo.resourcePlayerItem.error?.localizedDescription ?? "")")
|
||||
MP_AnalyticsManager.shared.player_b_failure_errorAction(currentVideo.song.videoId ?? "", videoname: currentVideo.title ?? "", artistname: currentVideo.song.shortBylineText ?? "", error: currentVideo.resourcePlayerItem.error?.localizedDescription ?? "Failed to buffer data")
|
||||
if loadPlayer?.currentVideo?.isKVO == true {
|
||||
suspendTimer()
|
||||
loadPlayer?.currentVideo?.isKVO = false
|
||||
statusObservation?.invalidate()
|
||||
loadedTimeRangesObservation?.invalidate()
|
||||
playbackLikelyToKeepUpObservation?.invalidate()
|
||||
errorObservation?.invalidate()
|
||||
//重新配置数据
|
||||
loadPlayer?.remakeImproveData {
|
||||
[weak self] in
|
||||
self?.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -140,15 +140,19 @@ struct JsonBrowses: Codable {
|
||||
}
|
||||
///图像数据内容
|
||||
struct Content: Codable {
|
||||
///常态数据通用
|
||||
let musicCarouselShelfRenderer:MusicCarouselShelfRenderer?
|
||||
|
||||
///模块详情特化
|
||||
let gridRenderer:GridRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case musicCarouselShelfRenderer = "musicCarouselShelfRenderer"
|
||||
case gridRenderer = "gridRenderer"
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
musicCarouselShelfRenderer = try values.decodeIfPresent(MusicCarouselShelfRenderer.self, forKey: .musicCarouselShelfRenderer)
|
||||
gridRenderer = try values.decodeIfPresent(GridRenderer.self, forKey: .gridRenderer)
|
||||
}
|
||||
struct MusicCarouselShelfRenderer: Codable {
|
||||
///指向模块标题
|
||||
@ -226,6 +230,82 @@ struct JsonBrowses: Codable {
|
||||
}
|
||||
}
|
||||
}
|
||||
struct GridRenderer: Codable {
|
||||
let items:[Item]?
|
||||
let header:Header?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case items = "items"
|
||||
case header = "header"
|
||||
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
items = try values.decodeIfPresent([Item].self, forKey: .items)
|
||||
header = try values.decodeIfPresent(Header.self, forKey: .header)
|
||||
}
|
||||
struct Item: Codable {
|
||||
///常规列表(通常是四组件构成,封面,一级标题,二级标题,三级标题,额外包含ID内容,通常是单曲)
|
||||
let musicResponsiveListItemRenderer:RootMusicResponsiveListItemRenderer?
|
||||
///两行式列表(通常是三组件构成,封面,一级标题,二级标题,额外包含ID内容,通常是歌单)
|
||||
let musicTwoRowItemRenderer:RootMusicTwoRowItemRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case musicResponsiveListItemRenderer = "musicResponsiveListItemRenderer"
|
||||
case musicTwoRowItemRenderer = "musicTwoRowItemRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
musicResponsiveListItemRenderer = try values.decodeIfPresent(RootMusicResponsiveListItemRenderer.self, forKey: .musicResponsiveListItemRenderer)
|
||||
musicTwoRowItemRenderer = try values.decodeIfPresent(RootMusicTwoRowItemRenderer.self, forKey: .musicTwoRowItemRenderer)
|
||||
}
|
||||
}
|
||||
struct Header: Codable {
|
||||
let gridHeaderRenderer:GridHeaderRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case gridHeaderRenderer = "gridHeaderRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
gridHeaderRenderer = try values.decodeIfPresent(GridHeaderRenderer.self, forKey: .gridHeaderRenderer)
|
||||
}
|
||||
struct GridHeaderRenderer: Codable {
|
||||
let title:Title?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case title = "title"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||||
}
|
||||
struct Title: Codable {
|
||||
///一般是第0位
|
||||
let runs:[Run]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case runs = "runs"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||||
}
|
||||
|
||||
//MARK: - 文本内容,标题/作者/专辑
|
||||
struct Run: Codable {
|
||||
///关键文本内容(代表各级标题)
|
||||
let text:String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case text = "text"
|
||||
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
///续页编码
|
||||
struct Continuation: Codable {
|
||||
|
||||
@ -0,0 +1,231 @@
|
||||
//
|
||||
// MPPositive_JsonGenres.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
///心情与流派结构
|
||||
struct JsonGenres: Codable {
|
||||
let contents:Contents?
|
||||
let header:Header?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case contents = "contents"
|
||||
case header = "header"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
contents = try values.decodeIfPresent(Contents.self, forKey: .contents)
|
||||
header = try values.decodeIfPresent(Header.self, forKey: .header)
|
||||
}
|
||||
struct Contents: Codable {
|
||||
let singleColumnBrowseResultsRenderer:SingleColumnBrowseResultsRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case singleColumnBrowseResultsRenderer = "singleColumnBrowseResultsRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
singleColumnBrowseResultsRenderer = try values.decodeIfPresent(SingleColumnBrowseResultsRenderer.self, forKey: .singleColumnBrowseResultsRenderer)
|
||||
}
|
||||
struct SingleColumnBrowseResultsRenderer: Codable {
|
||||
let tabs:[Tab]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case tabs = "tabs"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
tabs = try values.decodeIfPresent([Tab].self, forKey: .tabs)
|
||||
}
|
||||
struct Tab:Codable {
|
||||
let tabRenderer:TabRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case tabRenderer = "tabRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
tabRenderer = try values.decodeIfPresent(TabRenderer.self, forKey: .tabRenderer)
|
||||
}
|
||||
struct TabRenderer: Codable {
|
||||
let content:Content?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case content = "content"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
content = try values.decodeIfPresent(Content.self, forKey: .content)
|
||||
}
|
||||
struct Content: Codable {
|
||||
let sectionListRenderer:SectionListRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case sectionListRenderer = "sectionListRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
sectionListRenderer = try values.decodeIfPresent(SectionListRenderer.self, forKey: .sectionListRenderer)
|
||||
}
|
||||
struct SectionListRenderer: Codable {
|
||||
let contents:[Content]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case contents = "contents"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
contents = try values.decodeIfPresent([Content].self, forKey: .contents)
|
||||
}
|
||||
struct Content: Codable {
|
||||
let gridRenderer:GridRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case gridRenderer = "gridRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
gridRenderer = try values.decodeIfPresent(GridRenderer.self, forKey: .gridRenderer)
|
||||
}
|
||||
struct GridRenderer: Codable {
|
||||
let items:[Item]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case items = "items"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
items = try values.decodeIfPresent([Item].self, forKey: .items)
|
||||
}
|
||||
struct Item: Codable {
|
||||
let musicNavigationButtonRenderer:MusicNavigationButtonRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case musicNavigationButtonRenderer = "musicNavigationButtonRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
musicNavigationButtonRenderer = try values.decodeIfPresent(MusicNavigationButtonRenderer.self, forKey: .musicNavigationButtonRenderer)
|
||||
}
|
||||
struct MusicNavigationButtonRenderer: Codable {
|
||||
///对应标题
|
||||
let buttonText:ButtonText?
|
||||
///对应颜色
|
||||
let solid:Solid?
|
||||
///点击事件
|
||||
let clickCommand:ClickCommand?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case buttonText = "buttonText"
|
||||
case solid = "solid"
|
||||
case clickCommand = "clickCommand"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
buttonText = try values.decodeIfPresent(ButtonText.self, forKey: .buttonText)
|
||||
solid = try values.decodeIfPresent(Solid.self, forKey: .solid)
|
||||
clickCommand = try values.decodeIfPresent(ClickCommand.self, forKey: .clickCommand)
|
||||
}
|
||||
//对应标题
|
||||
struct ButtonText: Codable{
|
||||
//标题组
|
||||
let runs:[Run]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case runs = "runs"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||||
}
|
||||
struct Run: Codable {
|
||||
//标题文本
|
||||
let text:String?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case text = "text"
|
||||
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||||
}
|
||||
}
|
||||
}
|
||||
//对应颜色
|
||||
struct Solid: Codable {
|
||||
///颜色值
|
||||
let leftStripeColor:Int?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case leftStripeColor = "leftStripeColor"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
leftStripeColor = try values.decodeIfPresent(Int.self, forKey: .leftStripeColor)
|
||||
}
|
||||
}
|
||||
//对应事件
|
||||
struct ClickCommand: Codable {
|
||||
let browseEndpoint:BrowseEndpoint?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case browseEndpoint = "browseEndpoint"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
browseEndpoint = try values.decodeIfPresent(BrowseEndpoint.self, forKey: .browseEndpoint)
|
||||
}
|
||||
struct BrowseEndpoint: Codable {
|
||||
let browseId:String?
|
||||
let params:String?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case browseId = "browseId"
|
||||
case params = "params"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
browseId = try values.decodeIfPresent(String.self, forKey: .browseId)
|
||||
params = try values.decodeIfPresent(String.self, forKey: .params)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct Header: Codable {
|
||||
let musicHeaderRenderer:MusicHeaderRenderer?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case musicHeaderRenderer = "musicHeaderRenderer"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
musicHeaderRenderer = try values.decodeIfPresent(MusicHeaderRenderer.self, forKey: .musicHeaderRenderer)
|
||||
}
|
||||
struct MusicHeaderRenderer: Codable {
|
||||
let title:Title?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case title = "title"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
title = try values.decodeIfPresent(Title.self, forKey: .title)
|
||||
}
|
||||
struct Title: Codable {
|
||||
let runs:[Run]?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case runs = "runs"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
runs = try values.decodeIfPresent([Run].self, forKey: .runs)
|
||||
}
|
||||
struct Run: Codable {
|
||||
let text:String?
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case text = "text"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
text = try values.decodeIfPresent(String.self, forKey: .text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
//
|
||||
// MPPositive_AdModelModel.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
///广告模型
|
||||
class MPPositive_AdModelModel: NSObject, Codable {
|
||||
///阶级(从高到低)
|
||||
var level:Int
|
||||
///id内容
|
||||
var identifier:String
|
||||
///广告商
|
||||
var ad:String
|
||||
///广告类型
|
||||
var type:MPPositive_AdModelType
|
||||
init(level: Int, identifier: String, ad: String, type:MPPositive_AdModelType) {
|
||||
self.level = level
|
||||
self.identifier = identifier
|
||||
self.ad = ad
|
||||
self.type = type
|
||||
}
|
||||
}
|
||||
enum MPPositive_AdModelType: String, Codable {
|
||||
///开屏
|
||||
case Open = "Open"
|
||||
///插页
|
||||
case Insert = "Insert"
|
||||
///原生
|
||||
case Native = "Native"
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
//
|
||||
// MPPositive_GridModel.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class MPPositive_GridModel: NSObject, Codable {
|
||||
///标题
|
||||
var title:String
|
||||
///颜色阈值
|
||||
var stringColor:Int
|
||||
///预览id
|
||||
var browseId:String
|
||||
///params
|
||||
var params:String
|
||||
|
||||
init(title: String, stringColor: Int, browseId: String, params: String) {
|
||||
self.title = title
|
||||
self.stringColor = stringColor
|
||||
self.browseId = browseId
|
||||
self.params = params
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
//
|
||||
// MPPositive_GridViewModel.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
///模块ViewModel
|
||||
class MPPositive_GridViewModel: NSObject, Codable {
|
||||
///标题文本
|
||||
var title:String?
|
||||
///颜色
|
||||
var stringColor:Int64?
|
||||
///模块本身
|
||||
var grid:MPPositive_GridModel
|
||||
init(_ grid:MPPositive_GridModel) {
|
||||
self.grid = grid
|
||||
super.init()
|
||||
configure()
|
||||
}
|
||||
//生成配置
|
||||
private func configure() {
|
||||
self.title = self.grid.title
|
||||
self.stringColor = Int64(self.grid.stringColor)
|
||||
}
|
||||
}
|
||||
@ -92,6 +92,8 @@ class MPPositive_BrowseLoadViewModel: NSObject {
|
||||
browseModuleLists.removeAll()
|
||||
//调用网络请求工具的预览请求
|
||||
MP_NetWorkManager.shared.requestBrowseDatas()
|
||||
//同步更新gride
|
||||
MPPositive_GridLoadViewModel.shared.reloadGrides()
|
||||
}
|
||||
///缓存预览数据
|
||||
private func cacheResponseData(_ array: [MPPositive_BrowseModuleListViewModel]) {
|
||||
|
||||
@ -0,0 +1,65 @@
|
||||
//
|
||||
// MPPositive_GridLoadViewModel.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class MPPositive_GridLoadViewModel: NSObject {
|
||||
static let shared = MPPositive_GridLoadViewModel()
|
||||
var grideViewModels:[MPPositive_GridViewModel] = []
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
if let data = chachedData() {
|
||||
grideViewModels = data
|
||||
}
|
||||
}
|
||||
//更新grideModel
|
||||
func reloadGrides() {
|
||||
MP_NetWorkManager.shared.requestGenres { [weak self] array in
|
||||
guard let self = self else {return}
|
||||
DispatchQueue.main.async {
|
||||
self.grideViewModels = array
|
||||
self.cacheResponseData(self.grideViewModels)
|
||||
//发布通知
|
||||
NotificationCenter.notificationKey.post(notificationName: .search_gride_reload)
|
||||
}
|
||||
}
|
||||
}
|
||||
//存入默认数据
|
||||
private func cacheResponseData(_ array: [MPPositive_GridViewModel]) {
|
||||
guard grideViewModels.count != 0 else {
|
||||
print("Search Gride数据未加载,无法缓存")
|
||||
return
|
||||
}
|
||||
//将数据转为jsonData
|
||||
do{
|
||||
let jsonData = try JSONEncoder().encode(array)
|
||||
//使用UserDefaults存入缓存数据
|
||||
UserDefaults.standard.set(jsonData, forKey: "SearchGride")
|
||||
print("已经将Search Gride数据缓存")
|
||||
}catch{
|
||||
//转为jsonData失败
|
||||
print("Search Gride数据转为Data失败,失败原因\(error)")
|
||||
}
|
||||
}
|
||||
//获取默认数据
|
||||
private func chachedData() -> [MPPositive_GridViewModel]? {
|
||||
guard let cacheData = UserDefaults.standard.data(forKey: "SearchGride") else {
|
||||
print("获取Search Gride缓存数据失败")
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
let array:[MPPositive_GridViewModel] = try JSONDecoder().decode([MPPositive_GridViewModel].self, from: cacheData)
|
||||
print("已经将Search Gride缓存数据取出")
|
||||
return array
|
||||
} catch {
|
||||
//转为jsonData失败
|
||||
print("获取Search Gride缓存数据失败,失败原因\(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -113,7 +113,7 @@ class MPPositive_LoadCoreModel: NSObject {
|
||||
///更新搜索历史
|
||||
func reloadSearchTags(_ complection:(() -> Void)?) {
|
||||
MPPositive_SearchTagModel.fetchAll{ array in
|
||||
let s = array.sorted(by: {$1.date > $0.date})
|
||||
let s = array.sorted(by: {$0.date > $1.date})
|
||||
DispatchQueue.main.async {
|
||||
self.searchTags = s
|
||||
if complection != nil {
|
||||
|
||||
@ -30,7 +30,7 @@ class MPPositive_SearchResultsLoadViewModel: NSObject {
|
||||
//根据用户输入文本内容请求搜索接口
|
||||
private func getSearchResults(_ text:String) {
|
||||
MP_HUD.loading()
|
||||
|
||||
|
||||
//判断是否重复搜索历史
|
||||
MPPositive_SearchTagModel.fetch(predicate: .init(format: "text==%@", text)) { results in
|
||||
if results.count == 0 {
|
||||
@ -40,7 +40,6 @@ class MPPositive_SearchResultsLoadViewModel: NSObject {
|
||||
tag.date = Date().timeZone()
|
||||
tag.text = text
|
||||
MPPositive_SearchTagModel.save()
|
||||
MPPositive_LoadCoreModel.shared.reloadSearchTags(nil)
|
||||
}
|
||||
}
|
||||
MP_NetWorkManager.shared.requestSearchPreviewResults(text) { [weak self] results in
|
||||
|
||||
@ -111,7 +111,7 @@ extension MPPositive_TabBarController {
|
||||
self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(recommendVC, animated: false)
|
||||
}
|
||||
playerVC.searchBlock = { (text) in
|
||||
let resultVC = MPPositive_SearchResultShowViewController(text)
|
||||
let resultVC = MPPositive_SearchResultShowViewController(text, isShowAd: false)
|
||||
self?.viewControllers![self?.selectedIndex ?? 0].children[0].navigationController?.pushViewController(resultVC, animated: false)
|
||||
}
|
||||
self?.present(playerVC, animated: true)
|
||||
@ -163,6 +163,7 @@ extension MPPositive_TabBarController {
|
||||
//MARK: - 覆盖型广告代理 GADFullScreenContentDelegate
|
||||
//覆盖型广告将要将要展示
|
||||
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = true
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
print("当前展示的广告是播放插页广告,广告ID--\(MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? "")")
|
||||
MP_AnalyticsManager.shared.play_ads_showSuccessAction()
|
||||
@ -170,6 +171,7 @@ extension MPPositive_TabBarController {
|
||||
}
|
||||
//覆盖型广告已经消失
|
||||
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
MP_AdMobManager.shared.interstitialDate = Date()
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
let UUID = MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? ""
|
||||
@ -190,10 +192,15 @@ extension MPPositive_TabBarController {
|
||||
self?.present(playerVC, animated: true)
|
||||
}
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
//覆盖型广告加载出错
|
||||
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
MP_AdMobManager.shared.interstitialDate = Date()
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
let UUID = MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? ""
|
||||
@ -215,6 +222,10 @@ extension MPPositive_TabBarController {
|
||||
// self?.present(playerVC, animated: true)
|
||||
// }
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,189 @@
|
||||
//
|
||||
// MPPositive_GrideMoodViewController.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
///模块数据详情
|
||||
class MPPositive_GrideMoodViewController: MPPositive_BaseViewController {
|
||||
//tableView
|
||||
private lazy var tableView:UITableView = {
|
||||
let tableView = UITableView(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), style: .plain)
|
||||
tableView.backgroundColor = .clear
|
||||
tableView.separatorStyle = .none
|
||||
tableView.estimatedRowHeight = 200
|
||||
tableView.rowHeight = UITableView.automaticDimension
|
||||
tableView.dataSource = self
|
||||
tableView.delegate = self
|
||||
tableView.register(MPPositive_HomeSinglesTableViewCell.self, forCellReuseIdentifier: MPPositive_HomeSinglesTableViewCellID)
|
||||
tableView.register(MPPositive_HomeShowTableViewCell.self, forCellReuseIdentifier: MPPositive_HomeShowTableViewCellID)
|
||||
tableView.contentInset = .init(top: 0, left: 0, bottom: 70*width, right: 0)
|
||||
return tableView
|
||||
}()
|
||||
private let MPPositive_HomeSinglesTableViewCellID = "MPPositive_HomeSinglesTableViewCell"
|
||||
private let MPPositive_HomeShowTableViewCellID = "MPPositive_HomeShowTableViewCell"
|
||||
private var browseModuleLists:[MPPositive_BrowseModuleListViewModel]! = []{
|
||||
didSet{
|
||||
DispatchQueue.main.async {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
if browseModuleLists != nil{
|
||||
configure()
|
||||
reload()
|
||||
removeErrorView()
|
||||
MP_HUD.hideNow()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private var browseId:String!
|
||||
private var params:String!
|
||||
private var titleText:String!
|
||||
init(_ browseId:String, params:String, title:String) {
|
||||
self.browseId = browseId
|
||||
self.params = params
|
||||
self.titleText = title
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
//执行网络请求获取对应模块详情数据
|
||||
MP_HUD.loading()
|
||||
MP_NetWorkManager.shared.requestMoodDetails(browseId, params: params) { [weak self] result in
|
||||
guard let self = self else {return}
|
||||
browseModuleLists = result
|
||||
}
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
//设置页面标题
|
||||
setTitle(titleText)
|
||||
setPopBtn()
|
||||
errorBlock = {
|
||||
[weak self] in
|
||||
guard let self = self else {
|
||||
return
|
||||
}
|
||||
//移除所有(除了navView)的子控件,并告知页面处理错误,提示用户重试
|
||||
view.subviews.forEach { item in
|
||||
if item != self.navView {
|
||||
//移除
|
||||
if item.superview != nil {
|
||||
item.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
||||
//添加报错View
|
||||
setErrorView()
|
||||
MP_HUD.hideNow()
|
||||
}
|
||||
retryBlock = {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
MP_HUD.loading()
|
||||
MP_NetWorkManager.shared.requestMoodDetails(browseId, params: params) { [weak self] result in
|
||||
guard let self = self else {return}
|
||||
browseModuleLists = result
|
||||
}
|
||||
}
|
||||
}
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
reload()
|
||||
}
|
||||
//页面刷新
|
||||
private func reload() {
|
||||
tableView.reloadData()
|
||||
}
|
||||
private func configure() {
|
||||
view.addSubview(tableView)
|
||||
tableView.snp.makeConstraints { make in
|
||||
make.left.bottom.right.equalToSuperview()
|
||||
make.top.equalTo(navView.snp.bottom).offset(20*width)
|
||||
}
|
||||
}
|
||||
}
|
||||
//MARK: - tableView
|
||||
extension MPPositive_GrideMoodViewController: UITableViewDataSource, UITableViewDelegate {
|
||||
func numberOfSections(in tableView: UITableView) -> Int {
|
||||
return browseModuleLists.count
|
||||
}
|
||||
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
return 1
|
||||
}
|
||||
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
if let first = browseModuleLists[indexPath.section].items.first, first.browseItem.itemType == .single, first.browseItem.pageType == "MUSIC_VIDEO_TYPE_ATV" {
|
||||
//是单曲
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeSinglesTableViewCellID, for: indexPath) as! MPPositive_HomeSinglesTableViewCell
|
||||
cell.browseViewModel = browseModuleLists[indexPath.section]
|
||||
|
||||
return cell
|
||||
}else {
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: MPPositive_HomeShowTableViewCellID, for: indexPath) as! MPPositive_HomeShowTableViewCell
|
||||
cell.browseViewModel = browseModuleLists[indexPath.section]
|
||||
if let first = browseModuleLists[indexPath.section].items.first, first.browseItem.itemType == .single, first.browseItem.pageType == "MUSIC_VIDEO_TYPE_OMV" {
|
||||
cell.showType = .Fifth
|
||||
}else {
|
||||
//判断是列表还是艺术家
|
||||
if browseModuleLists[indexPath.section].items.first?.browseItem.pageType == "MUSIC_PAGE_TYPE_ARTIST" {
|
||||
cell.showType = .Fourth
|
||||
}else {
|
||||
cell.showType = .Third
|
||||
}
|
||||
}
|
||||
cell.requestNextBlock = {
|
||||
[weak self] (item) in
|
||||
guard let self = self else {return}
|
||||
switch item.browseItem.itemType {
|
||||
case .single:
|
||||
//单曲/视频跳转
|
||||
MPPositive_Debouncer.shared.call {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
guard MP_NetWorkManager.shared.netWorkStatu == .reachable else {
|
||||
MP_HUD.text("Weak connection.", delay: 2.0, completion: nil)
|
||||
return
|
||||
}
|
||||
MP_AnalyticsManager.shared.song_clickAction("Mood")
|
||||
//优先清除数据
|
||||
MP_PlayerManager.shared.loadPlayer = nil
|
||||
//弹出播放器
|
||||
NotificationCenter.notificationKey.post(notificationName: .pup_player_vc)
|
||||
MP_AnalyticsManager.shared.player_b_impAction()
|
||||
//触发next请求,优先获取列表全部单曲基础数据(不完善)
|
||||
MP_NetWorkManager.shared.requestNextList(item.browseItem.playListId ?? "", videoId: item.browseItem.videoId ?? ""){ [weak self] listSongs in
|
||||
guard let self = self else {return}
|
||||
//回掉的数据并不完善,生成一个playerloadViewModel
|
||||
let lodaViewModel = MPPositive_PlayerLoadViewModel(listSongs, currentVideoId: item.browseItem.videoId ?? "")
|
||||
lodaViewModel.improveData(item.browseItem.videoId ?? "")
|
||||
//更改播放器播放类型
|
||||
MP_PlayerManager.shared.setPlayType(.normal)
|
||||
MP_PlayerManager.shared.loadPlayer = lodaViewModel
|
||||
MP_AnalyticsManager.shared.player_b_listAction()
|
||||
}
|
||||
}
|
||||
case .list:
|
||||
//列表专辑
|
||||
let listVC = MPPositive_ListShowViewController(item.browseItem.browseId ?? "", params: "", title: item.title ?? "", subtitle: item.subtitle ?? "")
|
||||
navigationController?.pushViewController(listVC, animated: true)
|
||||
case .artist:
|
||||
//前往艺术家页面
|
||||
let artistVC = MPPositive_ArtistShowViewController(item.browseItem.artistId ?? "")
|
||||
navigationController?.pushViewController(artistVC, animated: true)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
cell.findMoreBlock = {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
let moreVC = MPPositive_MoreContentViewController(browseModuleLists[indexPath.section])
|
||||
navigationController?.pushViewController(moreVC, animated: true)
|
||||
}
|
||||
return cell
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,18 +57,21 @@ class MPPositive_SearchResultShowViewController: MPPositive_BaseViewController,
|
||||
}
|
||||
}
|
||||
}
|
||||
private var isShowAd = true
|
||||
//搜索文本
|
||||
private var searchText:String?
|
||||
//MARK: - 搜索建议View
|
||||
private lazy var suggestionView:MPPositive_SearchSuggestionsView = .init(frame: .zero)
|
||||
//MARK: - 结果展示View
|
||||
private lazy var resultsShowView:MPPositive_SearchResultsShowView = .init(frame: .zero)
|
||||
private lazy var resultsShowView:MPPositive_SearchResultsShowView = .init(frame: .zero, isShowAd: self.isShowAd)
|
||||
|
||||
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
|
||||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||||
}
|
||||
|
||||
init(_ text:String) {
|
||||
init(_ text:String, isShowAd:Bool = true) {
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
self.isShowAd = isShowAd
|
||||
searchTextField.text = text
|
||||
searchText = text
|
||||
resultsShowView.loadModel = .init(text)
|
||||
|
||||
@ -14,7 +14,8 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
return imageView
|
||||
}()
|
||||
private lazy var collectionView:UICollectionView = {
|
||||
//搜索历史展示
|
||||
private lazy var historyCollectionView:UICollectionView = {
|
||||
let layout = MPPositive_TagFlowLayout()
|
||||
layout.delegate = self
|
||||
let collectionView:UICollectionView = .init(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), collectionViewLayout: layout)
|
||||
@ -27,6 +28,21 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
return collectionView
|
||||
}()
|
||||
private let MPPositive_SearchTagCollectionViewCellID = "MPPositive_SearchTagCollectionViewCell"
|
||||
//模块展示
|
||||
private lazy var grideCollectionView:UICollectionView = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: 162*width, height: 60*width)
|
||||
layout.sectionInset = .init(top: 20*width, left: 18*width, bottom: 70*width, right: 18*width)
|
||||
let collectionView = UICollectionView(frame: .init(x: 0, y: 0, width: screen_Width, height: screen_Height), collectionViewLayout: layout)
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
collectionView.backgroundColor = .clear
|
||||
collectionView.dataSource = self
|
||||
collectionView.delegate = self
|
||||
collectionView.register(MPPositive_SearchGrideCollectionViewCell.self, forCellWithReuseIdentifier: MPPositive_SearchGrideCollectionViewCellID)
|
||||
return collectionView
|
||||
}()
|
||||
fileprivate let MPPositive_SearchGrideCollectionViewCellID = "MPPositive_SearchGrideCollectionViewCell"
|
||||
//历史标签
|
||||
private lazy var historyLabel:UILabel = createLabel("History", font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .init(hex: "#666666"), textAlignment: .left)
|
||||
//删除按钮
|
||||
@ -43,16 +59,25 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
//加载搜索原生广告
|
||||
MP_AdMobManager.shared.configureSreachNativeAd(rootController: self)
|
||||
MP_AdMobManager.shared.loadSearchNativeAd()
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(grideReloadAction(_ :)), notificationName: .search_gride_reload)
|
||||
}
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
MP_AnalyticsManager.shared.search_pvAction()
|
||||
collectionView.reloadData()
|
||||
MPPositive_LoadCoreModel.shared.reloadSearchTags {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
historyCollectionView.reloadData()
|
||||
}
|
||||
grideCollectionView.reloadData()
|
||||
}
|
||||
override func viewWillDisappear(_ animated: Bool) {
|
||||
super.viewWillDisappear(animated)
|
||||
|
||||
}
|
||||
deinit{
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
//配置
|
||||
private func configure() {
|
||||
let searchView = createSearchView()
|
||||
@ -78,12 +103,17 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
make.centerY.equalTo(deleteBtn)
|
||||
make.left.equalToSuperview().offset(18*width)
|
||||
}
|
||||
view.addSubview(collectionView)
|
||||
collectionView.snp.makeConstraints { make in
|
||||
view.addSubview(historyCollectionView)
|
||||
historyCollectionView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalTo(deleteBtn.snp.bottom).offset(6*width)
|
||||
make.height.equalTo(130*width)
|
||||
}
|
||||
view.addSubview(grideCollectionView)
|
||||
grideCollectionView.snp.makeConstraints { make in
|
||||
make.top.equalTo(historyCollectionView.snp.bottom)
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
//生成一个顶部搜索框
|
||||
private func createSearchView() -> UIView{
|
||||
@ -110,6 +140,14 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
searchView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(searchClick(_:))))
|
||||
return searchView
|
||||
}
|
||||
//刷新
|
||||
@objc private func grideReloadAction(_ sender:Notification) {
|
||||
DispatchQueue.main.async {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
grideCollectionView.reloadData()
|
||||
}
|
||||
}
|
||||
//前往搜索结果页
|
||||
@objc fileprivate func searchClick(_ sender:UITapGestureRecognizer) {
|
||||
let resultVC = MPPositive_SearchResultShowViewController()
|
||||
@ -124,7 +162,7 @@ class MPPositive_SearchViewController: MPPositive_BaseViewController {
|
||||
MPPositive_LoadCoreModel.shared.reloadSearchTags {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
collectionView.reloadData()
|
||||
historyCollectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,17 +177,36 @@ extension MPPositive_SearchViewController: UICollectionViewDataSource, UICollect
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return MPPositive_LoadCoreModel.shared.searchTags.count > 10 ? 10:MPPositive_LoadCoreModel.shared.searchTags.count
|
||||
if collectionView == historyCollectionView {
|
||||
return MPPositive_LoadCoreModel.shared.searchTags.count > 10 ? 10:MPPositive_LoadCoreModel.shared.searchTags.count
|
||||
}else {
|
||||
return MPPositive_GridLoadViewModel.shared.grideViewModels.count
|
||||
}
|
||||
}
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_SearchTagCollectionViewCellID, for: indexPath) as! MPPositive_SearchTagCollectionViewCell
|
||||
cell.setText(MPPositive_LoadCoreModel.shared.searchTags[indexPath.row].text)
|
||||
return cell
|
||||
if collectionView == historyCollectionView {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_SearchTagCollectionViewCellID, for: indexPath) as! MPPositive_SearchTagCollectionViewCell
|
||||
cell.setText(MPPositive_LoadCoreModel.shared.searchTags[indexPath.row].text)
|
||||
return cell
|
||||
}else {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MPPositive_SearchGrideCollectionViewCellID, for: indexPath) as! MPPositive_SearchGrideCollectionViewCell
|
||||
cell.gride = MPPositive_GridLoadViewModel.shared.grideViewModels[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
}
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let text = MPPositive_LoadCoreModel.shared.searchTags[indexPath.row].text ?? ""
|
||||
let resultVC = MPPositive_SearchResultShowViewController(text)
|
||||
navigationController?.pushViewController(resultVC, animated: false)
|
||||
if collectionView == historyCollectionView {
|
||||
let text = MPPositive_LoadCoreModel.shared.searchTags[indexPath.row].text ?? ""
|
||||
let resultVC = MPPositive_SearchResultShowViewController(text)
|
||||
navigationController?.pushViewController(resultVC, animated: false)
|
||||
}else {
|
||||
if indexPath.row <= (MPPositive_GridLoadViewModel.shared.grideViewModels.count - 1) {
|
||||
let item = MPPositive_GridLoadViewModel.shared.grideViewModels[indexPath.row]
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//MARK: - 宽度代理
|
||||
|
||||
@ -81,7 +81,7 @@ class MPPositive_HomeSinglesTableViewCell: UITableViewCell, UIViewControllerTran
|
||||
override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize {
|
||||
let size = super.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: horizontalFittingPriority, verticalFittingPriority: verticalFittingPriority)
|
||||
collectionView.layoutIfNeeded()
|
||||
let height = layout.itemSize.height*3 + layout.sectionInset.top
|
||||
let height = layout.itemSize.height*3 + layout.sectionInset.top + 10
|
||||
return CGSize(width: size.width, height: size.height + height)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
//
|
||||
// MPPositive_SearchGrideCollectionViewCell.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/7/12.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import MarqueeLabel
|
||||
class MPPositive_SearchGrideCollectionViewCell: UICollectionViewCell {
|
||||
//颜色块
|
||||
private lazy var colorView:UIView = .init()
|
||||
//标题Label
|
||||
private lazy var titleLabel:UILabel = createMarQueeLabel("Loading", font: .systemFont(ofSize: 16, weight: .bold), textColor: .white)
|
||||
var gride:MPPositive_GridViewModel!{
|
||||
didSet{
|
||||
colorView.backgroundColor = .randomColor
|
||||
titleLabel.text = gride.title
|
||||
}
|
||||
}
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .init(hex: "#1F1F1F")
|
||||
layer.masksToBounds = true
|
||||
layer.cornerRadius = 10*width
|
||||
confirgue()
|
||||
}
|
||||
required init?(coder: NSCoder) {
|
||||
super.init(coder: coder)
|
||||
}
|
||||
//配置
|
||||
private func confirgue() {
|
||||
addSubview(colorView)
|
||||
colorView.snp.makeConstraints { make in
|
||||
make.top.left.bottom.equalToSuperview()
|
||||
make.width.equalToSuperview().multipliedBy(0.2)
|
||||
}
|
||||
addSubview(titleLabel)
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalTo(colorView.snp.right).offset(12*width)
|
||||
make.right.equalToSuperview().offset(-12*width)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -17,17 +17,19 @@ class MPPositive_SearchResultsShowView: UIView {
|
||||
if loadModel == nil {
|
||||
emptyImageView.isHidden = false
|
||||
}else {
|
||||
MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable { [weak self] ad in
|
||||
guard let self = self else {return}
|
||||
//判断数据是否有值
|
||||
if loadModel?.sectionLists?.count != nil {
|
||||
//有值,不在展示
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(false)
|
||||
}else {
|
||||
MP_AdMobManager.shared.isShowingSearchInterstitialAd = true
|
||||
//没有值,展示
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(true)
|
||||
ad.present(fromRootViewController: nil)
|
||||
if isShowAd == true {
|
||||
MP_AdMobManager.shared.showSearchInterstitialAdIfAvailable { [weak self] ad in
|
||||
guard let self = self else {return}
|
||||
//判断数据是否有值
|
||||
if loadModel?.sectionLists?.count != nil {
|
||||
//有值,不在展示
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(false)
|
||||
}else {
|
||||
MP_AdMobManager.shared.isShowingSearchInterstitialAd = true
|
||||
//没有值,展示
|
||||
MP_AdMobManager.shared.setInterstitialSwitch(true)
|
||||
ad.present(fromRootViewController: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
//搜索成功了
|
||||
@ -43,6 +45,7 @@ class MPPositive_SearchResultsShowView: UIView {
|
||||
dataSource.titles = titles
|
||||
dataSource.reloadData(selectedIndex: 0)
|
||||
segmentView.reloadData()
|
||||
segmentView.selectItemAt(index: 0)
|
||||
emptyImageView.isHidden = !(titles.count == 0)
|
||||
}
|
||||
}
|
||||
@ -102,8 +105,11 @@ class MPPositive_SearchResultsShowView: UIView {
|
||||
return imageView
|
||||
}()
|
||||
var scrollBlock:(() -> Void)?
|
||||
override init(frame: CGRect) {
|
||||
//是否展示插页广告
|
||||
private var isShowAd:Bool = true
|
||||
init(frame: CGRect, isShowAd:Bool = true) {
|
||||
super.init(frame: frame)
|
||||
self.isShowAd = isShowAd
|
||||
backgroundColor = .init(hex: "1A1A1A")
|
||||
configure()
|
||||
MP_AdMobManager.shared.onSearchNativeAdBlock = {
|
||||
|
||||
@ -63,11 +63,17 @@ class MPSideA_LoadDataMusic: NSObject {
|
||||
homeSecondMusics = locallistMusics.filter{($0.type == .Second)}
|
||||
homeThirdMusics = convertToTwoArray(locallistMusics.filter{($0.type == .Third)}, raw: 3)
|
||||
//取出固定内容
|
||||
homeZeroMusics.append(homeThirdMusics.last!.last!)
|
||||
homeZeroMusics.append(homeSecondMusics.last!)
|
||||
homeZeroMusics.append(homeFirstMusics.last!)
|
||||
if userlistMusics.count != 0 {
|
||||
homeZeroMusics.append(userlistMusics.last!)
|
||||
if let last = homeThirdMusics.last?.last {
|
||||
homeZeroMusics.append(last)
|
||||
}
|
||||
if let last = homeSecondMusics.last {
|
||||
homeZeroMusics.append(last)
|
||||
}
|
||||
if let last = homeFirstMusics.last {
|
||||
homeZeroMusics.append(last)
|
||||
}
|
||||
if userlistMusics.count != 0, let last = userlistMusics.last {
|
||||
homeZeroMusics.append(last)
|
||||
}
|
||||
completion?()
|
||||
}
|
||||
|
||||
@ -259,6 +259,7 @@ extension MPSideA_TabBarController {
|
||||
//MARK: - 覆盖型广告代理 GADFullScreenContentDelegate
|
||||
//覆盖型广告将要将要展示
|
||||
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = true
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
print("当前展示的广告是播放插页广告,广告ID--\(MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? "")")
|
||||
MP_AnalyticsManager.shared.play_ads_showSuccessAction()
|
||||
@ -266,6 +267,7 @@ extension MPSideA_TabBarController {
|
||||
}
|
||||
//覆盖型广告已经消失
|
||||
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
MP_AdMobManager.shared.interstitialDate = Date()
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
let UUID = MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? ""
|
||||
@ -282,10 +284,15 @@ extension MPSideA_TabBarController {
|
||||
self?.present(playerVC, animated: true)
|
||||
}
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
//覆盖型广告加载出错
|
||||
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
// UIApplication.shared.isStatusBarHidden = false
|
||||
MP_AdMobManager.shared.interstitialDate = Date()
|
||||
if ad === MP_AdMobManager.shared.playInterstitialAd {//播放插页广告
|
||||
let UUID = MP_AdMobManager.shared.playInterstitialAd?.adUnitID ?? ""
|
||||
@ -304,6 +311,10 @@ extension MPSideA_TabBarController {
|
||||
// self?.present(playerVC, animated: true)
|
||||
// }
|
||||
}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3){
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
accessAppdelegate.setAudioSupport()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user