1.2.0对后台播放调整
@ -24,6 +24,7 @@
|
||||
CB0B36912C65EBFC004036E2 /* MPPositive_BaseShowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */; };
|
||||
CB0D33972C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0D33962C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift */; };
|
||||
CB0D339B2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0D339A2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift */; };
|
||||
CB108C872C901A5E0017C40F /* MP_LuxServerManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB108C862C901A5E0017C40F /* MP_LuxServerManager.swift */; };
|
||||
CB15B89B2C353B2400756E89 /* MP_GuideViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB15B8992C353B2400756E89 /* MP_GuideViewController.swift */; };
|
||||
CB15B89C2C353B2400756E89 /* MP_GuideViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = CB15B89A2C353B2400756E89 /* MP_GuideViewController.xib */; };
|
||||
CB1E3B662C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */; };
|
||||
@ -299,6 +300,7 @@
|
||||
CB0B36902C65EBFC004036E2 /* MPPositive_BaseShowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_BaseShowView.swift; sourceTree = "<group>"; };
|
||||
CB0D33962C7EF73700C85816 /* MPPositive_PersonalListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PersonalListViewModel.swift; sourceTree = "<group>"; };
|
||||
CB0D339A2C7F2AAC00C85816 /* MPPositive_PersonalisedRecommendationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_PersonalisedRecommendationsTableViewCell.swift; sourceTree = "<group>"; };
|
||||
CB108C862C901A5E0017C40F /* MP_LuxServerManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_LuxServerManager.swift; sourceTree = "<group>"; };
|
||||
CB15B8992C353B2400756E89 /* MP_GuideViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MP_GuideViewController.swift; sourceTree = "<group>"; };
|
||||
CB15B89A2C353B2400756E89 /* MP_GuideViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MP_GuideViewController.xib; sourceTree = "<group>"; };
|
||||
CB1E3B652C23DA8500071DEA /* MPPositive_CustomPlayListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MPPositive_CustomPlayListModel.swift; sourceTree = "<group>"; };
|
||||
@ -751,10 +753,11 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
CBAFCA272C0A10500054500E /* MP_NetWorkManager.swift */,
|
||||
CB108C862C901A5E0017C40F /* MP_LuxServerManager.swift */,
|
||||
CBAFCA282C0A10500054500E /* MP_PlayerManager.swift */,
|
||||
CBAFCA202C0A10500054500E /* MP_AVURLAsset.swift */,
|
||||
CBAFCA1F2C0A10500054500E /* MP_AnalyticsManager.swift */,
|
||||
CBB6372B2C1C17C300F1DEC9 /* MP_AdMobManager.swift */,
|
||||
CBAFCA202C0A10500054500E /* MP_AVURLAsset.swift */,
|
||||
CBAFCA212C0A10500054500E /* MP_CacheManager.swift */,
|
||||
CBAFCA232C0A10500054500E /* MP_CoreDataHandlerManager.swift */,
|
||||
CBAFCA242C0A10500054500E /* MP_DownloadManager.swift */,
|
||||
@ -1287,7 +1290,7 @@
|
||||
CBC2D6E62BFDF3D700E17703 /* Resources */,
|
||||
0018BD0A2C1050F60066717C /* ShellScript */,
|
||||
4F340A16CA4CBC1A386EF0AF /* [CP] Embed Pods Frameworks */,
|
||||
D1CFD1D7A1F3154E85EE0F93 /* [CP] Copy Pods Resources */,
|
||||
389B03C2C01E5C783CCE22ED /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@ -1454,6 +1457,23 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
389B03C2C01E5C783CCE22ED /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
4F340A16CA4CBC1A386EF0AF /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -1471,23 +1491,6 @@
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
D1CFD1D7A1F3154E85EE0F93 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-relax.offline.mp3.music/Pods-relax.offline.mp3.music-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
@ -1618,6 +1621,7 @@
|
||||
CBAFCB732C0A10500054500E /* MPPositive_SearchSuggestionItemTableViewCell.swift in Sources */,
|
||||
CBAFCB432C0A10500054500E /* MPPositive_NavigationController.swift in Sources */,
|
||||
CBAFCB302C0A10500054500E /* MPPositive_BrowseModuleListViewModel.swift in Sources */,
|
||||
CB108C872C901A5E0017C40F /* MP_LuxServerManager.swift in Sources */,
|
||||
CBAFCBA62C0A10500054500E /* MPSideA_Home_SecondListCollectionViewCell.swift in Sources */,
|
||||
CBAFCB202C0A10500054500E /* MPPositive_JsonSearchSuggestions.swift in Sources */,
|
||||
CBAFCB232C0A10500054500E /* MPPositive_ArtistHeaderModel.swift in Sources */,
|
||||
@ -1895,7 +1899,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1.1.9.1;
|
||||
CURRENT_PROJECT_VERSION = 1.2.0.1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH;
|
||||
@ -1916,7 +1920,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.9;
|
||||
MARKETING_VERSION = 1.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -1941,7 +1945,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 1.1.9.1;
|
||||
CURRENT_PROJECT_VERSION = 1.2.0.1;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = RAQJ4FNZUH;
|
||||
@ -1962,7 +1966,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.9;
|
||||
MARKETING_VERSION = 1.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = relax.offline.mp3.music;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
||||
@ -3,18 +3,4 @@
|
||||
uuid = "B2D42C7E-B789-40F0-8339-B70A223A3889"
|
||||
type = "0"
|
||||
version = "2.0">
|
||||
<Breakpoints>
|
||||
<BreakpointProxy
|
||||
BreakpointExtensionID = "Xcode.Breakpoint.ExceptionBreakpoint">
|
||||
<BreakpointContent
|
||||
uuid = "C55B60AF-F439-4924-A399-CD9EE440654E"
|
||||
shouldBeEnabled = "Yes"
|
||||
ignoreCount = "0"
|
||||
continueAfterRunningActions = "No"
|
||||
breakpointStackSelectionBehavior = "1"
|
||||
scope = "1"
|
||||
stopOnStyle = "0">
|
||||
</BreakpointContent>
|
||||
</BreakpointProxy>
|
||||
</Breakpoints>
|
||||
</Bucket>
|
||||
|
||||
@ -14,6 +14,8 @@ import Firebase
|
||||
import GoogleMobileAds
|
||||
import FacebookCore
|
||||
import StoreKit
|
||||
import UserMessagingPlatform
|
||||
|
||||
@_exported import IQKeyboardManagerSwift
|
||||
@UIApplicationMain
|
||||
class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
@ -57,8 +59,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
window?.backgroundColor = .init(hex: "#161616")
|
||||
//关联faceBook
|
||||
ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)
|
||||
//初始化三个控制器
|
||||
positiceVC = MPPositive_TabBarController()
|
||||
switch_lunch()
|
||||
//执行用户启动事件日志
|
||||
MP_AnalyticsManager.shared.user_launchAction()
|
||||
@ -162,7 +162,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
//销毁A面所有内容
|
||||
MPSideA_MediaCenterManager.shared.destroySideA()
|
||||
MPSideA_VolumeManager.shared.destroySideA()
|
||||
|
||||
positiceVC = MPPositive_TabBarController()
|
||||
//动画设置
|
||||
let transtition = CATransition()
|
||||
transtition.duration = 0.8
|
||||
|
||||
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 6.4 KiB After Width: | Height: | Size: 5.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 8.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 5.4 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 9.4 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 8.5 KiB After Width: | Height: | Size: 6.8 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 7.7 KiB |
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "img_v3_02b6_9dd8ad60-2766-4b89-9959-401f232d926g.png",
|
||||
"filename" : "img_v3_02ed_b27cf77e-1e80-492f-b990-6592a6be80ag.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "img_v3_02b6_9dd8ad60-2766-4b89-9959-401f232d926g 1.png",
|
||||
"filename" : "img_v3_02ed_b27cf77e-1e80-492f-b990-6592a6be80ag 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 192 KiB |
|
After Width: | Height: | Size: 192 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Lunch/Lunch'bg.imageset/20240909-100133 1.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Lunch/Lunch'bg.imageset/20240909-100133.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "启动页-NEW@2x.png",
|
||||
"filename" : "20240909-100133.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "启动页-NEW@3x.png",
|
||||
"filename" : "20240909-100133 1.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 873 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "蓝色背景@2x.png",
|
||||
"filename" : "Group_1597880777@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "蓝色背景@3x.png",
|
||||
"filename" : "Group_1597880777@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 95 KiB |
|
Before Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 140 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Positive/Center/Love Songs'bg.imageset/001@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Positive/Center/Love Songs'bg.imageset/001@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 90 KiB |
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "橙色背景@2x.png",
|
||||
"filename" : "001@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "橙色背景@3x.png",
|
||||
"filename" : "001@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 144 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Positive/Center/Offline Songs'bg.imageset/003@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
relax.offline.mp3.music/Assets.xcassets/Positive/Center/Offline Songs'bg.imageset/003@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 95 KiB |
@ -5,12 +5,12 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "紫色背景@2x.png",
|
||||
"filename" : "003@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "紫色背景@3x.png",
|
||||
"filename" : "003@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 134 KiB |
@ -32,12 +32,6 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
private var switchBlock:(() -> Void)?
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
//printCallStack()
|
||||
// 请求跟踪授权
|
||||
requestTrackingAuthorization { idfa in
|
||||
}
|
||||
}
|
||||
view.backgroundColor = .init(hex: "#000000")
|
||||
timer = CADisplayLink(target: self, selector: #selector(timerActionClick(_ :)))
|
||||
|
||||
@ -123,6 +117,7 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
guard UserDefaults.standard.bool(forKey: "MP_Into_B") != true else {
|
||||
MP_IAPManager.shared.startLunchStatus()
|
||||
MPPositive_BrowseLoadViewModel.shared.getRecentlyData()
|
||||
MP_LuxServerManager.shared.upDateOpenActiveEventTask()
|
||||
//更新开关以及响应的数据
|
||||
MP_AnalyticsManager.shared.getOpenStatus { [weak self] open in
|
||||
if open {
|
||||
@ -169,6 +164,7 @@ class MP_LunchViewController: UIViewController, GADFullScreenContentDelegate {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
MP_IAPManager.shared.startLunchStatus()
|
||||
MP_LuxServerManager.shared.upDateOpenActiveEventTask()
|
||||
//进行开关检测
|
||||
MP_AnalyticsManager.shared.getOpenStatus { [weak self] open in
|
||||
guard let self = self else {return}
|
||||
|
||||
@ -33,6 +33,8 @@ extension NotificationCenter{
|
||||
struct notificationKey:NotificationKey {
|
||||
///关键词
|
||||
enum Keys:String {
|
||||
///通知用户更新
|
||||
case update_reminder
|
||||
///切换taBarItem
|
||||
case switch_tabBarItem
|
||||
//MARK: - A面通知内容
|
||||
|
||||
@ -10,5 +10,4 @@
|
||||
///麦克风使用说明
|
||||
"NSMicrophoneUsageDescription" = "يتطلب \"HiMelody\" منك تشغيل الميكروفون الخاص بك للتعرف على وحدات الديسيبل المحيطة وتشغيل الضوضاء البيضاء تلقائيًا نيابةً عنك. هل تريد السماح لهذا التطبيق بالوصول إلى الميكروفون الخاص بك؟";
|
||||
///用户跟踪使用说明
|
||||
"NSUserTrackingUsageDescription" = "يحتاج \"HiMelody\" إلى طلب أذونات التتبع لتوفير تجربة إعلانية مخصصة. نحن نحترم ونحمي خصوصيتك ولن نبيع بياناتك لأطراف ثالث
|
||||
.";
|
||||
"NSUserTrackingUsageDescription" = "يحتاج \"HiMelody\" إلى طلب أذونات التتبع لتوفير تجربة إعلانية مخصصة. نحن نحترم ونحمي خصوصيتك ولن نبيع بياناتك لأطراف ثالث.";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "لأنك سمعت";
|
||||
///因为你喜欢
|
||||
"Because you like" = "لأنك تحب";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "إصدار جديد من تطبيقنا متاح الآن! قمنا بتحسينات مثيرة وأضفنا ميزات جديدة لتعزيز تجربتك. للاستمتاع بهذه التحديثات والمتابعة في استخدام تطبيقنا بسلاسة، يرجى تحديث إلى أحدث إصدار الآن.اضغط على 'تحديث' للحصول على أحدث الميزات والتحسينات.";
|
||||
///更新
|
||||
"Update" = "تحديث";
|
||||
///不是现在
|
||||
"Not now" = "ليس الآن";
|
||||
///更新提醒
|
||||
"Update available" = "تحديث متاح";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "تم نسخ عنوان البريد الإلكتروني بنجاح إلى الحافظة";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Weil du es gehört hast";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Weil es dir gefällt";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "Eine neue Version unserer App ist jetzt verfügbar! Wir haben aufregende Verbesserungen vorgenommen und neue Funktionen hinzugefügt, um Ihr Erlebnis zu verbessern. Um diese Updates zu genießen und unsere App nahtlos weiter zu verwenden, aktualisieren Sie bitte jetzt auf die neueste Version.\nTippen Sie auf 'Aktualisieren', um die neuesten Funktionen und Verbesserungen zu erhalten.";
|
||||
///更新
|
||||
"Update" = "Aktualisieren";
|
||||
///不是现在
|
||||
"Not now" = "Nicht jetzt";
|
||||
///更新提醒
|
||||
"Update available" = "Aktualisierung verfügbar";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "E-Mail-Adresse erfolgreich in die Zwischenablage kopiert";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Because you listen";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Because you like";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements.";
|
||||
///更新
|
||||
"Update" = "Update";
|
||||
///不是现在
|
||||
"Not now" = "Not now";
|
||||
///更新提醒
|
||||
"Update available" = "Update available";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Successfully copied the e-mail address to the clipboard";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Porque has escuchado";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Porque te gusta";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "¡Una nueva versión de nuestra aplicación ya está disponible! Hemos realizado emocionantes mejoras y añadido nuevas características para mejorar tu experiencia. Para disfrutar de estas actualizaciones y seguir utilizando nuestra aplicación sin problemas, por favor actualiza a la última versión ahora.\n¡Toca en 'Actualizar' para obtener las últimas características y mejoras.";
|
||||
///更新
|
||||
"Update" = "Actualizar";
|
||||
///不是现在
|
||||
"Not now" = "Ahora no";
|
||||
///更新提醒
|
||||
"Update available" = "Actualización disponible";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Dirección de correo electrónico copiada correctamente al portapapeles";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Parce que tu as entendu";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Parce que tu aimes";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "Une nouvelle version de notre application est désormais disponible ! Nous avons apporté des améliorations passionnantes et ajouté de nouvelles fonctionnalités pour améliorer votre expérience. Pour profiter de ces mises à jour et continuer à utiliser notre application sans problème, veuillez mettre à jour vers la dernière version maintenant.\nAppuyez sur 'Mettre à jour' pour obtenir les dernières fonctionnalités et améliorations.";
|
||||
///更新
|
||||
"Update" = "Mettre à jour";
|
||||
///不是现在
|
||||
"Not now" = "Pas maintenant";
|
||||
///更新提醒
|
||||
"Update available" = "Mise à jour disponible";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Adresse e-mail copiée avec succès dans le presse-papiers";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Perché hai sentito";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Perché ti piace";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "Una nuova versione della nostra app è ora disponibile! Abbiamo apportato eccitanti miglioramenti e aggiunto nuove funzionalità per migliorare la tua esperienza. Per godere di questi aggiornamenti e continuare ad utilizzare la nostra app senza intoppi, ti preghiamo di aggiornare alla versione più recente ora.\nTocca su 'Aggiorna' per ottenere le ultime funzionalità e miglioramenti.";
|
||||
///更新
|
||||
"Update" = "Aggiorna";
|
||||
///不是现在
|
||||
"Not now" = "Non ora";
|
||||
///更新提醒
|
||||
"Update available" = "Aggiornamento disponibile";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Indirizzo email copiato con successo negli appunti";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "Porque você ouviu";
|
||||
///因为你喜欢
|
||||
"Because you like" = "Porque você gosta";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "Uma nova versão do nosso aplicativo já está disponível! Fizemos melhorias emocionantes e adicionamos novos recursos para aprimorar sua experiência. Para aproveitar essas atualizações e continuar usando nosso aplicativo sem problemas, por favor atualize para a última versão agora.\nToque em 'Atualizar' para obter os últimos recursos e melhorias.";
|
||||
///更新
|
||||
"Update" = "Atualizar";
|
||||
///不是现在
|
||||
"Not now" = "Não agora";
|
||||
///更新提醒
|
||||
"Update available" = "Atualização disponível";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Endereço de e-mail copiado com sucesso para a área de transferência";
|
||||
|
||||
@ -134,6 +134,14 @@
|
||||
"Because you listen" = "çünkü duydun";
|
||||
///因为你喜欢
|
||||
"Because you like" = "çünkü seviyorsun";
|
||||
///提醒用户更新
|
||||
"A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements." = "Uygulamamızın yeni bir sürümü artık kullanılabilir! Heyecan verici iyileştirmeler yaptık ve deneyiminizi artırmak için yeni özellikler ekledik. Bu güncellemelerden yararlanmak ve uygulamamızı sorunsuz bir şekilde kullanmaya devam etmek için lütfen şimdi en son sürüme güncelleyin.\nEn son özellikleri ve geliştirmeleri almak için 'Güncelle'ye dokunun.";
|
||||
///更新
|
||||
"Update" = "Güncelle";
|
||||
///不是现在
|
||||
"Not now" = "Şimdi değil";
|
||||
///更新提醒
|
||||
"Update available" = "Güncelleme mevcut";
|
||||
//MARK: - HUD文本
|
||||
///已成功将电子邮件地址复制到剪贴板
|
||||
"Successfully copied the e-mail address to the clipboard" = "Herhangi bir yorumunuz veya öneriniz varsa lütfen aşağıdaki e-posta adresinden bizimle iletişime geçin.";
|
||||
|
||||
@ -70,7 +70,7 @@ let love_songBGImage:UIImage = UIImage(named: "Love Songs'bg")!
|
||||
///收藏歌手占位图
|
||||
let love_artistBGImage:UIImage = UIImage(named: "Love Artists'bg")!
|
||||
///离线下载占位图
|
||||
let offline_songBGImage:UIImage = UIImage(named: "Offline Songs")!
|
||||
let offline_songBGImage:UIImage = UIImage(named: "Offline Songs'bg")!
|
||||
///隐私政策网址
|
||||
let privacyUrl:URL = .init(string: "https://musiclax.mystrikingly.com/privacy")!
|
||||
///用户协议网址
|
||||
@ -81,6 +81,15 @@ let gradientTextColors:[CGColor] = [UIColor(red: 0, green: 0.863, blue: 1, alpha
|
||||
UIColor(red: 0.776, green: 1, blue: 0.639, alpha: 1).cgColor]
|
||||
///常用文本颜色-绿色
|
||||
let greenTextColor:UIColor = .init(hex: "#80F988", alpha: 1.0)
|
||||
///是否需要提醒用户更新
|
||||
var isUpDateReminder:Bool = false{
|
||||
willSet{
|
||||
if newValue == true {
|
||||
//新值为更新提醒,发布通知
|
||||
NotificationCenter.notificationKey.post(notificationName: .update_reminder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: - 全局变量与方法
|
||||
//存储默认配置值
|
||||
@ -504,3 +513,25 @@ func printCallStack() {
|
||||
let callStack = Thread.callStackSymbols
|
||||
print("Call Stack: \(callStack)")
|
||||
}
|
||||
///弹出一个更新通知弹窗
|
||||
func postUpdateReminder(_ observe:UIViewController) {
|
||||
let alter = UIAlertController(title: "Update available".localizableString(), message: "A new version of our app is now available! We've made some exciting improvements and added new features to enhance your experience. To enjoy these updates and continue using our app seamlessly, please update to the latest version now.\nTap on 'Update' to get the latest features and enhancements.".localizableString(), preferredStyle: .alert)
|
||||
//取消
|
||||
let not = UIAlertAction(title: "Not now".localizableString(), style: .cancel) { action in
|
||||
//用户取消更新事件
|
||||
MP_AnalyticsManager.shared.update_reminder_cancelAction()
|
||||
print("用户取消更新")
|
||||
}
|
||||
alter.addAction(not)
|
||||
let updata = UIAlertAction(title: "Update".localizableString(), style: .destructive) { action in
|
||||
//用户确定更新事件
|
||||
MP_AnalyticsManager.shared.update_reminder_sureAction()
|
||||
//跳转AppStore
|
||||
if let url = URL(string: "https://apps.apple.com/app/6502973957") {
|
||||
UIApplication.shared.open(url, options: [:], completionHandler: nil)
|
||||
}
|
||||
}
|
||||
alter.addAction(updata)
|
||||
MP_AnalyticsManager.shared.update_reminder_showAction()
|
||||
observe.present(alter, animated: true)
|
||||
}
|
||||
|
||||
@ -272,22 +272,8 @@ class MP_PlayerResourceLoader: NSObject, AVAssetResourceLoaderDelegate {
|
||||
processRequestList(id ?? "")
|
||||
}
|
||||
}
|
||||
// /// 缓存结果
|
||||
// func requestManagerIsCached(_ isCached: Bool, videoId:String){
|
||||
// if self.videoId == videoId {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
// /// 接收数据完成
|
||||
// func requestManagerDidComplete(withError errorCode: Int, videoId:String){
|
||||
// if self.videoId == videoId {
|
||||
//
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
///媒体播放器工具配置
|
||||
class MP_PlayerToolConfig:NSObject {
|
||||
///自定义URL链接
|
||||
@ -309,7 +295,6 @@ class MP_PlayerToolConfig:NSObject {
|
||||
return components.url
|
||||
}
|
||||
}
|
||||
|
||||
class MP_PlayerTaskManager:NSObject, URLSessionDataDelegate{
|
||||
static var shared = MP_PlayerTaskManager()
|
||||
///请求代理
|
||||
@ -340,6 +325,23 @@ class MP_PlayerTaskManager:NSObject, URLSessionDataDelegate{
|
||||
var titles:[String:String]!
|
||||
//后台加载执行任务
|
||||
var sessionCompletionHandler: (() -> Void)?
|
||||
//后台任务ID
|
||||
var backgroundTaskID: UIBackgroundTaskIdentifier?
|
||||
//开始后台任务
|
||||
func beginBackgroundTask() {
|
||||
backgroundTaskID = UIApplication.shared.beginBackgroundTask {
|
||||
// 在系统终止后台任务时调用
|
||||
UIApplication.shared.endBackgroundTask(self.backgroundTaskID!)
|
||||
self.backgroundTaskID = UIBackgroundTaskIdentifier.invalid
|
||||
}
|
||||
}
|
||||
//结束后台任务
|
||||
func endBackgroundTask() {
|
||||
if let backgroundTaskID = backgroundTaskID {
|
||||
UIApplication.shared.endBackgroundTask(backgroundTaskID)
|
||||
self.backgroundTaskID = UIBackgroundTaskIdentifier.invalid
|
||||
}
|
||||
}
|
||||
//默认任务最大数
|
||||
private var maxCount = 4
|
||||
override init() {
|
||||
@ -350,6 +352,8 @@ class MP_PlayerTaskManager:NSObject, URLSessionDataDelegate{
|
||||
configuration.timeoutIntervalForRequest = 30
|
||||
configuration.timeoutIntervalForResource = 30
|
||||
configuration.allowsCellularAccess = true
|
||||
configuration.sessionSendsLaunchEvents = true
|
||||
configuration.isDiscretionary = false
|
||||
//实现会话
|
||||
session = .init(configuration: configuration, delegate: self, delegateQueue: nil)
|
||||
//初始化
|
||||
@ -533,6 +537,11 @@ class MP_PlayerTaskManager:NSObject, URLSessionDataDelegate{
|
||||
}
|
||||
}
|
||||
}
|
||||
//后台触发任务时
|
||||
func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) {
|
||||
print("任务已经全部完成了")
|
||||
}
|
||||
|
||||
//重试机制
|
||||
private func retryTask(task:URLSessionTask) {
|
||||
accessQueue.async {
|
||||
|
||||
@ -99,6 +99,12 @@ class MP_AnalyticsManager: NSObject {
|
||||
private let VIP_buy_success = "VIP_buy_success"
|
||||
///购买失败
|
||||
private let VIP_buy_failure = "VIP_buy_failure"
|
||||
///弹出更新框
|
||||
private let update_reminder_show = "update_reminder_show"
|
||||
///取消更新
|
||||
private let update_reminder_cancel = "update_reminder_cancel"
|
||||
///确认更新
|
||||
private let update_reminder_sure = "update_reminder_sure"
|
||||
private override init() {
|
||||
//获取用户是新用户还是老用户
|
||||
if UserDefaults.standard.bool(forKey: "UserStatus") {
|
||||
@ -184,7 +190,37 @@ class MP_AnalyticsManager: NSObject {
|
||||
//更新通知
|
||||
scheduleDailyNotifications()
|
||||
}
|
||||
|
||||
//是否需要弹出更新弹窗
|
||||
if let updateReminder = self.remoteConfig.configValue(forKey: "updateReminder").jsonValue as? [String:Any] {
|
||||
//检索是否需要更新
|
||||
if let statu = updateReminder["statu"] as? Bool, let version = updateReminder["versionCode"] as? String {
|
||||
//获得更新状态,根据更新状态确定是否需要弹出广告
|
||||
if statu {
|
||||
//需要更新,检索当前版本是否为最新的版本
|
||||
if version == app_Version {
|
||||
//不用更新
|
||||
isUpDateReminder = false
|
||||
print("无需更新")
|
||||
}else {
|
||||
//需要更新
|
||||
isUpDateReminder = true
|
||||
print("需要更新")
|
||||
}
|
||||
}else {
|
||||
//不用更新
|
||||
isUpDateReminder = false
|
||||
print("无需更新")
|
||||
}
|
||||
}else {
|
||||
//不用更新
|
||||
isUpDateReminder = false
|
||||
print("无需更新")
|
||||
}
|
||||
}else {
|
||||
//不用更新
|
||||
isUpDateReminder = false
|
||||
print("无需更新")
|
||||
}
|
||||
let js = self.remoteConfig.configValue(forKey: "openStatus").jsonValue as! [String:Any]
|
||||
let value = js["versionCode"] as! String
|
||||
if value == app_Version {
|
||||
@ -499,6 +535,18 @@ class MP_AnalyticsManager: NSObject {
|
||||
Analytics.logEvent(VIP_buy_failure, parameters: ["productID":productID,
|
||||
"buy_error":error])
|
||||
}
|
||||
///弹出更新框
|
||||
func update_reminder_showAction() {
|
||||
Analytics.logEvent(update_reminder_show, parameters: nil)
|
||||
}
|
||||
///确认更新
|
||||
func update_reminder_sureAction() {
|
||||
Analytics.logEvent(update_reminder_sure, parameters: nil)
|
||||
}
|
||||
///取消更新
|
||||
func update_reminder_cancelAction() {
|
||||
Analytics.logEvent(update_reminder_cancel, parameters: nil)
|
||||
}
|
||||
//MARK: - 广告埋点事件
|
||||
//冷启动展示机会
|
||||
private let cold_ads_chance:String = "cold_ads_chance"
|
||||
@ -643,7 +691,6 @@ class MP_AnalyticsManager: NSObject {
|
||||
///冷启动关闭
|
||||
func cold_ads_closeAction() {
|
||||
let parameters:[String:String] = ["CS_STATUS":isOLD ? "Old":"New"]
|
||||
print("冷启动失败展示信息--\(parameters)")
|
||||
Analytics.logEvent(cold_ads_close, parameters: parameters)
|
||||
}
|
||||
///热启动展示机会
|
||||
|
||||
@ -158,7 +158,9 @@ class MP_DownloadManager: NSObject {
|
||||
self.downloadTasks?[nextVideoId]?.status = .downloading
|
||||
}
|
||||
//更新对应任务(videoId)的进度值
|
||||
loadQueue.async {
|
||||
self.progressStorage?[nextVideoId] = task.progress.fractionCompleted
|
||||
}
|
||||
//执行下载进度更新代理
|
||||
NotificationCenter.notificationKey.post(notificationName: .download_progress_source, object: ["videoId":nextVideoId])
|
||||
}
|
||||
@ -191,7 +193,9 @@ class MP_DownloadManager: NSObject {
|
||||
self.downloadTasks?[nextVideoId]?.status = .failed
|
||||
}
|
||||
downloadURLs?[nextVideoId] = nil
|
||||
progressStorage?[nextVideoId] = nil
|
||||
loadQueue.async {
|
||||
self.progressStorage?[nextVideoId] = nil
|
||||
}
|
||||
songHandlers?[nextVideoId] = nil
|
||||
MP_HUD.text("An error occurred while downloading. Please download again.".localizableString(), delay: 1.5, completion: nil)
|
||||
session.cancel(task) { _ in
|
||||
@ -214,7 +218,9 @@ class MP_DownloadManager: NSObject {
|
||||
}
|
||||
self.downloadURLs?[nextVideoId] = nil
|
||||
self.downloadTasks?[nextVideoId] = nil
|
||||
loadQueue.async {
|
||||
self.progressStorage?[nextVideoId] = nil
|
||||
}
|
||||
self.songHandlers?[nextVideoId] = nil
|
||||
//告知用户下载成功
|
||||
MP_HUD.downloadText("Download Successfull".localizableString(), delay: 1.0, completion: nil)
|
||||
@ -240,7 +246,9 @@ class MP_DownloadManager: NSObject {
|
||||
self.downloadTasks?[nextVideoId]?.status = .failed
|
||||
}
|
||||
downloadURLs?[nextVideoId] = nil
|
||||
progressStorage?[nextVideoId] = nil
|
||||
loadQueue.async {
|
||||
self.progressStorage?[nextVideoId] = nil
|
||||
}
|
||||
songHandlers?[nextVideoId] = nil
|
||||
switch error.localizedDescription {
|
||||
case "The operation couldn’t be completed. No space left on device":
|
||||
|
||||
@ -0,0 +1,305 @@
|
||||
//
|
||||
// MP_LuxServerManager.swift
|
||||
// relax.offline.mp3.music
|
||||
//
|
||||
// Created by Mr.Zhou on 2024/9/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Alamofire
|
||||
import Security
|
||||
import AdSupport
|
||||
///自家后台管理器
|
||||
class MP_LuxServerManager: NSObject {
|
||||
//单例工具
|
||||
static let shared = MP_LuxServerManager()
|
||||
///keychain关键词
|
||||
private let service = "relax.offline.mp3.music.deviceIdentifier"
|
||||
//MARK: - URL
|
||||
///基础链接
|
||||
private let baseUrl:String = "https://openapi.lux-ad.com"
|
||||
///报活链接
|
||||
private let activeUrl:String = "/statistic/appdatacollection/saveAppData"
|
||||
///报错链接
|
||||
private let errorUrl:String = "/statistic/applogscollection/save"
|
||||
|
||||
//MARK: - 通用参数值
|
||||
///唯一的设备UUID(重装应用后,也会使用该设备ID)
|
||||
private var uuID:String{
|
||||
get{
|
||||
return getDeviceUUID()
|
||||
}
|
||||
}
|
||||
///用户ID(每次重装应用都会生成一个新的用户ID)
|
||||
private var userID:String{
|
||||
get{
|
||||
return getUserID()
|
||||
}
|
||||
}
|
||||
///IDFA广告跟踪ID(检索用户是否具备权限,无权限/位置状态返回内容则是由0构成的字符串;具备权限则会返回正常的跟踪ID)
|
||||
private let IDFAID:String = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||||
///渠道
|
||||
private let channel:String = "ios"
|
||||
///包名
|
||||
private let pkgName:String = "relax.offline.mp3.music"
|
||||
///事件名
|
||||
private var eventName:String {
|
||||
get{
|
||||
return getEventName()
|
||||
}
|
||||
}
|
||||
///当前时间节点毫秒数
|
||||
private var timestamp:Int64 {
|
||||
get{
|
||||
//获取当前时间值
|
||||
let now = Date()
|
||||
//获取时间缀,并转为毫秒级别
|
||||
let currentTimestampInMillisInt:Int64 = Int64(now.timeIntervalSince1970 * 1000)
|
||||
return currentTimestampInMillisInt
|
||||
}
|
||||
}
|
||||
/// 设备类型
|
||||
private var deviceVersion: String {
|
||||
return UIDevice.current.name
|
||||
}
|
||||
///系统版本
|
||||
private var osVersion:String {
|
||||
return UIDevice.current.systemVersion
|
||||
}
|
||||
|
||||
//MARK: - 会话
|
||||
///后台会话
|
||||
private lazy var LuxSession:Session = {
|
||||
let configuration = URLSessionConfiguration.af.default
|
||||
///超时设置
|
||||
configuration.timeoutIntervalForRequest = 20
|
||||
configuration.timeoutIntervalForResource = 20
|
||||
// 可调整网络服务类型
|
||||
configuration.networkServiceType = .default
|
||||
let seesion = Alamofire.Session(configuration: configuration, interceptor: MP_CustomRetrier())
|
||||
return seesion
|
||||
}()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
///报活参数结构
|
||||
/**
|
||||
{
|
||||
"eventName": "app_open",
|
||||
"timestamp": 1711522237247,
|
||||
"uuid": "c1c4c016cd6276b41e2447653fe5a9b2",
|
||||
"app_version": "1.5.4",
|
||||
"channel": "google",
|
||||
"country": "cn",
|
||||
"device": "android",
|
||||
"language": "zh",
|
||||
"pkgName": "com.master.ae.safevpn",
|
||||
"userId": "55a7fa0c-be84-44b9-a73e-a4256dbb30ee",
|
||||
"adId": "995772a9-7748-418e-bef4-10ca1ad1abe1",
|
||||
"createdOn": "2022-03-10T12:15:50.000Z",
|
||||
"data": {
|
||||
"property1": {},
|
||||
"property2": {}
|
||||
}
|
||||
}**/
|
||||
|
||||
//MARK: - 报活操作
|
||||
///实现报活会话
|
||||
func upDateOpenActiveEventTask() {
|
||||
//生成报活链接
|
||||
guard let url = URL(string: baseUrl+activeUrl) else {
|
||||
return
|
||||
}
|
||||
//生成参数
|
||||
let parameters:[String:Any] = [
|
||||
"userId":userID,
|
||||
"ad_id":IDFAID,
|
||||
"uuid":uuID,
|
||||
"device":deviceVersion,
|
||||
"appVersion":app_Version,
|
||||
"language":Language_first_local,
|
||||
"channel":channel,
|
||||
"pkgName":pkgName,
|
||||
"eventName":eventName,
|
||||
"country":Language_first_local,
|
||||
"dataStr":"Active",
|
||||
"timestamp":timestamp
|
||||
]
|
||||
postUpDateOpenActiveEvent(url, parameters: parameters){
|
||||
[weak self] statu in
|
||||
guard let self = self, statu == true else {return}
|
||||
//检索更多报活信息,并执行报活任务
|
||||
var loads = loadPendingActivities()
|
||||
guard loads.isEmpty == false else {return}
|
||||
var indicesToRemove: [Int] = []
|
||||
let dispatchGroup = DispatchGroup()
|
||||
for (index, item) in loads.enumerated() {
|
||||
dispatchGroup.enter()
|
||||
postUpDateOpenActiveEvent(url, parameters: item, isRepeat: true) { [weak self] statu in
|
||||
guard let self = self, statu == true else {
|
||||
dispatchGroup.leave()
|
||||
return
|
||||
}
|
||||
//报活成功,将成功的报活信息移除
|
||||
indicesToRemove.append(index)
|
||||
dispatchGroup.leave()
|
||||
}
|
||||
}
|
||||
dispatchGroup.notify(queue: .main) {
|
||||
[weak self] in
|
||||
guard let self = self else {return}
|
||||
// 删除收集的索引
|
||||
for index in indicesToRemove.sorted(by: >) {
|
||||
loads.remove(at: index)
|
||||
}
|
||||
reloadActivities(loads)
|
||||
}
|
||||
}
|
||||
}
|
||||
//执行报活
|
||||
private func postUpDateOpenActiveEvent(_ url:URL, parameters:[String:Any], isRepeat:Bool = false, completion:((Bool) -> Void)?) {
|
||||
LuxSession.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default).responseDecodable(of: JsonActive.self) { [weak self] (response) in
|
||||
guard let self = self else {return}
|
||||
switch response.result {
|
||||
case .success(let value):
|
||||
print("成功报活:\(value)")
|
||||
completion?(true)
|
||||
case .failure(let error):
|
||||
print("报活失败,失败错误:\(error.localizedDescription)")
|
||||
if isRepeat == false {
|
||||
//非重复信息,报活信息存入表中
|
||||
saveActivity(parameters)
|
||||
}
|
||||
completion?(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
//保存未加载
|
||||
private func saveActivity(_ parameters:[String:Any]) {
|
||||
var pendingActivities = loadPendingActivities()
|
||||
pendingActivities.append(parameters)
|
||||
if let encoded = try? JSONSerialization.data(withJSONObject: pendingActivities, options: []) {
|
||||
UserDefaults.standard.set(encoded, forKey: "relax.offline.mp3.music.Activities")
|
||||
}
|
||||
}
|
||||
//更新未加载信息
|
||||
private func reloadActivities(_ loads:[[String:Any]]) {
|
||||
if let encoded = try? JSONSerialization.data(withJSONObject: loads, options: []) {
|
||||
UserDefaults.standard.set(encoded, forKey: "relax.offline.mp3.music.Activities")
|
||||
}
|
||||
}
|
||||
//加载未上传的报活信息
|
||||
private func loadPendingActivities() -> [[String:Any]] {
|
||||
if let savedData = UserDefaults.standard.data(forKey: "relax.offline.mp3.music.Activities"),
|
||||
let decoded = try? JSONSerialization.jsonObject(with: savedData, options: []) as? [[String: Any]] {
|
||||
return decoded
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
//MARK: - 设备ID
|
||||
///获得设备ID
|
||||
private func getDeviceUUID() -> String {
|
||||
if let uuid = loadUUIDFromKeychain() {
|
||||
return uuid
|
||||
} else {
|
||||
let newUUID = UUID().uuidString
|
||||
saveUUIDToKeychain(uuid: newUUID)
|
||||
return newUUID
|
||||
}
|
||||
}
|
||||
/// 从 Keychain 中加载 UUID
|
||||
private func loadUUIDFromKeychain() -> String? {
|
||||
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecReturnData as String: true,
|
||||
kSecMatchLimit as String: kSecMatchLimitOne]
|
||||
|
||||
var dataTypeRef: AnyObject? = nil
|
||||
let status = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
|
||||
if status == errSecSuccess {
|
||||
if let data = dataTypeRef as? Data,
|
||||
let uuid = String(data: data, encoding: .utf8) {
|
||||
return uuid
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
/// 保存 UUID 到 Keychain
|
||||
private func saveUUIDToKeychain(uuid: String) {
|
||||
if let data = uuid.data(using: .utf8) {
|
||||
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecValueData as String: data]
|
||||
SecItemAdd(query as CFDictionary, nil)
|
||||
}
|
||||
}
|
||||
//MARK: - 用户ID
|
||||
///获取用户ID
|
||||
private func getUserID() -> String {
|
||||
//检索Userdefaults的userID
|
||||
if let userID = UserDefaults.standard.string(forKey: "relax.offline.mp3.music.userIdentifier") {
|
||||
return userID
|
||||
}else {
|
||||
let newUUID = UIDevice.current.identifierForVendor?.uuidString ?? UUID().uuidString
|
||||
//存入UserDefaults
|
||||
UserDefaults.standard.set(newUUID, forKey: "relax.offline.mp3.music.userIdentifier")
|
||||
return newUUID
|
||||
}
|
||||
}
|
||||
///报活事件名
|
||||
private func getEventName() -> String {
|
||||
//检索
|
||||
if UserDefaults.standard.string(forKey: "relax.offline.mp3.music.firstEvent") != nil {
|
||||
return "app_open"
|
||||
}else {
|
||||
UserDefaults.standard.set("first_open", forKey: "relax.offline.mp3.music.firstEvent")
|
||||
return "first_open"
|
||||
}
|
||||
}
|
||||
//MARK: - 报错操作
|
||||
//上传报错日志
|
||||
func updateErrorLogEventTask(_ level:ErrorLevel, title:String, message:String) {
|
||||
//生成报错链接
|
||||
guard let url = URL(string: baseUrl+errorUrl) else {
|
||||
return
|
||||
}
|
||||
//生成参数
|
||||
let parameters:[String:Any] = [
|
||||
"pkgName":pkgName,
|
||||
"appVersion":app_Version,
|
||||
"os":osVersion,
|
||||
"device":deviceVersion,
|
||||
"Level":level.rawValue,
|
||||
"title":title,
|
||||
"message":message,
|
||||
]
|
||||
}
|
||||
|
||||
}
|
||||
///报活信息结构
|
||||
struct JsonActive:Codable {
|
||||
let message:String?
|
||||
let status:String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case message = "message"
|
||||
case status = "status"
|
||||
}
|
||||
init(from decoder: Decoder) throws {
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
message = try values.decodeIfPresent(String.self, forKey: .message)
|
||||
status = try values.decodeIfPresent(String.self, forKey: .status)
|
||||
}
|
||||
}
|
||||
///报错类型
|
||||
enum ErrorLevel:Int {
|
||||
case debug = 1
|
||||
case info = 2
|
||||
case warn = 3
|
||||
case error = 4
|
||||
case crash = 5
|
||||
}
|
||||
@ -29,10 +29,21 @@ class MP_NetWorkManager: NSObject {
|
||||
//单例工具
|
||||
static let shared = MP_NetWorkManager()
|
||||
//MARK: - 网络请求会话
|
||||
///会话实例
|
||||
///IP信息加载会话实例
|
||||
private lazy var IPSession:Session = {
|
||||
let configuration = URLSessionConfiguration.af.default
|
||||
configuration.timeoutIntervalForRequest = 8
|
||||
configuration.timeoutIntervalForResource = 8
|
||||
// 可调整网络服务类型
|
||||
configuration.networkServiceType = .default
|
||||
// 可调整缓存策略
|
||||
configuration.requestCachePolicy = .reloadIgnoringLocalCacheData
|
||||
let seesion = Alamofire.Session(configuration: configuration, interceptor: MP_CustomRetrier())
|
||||
return seesion
|
||||
}()
|
||||
///预览资源加载会话实例
|
||||
private lazy var MPSession:Session = {
|
||||
let configuration = URLSessionConfiguration.af.default
|
||||
//最多同时执行4条
|
||||
configuration.timeoutIntervalForRequest = 20
|
||||
configuration.timeoutIntervalForResource = 20
|
||||
// 可调整网络服务类型
|
||||
@ -42,7 +53,7 @@ class MP_NetWorkManager: NSObject {
|
||||
let seesion = Alamofire.Session(configuration: configuration, interceptor: MP_CustomRetrier())
|
||||
return seesion
|
||||
}()
|
||||
///播放资源会话实例
|
||||
///播放资源加载会话实例
|
||||
private lazy var PlayerSeesion:Session = {
|
||||
let configuration = URLSessionConfiguration.af.default
|
||||
configuration.timeoutIntervalForRequest = 20
|
||||
@ -87,10 +98,13 @@ class MP_NetWorkManager: NSObject {
|
||||
// "JP",
|
||||
// "KR"
|
||||
]
|
||||
///允许访问的区域Code(对部分内容进行塞选)
|
||||
///允许访问Youtube音乐的地区Code
|
||||
private let ISOs:[String] = ["DZ","LB","AS","LY","AR","LI","AW","LT","AU","LU","AT","MY","AZ","MT","BH","MX","BD","MA","BY","NP","BE","NL","BM","NZ","BO","NI","BA","NG","BR","MK","BG","MP","KH","NO","CA","OM","KY","PK","CL","PA","CO","PG","CR","PY","HR","PE","CY","PH","CZ","PL","DK","PT","DO","PR","EC","QA","EG","RE","SV","RO","EE","FI","SA","FR","SN","GF","RS","PF","SG","GE","SK","DE","SI","GH","ZA","GR","KR","GP","ES","GU","LK","GT","SE","HN","CH","HK","TW","HU","TZ","IS","TH","IN","TN","ID","IQ","TC","IE","VI","IL","UG","IT","UA","JM","AE","JP","GB","JO","US","KZ","UY","KE","VE","KW","VN","LA","YE","LV","ZW"]
|
||||
///允许访问排行榜的区域Code(对部分内容进行塞选)
|
||||
private let codes:[String] = [
|
||||
"CL","GB","ID","IN","IT","IL","HU","NZ","ES","UY","UA","UG","GT","TR","TZ","SA","RS","SV","CH","SE","JP","PT","NO","NG","NI","ZA","MX","PE","US","RO","LU","KE","ZW","CZ","CA","HN","NL","KR","CR","CO","FI","FR","EC","RU","DO","DK","BO","PL","IS","BE","BR","PA","PY","AU","AT","EE","IE","EG","AE","AR","ZZ"
|
||||
]
|
||||
|
||||
///禁止关键词
|
||||
private var trashKeyWords:[String] = []
|
||||
///设置禁止关键词
|
||||
@ -273,14 +287,14 @@ extension MP_NetWorkManager {
|
||||
}
|
||||
}
|
||||
private func requestPostIPInfo(_ url:URL, completion:@escaping((Bool) -> Void)) {
|
||||
MPSession.request(url, method: .get, encoding: JSONEncoding.default).responseDecodable(of: JsonIPInfo.self) { [weak self] (response) in
|
||||
IPSession.request(url, method: .get, encoding: JSONEncoding.default).responseDecodable(of: JsonIPInfo.self) { [weak self] (response) in
|
||||
guard let self = self else {return}
|
||||
switch response.result {
|
||||
case .success(let value):
|
||||
guard let data = value.data, let code = data.isoCode else {
|
||||
return
|
||||
}
|
||||
if codes.contains(code) {
|
||||
if ISOs.contains(code) {
|
||||
locaton = code
|
||||
}else {
|
||||
locaton = "US"
|
||||
@ -295,6 +309,8 @@ extension MP_NetWorkManager {
|
||||
case .failure(let error):
|
||||
// 请求失败,处理错误
|
||||
handleError(url, error: error)
|
||||
//请求失败默认为US
|
||||
locaton = "US"
|
||||
completion(true)
|
||||
}
|
||||
}
|
||||
@ -326,7 +342,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -415,7 +431,7 @@ extension MP_NetWorkManager {
|
||||
return
|
||||
}
|
||||
//异步执行任务
|
||||
var code = locaton ?? ""
|
||||
var code = locaton ?? "US"
|
||||
if codes.contains(code) == false {
|
||||
//没有包含在内,默认替换为US美国国家码
|
||||
code = "US"
|
||||
@ -433,7 +449,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
],
|
||||
"formData":[
|
||||
@ -480,7 +496,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
],
|
||||
"formData":[
|
||||
@ -537,7 +553,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -604,7 +620,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -660,7 +676,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -713,7 +729,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -762,7 +778,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -811,7 +827,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -869,7 +885,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -924,7 +940,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1042,7 +1058,7 @@ extension MP_NetWorkManager {
|
||||
// //语言
|
||||
// "hl":Language_first_local,
|
||||
// //地址
|
||||
// "gl":locaton ?? ""
|
||||
// "gl":locaton ?? "US"
|
||||
// ]
|
||||
// ],
|
||||
// "playbackContext": [
|
||||
@ -1099,7 +1115,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1146,7 +1162,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1204,7 +1220,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1264,7 +1280,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1326,7 +1342,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -1389,7 +1405,7 @@ extension MP_NetWorkManager {
|
||||
//语言
|
||||
"hl":Language_first_local,
|
||||
//地址
|
||||
"gl":locaton ?? ""
|
||||
"gl":locaton ?? "US"
|
||||
]
|
||||
]
|
||||
]
|
||||
|
||||
@ -43,16 +43,4 @@ enum LibraryType:Int {
|
||||
return placeholderImage
|
||||
}
|
||||
}
|
||||
var icon:UIImage?{
|
||||
switch self {
|
||||
case .love_songs:
|
||||
return UIImage(named: "Center_Songs'logo")
|
||||
case .love_aritists:
|
||||
return UIImage(named: "Center_Artists'logo")
|
||||
case .offline_songs:
|
||||
return UIImage(named: "Center_Offline'logo")
|
||||
case .custom_playlist:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,6 +21,7 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio
|
||||
}
|
||||
//是否Push
|
||||
private var isPush:Bool = false
|
||||
|
||||
var pushPlayerBlock:(() -> Void)?
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
@ -59,6 +60,8 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio
|
||||
}
|
||||
bottomView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(playerClick(_ :))))
|
||||
addNotification()
|
||||
//触发更新弹窗
|
||||
updateVersionEvent()
|
||||
}
|
||||
//监听通知
|
||||
private func addNotification() {
|
||||
@ -70,6 +73,7 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(bottomAnimationAction(_:)), notificationName: .player_delete_list)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(pushAction(_ :)), notificationName: .positive_nav_push)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(popAction(_ :)), notificationName: .positive_nav_pop)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(updateVersionEvent), notificationName: .update_reminder)
|
||||
}
|
||||
deinit {
|
||||
//移除所有监听
|
||||
@ -78,7 +82,19 @@ class MPPositive_TabBarController: UITabBarController, UIViewControllerTransitio
|
||||
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
|
||||
return MPPositive_PresentationController(presentedViewController: presented, presenting: presenting)
|
||||
}
|
||||
|
||||
//处理版本更新
|
||||
@objc private func updateVersionEvent() {
|
||||
//判断是否需要更新
|
||||
guard isUpDateReminder == true else {
|
||||
//不需要更新
|
||||
return
|
||||
}
|
||||
//需要更新
|
||||
DispatchQueue.main.async {
|
||||
//触发更新
|
||||
postUpdateReminder(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
//MARK: - 通知处理
|
||||
extension MPPositive_TabBarController {
|
||||
|
||||
@ -30,11 +30,11 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon
|
||||
return array
|
||||
}()
|
||||
///收藏单曲Label
|
||||
private lazy var songsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 12*width, weight: .light), textColor: .white, textAlignment: .left)
|
||||
private lazy var songsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 26*width, weight: .bold), textColor: .white, textAlignment: .left)
|
||||
///收藏歌手Label
|
||||
private lazy var artistsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 12*width, weight: .light), textColor: .white, textAlignment: .left)
|
||||
private lazy var artistsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 26*width, weight: .bold), textColor: .white, textAlignment: .left)
|
||||
///下载单曲Label
|
||||
private lazy var loadsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 12*width, weight: .light), textColor: .white, textAlignment: .left)
|
||||
private lazy var loadsLabel:UILabel = createLabel("0", font: .systemFont(ofSize: 26*width, weight: .bold), textColor: .white, textAlignment: .left)
|
||||
///事件View组
|
||||
private lazy var actionViews:UIView = showTopView()
|
||||
///广告View
|
||||
@ -114,17 +114,14 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon
|
||||
guard let self = self else {return}
|
||||
|
||||
//封面设置
|
||||
songsLabel.text = "\("Songs".localizableString()) \(MPPositive_LoadCoreModel.shared.songViewModels.count)"
|
||||
let songCover = MPPositive_LoadCoreModel.shared.songViewModels.first?.coverURL
|
||||
coverImageViews[0].kf.setImage(with: songCover, placeholder: love_songBGImage)
|
||||
songsLabel.text = "\(MPPositive_LoadCoreModel.shared.songViewModels.count)"
|
||||
coverImageViews[0].image = love_songBGImage
|
||||
|
||||
artistsLabel.text = "\("Artists".localizableString()) \(MPPositive_LoadCoreModel.shared.artistViewModels.count)"
|
||||
let artistCover = MPPositive_LoadCoreModel.shared.artistViewModels.first?.coverURL
|
||||
coverImageViews[1].kf.setImage(with: artistCover, placeholder: love_artistBGImage)
|
||||
artistsLabel.text = "\(MPPositive_LoadCoreModel.shared.artistViewModels.count)"
|
||||
coverImageViews[1].image = love_artistBGImage
|
||||
|
||||
loadsLabel.text = "\("Offline".localizableString()) \(MPPositive_LoadCoreModel.shared.loadViewModels.count)"
|
||||
let loadCover = MPPositive_LoadCoreModel.shared.loadViewModels.first?.reviewURL
|
||||
coverImageViews[2].kf.setImage(with: loadCover, placeholder: offline_songBGImage)
|
||||
loadsLabel.text = "\(MPPositive_LoadCoreModel.shared.loadViewModels.count)"
|
||||
coverImageViews[2].image = offline_songBGImage
|
||||
|
||||
}
|
||||
}
|
||||
@ -175,21 +172,21 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon
|
||||
let topView = UIView()
|
||||
topView.backgroundColor = .clear
|
||||
//添加事件按钮
|
||||
let first = actionView(songsLabel, text: "Center_Songs'logo", tag: 0)
|
||||
let first = actionView(songsLabel, text: "SONG", tag: 0)
|
||||
topView.addSubview(first)
|
||||
first.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.height.width.equalTo(109*width)
|
||||
make.left.equalToSuperview().offset(16*width)
|
||||
}
|
||||
let second = actionView(artistsLabel, text: "Center_Artists'logo", tag: 1)
|
||||
let second = actionView(artistsLabel, text: "ARTIST", tag: 1)
|
||||
topView.addSubview(second)
|
||||
second.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.height.width.equalTo(109*width)
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
let third = actionView(loadsLabel, text: "Center_Offline'logo", tag: 2)
|
||||
let third = actionView(loadsLabel, text: "OFFLINE", tag: 2)
|
||||
topView.addSubview(third)
|
||||
third.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
@ -200,7 +197,7 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon
|
||||
return topView
|
||||
}
|
||||
//生成一个事件View块
|
||||
private func actionView(_ label:UILabel, text:String, tag:Int) -> UIView {
|
||||
private func actionView(_ countLabel:UILabel, text:String, tag:Int) -> UIView {
|
||||
let actionView = UIView()
|
||||
actionView.backgroundColor = .clear
|
||||
//设置圆角
|
||||
@ -211,21 +208,18 @@ class MPPositive_LibraryViewController: MPPositive_BaseViewController, UIViewCon
|
||||
coverImageViews[tag].snp.makeConstraints { make in
|
||||
make.left.top.right.bottom.equalToSuperview()
|
||||
}
|
||||
//添加一个iconImage
|
||||
let iconImageView:UIImageView = .init(image: .init(named: text))
|
||||
iconImageView.contentMode = .scaleAspectFill
|
||||
actionView.addSubview(iconImageView)
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.width.height.equalTo(20*width)
|
||||
make.left.equalToSuperview().offset(8*width)
|
||||
make.top.equalToSuperview().offset(13*width)
|
||||
//添加一个主标题
|
||||
let titlelLabel = createLabel(text, font: .systemFont(ofSize: 10*width, weight: .semibold), textColor: .white, textAlignment: .left)
|
||||
actionView.addSubview(titlelLabel)
|
||||
titlelLabel.snp.makeConstraints { make in
|
||||
make.top.left.equalTo(10*width)
|
||||
}
|
||||
//添加一个标题
|
||||
actionView.addSubview(label)
|
||||
label.snp.makeConstraints { make in
|
||||
make.left.equalTo(iconImageView.snp.left)
|
||||
make.top.equalToSuperview().offset(40*width)
|
||||
make.right.equalToSuperview().offset(-8*width)
|
||||
//添加一个数量标题
|
||||
actionView.addSubview(countLabel)
|
||||
countLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titlelLabel.snp.left)
|
||||
make.top.equalTo(titlelLabel.snp.bottom).offset(8*width)
|
||||
make.right.equalToSuperview().offset(-10*width)
|
||||
}
|
||||
actionView.tag = tag
|
||||
actionView.isUserInteractionEnabled = true
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
import UIKit
|
||||
import MJRefresh
|
||||
import Lottie
|
||||
import UserMessagingPlatform
|
||||
class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewControllerTransitioningDelegate{
|
||||
//背景图片
|
||||
private lazy var bgImageView:UIImageView = {
|
||||
@ -93,8 +94,19 @@ class MPPositive_HomeViewController: MPPositive_BaseViewController, UIViewContro
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
// 请求跟踪授权
|
||||
requestTrackingAuthorization { idfa in
|
||||
UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(with: nil) { requestConsentError in
|
||||
if let consentError = requestConsentError {
|
||||
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("[UMP] GoogleUMP success")
|
||||
UMPConsentForm.loadAndPresentIfRequired(from: self) { loadAndPresentError in
|
||||
if let consentError = loadAndPresentError {
|
||||
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("[UMP] GoogleUMP success")
|
||||
}
|
||||
}
|
||||
}
|
||||
MP_IAPManager.shared.systemRestorePurchases()
|
||||
|
||||
@ -16,22 +16,17 @@ class MPPositive_HomeLibraryListCollectionViewCell: UICollectionViewCell {
|
||||
imageView.layer.cornerRadius = 16*width
|
||||
return imageView
|
||||
}()
|
||||
private lazy var iconImageView:UIImageView = {
|
||||
let iconImageView:UIImageView = .init()
|
||||
iconImageView.contentMode = .scaleAspectFill
|
||||
return iconImageView
|
||||
}()
|
||||
//标题Label
|
||||
private lazy var titleLabel:UILabel = createLabel("Title", font: .systemFont(ofSize: 14*width, weight: .regular), textColor: .white, textAlignment: .left)
|
||||
var library:MPPositive_LibraryViewModel!{
|
||||
didSet{
|
||||
switch library.library.libraryType {
|
||||
case .custom_playlist:
|
||||
coverImageView.kf.setImage(with: library.cover, placeholder: library.library.libraryType.image)
|
||||
titleLabel.text = library.title
|
||||
if let icon = library.library.libraryType.icon {
|
||||
iconImageView.image = icon
|
||||
}else {
|
||||
iconImageView.image = nil
|
||||
default:
|
||||
coverImageView.image = library.library.libraryType.image
|
||||
}
|
||||
titleLabel.text = library.title
|
||||
}
|
||||
}
|
||||
override init(frame: CGRect) {
|
||||
@ -51,12 +46,6 @@ class MPPositive_HomeLibraryListCollectionViewCell: UICollectionViewCell {
|
||||
make.left.top.right.equalToSuperview()
|
||||
make.height.equalTo(109*width)
|
||||
}
|
||||
addSubview(iconImageView)
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.width.height.equalTo(20*width)
|
||||
make.left.equalToSuperview().offset(8*width)
|
||||
make.top.equalToSuperview().offset(13*width)
|
||||
}
|
||||
addSubview(titleLabel)
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalTo(coverImageView.snp.bottom).offset(9*width)
|
||||
|
||||
@ -87,6 +87,9 @@ class MPSideA_TabBarController: UITabBarController, GADFullScreenContentDelegate
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(displayBottomViewAction(_ :)), notificationName: .sideA_display_show)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(hiddenBottomViewAction(_ :)), notificationName: .sideA_hidden_show)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(renameMusicAction(_ :)), notificationName: .sideA_rename_music)
|
||||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(updateVersionEvent), notificationName: .update_reminder)
|
||||
//触发更新弹窗
|
||||
updateVersionEvent()
|
||||
}
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
@ -118,6 +121,19 @@ class MPSideA_TabBarController: UITabBarController, GADFullScreenContentDelegate
|
||||
}
|
||||
}
|
||||
}
|
||||
//处理版本更新
|
||||
@objc private func updateVersionEvent() {
|
||||
//判断是否需要更新
|
||||
guard isUpDateReminder == true else {
|
||||
//不需要更新
|
||||
return
|
||||
}
|
||||
//需要更新
|
||||
DispatchQueue.main.async {
|
||||
//触发更新
|
||||
postUpdateReminder(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
//MARK: - 事件处理
|
||||
extension MPSideA_TabBarController: UIViewControllerTransitioningDelegate {
|
||||
|
||||
@ -31,6 +31,10 @@ class MPSideA_AboutViewController: MPSideA_BaseViewController {
|
||||
versionLabel.text = "\(NSLocalizedString("Version", comment: "版本号")) \(app_Version)"
|
||||
}
|
||||
@objc private func versionClick(){
|
||||
guard isUpDateReminder == false else {
|
||||
postUpdateReminder(self)
|
||||
return
|
||||
}
|
||||
let eventAlert = UIAlertController(title: NSLocalizedString("Version Update", comment: ""), message: NSLocalizedString("is the latest Version", comment: ""), preferredStyle: .alert)
|
||||
let canelAction = UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel,handler: nil)
|
||||
eventAlert.addAction(canelAction)
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import UserMessagingPlatform
|
||||
class MPSideA_HomeViewController: MPSideA_BaseViewController {
|
||||
@IBOutlet weak var tableView: UITableView!{
|
||||
didSet{
|
||||
@ -30,8 +31,19 @@ class MPSideA_HomeViewController: MPSideA_BaseViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
// 请求跟踪授权
|
||||
requestTrackingAuthorization { idfa in
|
||||
UMPConsentInformation.sharedInstance.requestConsentInfoUpdate(with: nil) { requestConsentError in
|
||||
if let consentError = requestConsentError {
|
||||
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("[UMP] GoogleUMP success")
|
||||
UMPConsentForm.loadAndPresentIfRequired(from: self) { loadAndPresentError in
|
||||
if let consentError = loadAndPresentError {
|
||||
print("[UMP] GoogleUMP error=\(consentError.localizedDescription)")
|
||||
return
|
||||
}
|
||||
print("[UMP] GoogleUMP success")
|
||||
}
|
||||
}
|
||||
}
|
||||
//触发音乐缺失闭包
|
||||
|
||||