diff --git a/NotificationService/Info.plist b/NotificationService/Info.plist new file mode 100644 index 0000000..fe81721 --- /dev/null +++ b/NotificationService/Info.plist @@ -0,0 +1,18 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + NSExtension + + NSExtensionPointIdentifier + com.apple.usernotifications.service + NSExtensionPrincipalClass + $(PRODUCT_MODULE_NAME).NotificationService + + + diff --git a/NotificationService/NotificationService.swift b/NotificationService/NotificationService.swift new file mode 100644 index 0000000..691b95c --- /dev/null +++ b/NotificationService/NotificationService.swift @@ -0,0 +1,69 @@ +// +// NotificationService.swift +// NotificationService +// +// Created by 长沙佳儿 on 2025/6/26. +// + +import UserNotifications + +class NotificationService: UNNotificationServiceExtension { + + var contentHandler: ((UNNotificationContent) -> Void)? + var bestAttemptContent: UNMutableNotificationContent? + + override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) { + + self.contentHandler = contentHandler + bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent) + + guard let bestAttemptContent = bestAttemptContent else { + contentHandler(request.content) + return + } + + if let options = request.content.userInfo["fcm_options"] as? [String : Any], + let imageURLString = options["image"] as? String, + let imageURL = URL(string: imageURLString) { + + downloadImage(from: imageURL) { attachment in + if let attachment = attachment { + bestAttemptContent.attachments = [attachment] + } + contentHandler(bestAttemptContent) + } + } else { + contentHandler(bestAttemptContent) + } + } + + override func serviceExtensionTimeWillExpire() { + // Called just before the extension will be terminated by the system. + // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used. + if let contentHandler = contentHandler, let bestAttemptContent = bestAttemptContent { + contentHandler(bestAttemptContent) + } + } + + private func downloadImage(from url: URL, completion: @escaping (UNNotificationAttachment?) -> Void) { + let task = URLSession.shared.downloadTask(with: url) { (downloadedUrl, _, error) in + guard let downloadedUrl = downloadedUrl else { + completion(nil) + return + } + + let tmpDir = FileManager.default.temporaryDirectory + let tmpFile = tmpDir.appendingPathComponent(url.lastPathComponent) + + do { + try FileManager.default.moveItem(at: downloadedUrl, to: tmpFile) + let attachment = try UNNotificationAttachment(identifier: UUID().uuidString, url: tmpFile, options: nil) + completion(attachment) + } catch { + completion(nil) + } + } + task.resume() + } + +} diff --git a/ThimraTV.xcodeproj/project.pbxproj b/ThimraTV.xcodeproj/project.pbxproj index 4d6944f..dc035fd 100644 --- a/ThimraTV.xcodeproj/project.pbxproj +++ b/ThimraTV.xcodeproj/project.pbxproj @@ -262,9 +262,11 @@ 1BB91E0C2E04FD6A00A2C715 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1BB91CD52E04FD6A00A2C715 /* GoogleService-Info.plist */; }; 1BB91E0E2E04FD6A00A2C715 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 1BB91CD82E04FD6A00A2C715 /* LaunchScreen.storyboard */; }; 1BB91E0F2E04FD6A00A2C715 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1BB91CDA2E04FD6A00A2C715 /* Localizable.strings */; }; - 1BC1F0D32E09389000B579A4 /* SPVerisionUpdateAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC1F0D22E09389000B579A4 /* SPVerisionUpdateAlertView.swift */; }; + 1BC1F0D32E09389000B579A4 /* SPVersionUpdateAlertView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC1F0D22E09389000B579A4 /* SPVersionUpdateAlertView.swift */; }; 1BC1F0D52E093E9900B579A4 /* SPVersionUpdateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC1F0D42E093E9900B579A4 /* SPVersionUpdateModel.swift */; }; 1BC1F0D72E0A35EF00B579A4 /* SPVideoRevolutionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC1F0D62E0A35EF00B579A4 /* SPVideoRevolutionManager.swift */; }; + 1BC1F0E32E0D268400B579A4 /* NotificationService.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 1BC1F0DC2E0D268400B579A4 /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; + 1BC1F0EB2E0D268B00B579A4 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BC1F0E92E0D268B00B579A4 /* NotificationService.swift */; }; 1BE7892B2DCB0E530001A8F1 /* FacebookCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1BE7892A2DCB0E530001A8F1 /* FacebookCore */; }; 1BE7892D2DCB0E530001A8F1 /* FacebookLogin in Frameworks */ = {isa = PBXBuildFile; productRef = 1BE7892C2DCB0E530001A8F1 /* FacebookLogin */; }; 1BF22FD12DC2169B0082429A /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = 1BF22FD02DC2169B0082429A /* FirebaseAnalytics */; }; @@ -273,6 +275,16 @@ C3D1CE788CA03A1878493356 /* Pods_ThimraTV.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B64805795B479324EB764157 /* Pods_ThimraTV.framework */; }; /* End PBXBuildFile section */ +/* Begin PBXContainerItemProxy section */ + 1BC1F0E12E0D268400B579A4 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1DBC40512DA4EDFC0093FCB0 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1BC1F0DB2E0D268400B579A4; + remoteInfo = NotificationService; + }; +/* End PBXContainerItemProxy section */ + /* Begin PBXCopyFilesBuildPhase section */ 1BB9206E2E050B1A00A2C715 /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; @@ -280,6 +292,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 1BC1F0E32E0D268400B579A4 /* NotificationService.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; runOnlyForDeploymentPostprocessing = 0; @@ -556,9 +569,12 @@ 1BB91D0A2E04FD6A00A2C715 /* ZKCycleScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZKCycleScrollView.swift; sourceTree = ""; }; 1BB91D0B2E04FD6A00A2C715 /* ZKCycleScrollViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZKCycleScrollViewFlowLayout.swift; sourceTree = ""; }; 1BB91D0E2E04FD6A00A2C715 /* ThimraTV.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ThimraTV.entitlements; sourceTree = ""; }; - 1BC1F0D22E09389000B579A4 /* SPVerisionUpdateAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVerisionUpdateAlertView.swift; sourceTree = ""; }; + 1BC1F0D22E09389000B579A4 /* SPVersionUpdateAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVersionUpdateAlertView.swift; sourceTree = ""; }; 1BC1F0D42E093E9900B579A4 /* SPVersionUpdateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVersionUpdateModel.swift; sourceTree = ""; }; 1BC1F0D62E0A35EF00B579A4 /* SPVideoRevolutionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVideoRevolutionManager.swift; sourceTree = ""; }; + 1BC1F0DC2E0D268400B579A4 /* NotificationService.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = NotificationService.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + 1BC1F0E82E0D268B00B579A4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1BC1F0E92E0D268B00B579A4 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; 1DBC40592DA4EDFC0093FCB0 /* ThimraTV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ThimraTV.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1F666DE0B12C863F26BE5027 /* Pods-MoviaBox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoviaBox.debug.xcconfig"; path = "Target Support Files/Pods-MoviaBox/Pods-MoviaBox.debug.xcconfig"; sourceTree = ""; }; A1174E10BCF2C606F7818792 /* Pods-ThimraTV.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ThimraTV.release.xcconfig"; path = "Target Support Files/Pods-ThimraTV/Pods-ThimraTV.release.xcconfig"; sourceTree = ""; }; @@ -568,6 +584,13 @@ /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ + 1BC1F0D92E0D268400B579A4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 1DBC40562DA4EDFC0093FCB0 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1145,7 +1168,7 @@ children = ( 1BB91CB02E04FD6A00A2C715 /* SPAlertView.swift */, 1BB91CB12E04FD6A00A2C715 /* SPAlertWindowManager.swift */, - 1BC1F0D22E09389000B579A4 /* SPVerisionUpdateAlertView.swift */, + 1BC1F0D22E09389000B579A4 /* SPVersionUpdateAlertView.swift */, ); path = Alert; sourceTree = ""; @@ -1426,10 +1449,20 @@ path = ThimraTV; sourceTree = ""; }; + 1BC1F0EA2E0D268B00B579A4 /* NotificationService */ = { + isa = PBXGroup; + children = ( + 1BC1F0E82E0D268B00B579A4 /* Info.plist */, + 1BC1F0E92E0D268B00B579A4 /* NotificationService.swift */, + ); + path = NotificationService; + sourceTree = ""; + }; 1DBC40502DA4EDFC0093FCB0 = { isa = PBXGroup; children = ( 1BB91D0F2E04FD6A00A2C715 /* ThimraTV */, + 1BC1F0EA2E0D268B00B579A4 /* NotificationService */, 1DBC405A2DA4EDFC0093FCB0 /* Products */, 0061C3496D158807460301A9 /* Pods */, B6C9E282BAC4C4B3E926A853 /* Frameworks */, @@ -1440,6 +1473,7 @@ isa = PBXGroup; children = ( 1DBC40592DA4EDFC0093FCB0 /* ThimraTV.app */, + 1BC1F0DC2E0D268400B579A4 /* NotificationService.appex */, ); name = Products; sourceTree = ""; @@ -1455,6 +1489,25 @@ /* End PBXGroup section */ /* Begin PBXNativeTarget section */ + 1BC1F0DB2E0D268400B579A4 /* NotificationService */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1BC1F0E52E0D268400B579A4 /* Build configuration list for PBXNativeTarget "NotificationService" */; + buildPhases = ( + 1BC1F0D82E0D268400B579A4 /* Sources */, + 1BC1F0D92E0D268400B579A4 /* Frameworks */, + 1BC1F0DA2E0D268400B579A4 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = NotificationService; + packageProductDependencies = ( + ); + productName = NotificationService; + productReference = 1BC1F0DC2E0D268400B579A4 /* NotificationService.appex */; + productType = "com.apple.product-type.app-extension"; + }; 1DBC40582DA4EDFC0093FCB0 /* ThimraTV */ = { isa = PBXNativeTarget; buildConfigurationList = 1DBC40822DA4EE010093FCB0 /* Build configuration list for PBXNativeTarget "ThimraTV" */; @@ -1469,6 +1522,7 @@ buildRules = ( ); dependencies = ( + 1BC1F0E22E0D268400B579A4 /* PBXTargetDependency */, ); name = ThimraTV; productName = ShortPlay; @@ -1485,6 +1539,9 @@ LastSwiftUpdateCheck = 1640; LastUpgradeCheck = 1620; TargetAttributes = { + 1BC1F0DB2E0D268400B579A4 = { + CreatedOnToolsVersion = 16.4; + }; 1DBC40582DA4EDFC0093FCB0 = { CreatedOnToolsVersion = 16.2; }; @@ -1509,11 +1566,19 @@ projectRoot = ""; targets = ( 1DBC40582DA4EDFC0093FCB0 /* ThimraTV */, + 1BC1F0DB2E0D268400B579A4 /* NotificationService */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ + 1BC1F0DA2E0D268400B579A4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 1DBC40572DA4EDFC0093FCB0 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1575,6 +1640,14 @@ /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ + 1BC1F0D82E0D268400B579A4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1BC1F0EB2E0D268B00B579A4 /* NotificationService.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 1DBC40552DA4EDFC0093FCB0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1768,7 +1841,7 @@ 1BB91DC92E04FD6A00A2C715 /* SPCoinOrderRecordCell.swift in Sources */, 1BB91DCA2E04FD6A00A2C715 /* SPCoinRechargeBigCell.swift in Sources */, 1BB91DCB2E04FD6A00A2C715 /* SPCoinRechargeCell.swift in Sources */, - 1BC1F0D32E09389000B579A4 /* SPVerisionUpdateAlertView.swift in Sources */, + 1BC1F0D32E09389000B579A4 /* SPVersionUpdateAlertView.swift in Sources */, 1BB91DCC2E04FD6A00A2C715 /* SPCoinRechargeSmallCell.swift in Sources */, 1BB91DCD2E04FD6A00A2C715 /* SPCoinRechargeView.swift in Sources */, 1BB91DCE2E04FD6A00A2C715 /* SPConsumptionRecordsCell.swift in Sources */, @@ -1837,6 +1910,14 @@ }; /* End PBXSourcesBuildPhase section */ +/* Begin PBXTargetDependency section */ + 1BC1F0E22E0D268400B579A4 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1BC1F0DB2E0D268400B579A4 /* NotificationService */; + targetProxy = 1BC1F0E12E0D268400B579A4 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + /* Begin PBXVariantGroup section */ 1BB91CD82E04FD6A00A2C715 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; @@ -1857,6 +1938,60 @@ /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ + 1BC1F0E62E0D268400B579A4 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = TWDZ3MP9DV; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = NotificationService/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = NotificationService; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app.NotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 1BC1F0E72E0D268400B579A4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = TWDZ3MP9DV; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = NotificationService/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = NotificationService; + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + IPHONEOS_DEPLOYMENT_TARGET = 15.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app.NotificationService; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; 1DBC40832DA4EE010093FCB0 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 0538826A0638D33FEF3A2E38 /* Pods-ThimraTV.debug.xcconfig */; @@ -1867,7 +2002,7 @@ CODE_SIGN_ENTITLEMENTS = ThimraTV/ThimraTV.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = TWDZ3MP9DV; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1891,7 +2026,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -1915,7 +2050,7 @@ CODE_SIGN_ENTITLEMENTS = ThimraTV/ThimraTV.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; + CURRENT_PROJECT_VERSION = 2; DEVELOPMENT_TEAM = TWDZ3MP9DV; ENABLE_USER_SCRIPT_SANDBOXING = NO; GENERATE_INFOPLIST_FILE = YES; @@ -1939,7 +2074,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 1.1.1; + MARKETING_VERSION = 1.1.2; PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -2077,6 +2212,15 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ + 1BC1F0E52E0D268400B579A4 /* Build configuration list for PBXNativeTarget "NotificationService" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1BC1F0E62E0D268400B579A4 /* Debug */, + 1BC1F0E72E0D268400B579A4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 1DBC40542DA4EDFC0093FCB0 /* Build configuration list for PBXProject "ThimraTV" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ThimraTV/Libs/APPTool/SPAPPTool.swift b/ThimraTV/Libs/APPTool/SPAPPTool.swift index b5a7e59..7ed97db 100644 --- a/ThimraTV/Libs/APPTool/SPAPPTool.swift +++ b/ThimraTV/Libs/APPTool/SPAPPTool.swift @@ -127,7 +127,7 @@ extension SPAPPTool { static func checkUpdates() { #if !DEBUG if let date = UserDefaults.standard.object(forKey: kSPVersionUpdateAlertDefaultsKey) as? Date { - if date.vp_isToday { return } + if date.sp_isToday { return } } UserDefaults.standard.set(Date(), forKey: kSPVersionUpdateAlertDefaultsKey) #endif @@ -141,7 +141,7 @@ extension SPAPPTool { } static private func showVersionUpdateAlert(model: SPVersionUpdateModel) { - SPVerisionUpdateAlertView(model: model).show() + SPVersionUpdateAlertView(model: model).show() } } diff --git a/ThimraTV/Libs/Alert/SPVerisionUpdateAlertView.swift b/ThimraTV/Libs/Alert/SPVersionUpdateAlertView.swift similarity index 97% rename from ThimraTV/Libs/Alert/SPVerisionUpdateAlertView.swift rename to ThimraTV/Libs/Alert/SPVersionUpdateAlertView.swift index d77f702..c3e37e9 100644 --- a/ThimraTV/Libs/Alert/SPVerisionUpdateAlertView.swift +++ b/ThimraTV/Libs/Alert/SPVersionUpdateAlertView.swift @@ -1,5 +1,5 @@ // -// SPVerisionUpdateAlertView.swift +// SPVersionUpdateAlertView.swift // ThimraTV // // Created by 长沙佳儿 on 2025/6/23. @@ -7,7 +7,7 @@ import UIKit -class SPVerisionUpdateAlertView: SPAlertView { +class SPVersionUpdateAlertView: SPAlertView { private var model: SPVersionUpdateModel @@ -101,7 +101,7 @@ class SPVerisionUpdateAlertView: SPAlertView { } -extension SPVerisionUpdateAlertView { +extension SPVersionUpdateAlertView { private func sp_setupUI() { self.addSubview(contentView)