Compare commits
No commits in common. "main" and "1.1.1" have entirely different histories.
3
.gitignore
vendored
@ -66,7 +66,7 @@ xcuserdata/
|
||||
|
||||
## Playgrounds
|
||||
timeline.xctimeline
|
||||
*.xcworkspace
|
||||
playground.xcworkspace
|
||||
|
||||
# Swift Package Manager
|
||||
#
|
||||
@ -89,7 +89,6 @@ timeline.xctimeline
|
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||
#
|
||||
Pods/
|
||||
Podfile.lock
|
||||
#
|
||||
# Add this line if you want to avoid checking in source code from the Xcode workspace
|
||||
# *.xcworkspace
|
||||
|
@ -39,6 +39,3 @@ NO.118 Xinling Rd Shanghai Branch
|
||||
沙盒账号:
|
||||
jiaer@test.com
|
||||
Cje12345
|
||||
|
||||
thimra@test.com
|
||||
Discover2024
|
||||
|
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSAppTransportSecurity</key>
|
||||
<dict>
|
||||
<key>NSAllowsArbitraryLoads</key>
|
||||
<true/>
|
||||
</dict>
|
||||
<key>NSExtension</key>
|
||||
<dict>
|
||||
<key>NSExtensionPointIdentifier</key>
|
||||
<string>com.apple.usernotifications.service</string>
|
||||
<key>NSExtensionPrincipalClass</key>
|
||||
<string>$(PRODUCT_MODULE_NAME).NotificationService</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
@ -1,69 +0,0 @@
|
||||
//
|
||||
// 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()
|
||||
}
|
||||
|
||||
}
|
13
Podfile
@ -35,17 +35,4 @@ target 'ThimraTV' do
|
||||
pod 'Adjust' # Adjust
|
||||
|
||||
|
||||
pod 'GoogleMobileAdsMediationAppLovin'
|
||||
pod 'GoogleMobileAdsMediationIronSource'
|
||||
pod 'GoogleMobileAdsMediationFacebook'
|
||||
pod 'GoogleMobileAdsMediationMintegral'
|
||||
pod 'GoogleMobileAdsMediationPangle'
|
||||
|
||||
pod 'AppLovinMediationFacebookAdapter'
|
||||
pod 'AppLovinMediationByteDanceAdapter'
|
||||
pod 'AppLovinMediationIronSourceAdapter'
|
||||
pod 'AppLovinMediationMintegralAdapter'
|
||||
pod 'AppLovinMediationGoogleAdapter'
|
||||
|
||||
|
||||
end
|
||||
|
165
Podfile.lock
@ -4,129 +4,32 @@ PODS:
|
||||
- Adjust/Adjust (5.4.0):
|
||||
- AdjustSignature (= 3.35.2)
|
||||
- AdjustSignature (3.35.2)
|
||||
- Ads-Global (7.1.1.1):
|
||||
- Ads-Global/BUAdSDK (= 7.1.1.1)
|
||||
- Ads-Global/BUAdSDK (7.1.1.1)
|
||||
- Alamofire (5.10.2)
|
||||
- AppLovinMediationByteDanceAdapter (7.1.1.1.0):
|
||||
- Ads-Global (= 7.1.1.1)
|
||||
- AppLovinSDK (>= 13.0.0)
|
||||
- AppLovinMediationFacebookAdapter (6.17.1.0):
|
||||
- AppLovinSDK (>= 13.0.0)
|
||||
- FBAudienceNetwork (= 6.17.1)
|
||||
- AppLovinMediationGoogleAdapter (12.5.0.0):
|
||||
- AppLovinSDK (>= 13.0.0)
|
||||
- Google-Mobile-Ads-SDK (= 12.5.0)
|
||||
- AppLovinMediationIronSourceAdapter (8.9.0.0.0):
|
||||
- AppLovinSDK (>= 13.0.0)
|
||||
- IronSourceSDK (= 8.9.0.0)
|
||||
- AppLovinMediationMintegralAdapter (7.7.8.0.0):
|
||||
- AppLovinSDK (>= 13.0.0)
|
||||
- MintegralAdSDK (= 7.7.8)
|
||||
- MintegralAdSDK/BidSplashAd (= 7.7.8)
|
||||
- AppLovinSDK (13.3.0)
|
||||
- CocoaAsyncSocket (7.6.5)
|
||||
- EmptyDataSet-Swift (5.0.0)
|
||||
- FBAudienceNetwork (6.17.1)
|
||||
- Google-Mobile-Ads-SDK (12.5.0):
|
||||
- GoogleUserMessagingPlatform (>= 1.1)
|
||||
- GoogleMobileAdsMediationAppLovin (13.3.0.0):
|
||||
- AppLovinSDK (= 13.3.0)
|
||||
- Google-Mobile-Ads-SDK (~> 12.0)
|
||||
- GoogleMobileAdsMediationFacebook (6.17.1.0):
|
||||
- FBAudienceNetwork (= 6.17.1)
|
||||
- Google-Mobile-Ads-SDK (~> 12.0)
|
||||
- GoogleMobileAdsMediationIronSource (8.9.0.0.0):
|
||||
- Google-Mobile-Ads-SDK (~> 12.0)
|
||||
- IronSourceSDK (= 8.9.0.0)
|
||||
- GoogleMobileAdsMediationMintegral (7.7.8.0):
|
||||
- Google-Mobile-Ads-SDK (~> 12.0)
|
||||
- MintegralAdSDK/All (= 7.7.8)
|
||||
- GoogleMobileAdsMediationPangle (7.1.1.1.0):
|
||||
- Ads-Global (= 7.1.1.1)
|
||||
- Google-Mobile-Ads-SDK (~> 12.0)
|
||||
- GoogleUserMessagingPlatform (3.0.0)
|
||||
- HWPanModal (0.9.9)
|
||||
- IronSourceAdQualitySDK (7.24.3)
|
||||
- IronSourceSDK (8.9.0.0):
|
||||
- IronSourceSDK/AdQuality (= 8.9.0.0)
|
||||
- IronSourceSDK/Ads (= 8.9.0.0)
|
||||
- IronSourceSDK/AdQuality (8.9.0.0):
|
||||
- IronSourceAdQualitySDK (~> 7.24.3)
|
||||
- IronSourceSDK/Ads (8.9.0.0)
|
||||
- Kingfisher (8.3.2)
|
||||
- KTVHTTPCache (3.0.2):
|
||||
- CocoaAsyncSocket
|
||||
- MintegralAdSDK (7.7.8):
|
||||
- MintegralAdSDK/BannerAd (= 7.7.8)
|
||||
- MintegralAdSDK/BidBannerAd (= 7.7.8)
|
||||
- MintegralAdSDK/BidInterstitialVideoAd (= 7.7.8)
|
||||
- MintegralAdSDK/BidNativeAd (= 7.7.8)
|
||||
- MintegralAdSDK/BidNewInterstitialAd (= 7.7.8)
|
||||
- MintegralAdSDK/BidRewardVideoAd (= 7.7.8)
|
||||
- MintegralAdSDK/InterstitialVideoAd (= 7.7.8)
|
||||
- MintegralAdSDK/NativeAd (= 7.7.8)
|
||||
- MintegralAdSDK/NewInterstitialAd (= 7.7.8)
|
||||
- MintegralAdSDK/RewardVideoAd (= 7.7.8)
|
||||
- MintegralAdSDK/All (7.7.8):
|
||||
- MintegralAdSDK/BannerAd
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/InterstitialVideoAd
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/NativeAdvancedAd
|
||||
- MintegralAdSDK/NewInterstitialAd
|
||||
- MintegralAdSDK/RewardVideoAd
|
||||
- MintegralAdSDK/SplashAd
|
||||
- MintegralAdSDK/BannerAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/BidBannerAd (7.7.8):
|
||||
- MintegralAdSDK/BannerAd
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/BidInterstitialVideoAd (7.7.8):
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/InterstitialVideoAd
|
||||
- MintegralAdSDK/BidNativeAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/BidNewInterstitialAd (7.7.8):
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/NewInterstitialAd
|
||||
- MintegralAdSDK/BidRewardVideoAd (7.7.8):
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/RewardVideoAd
|
||||
- MintegralAdSDK/BidSplashAd (7.7.8):
|
||||
- MintegralAdSDK/BidNativeAd
|
||||
- MintegralAdSDK/SplashAd
|
||||
- MintegralAdSDK/InterstitialVideoAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/NativeAd (7.7.8)
|
||||
- MintegralAdSDK/NativeAdvancedAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/NewInterstitialAd (7.7.8):
|
||||
- MintegralAdSDK/InterstitialVideoAd
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/RewardVideoAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MintegralAdSDK/SplashAd (7.7.8):
|
||||
- MintegralAdSDK/NativeAd
|
||||
- MJRefresh (3.7.9)
|
||||
- Moya (15.0.0):
|
||||
- Moya/Core (= 15.0.0)
|
||||
- Moya/Core (15.0.0):
|
||||
- Alamofire (~> 5.0)
|
||||
- ReachabilitySwift (5.2.4)
|
||||
- SmartCodable (5.0.9):
|
||||
- SmartCodable/Core (= 5.0.9)
|
||||
- SmartCodable/Core (5.0.9)
|
||||
- SmartCodable (5.0.12):
|
||||
- SmartCodable/Core (= 5.0.12)
|
||||
- SmartCodable/Core (5.0.12)
|
||||
- SnapKit (5.7.1)
|
||||
- SVProgressHUD (2.3.1):
|
||||
- SVProgressHUD/Core (= 2.3.1)
|
||||
- SVProgressHUD/Core (2.3.1)
|
||||
- Toast (4.1.1)
|
||||
- TZImagePickerController (3.8.8):
|
||||
- TZImagePickerController/Basic (= 3.8.8)
|
||||
- TZImagePickerController/Location (= 3.8.8)
|
||||
- TZImagePickerController/Basic (3.8.8)
|
||||
- TZImagePickerController/Location (3.8.8)
|
||||
- TZImagePickerController (3.8.9):
|
||||
- TZImagePickerController/Basic (= 3.8.9)
|
||||
- TZImagePickerController/Location (= 3.8.9)
|
||||
- TZImagePickerController/Basic (3.8.9)
|
||||
- TZImagePickerController/Location (3.8.9)
|
||||
- WMZPageController (1.5.5)
|
||||
- YYKit (1.0.9):
|
||||
- YYKit/no-arc (= 1.0.9)
|
||||
@ -137,17 +40,7 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- Adjust
|
||||
- AppLovinMediationByteDanceAdapter
|
||||
- AppLovinMediationFacebookAdapter
|
||||
- AppLovinMediationGoogleAdapter
|
||||
- AppLovinMediationIronSourceAdapter
|
||||
- AppLovinMediationMintegralAdapter
|
||||
- EmptyDataSet-Swift
|
||||
- GoogleMobileAdsMediationAppLovin
|
||||
- GoogleMobileAdsMediationFacebook
|
||||
- GoogleMobileAdsMediationIronSource
|
||||
- GoogleMobileAdsMediationMintegral
|
||||
- GoogleMobileAdsMediationPangle
|
||||
- HWPanModal
|
||||
- Kingfisher
|
||||
- KTVHTTPCache
|
||||
@ -167,30 +60,12 @@ SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
- Adjust
|
||||
- AdjustSignature
|
||||
- Ads-Global
|
||||
- Alamofire
|
||||
- AppLovinMediationByteDanceAdapter
|
||||
- AppLovinMediationFacebookAdapter
|
||||
- AppLovinMediationGoogleAdapter
|
||||
- AppLovinMediationIronSourceAdapter
|
||||
- AppLovinMediationMintegralAdapter
|
||||
- AppLovinSDK
|
||||
- CocoaAsyncSocket
|
||||
- EmptyDataSet-Swift
|
||||
- FBAudienceNetwork
|
||||
- Google-Mobile-Ads-SDK
|
||||
- GoogleMobileAdsMediationAppLovin
|
||||
- GoogleMobileAdsMediationFacebook
|
||||
- GoogleMobileAdsMediationIronSource
|
||||
- GoogleMobileAdsMediationMintegral
|
||||
- GoogleMobileAdsMediationPangle
|
||||
- GoogleUserMessagingPlatform
|
||||
- HWPanModal
|
||||
- IronSourceAdQualitySDK
|
||||
- IronSourceSDK
|
||||
- Kingfisher
|
||||
- KTVHTTPCache
|
||||
- MintegralAdSDK
|
||||
- MJRefresh
|
||||
- Moya
|
||||
- ReachabilitySwift
|
||||
@ -206,42 +81,24 @@ SPEC REPOS:
|
||||
SPEC CHECKSUMS:
|
||||
Adjust: a5f881d0cbfe9a6df979b076dc7116fe19ece797
|
||||
AdjustSignature: 23b9e5d4adcadffc303bb6b410fde617dd88504f
|
||||
Ads-Global: b81917c405e94ad38dd45022f0fe17042429f578
|
||||
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||
AppLovinMediationByteDanceAdapter: 82f5a49494a40a3dfa4b959d6f089986c924511b
|
||||
AppLovinMediationFacebookAdapter: 413c7188e2a21e4c9256aa2b096ddc27240b1443
|
||||
AppLovinMediationGoogleAdapter: 36d9926e84420b49a7cba45800c6eada3be58b05
|
||||
AppLovinMediationIronSourceAdapter: 240be5366f735418d01f52304a0dc9c3d521e546
|
||||
AppLovinMediationMintegralAdapter: 5f64aa8427ba19efea2e0d583abc22dc4633705b
|
||||
AppLovinSDK: 5ed9dbada0de5a80e4546116994470011ed01f53
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
|
||||
FBAudienceNetwork: eb3ffbf2b35df25e21e163657044ffef66616a40
|
||||
Google-Mobile-Ads-SDK: 6df9aadcee32bce0ff05bcad56ef2c88a4a5e82b
|
||||
GoogleMobileAdsMediationAppLovin: efd0c6ebe304747b61e115ddc5bd0ed28346f499
|
||||
GoogleMobileAdsMediationFacebook: 750a2c14ce0bdf813e4e1d4ab4aa283f72f8a875
|
||||
GoogleMobileAdsMediationIronSource: e0e19ab5f8af55aacb30612ae1c84093db1e2e6e
|
||||
GoogleMobileAdsMediationMintegral: 0aefaa2f0608c210eb26dd6a6207d8c1bd992bbd
|
||||
GoogleMobileAdsMediationPangle: 62f9bdabf7ed168f6b0f04831c1cc04da0eec10e
|
||||
GoogleUserMessagingPlatform: f8d0cdad3ca835406755d0a69aa634f00e76d576
|
||||
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
|
||||
IronSourceAdQualitySDK: 9974aea1ec73b24fd0eb7e74e7936bcae9fead1d
|
||||
IronSourceSDK: 285da6cf55cb80a1b258260ee27df8332552ec0d
|
||||
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
|
||||
KTVHTTPCache: 5711692cdf9a5ecfe829b1e16577deb3ffe3dc86
|
||||
MintegralAdSDK: 07e018290689b906499d8285654bba42681cafcf
|
||||
MJRefresh: ff9e531227924c84ce459338414550a05d2aea78
|
||||
Moya: 138f0573e53411fb3dc17016add0b748dfbd78ee
|
||||
ReachabilitySwift: 32793e867593cfc1177f5d16491e3a197d2fccda
|
||||
SmartCodable: 68b3598438181a938eed8ee5623e58ef3e3ea443
|
||||
SmartCodable: da8e371c447392e4a5995a60421772713eed0239
|
||||
SnapKit: d612e99e678a2d3b95bf60b0705ed0a35c03484a
|
||||
SVProgressHUD: 4837c74bdfe2e51e8821c397825996a8d7de6e22
|
||||
Toast: 1f5ea13423a1e6674c4abdac5be53587ae481c4e
|
||||
TZImagePickerController: d084a7b97c82d387e7669dd86dc9a9057500aacf
|
||||
TZImagePickerController: 456f470b5dea97b37226ec7a694994a8663340b2
|
||||
WMZPageController: 87dd82d1e3528cd362de19b9a74fd6890d6e1906
|
||||
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
|
||||
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
|
||||
|
||||
PODFILE CHECKSUM: 12eed82b2517a28e085576b5b940ed72b5ab1b94
|
||||
PODFILE CHECKSUM: 25e7f44d27dd18aad94fde84cae1f0c157c60341
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
@ -7,7 +7,6 @@
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1B222BCF2E2B80DD002F5A68 /* SPPayTemplateRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1B222BCE2E2B80DD002F5A68 /* SPPayTemplateRequest.swift */; };
|
||||
1BB91D102E04FD6A00A2C715 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BB91BBD2E04FD6A00A2C715 /* AppDelegate.swift */; };
|
||||
1BB91D112E04FD6A00A2C715 /* AppDelegate+APNS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BB91BBE2E04FD6A00A2C715 /* AppDelegate+APNS.swift */; };
|
||||
1BB91D122E04FD6A00A2C715 /* AppDelegate+Config.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BB91BBF2E04FD6A00A2C715 /* AppDelegate+Config.swift */; };
|
||||
@ -263,44 +262,14 @@
|
||||
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 /* 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 */; };
|
||||
1BDE20132E1E15A700C2C2B5 /* SPAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BDE20122E1E159B00C2C2B5 /* SPAdManager.swift */; };
|
||||
1BDE20172E1E164600C2C2B5 /* SPAdAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BDE20162E1E163E00C2C2B5 /* SPAdAPI.swift */; };
|
||||
1BDE20192E1E175800C2C2B5 /* SPAdInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BDE20182E1E175800C2C2B5 /* SPAdInfo.swift */; };
|
||||
1BDE201E2E1E3D3E00C2C2B5 /* SPRewardedAdManager+Admob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BDE201D2E1E384100C2C2B5 /* SPRewardedAdManager+Admob.swift */; };
|
||||
1BDE20202E1E669600C2C2B5 /* AttributedString+SPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BDE201F2E1E669000C2C2B5 /* AttributedString+SPAdd.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 */; };
|
||||
1BF22FD32DC2169B0082429A /* FirebaseCore in Frameworks */ = {isa = PBXBuildFile; productRef = 1BF22FD22DC2169B0082429A /* FirebaseCore */; };
|
||||
1BF22FD52DC2169B0082429A /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 1BF22FD42DC2169B0082429A /* FirebaseMessaging */; };
|
||||
1BF5130C2E1F4660009750EA /* SPRewardedAdManager+AppLovin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5130B2E1F4654009750EA /* SPRewardedAdManager+AppLovin.swift */; };
|
||||
1BF5130E2E1F5D9B009750EA /* SPRewardedAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5130D2E1F5D8F009750EA /* SPRewardedAdManager.swift */; };
|
||||
1BF513112E1FA138009750EA /* SPStatAdModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513102E1FA138009750EA /* SPStatAdModel.swift */; };
|
||||
1BF513142E1FB8C1009750EA /* SPAppOpenAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */; };
|
||||
1BF513162E20ADB4009750EA /* SPAppOpenAdViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */; };
|
||||
1BF513192E20DC85009750EA /* SPBannerAdManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513182E20DC85009750EA /* SPBannerAdManager.swift */; };
|
||||
1BF5131B2E265880009750EA /* SPAdmobAppOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5131A2E265880009750EA /* SPAdmobAppOpenAd.swift */; };
|
||||
1BF5131D2E265A80009750EA /* SPApplovinAppOpenAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5131C2E265A80009750EA /* SPApplovinAppOpenAd.swift */; };
|
||||
1BF513212E2662DC009750EA /* SPAdmobBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513202E2662DC009750EA /* SPAdmobBannerAd.swift */; };
|
||||
1BF513232E273482009750EA /* SPApplovinBannerAd.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1BF513222E273479009750EA /* SPApplovinBannerAd.swift */; };
|
||||
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;
|
||||
@ -308,7 +277,6 @@
|
||||
dstPath = "";
|
||||
dstSubfolderSpec = 13;
|
||||
files = (
|
||||
1BC1F0E32E0D268400B579A4 /* NotificationService.appex in Embed Foundation Extensions */,
|
||||
);
|
||||
name = "Embed Foundation Extensions";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -317,7 +285,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0538826A0638D33FEF3A2E38 /* Pods-ThimraTV.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ThimraTV.debug.xcconfig"; path = "Target Support Files/Pods-ThimraTV/Pods-ThimraTV.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
1B222BCE2E2B80DD002F5A68 /* SPPayTemplateRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPPayTemplateRequest.swift; sourceTree = "<group>"; };
|
||||
109EB01BE447EE135493CA38 /* Pods-MoviaBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MoviaBox.release.xcconfig"; path = "Target Support Files/Pods-MoviaBox/Pods-MoviaBox.release.xcconfig"; sourceTree = "<group>"; };
|
||||
1BB91BBD2E04FD6A00A2C715 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
1BB91BBE2E04FD6A00A2C715 /* AppDelegate+APNS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+APNS.swift"; sourceTree = "<group>"; };
|
||||
1BB91BBF2E04FD6A00A2C715 /* AppDelegate+Config.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Config.swift"; sourceTree = "<group>"; };
|
||||
@ -585,40 +553,15 @@
|
||||
1BB91D0A2E04FD6A00A2C715 /* ZKCycleScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZKCycleScrollView.swift; sourceTree = "<group>"; };
|
||||
1BB91D0B2E04FD6A00A2C715 /* ZKCycleScrollViewFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZKCycleScrollViewFlowLayout.swift; sourceTree = "<group>"; };
|
||||
1BB91D0E2E04FD6A00A2C715 /* ThimraTV.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ThimraTV.entitlements; sourceTree = "<group>"; };
|
||||
1BC1F0D22E09389000B579A4 /* SPVersionUpdateAlertView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVersionUpdateAlertView.swift; sourceTree = "<group>"; };
|
||||
1BC1F0D42E093E9900B579A4 /* SPVersionUpdateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVersionUpdateModel.swift; sourceTree = "<group>"; };
|
||||
1BC1F0D62E0A35EF00B579A4 /* SPVideoRevolutionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPVideoRevolutionManager.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
1BC1F0E92E0D268B00B579A4 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = "<group>"; };
|
||||
1BDE20122E1E159B00C2C2B5 /* SPAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAdManager.swift; sourceTree = "<group>"; };
|
||||
1BDE20162E1E163E00C2C2B5 /* SPAdAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAdAPI.swift; sourceTree = "<group>"; };
|
||||
1BDE20182E1E175800C2C2B5 /* SPAdInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAdInfo.swift; sourceTree = "<group>"; };
|
||||
1BDE201D2E1E384100C2C2B5 /* SPRewardedAdManager+Admob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SPRewardedAdManager+Admob.swift"; sourceTree = "<group>"; };
|
||||
1BDE201F2E1E669000C2C2B5 /* AttributedString+SPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AttributedString+SPAdd.swift"; sourceTree = "<group>"; };
|
||||
1BF5130B2E1F4654009750EA /* SPRewardedAdManager+AppLovin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SPRewardedAdManager+AppLovin.swift"; sourceTree = "<group>"; };
|
||||
1BF5130D2E1F5D8F009750EA /* SPRewardedAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPRewardedAdManager.swift; sourceTree = "<group>"; };
|
||||
1BF513102E1FA138009750EA /* SPStatAdModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPStatAdModel.swift; sourceTree = "<group>"; };
|
||||
1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdManager.swift; sourceTree = "<group>"; };
|
||||
1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAppOpenAdViewController.swift; sourceTree = "<group>"; };
|
||||
1BF513182E20DC85009750EA /* SPBannerAdManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPBannerAdManager.swift; sourceTree = "<group>"; };
|
||||
1BF5131A2E265880009750EA /* SPAdmobAppOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAdmobAppOpenAd.swift; sourceTree = "<group>"; };
|
||||
1BF5131C2E265A80009750EA /* SPApplovinAppOpenAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPApplovinAppOpenAd.swift; sourceTree = "<group>"; };
|
||||
1BF513202E2662DC009750EA /* SPAdmobBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPAdmobBannerAd.swift; sourceTree = "<group>"; };
|
||||
1BF513222E273479009750EA /* SPApplovinBannerAd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SPApplovinBannerAd.swift; sourceTree = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
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 = "<group>"; };
|
||||
B64805795B479324EB764157 /* Pods_ThimraTV.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ThimraTV.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
F7763FEFB6BEB1A75D6FBA0A /* Pods-Thimra.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Thimra.debug.xcconfig"; path = "Target Support Files/Pods-Thimra/Pods-Thimra.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FEA583158A7C05D8D7C5A9FC /* Pods-Thimra.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Thimra.release.xcconfig"; path = "Target Support Files/Pods-Thimra/Pods-Thimra.release.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
1BC1F0D92E0D268400B579A4 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
1DBC40562DA4EDFC0093FCB0 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@ -638,6 +581,10 @@
|
||||
0061C3496D158807460301A9 /* Pods */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F7763FEFB6BEB1A75D6FBA0A /* Pods-Thimra.debug.xcconfig */,
|
||||
FEA583158A7C05D8D7C5A9FC /* Pods-Thimra.release.xcconfig */,
|
||||
1F666DE0B12C863F26BE5027 /* Pods-MoviaBox.debug.xcconfig */,
|
||||
109EB01BE447EE135493CA38 /* Pods-MoviaBox.release.xcconfig */,
|
||||
0538826A0638D33FEF3A2E38 /* Pods-ThimraTV.debug.xcconfig */,
|
||||
A1174E10BCF2C606F7818792 /* Pods-ThimraTV.release.xcconfig */,
|
||||
);
|
||||
@ -680,7 +627,6 @@
|
||||
1BB91BDF2E04FD6A00A2C715 /* Extension */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BDE201F2E1E669000C2C2B5 /* AttributedString+SPAdd.swift */,
|
||||
1BB91BCC2E04FD6A00A2C715 /* CGMutablePath+SPAdd.swift */,
|
||||
1BB91BCD2E04FD6A00A2C715 /* Date+SPAdd.swift */,
|
||||
1BB91BCE2E04FD6A00A2C715 /* Dictionary+SPAdd.swift */,
|
||||
@ -717,7 +663,6 @@
|
||||
1BB91BEC2E04FD6A00A2C715 /* API */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BDE20162E1E163E00C2C2B5 /* SPAdAPI.swift */,
|
||||
1BB91BE42E04FD6A00A2C715 /* SPApnsAPI.swift */,
|
||||
1BB91BE52E04FD6A00A2C715 /* SPHomeAPI.swift */,
|
||||
1BB91BE62E04FD6A00A2C715 /* SPRewardsAPI.swift */,
|
||||
@ -839,7 +784,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BB91C142E04FD6A00A2C715 /* SPGuideViewController.swift */,
|
||||
1BF513152E20ADB4009750EA /* SPAppOpenAdViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
@ -971,7 +915,6 @@
|
||||
children = (
|
||||
1BB91C542E04FD6A00A2C715 /* SPLanguageModel.swift */,
|
||||
1BB91C552E04FD6A00A2C715 /* SPMineItem.swift */,
|
||||
1BC1F0D42E093E9900B579A4 /* SPVersionUpdateModel.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@ -1084,7 +1027,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BB91C8A2E04FD6A00A2C715 /* SPPlayerListViewModel.swift */,
|
||||
1BC1F0D62E0A35EF00B579A4 /* SPVideoRevolutionManager.swift */,
|
||||
);
|
||||
path = ViewModel;
|
||||
sourceTree = "<group>";
|
||||
@ -1195,7 +1137,6 @@
|
||||
children = (
|
||||
1BB91CB02E04FD6A00A2C715 /* SPAlertView.swift */,
|
||||
1BB91CB12E04FD6A00A2C715 /* SPAlertWindowManager.swift */,
|
||||
1BC1F0D22E09389000B579A4 /* SPVersionUpdateAlertView.swift */,
|
||||
);
|
||||
path = Alert;
|
||||
sourceTree = "<group>";
|
||||
@ -1269,7 +1210,6 @@
|
||||
1BB91CC82E04FD6A00A2C715 /* SPIAPOrderModel.swift */,
|
||||
1BB91CC92E04FD6A00A2C715 /* SPIAPVerifyModel.swift */,
|
||||
1BB91CCA2E04FD6A00A2C715 /* SPWaitRestoreModel.swift */,
|
||||
1B222BCE2E2B80DD002F5A68 /* SPPayTemplateRequest.swift */,
|
||||
);
|
||||
path = SPIAPManager;
|
||||
sourceTree = "<group>";
|
||||
@ -1294,7 +1234,6 @@
|
||||
1BB91CD12E04FD6A00A2C715 /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BDE20112E1E158400C2C2B5 /* AdManager */,
|
||||
1BB91CB22E04FD6A00A2C715 /* Alert */,
|
||||
1BB91CB42E04FD6A00A2C715 /* APPTool */,
|
||||
1BB91CB62E04FD6A00A2C715 /* Cache */,
|
||||
@ -1478,63 +1417,10 @@
|
||||
path = ThimraTV;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BC1F0EA2E0D268B00B579A4 /* NotificationService */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BC1F0E82E0D268B00B579A4 /* Info.plist */,
|
||||
1BC1F0E92E0D268B00B579A4 /* NotificationService.swift */,
|
||||
);
|
||||
path = NotificationService;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BDE20112E1E158400C2C2B5 /* AdManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BF513172E20DC63009750EA /* BannerAd */,
|
||||
1BF513122E1FB897009750EA /* AppOpenAd */,
|
||||
1BF5130F2E1F5EE4009750EA /* RewardedAd */,
|
||||
1BDE20122E1E159B00C2C2B5 /* SPAdManager.swift */,
|
||||
1BDE20182E1E175800C2C2B5 /* SPAdInfo.swift */,
|
||||
1BF513102E1FA138009750EA /* SPStatAdModel.swift */,
|
||||
);
|
||||
path = AdManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BF5130F2E1F5EE4009750EA /* RewardedAd */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BF5130D2E1F5D8F009750EA /* SPRewardedAdManager.swift */,
|
||||
1BDE201D2E1E384100C2C2B5 /* SPRewardedAdManager+Admob.swift */,
|
||||
1BF5130B2E1F4654009750EA /* SPRewardedAdManager+AppLovin.swift */,
|
||||
);
|
||||
path = RewardedAd;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BF513122E1FB897009750EA /* AppOpenAd */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BF513132E1FB8C1009750EA /* SPAppOpenAdManager.swift */,
|
||||
1BF5131A2E265880009750EA /* SPAdmobAppOpenAd.swift */,
|
||||
1BF5131C2E265A80009750EA /* SPApplovinAppOpenAd.swift */,
|
||||
);
|
||||
path = AppOpenAd;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1BF513172E20DC63009750EA /* BannerAd */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BF513182E20DC85009750EA /* SPBannerAdManager.swift */,
|
||||
1BF513202E2662DC009750EA /* SPAdmobBannerAd.swift */,
|
||||
1BF513222E273479009750EA /* SPApplovinBannerAd.swift */,
|
||||
);
|
||||
path = BannerAd;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1DBC40502DA4EDFC0093FCB0 = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1BB91D0F2E04FD6A00A2C715 /* ThimraTV */,
|
||||
1BC1F0EA2E0D268B00B579A4 /* NotificationService */,
|
||||
1DBC405A2DA4EDFC0093FCB0 /* Products */,
|
||||
0061C3496D158807460301A9 /* Pods */,
|
||||
B6C9E282BAC4C4B3E926A853 /* Frameworks */,
|
||||
@ -1545,7 +1431,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1DBC40592DA4EDFC0093FCB0 /* ThimraTV.app */,
|
||||
1BC1F0DC2E0D268400B579A4 /* NotificationService.appex */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -1561,23 +1446,6 @@
|
||||
/* 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;
|
||||
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" */;
|
||||
@ -1588,12 +1456,10 @@
|
||||
1DBC40572DA4EDFC0093FCB0 /* Resources */,
|
||||
4E1CBF3F1205E28DFCF11722 /* [CP] Embed Pods Frameworks */,
|
||||
1BB9206E2E050B1A00A2C715 /* Embed Foundation Extensions */,
|
||||
D05FE8FEDBB2F36A4EF15C23 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
1BC1F0E22E0D268400B579A4 /* PBXTargetDependency */,
|
||||
);
|
||||
name = ThimraTV;
|
||||
productName = ShortPlay;
|
||||
@ -1610,9 +1476,6 @@
|
||||
LastSwiftUpdateCheck = 1640;
|
||||
LastUpgradeCheck = 1620;
|
||||
TargetAttributes = {
|
||||
1BC1F0DB2E0D268400B579A4 = {
|
||||
CreatedOnToolsVersion = 16.4;
|
||||
};
|
||||
1DBC40582DA4EDFC0093FCB0 = {
|
||||
CreatedOnToolsVersion = 16.2;
|
||||
};
|
||||
@ -1637,19 +1500,11 @@
|
||||
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;
|
||||
@ -1708,38 +1563,9 @@
|
||||
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;
|
||||
};
|
||||
D05FE8FEDBB2F36A4EF15C23 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ThimraTV/Pods-ThimraTV-resources-${CONFIGURATION}-input-files.xcfilelist",
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputFileListPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-ThimraTV/Pods-ThimraTV-resources-${CONFIGURATION}-output-files.xcfilelist",
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ThimraTV/Pods-ThimraTV-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* 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;
|
||||
@ -1750,7 +1576,6 @@
|
||||
1BB91D132E04FD6A00A2C715 /* AppDelegate+OpenApp.swift in Sources */,
|
||||
1BB91D142E04FD6A00A2C715 /* AppDelegate+Thirdparty.swift in Sources */,
|
||||
1BB91D152E04FD6A00A2C715 /* SceneDelegate.swift in Sources */,
|
||||
1BF5131D2E265A80009750EA /* SPApplovinAppOpenAd.swift in Sources */,
|
||||
1BB91D162E04FD6A00A2C715 /* SPNavigationController.swift in Sources */,
|
||||
1BB91D172E04FD6A00A2C715 /* SPTabBarController.swift in Sources */,
|
||||
1BB91D182E04FD6A00A2C715 /* SPViewController.swift in Sources */,
|
||||
@ -1781,10 +1606,8 @@
|
||||
1BB91D312E04FD6A00A2C715 /* SPApnsAPI.swift in Sources */,
|
||||
1BB91D322E04FD6A00A2C715 /* SPHomeAPI.swift in Sources */,
|
||||
1BB91D332E04FD6A00A2C715 /* SPRewardsAPI.swift in Sources */,
|
||||
1BC1F0D72E0A35EF00B579A4 /* SPVideoRevolutionManager.swift in Sources */,
|
||||
1BB91D342E04FD6A00A2C715 /* SPSettingAPI.swift in Sources */,
|
||||
1BB91D352E04FD6A00A2C715 /* SPStatAPI.swift in Sources */,
|
||||
1BF5131B2E265880009750EA /* SPAdmobAppOpenAd.swift in Sources */,
|
||||
1BB91D362E04FD6A00A2C715 /* SPUserAPI.swift in Sources */,
|
||||
1BB91D372E04FD6A00A2C715 /* SPVideoAPI.swift in Sources */,
|
||||
1BB91D382E04FD6A00A2C715 /* SPWalletAPI.swift in Sources */,
|
||||
@ -1807,8 +1630,6 @@
|
||||
1BB91D492E04FD6A00A2C715 /* SPTextField.swift in Sources */,
|
||||
1BB91D4A2E04FD6A00A2C715 /* SPCampaignWebViewController.swift in Sources */,
|
||||
1BB91D4B2E04FD6A00A2C715 /* SPWebMessageModel.swift in Sources */,
|
||||
1BF513142E1FB8C1009750EA /* SPAppOpenAdManager.swift in Sources */,
|
||||
1BDE20192E1E175800C2C2B5 /* SPAdInfo.swift in Sources */,
|
||||
1BB91D4C2E04FD6A00A2C715 /* SPWebView.swift in Sources */,
|
||||
1BB91D4D2E04FD6A00A2C715 /* SPWebViewController.swift in Sources */,
|
||||
1BB91D4E2E04FD6A00A2C715 /* SPWebViewController+ScriptMessage.swift in Sources */,
|
||||
@ -1825,8 +1646,6 @@
|
||||
1BB91D592E04FD6A00A2C715 /* SPHomeChildController.swift in Sources */,
|
||||
1BB91D5A2E04FD6A00A2C715 /* SPHomePageController.swift in Sources */,
|
||||
1BB91D5B2E04FD6A00A2C715 /* SPHomeV2ViewController.swift in Sources */,
|
||||
1BDE201E2E1E3D3E00C2C2B5 /* SPRewardedAdManager+Admob.swift in Sources */,
|
||||
1BF513212E2662DC009750EA /* SPAdmobBannerAd.swift in Sources */,
|
||||
1BB91D5C2E04FD6A00A2C715 /* SPHomeViewController.swift in Sources */,
|
||||
1BB91D5D2E04FD6A00A2C715 /* SPSearchViewController.swift in Sources */,
|
||||
1BB91D5E2E04FD6A00A2C715 /* SPHomeCategoryModel.swift in Sources */,
|
||||
@ -1845,16 +1664,12 @@
|
||||
1BB91D6B2E04FD6A00A2C715 /* SPHomeHeaderView.swift in Sources */,
|
||||
1BB91D6C2E04FD6A00A2C715 /* SPHomeHistoryContentCell.swift in Sources */,
|
||||
1BB91D6D2E04FD6A00A2C715 /* SPHomeHotCell.swift in Sources */,
|
||||
1BF513112E1FA138009750EA /* SPStatAdModel.swift in Sources */,
|
||||
1BB91D6E2E04FD6A00A2C715 /* SPHomeHotContentCell.swift in Sources */,
|
||||
1BB91D6F2E04FD6A00A2C715 /* SPHomeHotSearchCell.swift in Sources */,
|
||||
1BB91D702E04FD6A00A2C715 /* SPHomeHotSearchView.swift in Sources */,
|
||||
1BF5130C2E1F4660009750EA /* SPRewardedAdManager+AppLovin.swift in Sources */,
|
||||
1BB91D712E04FD6A00A2C715 /* SPHomeHotView.swift in Sources */,
|
||||
1BB91D722E04FD6A00A2C715 /* SPHomeNineSquareContentCell.swift in Sources */,
|
||||
1BF513192E20DC85009750EA /* SPBannerAdManager.swift in Sources */,
|
||||
1BB91D732E04FD6A00A2C715 /* SPHomePlayHistoricalView.swift in Sources */,
|
||||
1BDE20172E1E164600C2C2B5 /* SPAdAPI.swift in Sources */,
|
||||
1BB91D742E04FD6A00A2C715 /* SPHomePlayHistoryCell.swift in Sources */,
|
||||
1BB91D752E04FD6A00A2C715 /* SPHomePlayHistoryView.swift in Sources */,
|
||||
1BB91D762E04FD6A00A2C715 /* SPHomeSearchButton.swift in Sources */,
|
||||
@ -1877,7 +1692,6 @@
|
||||
1BB91D872E04FD6A00A2C715 /* SPAboutUsViewController.swift in Sources */,
|
||||
1BB91D882E04FD6A00A2C715 /* SPDeleteAccountViewController.swift in Sources */,
|
||||
1BB91D892E04FD6A00A2C715 /* SPFeedbackViewController.swift in Sources */,
|
||||
1B222BCF2E2B80DD002F5A68 /* SPPayTemplateRequest.swift in Sources */,
|
||||
1BB91D8A2E04FD6A00A2C715 /* SPLanguageViewController.swift in Sources */,
|
||||
1BB91D8B2E04FD6A00A2C715 /* SPMineViewController.swift in Sources */,
|
||||
1BB91D8C2E04FD6A00A2C715 /* SPSettingsViewController.swift in Sources */,
|
||||
@ -1897,7 +1711,6 @@
|
||||
1BB91D9A2E04FD6A00A2C715 /* SPMineMemberYesView.swift in Sources */,
|
||||
1BB91D9B2E04FD6A00A2C715 /* SPMinePlayHistoryCell.swift in Sources */,
|
||||
1BB91D9C2E04FD6A00A2C715 /* SPMinePlayHistoryView.swift in Sources */,
|
||||
1BDE20202E1E669600C2C2B5 /* AttributedString+SPAdd.swift in Sources */,
|
||||
1BB91D9D2E04FD6A00A2C715 /* SPMineWalletView.swift in Sources */,
|
||||
1BB91D9E2E04FD6A00A2C715 /* SPSettingsCell.swift in Sources */,
|
||||
1BB91D9F2E04FD6A00A2C715 /* SPCollectListViewController.swift in Sources */,
|
||||
@ -1929,10 +1742,8 @@
|
||||
1BB91DB92E04FD6A00A2C715 /* SPSpeedSelectedView.swift in Sources */,
|
||||
1BB91DBA2E04FD6A00A2C715 /* SPPlayerListViewModel.swift in Sources */,
|
||||
1BB91DBB2E04FD6A00A2C715 /* SPRewardsViewController.swift in Sources */,
|
||||
1BDE20132E1E15A700C2C2B5 /* SPAdManager.swift in Sources */,
|
||||
1BB91DBC2E04FD6A00A2C715 /* SPCoinOrderRecordViewController.swift in Sources */,
|
||||
1BB91DBD2E04FD6A00A2C715 /* SPConsumptionRecordsViewController.swift in Sources */,
|
||||
1BF5130E2E1F5D9B009750EA /* SPRewardedAdManager.swift in Sources */,
|
||||
1BB91DBE2E04FD6A00A2C715 /* SPOrderRecordsPageViewController.swift in Sources */,
|
||||
1BB91DBF2E04FD6A00A2C715 /* SPRewardCoinsViewController.swift in Sources */,
|
||||
1BB91DC02E04FD6A00A2C715 /* SPStoreViewController.swift in Sources */,
|
||||
@ -1947,7 +1758,6 @@
|
||||
1BB91DC92E04FD6A00A2C715 /* SPCoinOrderRecordCell.swift in Sources */,
|
||||
1BB91DCA2E04FD6A00A2C715 /* SPCoinRechargeBigCell.swift in Sources */,
|
||||
1BB91DCB2E04FD6A00A2C715 /* SPCoinRechargeCell.swift in Sources */,
|
||||
1BC1F0D32E09389000B579A4 /* SPVersionUpdateAlertView.swift in Sources */,
|
||||
1BB91DCC2E04FD6A00A2C715 /* SPCoinRechargeSmallCell.swift in Sources */,
|
||||
1BB91DCD2E04FD6A00A2C715 /* SPCoinRechargeView.swift in Sources */,
|
||||
1BB91DCE2E04FD6A00A2C715 /* SPConsumptionRecordsCell.swift in Sources */,
|
||||
@ -1975,7 +1785,6 @@
|
||||
1BB91DE42E04FD6A00A2C715 /* SPTokenModel.swift in Sources */,
|
||||
1BB91DE52E04FD6A00A2C715 /* SPPlayer.swift in Sources */,
|
||||
1BB91DE62E04FD6A00A2C715 /* SPIAPManager.swift in Sources */,
|
||||
1BF513232E273482009750EA /* SPApplovinBannerAd.swift in Sources */,
|
||||
1BB91DE72E04FD6A00A2C715 /* SPIAPOrderModel.swift in Sources */,
|
||||
1BB91DE82E04FD6A00A2C715 /* SPIAPVerifyModel.swift in Sources */,
|
||||
1BB91DE92E04FD6A00A2C715 /* SPWaitRestoreModel.swift in Sources */,
|
||||
@ -1994,7 +1803,6 @@
|
||||
1BB91DF62E04FD6A00A2C715 /* JXTransitionDelegateBridge.swift in Sources */,
|
||||
1BB91DF72E04FD6A00A2C715 /* UIGestureRecognizer+JXTransition.swift in Sources */,
|
||||
1BB91DF82E04FD6A00A2C715 /* UINavigationController+JXTransition.swift in Sources */,
|
||||
1BC1F0D52E093E9900B579A4 /* SPVersionUpdateModel.swift in Sources */,
|
||||
1BB91DF92E04FD6A00A2C715 /* UIViewController+JXTransition.swift in Sources */,
|
||||
1BB91DFA2E04FD6A00A2C715 /* JXUUID.m in Sources */,
|
||||
1BB91DFB2E04FD6A00A2C715 /* PDKeyChain.m in Sources */,
|
||||
@ -2011,21 +1819,12 @@
|
||||
1BB91E062E04FD6A00A2C715 /* UIViewController+WMPageController.m in Sources */,
|
||||
1BB91E072E04FD6A00A2C715 /* WMPageController.m in Sources */,
|
||||
1BB91E082E04FD6A00A2C715 /* ZKCycleScrollView.swift in Sources */,
|
||||
1BF513162E20ADB4009750EA /* SPAppOpenAdViewController.swift in Sources */,
|
||||
1BB91E092E04FD6A00A2C715 /* ZKCycleScrollViewFlowLayout.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* 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;
|
||||
@ -2046,60 +1845,6 @@
|
||||
/* 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 */;
|
||||
@ -2110,17 +1855,15 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ThimraTV/ThimraTV.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = TWDZ3MP9DV;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = ThimraTV/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ThimraTV;
|
||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "The APP needs to access your location to recommend better short dramas for you";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
@ -2134,7 +1877,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.3;
|
||||
MARKETING_VERSION = 1.1.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -2158,17 +1901,15 @@
|
||||
CODE_SIGN_ENTITLEMENTS = ThimraTV/ThimraTV.entitlements;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 5;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = TWDZ3MP9DV;
|
||||
ENABLE_USER_SCRIPT_SANDBOXING = NO;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = ThimraTV/Source/Info.plist;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = ThimraTV;
|
||||
INFOPLIST_KEY_ITSAppUsesNonExemptEncryption = NO;
|
||||
INFOPLIST_KEY_NSCameraUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSLocationWhenInUseUsageDescription = "The APP needs to access your location to recommend better short dramas for you";
|
||||
INFOPLIST_KEY_NSPhotoLibraryUsageDescription = "The APP needs to access your album to provide screenshots for feedback.";
|
||||
INFOPLIST_KEY_NSUserTrackingUsageDescription = "We will use your advertising identifier (IDFA) to provide a personalized advertising experience.";
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
|
||||
INFOPLIST_KEY_UIMainStoryboardFile = "";
|
||||
@ -2182,7 +1923,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.1.3;
|
||||
MARKETING_VERSION = 1.1.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.thimratv.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
@ -2320,15 +2061,6 @@
|
||||
/* 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 = (
|
||||
|
141
ThimraTV.xcworkspace/xcshareddata/swiftpm/Package.resolved
Normal file
@ -0,0 +1,141 @@
|
||||
{
|
||||
"originHash" : "356668427da72005d8cb60963e877385296f1863605fc5a20d1f75f2cec3b22c",
|
||||
"pins" : [
|
||||
{
|
||||
"identity" : "abseil-cpp-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/abseil-cpp-binary.git",
|
||||
"state" : {
|
||||
"revision" : "bbe8b69694d7873315fd3a4ad41efe043e1c07c5",
|
||||
"version" : "1.2024072200.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "app-check",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/app-check.git",
|
||||
"state" : {
|
||||
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
|
||||
"version" : "11.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "facebook-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/facebook/facebook-ios-sdk",
|
||||
"state" : {
|
||||
"revision" : "c19607d535864533523d1f437c84035e5fb101cf",
|
||||
"version" : "14.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "firebase-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/firebase-ios-sdk",
|
||||
"state" : {
|
||||
"revision" : "45d327fcbe7793747295346c2209ad419bdead74",
|
||||
"version" : "11.14.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "google-ads-on-device-conversion-ios-sdk",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/googleads/google-ads-on-device-conversion-ios-sdk",
|
||||
"state" : {
|
||||
"revision" : "428d8bb138e00f9a3f4f61cc6cd8863607524f65",
|
||||
"version" : "2.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleappmeasurement",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleAppMeasurement.git",
|
||||
"state" : {
|
||||
"revision" : "406f72d0d5e9445fd1cf782db3e9e338cee2bed4",
|
||||
"version" : "11.14.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googledatatransport",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleDataTransport.git",
|
||||
"state" : {
|
||||
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
|
||||
"version" : "10.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "googleutilities",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/GoogleUtilities.git",
|
||||
"state" : {
|
||||
"revision" : "60da361632d0de02786f709bdc0c4df340f7613e",
|
||||
"version" : "8.1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "grpc-binary",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/grpc-binary.git",
|
||||
"state" : {
|
||||
"revision" : "cc0001a0cf963aa40501d9c2b181e7fc9fd8ec71",
|
||||
"version" : "1.69.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "gtm-session-fetcher",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/gtm-session-fetcher.git",
|
||||
"state" : {
|
||||
"revision" : "c756a29784521063b6a1202907e2cc47f41b667c",
|
||||
"version" : "4.5.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "interop-ios-for-google-sdks",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
|
||||
"state" : {
|
||||
"revision" : "040d087ac2267d2ddd4cca36c757d1c6a05fdbfe",
|
||||
"version" : "101.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "leveldb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/leveldb.git",
|
||||
"state" : {
|
||||
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
|
||||
"version" : "1.22.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "nanopb",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/firebase/nanopb.git",
|
||||
"state" : {
|
||||
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
|
||||
"version" : "2.30910.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "promises",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/google/promises.git",
|
||||
"state" : {
|
||||
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
|
||||
"version" : "2.4.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"identity" : "swift-protobuf",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/apple/swift-protobuf.git",
|
||||
"state" : {
|
||||
"revision" : "102a647b573f60f73afdce5613a51d71349fe507",
|
||||
"version" : "1.30.0"
|
||||
}
|
||||
}
|
||||
],
|
||||
"version" : 3
|
||||
}
|
@ -12,13 +12,8 @@ import FirebaseCore
|
||||
extension AppDelegate {
|
||||
///是否展示过通知提示
|
||||
static var haveBeenShownAPNS = false
|
||||
///是否申请过权限
|
||||
static var isRequestAuthorization = false
|
||||
|
||||
func registerAPNS() {
|
||||
guard !Self.isRequestAuthorization else { return }
|
||||
Self.isRequestAuthorization = true
|
||||
|
||||
FirebaseApp.configure()
|
||||
Messaging.messaging().delegate = self
|
||||
|
||||
|
@ -9,7 +9,6 @@ import UIKit
|
||||
#if canImport(FacebookCore)
|
||||
import FacebookCore
|
||||
#endif
|
||||
import AdjustSdk
|
||||
|
||||
|
||||
extension SceneDelegate {
|
||||
@ -25,9 +24,6 @@ extension SceneDelegate {
|
||||
result = ApplicationDelegate.shared.application(UIApplication.shared, open: url, sourceApplication: nil, annotation: [UIApplication.OpenURLOptionsKey.annotation])
|
||||
#endif
|
||||
if !result {
|
||||
if let link = ADJDeeplink(deeplink: url) {
|
||||
Adjust.processDeeplink(link)
|
||||
}
|
||||
handleOpenAppMessage(webpageURL: url)
|
||||
}
|
||||
|
||||
@ -36,30 +32,22 @@ extension SceneDelegate {
|
||||
///UniversalLink 打开app
|
||||
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
|
||||
guard let webpageURL = userActivity.webpageURL else { return }
|
||||
let result = ApplicationDelegate.shared.application(UIApplication.shared, continue: userActivity)
|
||||
|
||||
if !result {
|
||||
handleOpenAppMessage(webpageURL: webpageURL)
|
||||
}
|
||||
handleOpenAppMessage(webpageURL: webpageURL)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension SceneDelegate {
|
||||
///是否允许打开消息(每次打开APP只允许打开一次消息)
|
||||
static var allowOpenMessage = true
|
||||
static var hasOpenMessage = false
|
||||
///是否需要重试
|
||||
static var isNeedRetry = false
|
||||
|
||||
private static var webpageURL: URL?
|
||||
|
||||
func handleOpenAppMessage(webpageURL: URL?) {
|
||||
guard SPNetworkReachabilityManager.manager.isReachable == true,
|
||||
// AppDelegate.haveBeenShownAPNS,
|
||||
SPAPPTool.isAppOpen,
|
||||
SPAPPTool.idfaAuthorizationFinish //idfa授权完成
|
||||
else {
|
||||
guard SPNetworkReachabilityManager.manager.isReachable == true, AppDelegate.haveBeenShownAPNS, SPAPPTool.isAppOpen else {
|
||||
if let webpageURL = webpageURL {
|
||||
SceneDelegate.webpageURL = webpageURL
|
||||
}
|
||||
@ -82,15 +70,21 @@ extension SceneDelegate {
|
||||
}
|
||||
|
||||
private func _handleOpenAppMessage(webpageURL: URL?) {
|
||||
if !SPAPPTool.isAppOpen { return }
|
||||
|
||||
guard SceneDelegate.allowOpenMessage else { return }
|
||||
SceneDelegate.allowOpenMessage = false
|
||||
if Self.hasOpenMessage { return }
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
|
||||
Self.hasOpenMessage = false
|
||||
}
|
||||
|
||||
Self.hasOpenMessage = true
|
||||
|
||||
//统计用URL
|
||||
var statUrlStr: String? = webpageURL?.absoluteString
|
||||
var data: [String : Any]? = webpageURL?.query?.urlQuryToDictionary()
|
||||
var statUrlStr: String?
|
||||
var data: [String : Any]?
|
||||
|
||||
if statUrlStr == nil, let pasteStr = UIPasteboard.general.string, pasteStr.contains("movia") {
|
||||
if let pasteStr = UIPasteboard.general.string, pasteStr.contains("movia") {
|
||||
UIPasteboard.general.string = nil
|
||||
let tempArr = pasteStr.components(separatedBy: "?")
|
||||
let query = tempArr.last
|
||||
|
||||
@ -100,7 +94,13 @@ extension SceneDelegate {
|
||||
statUrlStr = pasteStr
|
||||
}
|
||||
}
|
||||
UIPasteboard.general.string = nil
|
||||
|
||||
|
||||
|
||||
if data == nil {
|
||||
data = webpageURL?.query?.urlQuryToDictionary()
|
||||
statUrlStr = webpageURL?.absoluteString
|
||||
}
|
||||
|
||||
if let urlStr = statUrlStr {//上报结果
|
||||
SPStatAPI.requestStatW2a(data: urlStr)
|
||||
|
@ -18,38 +18,16 @@ extension AppDelegate {
|
||||
#if canImport(FacebookCore)
|
||||
ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
|
||||
#endif
|
||||
///初始化广告sdk
|
||||
SPAdManager.manager.start()
|
||||
|
||||
registAdjust()
|
||||
///设置刷新控件的语言
|
||||
MJRefreshConfig.default.languageCode = SPLocalizedManager.shared.mjLocalizedKey
|
||||
|
||||
AppLinkUtility.fetchDeferredAppLink { url, error in
|
||||
if let url = url, error != nil {
|
||||
SPAPPTool.sceneDelegate?.handleOpenAppMessage(webpageURL: url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func registAdjust() {
|
||||
#if DEBUG
|
||||
let config = ADJConfig(appToken: "7z38v0rvceww", environment: ADJEnvironmentSandbox)
|
||||
config?.logLevel = .verbose
|
||||
#else
|
||||
let config = ADJConfig(appToken: "7z38v0rvceww", environment: ADJEnvironmentProduction)
|
||||
#endif
|
||||
|
||||
config?.delegate = self
|
||||
Adjust.initSdk(config)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- AdjustDelegate --------------
|
||||
extension AppDelegate: AdjustDelegate {
|
||||
func adjustDeferredDeeplinkReceived(_ deeplink: URL?) -> Bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
// SPLoginManager.manager.requestVisitorLogin(completer: nil)
|
||||
SPLoginManager.manager.updateUserInfo(completer: nil)
|
||||
///注册消息通知
|
||||
// registerAPNS()
|
||||
registerAPNS()
|
||||
|
||||
return true
|
||||
}
|
||||
@ -54,8 +54,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
if SPNetworkReachabilityManager.manager.isReachable == true {
|
||||
// SPLoginManager.manager.requestVisitorLogin(completer: nil)
|
||||
SPLoginManager.manager.updateUserInfo(completer: nil)
|
||||
|
||||
SPRewardedAdManager.manager.preloadRewardedAd()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
// Called as the scene transitions from the foreground to the background.
|
||||
// Use this method to save data, release shared resources, and store enough scene-specific state information
|
||||
// to restore the scene back to its current state.
|
||||
SceneDelegate.allowOpenMessage = true
|
||||
}
|
||||
|
||||
|
||||
@ -110,32 +109,22 @@ extension SceneDelegate {
|
||||
}
|
||||
|
||||
private func setRootVC() {
|
||||
///是否首次开启过
|
||||
let hasOpenApp = UserDefaults.standard.object(forKey: kSPHasBeenOpenedAPPDefaultsKey) as? Bool
|
||||
///引导页
|
||||
let guideVc = SPGuideViewController()
|
||||
|
||||
|
||||
if hasOpenApp != true && guideVc.lanuchVC != nil {
|
||||
guideVc.openAppBlock = { [weak self] in
|
||||
self?.handleOpenApp()
|
||||
SPAPPTool.isAppOpen = false
|
||||
guideVc.openAppBlock = {
|
||||
self.handleOpenApp()
|
||||
}
|
||||
window?.rootViewController = guideVc
|
||||
window?.makeKeyAndVisible()
|
||||
|
||||
SPAPPTool.appDelegate?.registerAPNS()
|
||||
|
||||
} else if SPLoginManager.manager.userInfo?.user_level == .ad, !SPAPPTool.isAppOpen, hasOpenApp == true, SPNetworkReachabilityManager.manager.isReachable == true { //开屏广告
|
||||
let openAdVC = SPAppOpenAdViewController()
|
||||
openAdVC.didEndBlock = { [weak self] in
|
||||
self?.handleOpenApp()
|
||||
SPAPPTool.appDelegate?.registerAPNS()
|
||||
}
|
||||
window?.rootViewController = openAdVC
|
||||
window?.makeKeyAndVisible()
|
||||
|
||||
} else {
|
||||
handleOpenApp()
|
||||
SPAPPTool.appDelegate?.registerAPNS()
|
||||
SPAPPTool.isAppOpen = true
|
||||
setTabBarController()
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,7 +138,6 @@ extension SceneDelegate {
|
||||
|
||||
///打开app
|
||||
@objc private func handleOpenApp() {
|
||||
SPAPPTool.isAppOpen = true
|
||||
setTabBarController()
|
||||
|
||||
retryHandleOpenAppMessage()
|
||||
|
@ -20,22 +20,13 @@ class SPTabBarController: UITabBarController {
|
||||
|
||||
let nav3 = createNavigationController(viewController: SPMyListViewController(), title: "movia_my_list".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||
|
||||
let nav4 = createNavigationController(viewController: SPRewardsViewController(), title: "movia_rewards".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
|
||||
let nav4 = createNavigationController(viewController: SPRewardsViewController(), title: "movia_rewards".localized, image: UIImage(named: "tabbar_icon_04"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||
|
||||
let nav5 = createNavigationController(viewController: SPMineViewController(), title: "movia_profile".localized, image: UIImage(named: "tabbar_icon_05"), selectedImage: UIImage(named: "tabbar_icon_05_selected"))
|
||||
|
||||
self.viewControllers = [nav1, nav2, nav3, nav4, nav5]
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
SPAPPTool.checkUpdates()
|
||||
}
|
||||
|
||||
///授权idfa
|
||||
SPAPPTool.requestIDFAAuthorization { idfa in
|
||||
|
||||
}
|
||||
///加载激励广告
|
||||
SPRewardedAdManager.manager.preloadRewardedAd()
|
||||
}
|
||||
|
||||
|
||||
@ -100,5 +91,3 @@ extension SPTabBarController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,4 +8,4 @@
|
||||
import UIKit
|
||||
|
||||
let kSPAppleAppId = "6745007239"
|
||||
let kSPAppleDownloadPath = "https://apps.apple.com/app/id6745007239"
|
||||
let kSPAppleDownloadPath = "https://apps.apple.com/app/id6670203263"
|
||||
|
@ -26,9 +26,3 @@ let kSPApnsAlertDefaultsKey = "kSPApnsAlertDefaultsKey"
|
||||
|
||||
///vip弹窗时间
|
||||
let kSPVipAlertDateDefaultsKey = "kSPVipAlertDateDefaultsKey"
|
||||
|
||||
///更新提示
|
||||
let kSPVersionUpdateAlertDefaultsKey = "kSPVersionUpdateAlertDefaultsKey"
|
||||
|
||||
///视频清晰度
|
||||
let kSPVideoRevolutionDefaultsKey = "kSPVideoRevolutionDefaultsKey"
|
||||
|
@ -1,15 +0,0 @@
|
||||
//
|
||||
// AttributedString+SPAdd.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/9.
|
||||
//
|
||||
|
||||
|
||||
extension AttributedString {
|
||||
|
||||
static func sp_create(text: String, color: UIColor, font: UIFont) -> AttributedString {
|
||||
return AttributedString.init(text, attributes: AttributeContainer([.font : font, .foregroundColor : color]))
|
||||
}
|
||||
|
||||
}
|
@ -556,9 +556,5 @@ extension UIColor {
|
||||
static func color94550E(alpha: CGFloat = 1) -> UIColor {
|
||||
return color(hex: 0x94550E, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorE0E0E0(alpha: CGFloat = 1) -> UIColor {
|
||||
return color(hex: 0xE0E0E0, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
//
|
||||
// SPAdAPI.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/9.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPAdAPI {
|
||||
|
||||
///获取激励广告信息
|
||||
static func requestShowAdInfo(completer: ((_ adInfo: SPAdInfo?) -> Void)?) {
|
||||
var param = SPNetworkParameters(path: "/ad/getShowAdInfo")
|
||||
param.method = .get
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPAdDataModel>) in
|
||||
if response.code != SPNetworkCodeSucceed || response.data?.ad?.platform_key == nil {
|
||||
let adInfo = SPAdInfo()
|
||||
adInfo.platform_key = .google
|
||||
adInfo.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
|
||||
completer?(adInfo)
|
||||
} else {
|
||||
completer?(response.data?.ad)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///广告解锁视频
|
||||
static func requestAdUnlockVideo(shortPlayId: String, videoId: String, adInfo: SPAdInfo, completer: ((_ model: SPVideoUnlockModel?) -> Void)?) {
|
||||
|
||||
var param = SPNetworkParameters(path: "/viewAdsUnlockVideo")
|
||||
param.isLoding = true
|
||||
param.parameters = [
|
||||
"short_play_id" : shortPlayId,
|
||||
"video_id" : videoId,
|
||||
"ads_id" : adInfo.ads_id ?? "",
|
||||
"ads_platform_key" : adInfo.platform_key?.rawValue ?? "",
|
||||
"trans_id" : adInfo.ads_id ?? "",
|
||||
]
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPVideoUnlockModel>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
}
|
@ -34,16 +34,5 @@ class SPSettingAPI: NSObject {
|
||||
|
||||
}
|
||||
|
||||
//获取版本更新数据
|
||||
static func requestVersionUpdateData(completer: ((_ model: SPVersionUpdateModel?) -> Void)?) {
|
||||
|
||||
var param = SPNetworkParameters(path: "/customer/versionControl")
|
||||
param.method = .get
|
||||
param.isToast = false
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPVersionUpdateModel>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,18 +72,4 @@ class SPStatAPI: NSObject {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///广告统计
|
||||
static func requestStatAd(model: SPStatAdModel, completer: (() -> Void)? = nil) {
|
||||
|
||||
var param = SPNetworkParameters(path: "/ad/history")
|
||||
param.isToast = false
|
||||
param.isLoding = false
|
||||
param.parameters = model.toDictionary()
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
|
||||
completer?()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -10,11 +10,13 @@ import UIKit
|
||||
class SPVideoAPI: NSObject {
|
||||
|
||||
///获取视频详情
|
||||
static func requestVideoDetail(videoId: String?, shortPlayId: String, activityId: String? = nil, completer: ((_ model: SPVideoDetailModel?, _ code: Int?, _ msg: String?) -> Void)?) {
|
||||
static func requestVideoDetail(videoId: String?, shortPlayId: String, activityId: String? = nil, completer: ((_ model: SPVideoDetailModel?) -> Void)?) {
|
||||
var parameters: [String : Any] = [
|
||||
"short_play_id" : shortPlayId
|
||||
]
|
||||
|
||||
// if let videoId = videoId {
|
||||
// }
|
||||
parameters["video_id"] = "0"
|
||||
if let activityId = activityId {
|
||||
parameters["activity_id"] = activityId
|
||||
@ -23,20 +25,10 @@ class SPVideoAPI: NSObject {
|
||||
var param = SPNetworkParameters(path: "/getVideoDetails")
|
||||
param.method = .get
|
||||
param.parameters = parameters
|
||||
param.isLoding = false
|
||||
param.isToast = false
|
||||
param.isLoding = true
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPVideoDetailModel>) in
|
||||
|
||||
if response.code == SPNetworkCodeSucceed {
|
||||
|
||||
} else if response.code == 10014 {
|
||||
SPToast.show(text: "movia_no_short_found".localized)
|
||||
} else {
|
||||
SPToast.show(text: response.msg)
|
||||
}
|
||||
|
||||
completer?(response.data, response.code, response.msg)
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,20 +14,15 @@ class SPWalletAPI: NSObject {
|
||||
}
|
||||
|
||||
///获取支付模版
|
||||
static func requestPayTemplate(isLoding: Bool = false, isToast: Bool = true, completer: ((_ model: SPPayTemplateModel?) -> Void)?) {
|
||||
|
||||
static func requestPayTemplate(completer: ((_ model: SPPayTemplateModel?) -> Void)?) {
|
||||
var param = SPNetworkParameters(path: "/paySettingsV3")
|
||||
param.method = .get
|
||||
param.isToast = isToast
|
||||
param.isLoding = false
|
||||
|
||||
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<SPPayTemplateModel>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
///创建内购订单
|
||||
static func requestCreateOrder(payId: String, shortPlayId: String, videoId: String, completer: ((_ orderModel: SPIAPOrderModel?) -> Void)?) {
|
||||
var param = SPNetworkParameters(path: "/createOrder")
|
||||
|
@ -84,13 +84,14 @@ extension SPApi: TargetType {
|
||||
"lang-key" : SPLocalizedManager.shared.currentLocalizedKey,//当前语言
|
||||
"time-zone" : String.timeZone(), //时区
|
||||
"app-version" : kSPAPPVersion,
|
||||
// "device-id" : JXUUID.systemUUID(), //设备id
|
||||
"device-id" : JXUUID.uuid(), //设备id
|
||||
"brand" : "apple", //品牌
|
||||
"app-name" : kSPAPPBundleIdentifier,
|
||||
"system-type" : "ios",
|
||||
"idfa" : SPAPPTool.getIdfa(),
|
||||
"idfa" : JXUUID.idfa(),
|
||||
"model" : UIDevice.sp_machineModelName(),
|
||||
"device-gaid" : JXUUID.idfv()
|
||||
// "security" : "false",
|
||||
]
|
||||
//登录信息
|
||||
dic["authorization"] = userToken
|
||||
|
@ -121,11 +121,10 @@ class SPNetwork: NSObject {
|
||||
|
||||
|
||||
DispatchQueue.global().async {
|
||||
var response: SPNetworkResponse<T> = _deserialize(data: tempData)
|
||||
let response: SPNetworkResponse<T> = _deserialize(data: tempData)
|
||||
|
||||
DispatchQueue.main.async {
|
||||
if response.code != SPNetworkCodeSucceed {
|
||||
response.data = nil
|
||||
if parameters.isToast {
|
||||
SPToast.show(text: response.msg)
|
||||
}
|
||||
|
@ -11,14 +11,38 @@ import Combine
|
||||
import Alamofire
|
||||
|
||||
class SPNetworkReachabilityManager {
|
||||
// enum Status {
|
||||
// case notReachable
|
||||
// case reachableViaWiFi
|
||||
// case reachableViaWWAN
|
||||
// case ethernet
|
||||
// }
|
||||
|
||||
static let manager: SPNetworkReachabilityManager = SPNetworkReachabilityManager()
|
||||
|
||||
///是否有网
|
||||
var isReachable: Bool?
|
||||
|
||||
private(set) var connectionType: NWInterface.InterfaceType?
|
||||
private(set) var status: NWPath.Status?
|
||||
/*
|
||||
private let reachabilityManager = NetworkReachabilityManager()
|
||||
|
||||
func startMonitoring() {
|
||||
|
||||
reachabilityManager?.startListening(onUpdatePerforming: { status in
|
||||
switch status {
|
||||
case .notReachable:
|
||||
print("网络不可用")
|
||||
case .unknown:
|
||||
print("网络状态未知")
|
||||
case .reachable(.cellular):
|
||||
print("蜂窝网络连接")
|
||||
case .reachable(.ethernetOrWiFi):
|
||||
print("WiFi 或有线网络连接")
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
private let monitor = NWPathMonitor()
|
||||
private let queue = DispatchQueue(label: "NetworkMonitorQueue")
|
||||
@ -27,24 +51,9 @@ class SPNetworkReachabilityManager {
|
||||
|
||||
monitor.pathUpdateHandler = { [weak self] path in
|
||||
guard let self = self else { return }
|
||||
self.status = path.status
|
||||
|
||||
if path.usesInterfaceType(.wifi) {
|
||||
self.connectionType = .wifi
|
||||
spLog(message: "+++++++++++++++网络变化==wifi")
|
||||
} else if path.usesInterfaceType(.cellular) {
|
||||
self.connectionType = .cellular
|
||||
spLog(message: "+++++++++++++++网络变化==cellular")
|
||||
} else if path.usesInterfaceType(.wiredEthernet) {
|
||||
self.connectionType = .wiredEthernet
|
||||
spLog(message: "+++++++++++++++网络变化==wiredEthernet")
|
||||
} else {
|
||||
self.connectionType = nil
|
||||
spLog(message: "+++++++++++++++网络变化==???")
|
||||
}
|
||||
|
||||
if path.status == .satisfied, self.connectionType != nil {
|
||||
if path.status == .satisfied {
|
||||
if self.isReachable == false {
|
||||
print("++++++有网")
|
||||
self.isReachable = true
|
||||
DispatchQueue.main.async {
|
||||
NotificationCenter.default.post(name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
|
||||
@ -55,6 +64,7 @@ class SPNetworkReachabilityManager {
|
||||
|
||||
} else {
|
||||
if self.isReachable == true {
|
||||
print("++++++无网")
|
||||
self.isReachable = false
|
||||
DispatchQueue.main.async {
|
||||
NotificationCenter.default.post(name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
|
||||
@ -63,6 +73,14 @@ class SPNetworkReachabilityManager {
|
||||
self.isReachable = false
|
||||
}
|
||||
}
|
||||
|
||||
// if path.usesInterfaceType(.wifi) {
|
||||
// print("++++++Using Wi-Fi")
|
||||
// }
|
||||
//
|
||||
// if path.usesInterfaceType(.cellular) {
|
||||
// print("++++++Using Cellular")
|
||||
// }
|
||||
}
|
||||
|
||||
monitor.start(queue: queue)
|
||||
|
@ -17,7 +17,6 @@ class SPWebView: WKWebView {
|
||||
WebMessageOpenFeedbackList,
|
||||
WebMessageOpenFeedbackDetail,
|
||||
WebMessageOpenPhotoPicker,
|
||||
WebMessageOpenCheckSignIn,
|
||||
]
|
||||
|
||||
|
||||
@ -63,8 +62,7 @@ class SPWebView: WKWebView {
|
||||
|
||||
func load(urlStr: String) {
|
||||
guard let url = URL(string: urlStr) else { return }
|
||||
// let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
|
||||
let request = URLRequest(url: url, cachePolicy: .returnCacheDataElseLoad, timeoutInterval: 30)
|
||||
var request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalCacheData, timeoutInterval: 30)
|
||||
self.load(request)
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,6 @@ let WebMessageOpenFeedbackList: SPWebViewMessageName = "openFeedbackList"
|
||||
let WebMessageOpenFeedbackDetail: SPWebViewMessageName = "openFeedbackDetail"
|
||||
///打开相册
|
||||
let WebMessageOpenPhotoPicker: SPWebViewMessageName = "openPhotoPicker"
|
||||
///点击签到
|
||||
let WebMessageOpenCheckSignIn: SPWebViewMessageName = "openCheckSignIn"
|
||||
|
||||
|
||||
extension SPWebViewController {
|
||||
@ -75,19 +73,8 @@ extension SPWebViewController {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else if name == WebMessageOpenCheckSignIn { //点击点到
|
||||
|
||||
guard SPRewardedAdManager.manager.isAdAvailable() else {
|
||||
SPRewardedAdManager.manager.showToast()
|
||||
return
|
||||
}
|
||||
|
||||
self.needAutoRefresh = false
|
||||
let manager = SPRewardedAdManager.manager
|
||||
manager.statScene = .reward
|
||||
manager.delegate = self
|
||||
manager.loadAndShowRewardedAd()
|
||||
|
||||
}
|
||||
|
||||
@ -130,26 +117,3 @@ extension SPWebViewController: TZImagePickerControllerDelegate {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- SPRewardedAdManagerDelegate --------------
|
||||
extension SPWebViewController: SPRewardedAdManagerDelegate {
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didLoadFail error: any Error) {
|
||||
self.needAutoRefresh = true
|
||||
SPRewardedAdManager.manager.delegate = nil
|
||||
}
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didDisplayFail error: any Error) {
|
||||
self.needAutoRefresh = true
|
||||
SPRewardedAdManager.manager.delegate = nil
|
||||
}
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didDismiss adInfo: SPAdInfo) {
|
||||
self.needAutoRefresh = true
|
||||
|
||||
let js = "uploadCheckSignIn()"
|
||||
self.webView.evaluateJavaScript(js)
|
||||
SPRewardedAdManager.manager.delegate = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ class SPWebViewController: SPViewController {
|
||||
///自动设置标题
|
||||
var autoTitle = true
|
||||
|
||||
var needAutoRefresh = true
|
||||
|
||||
private(set) lazy var webView: SPWebView = {
|
||||
let controller = WKUserContentController()
|
||||
|
||||
@ -53,7 +51,10 @@ class SPWebViewController: SPViewController {
|
||||
func load(urlString: String) {
|
||||
let str: String = urlString
|
||||
|
||||
self.webView.load(urlStr: str)
|
||||
guard let url = URL(string: str) else { return }
|
||||
let request = URLRequest(url: url, timeoutInterval: 30)
|
||||
|
||||
self.webView.load(request)
|
||||
}
|
||||
|
||||
func reload() {
|
||||
|
@ -1,59 +0,0 @@
|
||||
//
|
||||
// SPAppOpenAdViewController.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPAppOpenAdViewController: SPViewController {
|
||||
|
||||
var didEndBlock: (() -> Void)?
|
||||
|
||||
private(set) lazy var lanuchVC: UIViewController? = {
|
||||
let vc = SPAPPTool.getLanuchViewController()
|
||||
return vc
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
if let vc = lanuchVC {
|
||||
addChild(vc)
|
||||
view.addSubview(vc.view)
|
||||
}
|
||||
|
||||
|
||||
let manager = SPAppOpenAdManager.manager
|
||||
manager.delegate = self
|
||||
manager.showAdIfAvailable()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private func openApp() {
|
||||
self.didEndBlock?()
|
||||
NotificationCenter.default.post(name: SPGuideViewController.didOpenAppNotification, object: nil, userInfo: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPAppOpenAdViewController: SPAppOpenAdManagerDelegate {
|
||||
|
||||
///广告加载失败
|
||||
func appOpenAdManager(manager: SPAppOpenAdManager, didLoadFail error: Error) {
|
||||
openApp()
|
||||
}
|
||||
///广告展示失败
|
||||
func appOpenAdManager(manager: SPAppOpenAdManager, didDisplayFail error: Error) {
|
||||
openApp()
|
||||
}
|
||||
///广告被关闭
|
||||
func appOpenAdManagerDidDismiss(manager: SPAppOpenAdManager) {
|
||||
openApp()
|
||||
}
|
||||
func appOpenAdManager(manager: SPAppOpenAdManager, didOtherFail error: any Error) {
|
||||
openApp()
|
||||
}
|
||||
}
|
@ -24,12 +24,7 @@ class SPMineViewController: SPViewController {
|
||||
///是否进入过
|
||||
private var isHaveEntered = false
|
||||
|
||||
///是否需要展示激励广告
|
||||
private var needShowRewardedAd: Bool = false
|
||||
|
||||
weak var vipAlertView: SPVipAlertView?
|
||||
|
||||
private var payTemplateRequest: SPPayTemplateRequest?
|
||||
//MARK: UI 属性
|
||||
private lazy var headerView: SPMineHeaderView = {
|
||||
let view = SPMineHeaderView()
|
||||
@ -74,10 +69,8 @@ class SPMineViewController: SPViewController {
|
||||
|
||||
isHaveEntered = true
|
||||
|
||||
self.showRewardedAd()
|
||||
///弹出VIP提示框
|
||||
showVipAlert()
|
||||
|
||||
}
|
||||
|
||||
private func updateHeaderView() {
|
||||
@ -99,14 +92,10 @@ class SPMineViewController: SPViewController {
|
||||
extension SPMineViewController {
|
||||
|
||||
private func showVipAlert() {
|
||||
guard SPLoginManager.manager.userInfo?.user_level != .ad else { return }
|
||||
guard SPLoginManager.manager.userInfo?.is_vip != true else { return }
|
||||
guard SPVipAlertView.isShowAlert else { return }
|
||||
|
||||
self.payTemplateRequest = SPPayTemplateRequest()
|
||||
self.payTemplateRequest?.requestProducts(isToast: false) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
|
||||
SPWalletAPI.requestPayTemplate { model in
|
||||
guard let list = model?.list_sub_vip, list.count > 0 else { return }
|
||||
if !self.isDidAppear { return }
|
||||
if self.vipAlertView != nil { return }
|
||||
@ -119,20 +108,6 @@ extension SPMineViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func showRewardedAd() {
|
||||
guard SPLoginManager.manager.userInfo?.user_level == .ad else { return }
|
||||
guard needShowRewardedAd else { return }
|
||||
needShowRewardedAd = false
|
||||
guard SPRewardedAdManager.manager.isAdAvailable() else {
|
||||
return
|
||||
}
|
||||
|
||||
let manager = SPRewardedAdManager.manager
|
||||
manager.delegate = nil
|
||||
manager.statScene = .me
|
||||
manager.loadAndShowRewardedAd(isShowToast: false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPMineViewController {
|
||||
@ -163,8 +138,6 @@ extension SPMineViewController: UITableViewDelegate, UITableViewDataSource {
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
self.needShowRewardedAd = true
|
||||
|
||||
let item = dataArr[indexPath.row]
|
||||
switch item.type {
|
||||
case .privacyPolicy:
|
||||
|
@ -1,40 +0,0 @@
|
||||
//
|
||||
// SPVersionUpdateModel.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class SPVersionUpdateModel: SPModel, SmartCodable {
|
||||
|
||||
var version_code: String?
|
||||
var des: String?
|
||||
var version_name: String?
|
||||
|
||||
|
||||
|
||||
func canUpdate() -> Bool {
|
||||
// let currentCode = NSNumber(string: kSPAPPBundleVersion)?.intValue ?? 0
|
||||
// let serverCode = NSNumber(string: version_code ?? "0")?.intValue ?? 0
|
||||
// return serverCode > currentCode
|
||||
|
||||
guard let versionName = version_name else { return false }
|
||||
|
||||
let result = kSPAPPVersion.compare(versionName, options: .numeric)
|
||||
if result == .orderedAscending {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||
return [
|
||||
CodingKeys.des <--- ["description"]
|
||||
]
|
||||
}
|
||||
}
|
@ -13,18 +13,13 @@ class SPMineHeaderView: UIView {
|
||||
var height: CGFloat = kSPStatusbarHeight + 100
|
||||
|
||||
var stackHeight = 0.0
|
||||
stackHeight += memberView.intrinsicContentSize.height
|
||||
|
||||
if userInfo?.user_level != .ad {
|
||||
stackHeight += memberView.intrinsicContentSize.height
|
||||
|
||||
stackHeight += self.stackView.spacing
|
||||
stackHeight += walletView.intrinsicContentSize.height
|
||||
}
|
||||
stackHeight += self.stackView.spacing
|
||||
stackHeight += walletView.intrinsicContentSize.height
|
||||
|
||||
if playHistoryArr?.count ?? 0 > 0 {
|
||||
if stackHeight > 0 {
|
||||
stackHeight += self.stackView.spacing
|
||||
}
|
||||
stackHeight += self.stackView.spacing
|
||||
stackHeight += playHistoryView.contentHeight
|
||||
}
|
||||
|
||||
@ -54,8 +49,6 @@ class SPMineHeaderView: UIView {
|
||||
memberView.userInfo = self.userInfo
|
||||
|
||||
walletView.userInfo = self.userInfo
|
||||
|
||||
updateStackViewLayout()
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,15 +150,9 @@ class SPMineHeaderView: UIView {
|
||||
private func updateStackViewLayout() {
|
||||
stackView.removeAllArrangedSubview()
|
||||
|
||||
if userInfo?.user_level != .ad {
|
||||
stackView.addArrangedSubview(memberView)
|
||||
|
||||
stackView.addArrangedSubview(walletView)
|
||||
|
||||
loginButton.isHidden = false
|
||||
} else {
|
||||
loginButton.isHidden = true
|
||||
}
|
||||
stackView.addArrangedSubview(memberView)
|
||||
|
||||
stackView.addArrangedSubview(walletView)
|
||||
|
||||
if let arr = playHistoryArr, arr.count > 0 {
|
||||
stackView.addArrangedSubview(playHistoryView)
|
||||
|
@ -23,9 +23,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
|
||||
var activityId: String?
|
||||
var playHistoryModel: SPShortModel?
|
||||
|
||||
// private var detailModel: SPVideoDetailModel?
|
||||
|
||||
private var detailDataArr: [Any] = []
|
||||
private var detailModel: SPVideoDetailModel?
|
||||
|
||||
///上一次上报播放时长的节点
|
||||
private var lastUploadTime: Int = 0
|
||||
@ -59,13 +57,6 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var revolutionButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "revolution_icon_01"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleRevolutionButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var bottomView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .color1C1C1E()
|
||||
@ -80,7 +71,6 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
|
||||
super.viewDidLoad()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: SPIAPManager.buyVipFinishNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didChangeRevolutionNotification), name: SPVideoRevolutionManager.didChangeRevolutionNotification, object: nil)
|
||||
|
||||
self.autoNextEpisode = true
|
||||
self.dataSource = self
|
||||
@ -162,21 +152,9 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
|
||||
|
||||
self.pause()
|
||||
let view = SPPlayerDetailRecommandView()
|
||||
view.currentVideoInfo = self.viewModel.currentPlayer?.videoInfo
|
||||
view.clickCloseButton = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self._handleBack()
|
||||
|
||||
if SPLoginManager.manager.userInfo?.user_level == .ad {
|
||||
let manager = SPRewardedAdManager.manager
|
||||
manager.delegate = nil
|
||||
manager.statScene = .detail
|
||||
manager.videoInfo = self.viewModel.currentPlayer?.videoInfo
|
||||
if manager.isAdAvailable() {
|
||||
manager.loadAndShowRewardedAd()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
view.clickPlayButton = { [weak self] model in
|
||||
@ -202,7 +180,6 @@ extension SPPlayerDetailViewController {
|
||||
view.addSubview(backButton)
|
||||
view.addSubview(titleLabel)
|
||||
view.addSubview(episodeLabel)
|
||||
// view.addSubview(revolutionButton)
|
||||
view.addSubview(bottomView)
|
||||
|
||||
backButton.snp.makeConstraints { make in
|
||||
@ -223,11 +200,6 @@ extension SPPlayerDetailViewController {
|
||||
make.left.equalTo(titleLabel.snp.right).offset(16)
|
||||
}
|
||||
|
||||
// revolutionButton.snp.makeConstraints { make in
|
||||
// make.right.equalToSuperview().offset(-22)
|
||||
// make.centerY.equalTo(titleLabel)
|
||||
// }
|
||||
|
||||
bottomView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(self.collectionView.snp.bottom)
|
||||
@ -239,26 +211,18 @@ extension SPPlayerDetailViewController {
|
||||
self?.onEpisode()
|
||||
}
|
||||
|
||||
self.viewModel.updateDetailDataBlock = { [weak self] indexPath in
|
||||
self?.requestDetailData(indexPath: indexPath)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
extension SPPlayerDetailViewController {
|
||||
|
||||
private func onEpisode() {
|
||||
guard detailDataArr.count > 0 else { return }
|
||||
guard let detailModel = detailDataArr[self.viewModel.currentIndexPath.section] as? SPVideoDetailModel else { return }
|
||||
|
||||
|
||||
let view = SPEpisodeView()
|
||||
view.dataArr = detailModel.episodeList ?? []
|
||||
view.shortModel = detailModel.shortPlayInfo
|
||||
view.currentIndex = self.viewModel.currentIndexPath.row
|
||||
view.dataArr = detailModel?.episodeList ?? []
|
||||
view.shortModel = detailModel?.shortPlayInfo
|
||||
view.currentIndex = self.currentIndexPath.row
|
||||
view.didSelectedIndex = { [weak self] (index) in
|
||||
self?.scrollToItem(indexPath: IndexPath(row: index, section: self?.viewModel.currentIndexPath.section ?? 0), animated: false)
|
||||
self?.scrollToItem(indexPath: IndexPath(row: index, section: 0), animated: false)
|
||||
}
|
||||
view.present(in: nil)
|
||||
self.episodeView = view
|
||||
@ -266,36 +230,56 @@ extension SPPlayerDetailViewController {
|
||||
|
||||
///打开支付页面
|
||||
private func onPlayBuy() {
|
||||
self.viewModel.onPlayBuy()
|
||||
guard let videoInfo = self.viewModel.currentPlayer?.videoInfo else { return }
|
||||
|
||||
let view = SPPlayBuyView()
|
||||
view.shortPlayId = videoInfo.short_play_id
|
||||
view.videoId = videoInfo.short_play_video_id
|
||||
view.buyFinishBlock = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.requestDetailData(indexPath: self.currentIndexPath)
|
||||
}
|
||||
view.present(in: nil)
|
||||
}
|
||||
|
||||
///解锁视频
|
||||
private func unlockVideo(indexPath: IndexPath) {
|
||||
self.viewModel.unlockVideo { [weak self] finish in
|
||||
guard let self = self else { return }
|
||||
if finish {
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///广告解锁
|
||||
private func adUnlockVideo() {
|
||||
self.viewModel.adUnlockVideo { [weak self] in
|
||||
|
||||
guard let videoInfo = detailModel?.episodeList?[indexPath.row] else { return }
|
||||
|
||||
guard let shortPlayId = videoInfo.short_play_id, let videoId = videoInfo.short_play_video_id else { return }
|
||||
|
||||
SPWalletAPI.requestCoinUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.play()
|
||||
switch model.status {
|
||||
case .jump:
|
||||
SPToast.show(text: "movia_jump_unlock_error".localized)
|
||||
|
||||
case .noPlay:
|
||||
SPToast.show(text: "movia_buy_fail_toast_01".localized)
|
||||
|
||||
case .notEnough:
|
||||
self.onPlayBuy()
|
||||
|
||||
case .success:
|
||||
videoInfo.is_lock = false
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.play()
|
||||
}
|
||||
//更新用户信息
|
||||
SPLoginManager.manager.updateUserInfo(completer: nil)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
///上报播放进度
|
||||
private func uploadPlayTime() {
|
||||
let videoInfo = self.viewModel.currentPlayer?.videoInfo
|
||||
@ -327,7 +311,7 @@ extension SPPlayerDetailViewController {
|
||||
}
|
||||
///网络切换通知
|
||||
@objc private func reachabilityDidChangeNotification() {
|
||||
if SPNetworkReachabilityManager.manager.isReachable == true && self.detailDataArr.isEmpty {
|
||||
if SPNetworkReachabilityManager.manager.isReachable == true && self.detailModel == nil {
|
||||
self.requestDetailData()
|
||||
}
|
||||
}
|
||||
@ -336,23 +320,11 @@ extension SPPlayerDetailViewController {
|
||||
self.isShowRecommand = true
|
||||
}
|
||||
|
||||
///分辨率发生变化
|
||||
@objc private func didChangeRevolutionNotification() {
|
||||
self.requestDetailData(indexPath: self.viewModel.currentIndexPath)
|
||||
}
|
||||
|
||||
@objc private func handleRevolutionButton() {
|
||||
|
||||
spLog(message: "点击分辨率")
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -------------- SPPlayerListViewControllerDataSource --------------
|
||||
extension SPPlayerDetailViewController: SPPlayerListViewControllerDataSource, SPPlayerListViewControllerDelegate {
|
||||
func sp_playerListViewController(_ viewController: SPPlayerListViewController, _ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath, oldCell: UICollectionViewCell) -> UICollectionViewCell {
|
||||
let detailModel = self.detailDataArr[indexPath.section] as? SPVideoDetailModel
|
||||
|
||||
if let cell = oldCell as? SPPlayerDetailCell {
|
||||
cell.shortModel = detailModel?.shortPlayInfo
|
||||
cell.videoInfo = detailModel?.episodeList?[indexPath.row]
|
||||
@ -371,49 +343,20 @@ extension SPPlayerDetailViewController: SPPlayerListViewControllerDataSource, SP
|
||||
self.unlockVideo(indexPath: indexPath)
|
||||
}
|
||||
|
||||
cell.clickAdUnlockButton = { [weak self] cell in
|
||||
self?.adUnlockVideo()
|
||||
}
|
||||
|
||||
}
|
||||
return oldCell
|
||||
}
|
||||
|
||||
func sp_playerListViewController(_ viewController: SPPlayerListViewController, _ collectionView: UICollectionView, numberOfItemsInSection section: Int, oldNumber: Int) -> Int {
|
||||
if let model = self.detailDataArr[section] as? SPVideoDetailModel {
|
||||
return model.episodeList?.count ?? 0
|
||||
} else {
|
||||
return 1
|
||||
}
|
||||
return detailModel?.episodeList?.count ?? 0
|
||||
}
|
||||
|
||||
func sp_playerListViewController(_ viewController: SPPlayerListViewController, didChangeIndexPathForVisible indexPath: IndexPath) {
|
||||
// self.episodeView?.currentIndex = indexPath.row
|
||||
|
||||
if let detailModel = self.detailDataArr[indexPath.section] as? SPVideoDetailModel {
|
||||
let videoInfo = detailModel.episodeList?[indexPath.row]
|
||||
|
||||
titleLabel.text = detailModel.shortPlayInfo?.name
|
||||
episodeLabel.text = "\(videoInfo?.episode ?? "0")/\(detailModel.shortPlayInfo?.episode_total ?? 0)"
|
||||
} else {
|
||||
titleLabel.text = ""
|
||||
episodeLabel.text = ""
|
||||
}
|
||||
}
|
||||
|
||||
func sp_numberOfSections(in viewController: SPPlayerListViewController) -> Int {
|
||||
return self.detailDataArr.count
|
||||
}
|
||||
|
||||
func sp_shouldAutoScrollNextEpisode(_ viewController: SPPlayerListViewController) -> Bool {
|
||||
if episodeView != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func sp_playerViewControllerLoadMoreData(playerViewController: SPPlayerListViewController) {
|
||||
|
||||
self.episodeView?.currentIndex = indexPath.row
|
||||
let videoInfo = detailModel?.episodeList?[indexPath.row]
|
||||
|
||||
titleLabel.text = detailModel?.shortPlayInfo?.name
|
||||
episodeLabel.text = "\(videoInfo?.episode ?? "0")/\(detailModel?.shortPlayInfo?.episode_total ?? 0)"
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,42 +379,33 @@ extension SPPlayerDetailViewController {
|
||||
recommandTimer = nil
|
||||
recommandTimer = Timer.scheduledTimer(timeInterval: 6, target: YYWeakProxy(target: self), selector: #selector(handleRecommandTimer), userInfo: nil, repeats: false)
|
||||
|
||||
|
||||
SPHUD.show(containerView: self.view)
|
||||
SPVideoAPI.requestVideoDetail(videoId: videoId, shortPlayId: shortPlayId, activityId: activityId) { [weak self] model, code, msg in
|
||||
SPHUD.dismiss()
|
||||
SPVideoAPI.requestVideoDetail(videoId: videoId, shortPlayId: shortPlayId, activityId: activityId) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
if code == 10014 {
|
||||
self.navigationController?.popViewController(animated: true)
|
||||
return
|
||||
}
|
||||
guard let model = model else { return }
|
||||
|
||||
self.detailDataArr.removeAll()
|
||||
self.detailDataArr.append(model)
|
||||
|
||||
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let indexPath = indexPath, indexPath.row < (model.episodeList?.count ?? 0) {
|
||||
self.scrollToItem(indexPath: indexPath, animated: false)
|
||||
if let model = model {
|
||||
self.detailModel = model
|
||||
self.reloadData { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
} else if let videoInfo = model.video_info {
|
||||
var row: Int?
|
||||
model.episodeList?.enumerated().forEach({
|
||||
if $1.id == videoInfo.id {
|
||||
row = $0
|
||||
if let indexPath = indexPath, indexPath.row < (model.episodeList?.count ?? 0) {
|
||||
self.scrollToItem(indexPath: indexPath, animated: false)
|
||||
|
||||
} else if let videoInfo = self.detailModel?.video_info {
|
||||
var row: Int?
|
||||
self.detailModel?.episodeList?.enumerated().forEach({
|
||||
if $1.id == videoInfo.id {
|
||||
row = $0
|
||||
}
|
||||
})
|
||||
if let row = row {
|
||||
self.scrollToItem(indexPath: .init(row: row, section: 0), animated: false)
|
||||
} else {
|
||||
self.scrollToItem(indexPath: .init(row: 0, section: 0), animated: false)
|
||||
}
|
||||
})
|
||||
if let row = row {
|
||||
self.scrollToItem(indexPath: .init(row: row, section: 0), animated: false)
|
||||
} else {
|
||||
self.scrollToItem(indexPath: .init(row: 0, section: 0), animated: false)
|
||||
}
|
||||
} else {
|
||||
self.scrollToItem(indexPath: .init(row: 0, section: 0), animated: false)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,14 +17,15 @@ import AVKit
|
||||
@objc optional func sp_playerViewControllerShouldLoadMoreData(playerViewController: SPPlayerListViewController) -> Bool
|
||||
///加载更多数据
|
||||
@objc optional func sp_playerViewControllerLoadMoreData(playerViewController: SPPlayerListViewController)
|
||||
///向上加载更多数据
|
||||
@objc optional func sp_playerViewControllerLoadUpMoreData(playerViewController: SPPlayerListViewController)
|
||||
|
||||
///当前展示的发生变化
|
||||
@objc optional func sp_playerListViewController(_ viewController: SPPlayerListViewController, didChangeIndexPathForVisible indexPath: IndexPath)
|
||||
|
||||
///即将自动滑至下一级
|
||||
@objc optional func sp_shouldAutoScrollNextEpisode(_ viewController: SPPlayerListViewController) -> Bool
|
||||
|
||||
|
||||
// @objc optional func sp_playerListViewController(_ viewController: SPPlayerListViewController, didScrollFromIndex fromIndex: Int, toIndex: Int)
|
||||
///新页面展示完成
|
||||
// @objc optional func yd_playerViewController(playerListViewController: BCListPlayerViewController, didShowPlayerPage playerViewController: YDBasePlayerViewController)
|
||||
}
|
||||
|
||||
@objc protocol SPPlayerListViewControllerDataSource {
|
||||
@ -34,7 +35,7 @@ import AVKit
|
||||
|
||||
func sp_playerListViewController(_ viewController: SPPlayerListViewController, _ collectionView: UICollectionView, numberOfItemsInSection section: Int, oldNumber: Int) -> Int
|
||||
|
||||
@objc optional func sp_numberOfSections(in viewController: SPPlayerListViewController) -> Int
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -58,8 +59,12 @@ class SPPlayerListViewController: SPViewController {
|
||||
///自动下一级
|
||||
var autoNextEpisode = false
|
||||
|
||||
///是否为首次播放
|
||||
private(set) var isFirstPlay = true
|
||||
|
||||
private(set) var viewModel = SPPlayerListViewModel()
|
||||
|
||||
private(set) var currentIndexPath = IndexPath(row: 0, section: 0)
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
@ -71,6 +76,8 @@ class SPPlayerListViewController: SPViewController {
|
||||
|
||||
private(set) lazy var collectionView: SPCollectionView = {
|
||||
let collectionView = SPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.isPagingEnabled = true
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.showsHorizontalScrollIndicator = false
|
||||
@ -82,9 +89,6 @@ class SPPlayerListViewController: SPViewController {
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
self.collectionView.delegate = nil
|
||||
self.collectionView.dataSource = nil
|
||||
self.collectionView.removeFromSuperview()
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
@ -98,8 +102,6 @@ class SPPlayerListViewController: SPViewController {
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didBecomeActiveNotification), name: UIApplication.didBecomeActiveNotification, object: nil)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(willResignActiveNotification), name: UIApplication.willResignActiveNotification, object: nil)
|
||||
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
|
||||
sp_setupUI()
|
||||
sp_addActio()
|
||||
@ -156,7 +158,7 @@ class SPPlayerListViewController: SPViewController {
|
||||
func clearDataArr() {
|
||||
self.dataArr.removeAll()
|
||||
self.viewModel.currentPlayer = nil
|
||||
self.viewModel.currentIndexPath = .init(row: 0, section: 0)
|
||||
self.currentIndexPath = .init(row: 0, section: 0)
|
||||
self.collectionView.contentOffset = .init(x: 0, y: 0)
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
@ -169,10 +171,20 @@ class SPPlayerListViewController: SPViewController {
|
||||
|
||||
self.viewModel.isPlaying = true
|
||||
|
||||
if (self.collectionView.contentSize.height - self.collectionView.contentOffset.y) / self.contentSize.height <= 3 {
|
||||
if getDataCount() - currentIndexPath.row <= 2 {
|
||||
self.loadMoreData()
|
||||
}
|
||||
|
||||
if isFirstPlay {
|
||||
isFirstPlay = false
|
||||
let offset = self.collectionView.contentOffset.y + 0.2
|
||||
self.collectionView.setContentOffset(CGPoint(x: 0, y: offset), animated: false)
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
let offset = self.collectionView.contentOffset.y
|
||||
self.collectionView.setContentOffset(CGPoint(x: 0, y: floor(offset)), animated: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func pause() {
|
||||
@ -181,30 +193,27 @@ class SPPlayerListViewController: SPViewController {
|
||||
}
|
||||
|
||||
func reloadData(completion: (() -> Void)? = nil) {
|
||||
UIView.performWithoutAnimation {
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
|
||||
self.collectionView.performBatchUpdates(nil) { [weak self] _ in
|
||||
CATransaction.setCompletionBlock { [weak self] in
|
||||
guard let self = self else { return }
|
||||
let cell = self.collectionView.cellForItem(at: self.viewModel.currentIndexPath) as? SPPlayerListCell
|
||||
let cell = self.collectionView.cellForItem(at: self.currentIndexPath) as? SPPlayerListCell
|
||||
self.viewModel.currentPlayer = cell
|
||||
|
||||
completion?()
|
||||
}
|
||||
|
||||
CATransaction.begin()
|
||||
self.collectionView.reloadData()
|
||||
CATransaction.commit()
|
||||
}
|
||||
|
||||
func getDataCount() -> Int {
|
||||
return Int(self.collectionView.contentSize.height / self.contentSize.height)
|
||||
// return self.collectionView(self.collectionView, numberOfItemsInSection: 0)
|
||||
return self.collectionView(self.collectionView, numberOfItemsInSection: 0)
|
||||
}
|
||||
|
||||
func scrollToItem(indexPath: IndexPath, animated: Bool = true, completer: (() -> Void)? = nil) {
|
||||
CATransaction.setCompletionBlock { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if !animated {
|
||||
if self.viewModel.currentIndexPath != indexPath {
|
||||
if self.currentIndexPath != indexPath {
|
||||
self.skip(indexPath: indexPath)
|
||||
} else {
|
||||
self.play()
|
||||
@ -219,19 +228,10 @@ class SPPlayerListViewController: SPViewController {
|
||||
|
||||
///当前播放完成 子类可重写
|
||||
func currentPlayFinish() {
|
||||
self.viewModel.currentPlayer?.videoInfo?.play_seconds = 0
|
||||
|
||||
var autoNextEpisode = self.autoNextEpisode
|
||||
|
||||
if let result = self.delegate?.sp_shouldAutoScrollNextEpisode?(self) {
|
||||
autoNextEpisode = result
|
||||
}
|
||||
|
||||
if autoNextEpisode {
|
||||
if self.autoNextEpisode {
|
||||
scrollToNextEpisode()
|
||||
} else {
|
||||
viewModel.currentPlayer?.replay()
|
||||
}
|
||||
self.viewModel.currentPlayer?.videoInfo?.play_seconds = 0
|
||||
}
|
||||
|
||||
///当前播放进度变更 子类可重写
|
||||
@ -331,8 +331,8 @@ extension SPPlayerListViewController: UICollectionViewDelegate, UICollectionView
|
||||
|
||||
}
|
||||
|
||||
if self.viewModel.currentPlayer == nil, indexPath == self.viewModel.currentIndexPath, let playerProtocol = cell as? SPPlayerProtocol {
|
||||
self.viewModel.currentIndexPath = indexPath
|
||||
if self.viewModel.currentPlayer == nil, indexPath == currentIndexPath, let playerProtocol = cell as? SPPlayerProtocol {
|
||||
self.currentIndexPath = indexPath
|
||||
self.viewModel.currentPlayer = playerProtocol
|
||||
didChangeIndexPathForVisible()
|
||||
}
|
||||
@ -352,10 +352,6 @@ extension SPPlayerListViewController: UICollectionViewDelegate, UICollectionView
|
||||
}
|
||||
}
|
||||
|
||||
func numberOfSections(in collectionView: UICollectionView) -> Int {
|
||||
return self.dataSource?.sp_numberOfSections?(in: self) ?? 1
|
||||
}
|
||||
|
||||
//滑动停止
|
||||
func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
|
||||
scrollDidEnd(scrollView)
|
||||
@ -371,7 +367,7 @@ extension SPPlayerListViewController: UICollectionViewDelegate, UICollectionView
|
||||
for indexPath in indexPaths {
|
||||
guard let cell = self.collectionView.cellForItem(at: indexPath) else { continue }
|
||||
if floor(offsetY) == floor(cell.frame.origin.y) {
|
||||
if self.viewModel.currentIndexPath != indexPath {
|
||||
if self.currentIndexPath != indexPath {
|
||||
self.skip(indexPath: indexPath)
|
||||
}
|
||||
}
|
||||
@ -379,7 +375,7 @@ extension SPPlayerListViewController: UICollectionViewDelegate, UICollectionView
|
||||
}
|
||||
|
||||
private func skip(indexPath: IndexPath) {
|
||||
self.viewModel.currentIndexPath = indexPath
|
||||
currentIndexPath = indexPath
|
||||
guard let currentPlayer = self.collectionView.cellForItem(at: indexPath) as? SPPlayerProtocol else { return }
|
||||
self.viewModel.currentPlayer = currentPlayer
|
||||
// currentCell = self.collectionView.cellForItem(at: indexPath) as? BCListPlayerCell
|
||||
@ -415,7 +411,14 @@ extension SPPlayerListViewController {
|
||||
}
|
||||
}
|
||||
|
||||
private func loadUpMoreData() {
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
|
||||
// guard let self = self else { return }
|
||||
// }
|
||||
self.delegate?.sp_playerViewControllerLoadUpMoreData?(playerViewController: self)
|
||||
}
|
||||
|
||||
private func didChangeIndexPathForVisible() {
|
||||
self.delegate?.sp_playerListViewController?(self, didChangeIndexPathForVisible: self.viewModel.currentIndexPath)
|
||||
self.delegate?.sp_playerListViewController?(self, didChangeIndexPathForVisible: self.currentIndexPath)
|
||||
}
|
||||
}
|
||||
|
@ -10,32 +10,6 @@ import SmartCodable
|
||||
|
||||
class SPShortModel: SPModel, SmartCodable {
|
||||
|
||||
enum VideoRevolution: String, SmartCaseDefaultable {
|
||||
case r_540 = "540"
|
||||
case r_720 = "720"
|
||||
case r_1080 = "1080"
|
||||
|
||||
var needLogin: Bool {
|
||||
if self == .r_720 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var needVip: Bool {
|
||||
if self == .r_1080 {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var toString: String {
|
||||
return "\(self.rawValue)P"
|
||||
}
|
||||
}
|
||||
|
||||
enum TagType: String, SmartCaseDefaultable {
|
||||
case hot = "hot"
|
||||
case new = "new"
|
||||
@ -64,9 +38,6 @@ class SPShortModel: SPModel, SmartCodable {
|
||||
var current_episode: String?
|
||||
var video_url: String?
|
||||
|
||||
///视频分辨率
|
||||
var revolution: VideoRevolution?
|
||||
|
||||
@IgnoredKey
|
||||
var titleAttributedString: NSAttributedString?
|
||||
@IgnoredKey
|
||||
|
@ -24,8 +24,6 @@ class SPPlayBuyView: HWPanModalContentView {
|
||||
}
|
||||
}
|
||||
|
||||
private var payTemplateRequest: SPPayTemplateRequest?
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var bgView: UIImageView = {
|
||||
let view = UIImageView(image: UIImage(named: "buy_bg_image_01"))
|
||||
@ -248,45 +246,27 @@ extension SPPlayBuyView {
|
||||
|
||||
///请求支付模版
|
||||
private func requestPayTemplate() {
|
||||
|
||||
self.payTemplateRequest = SPPayTemplateRequest()
|
||||
self.payTemplateRequest?.requestProducts { [weak self] model in
|
||||
SPWalletAPI.requestPayTemplate { [weak self] templateModel in
|
||||
guard let self = self else { return }
|
||||
self.stackView.removeAllArrangedSubview()
|
||||
|
||||
if let sort = model?.sort, sort.count > 0 {
|
||||
sort.forEach {
|
||||
if $0 == .vip {
|
||||
self.addMemberView(list: model?.list_sub_vip)
|
||||
} else if $0 == .coin {
|
||||
self.addCoinView(list: model?.list_coins)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.addMemberView(list: model?.list_sub_vip)
|
||||
self.addCoinView(list: model?.list_coins)
|
||||
|
||||
if let list = templateModel?.list_sub_vip, list.count > 0 {
|
||||
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
|
||||
self.stackView.addArrangedSubview(self.memberView)
|
||||
}
|
||||
|
||||
if let list = templateModel?.list_coins, list.count > 0 {
|
||||
self.rechargeView.dataArr = templateModel?.list_coins
|
||||
self.stackView.addArrangedSubview(self.rechargeView)
|
||||
}
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
self.panModalSetNeedsLayoutUpdate()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func addMemberView(list: [SPPayTemplateItem]?) {
|
||||
if let list = list, list.count > 0 {
|
||||
self.memberView.setDataArr(dataArr: list)
|
||||
self.stackView.addArrangedSubview(self.memberView)
|
||||
}
|
||||
}
|
||||
|
||||
private func addCoinView(list: [SPPayTemplateItem]?) {
|
||||
if let list = list, list.count > 0 {
|
||||
self.rechargeView.dataArr = list
|
||||
self.stackView.addArrangedSubview(self.rechargeView)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -9,12 +9,6 @@ import UIKit
|
||||
|
||||
class SPPlayLockView: UIView {
|
||||
|
||||
///点击解锁按钮
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
|
||||
///点击广告解锁
|
||||
var clickAdUnlockButton: (() -> Void)?
|
||||
|
||||
///是否是解锁上一集
|
||||
var isUnlockUpEpisode: Bool = false {
|
||||
didSet {
|
||||
@ -24,22 +18,12 @@ class SPPlayLockView: UIView {
|
||||
|
||||
var videoInfo: SPVideoInfoModel? {
|
||||
didSet {
|
||||
let userInfo = SPLoginManager.manager.userInfo
|
||||
let coins = videoInfo?.coins ?? 0
|
||||
let myCoins = (userInfo?.coin_left_total ?? 0) + (userInfo?.send_coin_left_total ?? 0)
|
||||
coinView.setTitle("\(coins)", for: .normal)
|
||||
|
||||
|
||||
if SPLoginManager.manager.userInfo?.user_level == .ad && (coins == 0 || myCoins < coins) {
|
||||
adUnlockButton.isHidden = false
|
||||
unlockButton.isHidden = true
|
||||
} else {
|
||||
adUnlockButton.isHidden = true
|
||||
unlockButton.isHidden = false
|
||||
}
|
||||
coinView.setTitle("\(videoInfo?.coins ?? 0)", for: .normal)
|
||||
}
|
||||
}
|
||||
|
||||
///点击解锁按钮
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var containerView: UIView = {
|
||||
@ -107,38 +91,12 @@ class SPPlayLockView: UIView {
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var adUnlockButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.image = UIImage(named: "video_icon_01")
|
||||
config.imagePadding = 6
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.isHidden = true
|
||||
button.layer.cornerRadius = 27
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.borderWidth = 1
|
||||
button.layer.borderColor = UIColor.colorFFFFFF().cgColor
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let self = self else { return }
|
||||
if isUnlockUpEpisode {
|
||||
button.configuration?.attributedTitle = AttributedString.sp_create(text: "movia_video_lock_tip_02".localized, color: .colorFFFFFF(), font: .fontMedium(ofSize: 16))
|
||||
} else {
|
||||
button.configuration?.attributedTitle = AttributedString.sp_create(text: "movia_video_lock_tip_03".localized, color: .colorFFFFFF(), font: .fontMedium(ofSize: 16))
|
||||
}
|
||||
}
|
||||
button.addTarget(self, action: #selector(handleAdUnlockButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
backgroundColor = .color000000(alpha: 0.75)
|
||||
updateUnlockButton()
|
||||
|
||||
|
||||
|
||||
|
||||
_setupUI()
|
||||
}
|
||||
|
||||
@ -157,15 +115,6 @@ class SPPlayLockView: UIView {
|
||||
|
||||
}
|
||||
|
||||
@objc private func handleAdUnlockButton() {
|
||||
if isUnlockUpEpisode {
|
||||
SPToast.show(text: "movia_jump_unlock_error".localized)
|
||||
return
|
||||
}
|
||||
|
||||
self.clickAdUnlockButton?()
|
||||
}
|
||||
|
||||
private func updateUnlockButton() {
|
||||
unlockStackView.removeAllArrangedSubview()
|
||||
|
||||
@ -180,8 +129,6 @@ class SPPlayLockView: UIView {
|
||||
|
||||
unlockStackView.addArrangedSubview(coinView)
|
||||
}
|
||||
|
||||
adUnlockButton.setNeedsUpdateConfiguration()
|
||||
}
|
||||
|
||||
}
|
||||
@ -194,7 +141,6 @@ extension SPPlayLockView {
|
||||
containerView.addSubview(lockTextLabel)
|
||||
containerView.addSubview(unlockButton)
|
||||
unlockButton.addSubview(unlockStackView)
|
||||
containerView.addSubview(adUnlockButton)
|
||||
|
||||
containerView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
@ -224,9 +170,6 @@ extension SPPlayLockView {
|
||||
make.centerX.equalToSuperview()
|
||||
}
|
||||
|
||||
adUnlockButton.snp.makeConstraints { make in
|
||||
make.edges.equalTo(unlockButton)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -15,8 +15,6 @@ class SPPlayerDetailCell: SPPlayerListCell {
|
||||
|
||||
///点击解锁按钮
|
||||
var clickUnlockButton: ((_ cell: SPPlayerDetailCell) -> Void)?
|
||||
///点击广告解锁
|
||||
var clickAdUnlockButton: ((_ cell: SPPlayerDetailCell) -> Void)?
|
||||
|
||||
///上一集是否加锁
|
||||
var hasLockUpEpisode = false {
|
||||
@ -34,11 +32,6 @@ class SPPlayerDetailCell: SPPlayerListCell {
|
||||
self.clickUnlockButton?(self)
|
||||
}
|
||||
|
||||
controlView.clickAdUnlockButton = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.clickAdUnlockButton?(self)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,8 +92,6 @@ class SPPlayerDetailControlView: SPPlayerControlView {
|
||||
|
||||
///点击解锁按钮
|
||||
var clickUnlockButton: (() -> Void)?
|
||||
///点击广告解锁
|
||||
var clickAdUnlockButton: (() -> Void)?
|
||||
|
||||
///暂停按钮倒计时
|
||||
private var timer: Timer?
|
||||
@ -152,9 +150,6 @@ class SPPlayerDetailControlView: SPPlayerControlView {
|
||||
view.clickUnlockButton = { [weak self] in
|
||||
self?.clickUnlockButton?()
|
||||
}
|
||||
view.clickAdUnlockButton = { [weak self] in
|
||||
self?.clickAdUnlockButton?()
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
|
@ -14,14 +14,6 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
|
||||
var clickCloseButton: (() -> Void)?
|
||||
var clickPlayButton: ((_ model: SPShortModel) -> Void)?
|
||||
|
||||
var currentVideoInfo: SPVideoInfoModel? {
|
||||
didSet {
|
||||
if SPLoginManager.manager.userInfo?.user_level == .ad {
|
||||
bannerAd.videoInfo = currentVideoInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private var _currentCell: SPPlayerDetailRecommandCell?
|
||||
private var currentCell: SPPlayerDetailRecommandCell? {
|
||||
@ -36,11 +28,6 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var bannerAd: SPBannerAdManager = {
|
||||
let ad = SPBannerAdManager()
|
||||
return ad
|
||||
}()
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "recommand_bg_image_01"))
|
||||
@ -115,11 +102,7 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
|
||||
|
||||
//MARK: HWPanModalPresentable
|
||||
override func longFormHeight() -> PanModalHeight {
|
||||
if SPLoginManager.manager.userInfo?.user_level == .ad {
|
||||
return PanModalHeightMake(.content, 540 + bannerAd.size.height + kSPTabbarSafeBottomMargin)
|
||||
} else {
|
||||
return PanModalHeightMake(.content, 540 + kSPTabbarSafeBottomMargin)
|
||||
}
|
||||
return PanModalHeightMake(.content, 540 + kSPTabbarSafeBottomMargin)
|
||||
}
|
||||
|
||||
override func showDragIndicator() -> Bool {
|
||||
@ -153,8 +136,6 @@ class SPPlayerDetailRecommandView: HWPanModalContentView {
|
||||
extension SPPlayerDetailRecommandView {
|
||||
|
||||
@objc private func handleCloseButton() {
|
||||
self.bannerAd.requestStatAd(type: "close", errorMsg: nil)
|
||||
|
||||
self.dismiss(animated: true) {
|
||||
}
|
||||
self.clickCloseButton?()
|
||||
@ -214,18 +195,6 @@ extension SPPlayerDetailRecommandView {
|
||||
make.top.equalTo(bannerView.snp.bottom).offset(81)
|
||||
make.height.equalTo(46)
|
||||
}
|
||||
|
||||
if SPLoginManager.manager.userInfo?.user_level == .ad {
|
||||
addSubview(bannerAd.view)
|
||||
|
||||
bannerAd.view.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-kSPTabbarSafeBottomMargin)
|
||||
make.size.equalTo(bannerAd.size)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -216,7 +216,6 @@ extension SPPlayerListCell: SPPlayerDelegate {
|
||||
|
||||
func sp_playerReadyToPlay(_ player: SPPlayer) {
|
||||
self.seekToTime(toTime: (videoInfo?.play_seconds ?? 0) / 1000)
|
||||
player.rate = self.viewModel?.speedModel.getRate() ?? 1
|
||||
// spLog(message: "play_seconds ====== \(videoInfo?.play_seconds ?? 0)")
|
||||
}
|
||||
|
||||
|
@ -11,8 +11,6 @@ class SPPlayerListViewModel: NSObject {
|
||||
|
||||
@objc dynamic var isPlaying: Bool = true
|
||||
|
||||
var currentIndexPath = IndexPath(row: 0, section: 0)
|
||||
|
||||
private var _currentPlayer: SPPlayerProtocol?
|
||||
var currentPlayer: SPPlayerProtocol? {
|
||||
set {
|
||||
@ -33,9 +31,6 @@ class SPPlayerListViewModel: NSObject {
|
||||
|
||||
@objc dynamic private(set) lazy var speedModel = SPSpeedModel(speed: .x1)
|
||||
|
||||
///视频解锁成功
|
||||
private var videoUnlockFinishBlock: (() -> Void)?
|
||||
|
||||
///设置倍速播放
|
||||
func setSpeedPlay(speedModel: SPSpeedModel) {
|
||||
self.speedModel = speedModel
|
||||
@ -55,140 +50,5 @@ class SPPlayerListViewModel: NSObject {
|
||||
var handlePlayTimeDidChange: ((_ time: Int) -> Void)?
|
||||
///选集
|
||||
var handleEpisode: (() -> Void)?
|
||||
///更新数据
|
||||
var updateDetailDataBlock: ((_ toIndexPath: IndexPath?) -> Void)?
|
||||
|
||||
}
|
||||
|
||||
extension SPPlayerListViewModel {
|
||||
///选择分辨路
|
||||
func selectedRevolution(revolution: SPShortModel.VideoRevolution) {
|
||||
guard SPVideoRevolutionManager.manager.revolution != revolution else { return }
|
||||
let userInfo = SPLoginManager.manager.userInfo
|
||||
|
||||
|
||||
if revolution.needLogin, userInfo?.is_tourist != false, userInfo?.is_vip != true {
|
||||
|
||||
// SPLoginManager.manager.openLogin { [weak self] in
|
||||
// guard let _ = self else { return }
|
||||
// VPVideoRevolutionManager.manager.setVideoRevolution(revolution: revolution)
|
||||
// }
|
||||
|
||||
} else if revolution.needVip, userInfo?.is_vip != true {
|
||||
// let alert = VPAlertView(title: "veloria_vip_activate_title".localized, subtitle: "veloria_vip_activate_content".localized, icon: UIImage(named: "alert_icon_06"), normalButtonText: "veloria_later".localized, highlightButtonText: "veloria_go".localized).show()
|
||||
// alert.clickHighlightButton = { [weak self] in
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + 0.4) {
|
||||
// }
|
||||
// }
|
||||
// self?.showRechargeView(revolution: revolution)
|
||||
|
||||
} else {
|
||||
SPVideoRevolutionManager.manager.setVideoRevolution(revolution: revolution)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
///打开支付页面
|
||||
func onPlayBuy() {
|
||||
let userInfo = SPLoginManager.manager.userInfo
|
||||
guard let videoInfo = self.currentPlayer?.videoInfo else { return }
|
||||
guard userInfo?.user_level != .ad else { return }
|
||||
|
||||
let view = SPPlayBuyView()
|
||||
view.shortPlayId = videoInfo.short_play_id
|
||||
view.videoId = videoInfo.short_play_video_id
|
||||
view.buyFinishBlock = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
// self.requestDetailData(indexPath: self.currentIndexPath)
|
||||
self.updateDetailDataBlock?(self.currentIndexPath)
|
||||
}
|
||||
view.present(in: nil)
|
||||
}
|
||||
|
||||
func unlockVideo(completer: ((_ finish: Bool) -> Void)?) {
|
||||
let videoInfo = self.currentPlayer?.videoInfo
|
||||
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
|
||||
|
||||
SPWalletAPI.requestCoinUnlockVideo(shortPlayId: shortPlayId, videoId: videoId) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else { return }
|
||||
|
||||
switch model.status {
|
||||
case .jump:
|
||||
SPToast.show(text: "movia_jump_unlock_error".localized)
|
||||
completer?(false)
|
||||
|
||||
case .noPlay:
|
||||
SPToast.show(text: "movia_buy_fail_toast_01".localized)
|
||||
completer?(false)
|
||||
|
||||
case .notEnough:
|
||||
self.onPlayBuy()
|
||||
completer?(false)
|
||||
|
||||
case .success:
|
||||
|
||||
//更新用户信息
|
||||
SPLoginManager.manager.updateUserInfo {
|
||||
videoInfo?.is_lock = false
|
||||
completer?(true)
|
||||
}
|
||||
|
||||
default:
|
||||
completer?(false)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func adUnlockVideo(finish: (() -> Void)?) {
|
||||
|
||||
guard SPRewardedAdManager.manager.isAdAvailable() else {
|
||||
SPRewardedAdManager.manager.showToast()
|
||||
return
|
||||
}
|
||||
|
||||
let manager = SPRewardedAdManager.manager
|
||||
manager.delegate = self
|
||||
manager.videoInfo = self.currentPlayer?.videoInfo
|
||||
manager.statScene = .detail
|
||||
manager.loadAndShowRewardedAd()
|
||||
|
||||
self.videoUnlockFinishBlock = finish
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- SPAdManagerDelegate --------------
|
||||
extension SPPlayerListViewModel: SPRewardedAdManagerDelegate {
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didDismiss adInfo: SPAdInfo) {
|
||||
manager.delegate = nil
|
||||
|
||||
let videoInfo = self.currentPlayer?.videoInfo
|
||||
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
|
||||
|
||||
SPAdAPI.requestAdUnlockVideo(shortPlayId: shortPlayId, videoId: videoId, adInfo: adInfo) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
|
||||
if model?.status == .jump {
|
||||
SPToast.show(text: "movia_jump_unlock_error".localized)
|
||||
|
||||
} else if model?.status == .success {
|
||||
self.currentPlayer?.videoInfo?.is_lock = false
|
||||
self.videoUnlockFinishBlock?()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didLoadFail error: any Error) {
|
||||
manager.delegate = nil
|
||||
}
|
||||
|
||||
func rewardedAdManager(manager: SPRewardedAdManager, didDisplayFail error: any Error) {
|
||||
manager.delegate = nil
|
||||
}
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
//
|
||||
// SPVideoRevolutionManager.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/6/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPVideoRevolutionManager: NSObject {
|
||||
|
||||
static let manager = SPVideoRevolutionManager()
|
||||
|
||||
///当前分辨率
|
||||
lazy var revolution: SPShortModel.VideoRevolution = {
|
||||
let userInfo = SPLoginManager.manager.userInfo
|
||||
|
||||
if let revolution = UserDefaults.standard.object(forKey: kSPVideoRevolutionDefaultsKey) as? String {
|
||||
var revolution = verify(revolution: SPShortModel.VideoRevolution.init(rawValue: revolution) ?? .r_540)
|
||||
return revolution
|
||||
}
|
||||
return .r_540
|
||||
}()
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(userInfoUpdateNotification), name: SPLoginManager.userInfoUpdateNotification, object: nil)
|
||||
}
|
||||
|
||||
@objc private func userInfoUpdateNotification() {
|
||||
self.setVideoRevolution(revolution: self.revolution)
|
||||
}
|
||||
|
||||
func setVideoRevolution(revolution: SPShortModel.VideoRevolution) {
|
||||
let newRevolution = verify(revolution: revolution)
|
||||
|
||||
if newRevolution != self.revolution {
|
||||
self.revolution = newRevolution
|
||||
NotificationCenter.default.post(name: SPVideoRevolutionManager.didChangeRevolutionNotification, object: nil)
|
||||
UserDefaults.standard.set(newRevolution.rawValue, forKey: kSPVideoRevolutionDefaultsKey)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SPVideoRevolutionManager {
|
||||
|
||||
///校验分辨率是否可用,并返回可用分辨率
|
||||
func verify(revolution: SPShortModel.VideoRevolution) -> SPShortModel.VideoRevolution {
|
||||
let userInfo = SPLoginManager.manager.userInfo
|
||||
var newRevolution = revolution
|
||||
if userInfo?.is_vip != true {
|
||||
if newRevolution == .r_1080 {
|
||||
newRevolution = .r_720
|
||||
}
|
||||
if userInfo?.is_tourist != false, revolution != .r_540 {
|
||||
newRevolution = .r_540
|
||||
}
|
||||
}
|
||||
return newRevolution
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPVideoRevolutionManager {
|
||||
|
||||
///分辨率发生变化
|
||||
@objc static let didChangeRevolutionNotification = NSNotification.Name(rawValue: "SPVideoRevolutionManager.didChangeRevolutionNotification")
|
||||
}
|
@ -16,7 +16,6 @@ class SPRewardsViewController: SPCampaignWebViewController {
|
||||
private var isFirst = true
|
||||
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
self.urlStr = SPRewardsWebUrl
|
||||
super.viewDidLoad()
|
||||
@ -55,9 +54,7 @@ class SPRewardsViewController: SPCampaignWebViewController {
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if !isFirst {
|
||||
if needAutoRefresh {
|
||||
self.reload()
|
||||
}
|
||||
self.reload()
|
||||
} else {
|
||||
isFirst = false
|
||||
}
|
||||
|
@ -9,8 +9,6 @@ import UIKit
|
||||
|
||||
class SPStoreViewController: SPViewController {
|
||||
|
||||
private var payTemplateRequest: SPPayTemplateRequest?
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var scrollView: SPScrollView = {
|
||||
let scrollView = SPScrollView()
|
||||
@ -186,40 +184,23 @@ extension SPStoreViewController {
|
||||
|
||||
///请求支付模版
|
||||
private func requestPayTemplate() {
|
||||
|
||||
self.payTemplateRequest = SPPayTemplateRequest()
|
||||
self.payTemplateRequest?.requestProducts { [weak self] model in
|
||||
SPWalletAPI.requestPayTemplate { [weak self] templateModel in
|
||||
guard let self = self else { return }
|
||||
self.stackView.removeAllArrangedSubview()
|
||||
|
||||
if let sort = model?.sort, sort.count > 0 {
|
||||
sort.forEach {
|
||||
if $0 == .vip {
|
||||
self.addMemberView(list: model?.list_sub_vip)
|
||||
} else if $0 == .coin {
|
||||
self.addCoinView(list: model?.list_coins)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.addMemberView(list: model?.list_sub_vip)
|
||||
self.addCoinView(list: model?.list_coins)
|
||||
if let list = templateModel?.list_sub_vip, list.count > 0 {
|
||||
self.memberView.setDataArr(dataArr: templateModel?.list_sub_vip)
|
||||
self.stackView.addArrangedSubview(self.memberView)
|
||||
}
|
||||
|
||||
if let list = templateModel?.list_coins, list.count > 0 {
|
||||
self.rechargeView.dataArr = templateModel?.list_coins
|
||||
self.stackView.addArrangedSubview(self.rechargeView)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private func addMemberView(list: [SPPayTemplateItem]?) {
|
||||
if let list = list, list.count > 0 {
|
||||
self.memberView.setDataArr(dataArr: list)
|
||||
self.stackView.addArrangedSubview(self.memberView)
|
||||
}
|
||||
}
|
||||
|
||||
private func addCoinView(list: [SPPayTemplateItem]?) {
|
||||
if let list = list, list.count > 0 {
|
||||
self.rechargeView.dataArr = list
|
||||
self.stackView.addArrangedSubview(self.rechargeView)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -9,14 +9,7 @@ import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class SPPayTemplateModel: SPModel, SmartCodable {
|
||||
|
||||
enum SortName: String, SmartCaseDefaultable {
|
||||
case coin = "list_coins"
|
||||
case vip = "list_sub_vip"
|
||||
}
|
||||
|
||||
var list_coins: [SPPayTemplateItem]?
|
||||
var list_sub_vip: [SPPayTemplateItem]?
|
||||
|
||||
var sort: [SortName]?
|
||||
}
|
||||
|
@ -6,13 +6,11 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AppTrackingTransparency
|
||||
import AdSupport
|
||||
|
||||
class SPAPPTool: NSObject {
|
||||
|
||||
///app开启状态 引导页结束后变为已开启
|
||||
static var isAppOpen = false
|
||||
static var isAppOpen = true
|
||||
|
||||
static var appDelegate: AppDelegate?
|
||||
static var sceneDelegate: SceneDelegate?
|
||||
@ -121,52 +119,3 @@ extension SPAPPTool {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
///检查更新
|
||||
extension SPAPPTool {
|
||||
static func checkUpdates() {
|
||||
#if !DEBUG
|
||||
if let date = UserDefaults.standard.object(forKey: kSPVersionUpdateAlertDefaultsKey) as? Date {
|
||||
if date.sp_isToday { return }
|
||||
}
|
||||
UserDefaults.standard.set(Date(), forKey: kSPVersionUpdateAlertDefaultsKey)
|
||||
#endif
|
||||
|
||||
SPSettingAPI.requestVersionUpdateData { model in
|
||||
guard let model = model else { return }
|
||||
if model.canUpdate() {
|
||||
self.showVersionUpdateAlert(model: model)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static private func showVersionUpdateAlert(model: SPVersionUpdateModel) {
|
||||
SPVersionUpdateAlertView(model: model).show()
|
||||
}
|
||||
}
|
||||
|
||||
///idfa授权
|
||||
extension SPAPPTool {
|
||||
///idfa是否授权结束
|
||||
static var idfaAuthorizationFinish = false
|
||||
static var idfa: String?
|
||||
|
||||
static func getIdfa() -> String {
|
||||
if let idfa = idfa {
|
||||
return idfa
|
||||
} else {
|
||||
return ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||||
}
|
||||
}
|
||||
|
||||
static func requestIDFAAuthorization(completion: @escaping (String?) -> Void) {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
|
||||
ATTrackingManager.requestTrackingAuthorization { status in
|
||||
idfaAuthorizationFinish = true
|
||||
SPAPPTool.idfa = ASIdentifierManager.shared().advertisingIdentifier.uuidString
|
||||
SPAPPTool.sceneDelegate?.retryHandleOpenAppMessage()
|
||||
completion(idfa)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,67 +0,0 @@
|
||||
//
|
||||
// SPAdmobAppOpenAd.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GoogleMobileAds
|
||||
|
||||
class SPAdmobAppOpenAd: NSObject, SPAppOpenAd {
|
||||
|
||||
private var appOpenAd: AppOpenAd?
|
||||
|
||||
var delegate: (any SPAppOpenAdDelegate)?
|
||||
|
||||
var adPlatformKey: String {
|
||||
return SPAdPlatformKey.google.rawValue
|
||||
}
|
||||
|
||||
var adUnitID: String {
|
||||
return SPAdManager.manager.admob_appOpenAdUnitID
|
||||
}
|
||||
|
||||
var isReady: Bool {
|
||||
return appOpenAd != nil
|
||||
}
|
||||
|
||||
func loadAd() {
|
||||
AppOpenAd.load(with: adUnitID, request: Request()) { [weak self] appOpenAd, error in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.appOpenAd = appOpenAd
|
||||
self.appOpenAd?.fullScreenContentDelegate = self
|
||||
|
||||
if let error = error {
|
||||
self.delegate?.appOpenAd?(ad: self, didLoadFail: error)
|
||||
} else {
|
||||
self.delegate?.appOpenAdDidLoadFinish?(ad: self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showAd() {
|
||||
appOpenAd?.present(from: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPAdmobAppOpenAd: FullScreenContentDelegate {
|
||||
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||
self.delegate?.appOpenAdDidShow?(ad: self)
|
||||
}
|
||||
|
||||
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||
self.delegate?.appOpenAdDidDismiss?(ad: self)
|
||||
}
|
||||
|
||||
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
self.delegate?.appOpenAd?(ad: self, didDisplayFail: error)
|
||||
}
|
||||
|
||||
func adDidRecordClick(_ ad: any FullScreenPresentingAd) {
|
||||
self.delegate?.appOpenAdDidClick?(ad: self)
|
||||
}
|
||||
|
||||
}
|
@ -1,221 +0,0 @@
|
||||
//
|
||||
// SPAppOpenAdManager.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc protocol SPAppOpenAdManagerDelegate: NSObjectProtocol {
|
||||
///广告加载失败
|
||||
@objc optional func appOpenAdManager(manager: SPAppOpenAdManager, didLoadFail error: Error)
|
||||
///广告加载成功
|
||||
@objc optional func appOpenAdManagerDidLoadFinish(manager: SPAppOpenAdManager)
|
||||
///广告展示失败
|
||||
@objc optional func appOpenAdManager(manager: SPAppOpenAdManager, didDisplayFail error: Error)
|
||||
///广告被展示
|
||||
@objc optional func appOpenAdManagerDidShow(manager: SPAppOpenAdManager)
|
||||
///广告被关闭
|
||||
@objc optional func appOpenAdManagerDidDismiss(manager: SPAppOpenAdManager)
|
||||
|
||||
///其它错误
|
||||
@objc optional func appOpenAdManager(manager: SPAppOpenAdManager, didOtherFail error: Error)
|
||||
}
|
||||
|
||||
@objc protocol SPAppOpenAdDelegate: NSObjectProtocol {
|
||||
|
||||
///广告加载失败
|
||||
@objc optional func appOpenAd(ad: SPAppOpenAd, didLoadFail error: Error)
|
||||
///广告加载成功
|
||||
@objc optional func appOpenAdDidLoadFinish(ad: SPAppOpenAd)
|
||||
///广告展示失败
|
||||
@objc optional func appOpenAd(ad: SPAppOpenAd, didDisplayFail error: Error)
|
||||
///广告被展示
|
||||
@objc optional func appOpenAdDidShow(ad: SPAppOpenAd)
|
||||
///广告被关闭
|
||||
@objc optional func appOpenAdDidDismiss(ad: SPAppOpenAd)
|
||||
///广告被点击
|
||||
@objc optional func appOpenAdDidClick(ad: SPAppOpenAd)
|
||||
}
|
||||
|
||||
|
||||
@objc protocol SPAppOpenAd: NSObjectProtocol {
|
||||
|
||||
weak var delegate: SPAppOpenAdDelegate? { get set }
|
||||
|
||||
var adPlatformKey: String { get }
|
||||
|
||||
var adUnitID: String { get }
|
||||
|
||||
var isReady: Bool { get }
|
||||
|
||||
func loadAd()
|
||||
func showAd()
|
||||
|
||||
}
|
||||
|
||||
class SPAppOpenAdManager: NSObject {
|
||||
static let manager = SPAppOpenAdManager()
|
||||
|
||||
weak var delegate: SPAppOpenAdManagerDelegate?
|
||||
|
||||
let adUnitID = SPAdManager.manager.admob_appOpenAdUnitID
|
||||
|
||||
|
||||
private var appOpenAd: SPAppOpenAd?
|
||||
|
||||
|
||||
private(set) var isLoadingAd = false
|
||||
private(set) var isShowingAd = false
|
||||
private var isNeedShow = false
|
||||
|
||||
private var timeOutTimer: Timer?
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
}
|
||||
|
||||
private func loadAd() {
|
||||
// Do not load ad if there is an unused ad or one is already loading.
|
||||
if isLoadingAd || isAdAvailable() {
|
||||
return
|
||||
}
|
||||
isLoadingAd = true
|
||||
|
||||
appOpenAd = SPAdmobAppOpenAd()
|
||||
appOpenAd?.delegate = self
|
||||
appOpenAd?.loadAd()
|
||||
}
|
||||
|
||||
func showAd() {
|
||||
if let ad = appOpenAd {
|
||||
self.isNeedShow = false
|
||||
isShowingAd = true
|
||||
ad.showAd()
|
||||
}
|
||||
}
|
||||
|
||||
func showAdIfAvailable() {
|
||||
// If the app open ad is already showing, do not show the ad again.
|
||||
guard !isShowingAd else { return }
|
||||
|
||||
self.isNeedShow = true
|
||||
|
||||
self.timeOutTimer = Timer.scheduledTimer(timeInterval: 5, target: self, selector: #selector(handleTimeOutTimer), userInfo: nil, repeats: false)
|
||||
|
||||
// If the app open ad is not available yet but is supposed to show, load
|
||||
// a new ad.
|
||||
if !isAdAvailable() {
|
||||
self.loadAd()
|
||||
return
|
||||
}
|
||||
|
||||
showAd()
|
||||
}
|
||||
|
||||
|
||||
private func isAdAvailable() -> Bool {
|
||||
return appOpenAd?.isReady ?? false
|
||||
}
|
||||
|
||||
@objc private func handleTimeOutTimer() {
|
||||
self.isNeedShow = false
|
||||
self.timeOutTimer?.invalidate()
|
||||
self.timeOutTimer = nil
|
||||
clearTimer()
|
||||
|
||||
let error = NSError(domain: "time-out", code: -1)
|
||||
self.delegate?.appOpenAdManager?(manager: self, didOtherFail: error)
|
||||
}
|
||||
|
||||
private func clearTimer() {
|
||||
self.timeOutTimer?.invalidate()
|
||||
self.timeOutTimer = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- SPAppOpenAdDelegate --------------
|
||||
extension SPAppOpenAdManager: SPAppOpenAdDelegate {
|
||||
|
||||
///广告加载失败
|
||||
func appOpenAd(ad: SPAppOpenAd, didLoadFail error: Error) {
|
||||
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||
isLoadingAd = false
|
||||
clearTimer()
|
||||
|
||||
self.delegate?.appOpenAdManager?(manager: self, didLoadFail: error)
|
||||
}
|
||||
///广告加载成功
|
||||
func appOpenAdDidLoadFinish(ad: SPAppOpenAd) {
|
||||
isLoadingAd = false
|
||||
clearTimer()
|
||||
self.delegate?.appOpenAdManagerDidLoadFinish?(manager: self)
|
||||
|
||||
if isNeedShow {
|
||||
self.showAd()
|
||||
}
|
||||
|
||||
}
|
||||
///广告展示失败
|
||||
func appOpenAd(ad: SPAppOpenAd, didDisplayFail error: Error) {
|
||||
|
||||
self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
|
||||
|
||||
appOpenAd = nil
|
||||
isShowingAd = false
|
||||
clearTimer()
|
||||
|
||||
self.delegate?.appOpenAdManager?(manager: self, didDisplayFail: error)
|
||||
}
|
||||
///广告被展示
|
||||
func appOpenAdDidShow(ad: SPAppOpenAd) {
|
||||
self.requestStatAd(type: "start", errorMsg: nil)
|
||||
self.delegate?.appOpenAdManagerDidShow?(manager: self)
|
||||
}
|
||||
///广告被关闭
|
||||
func appOpenAdDidDismiss(ad: SPAppOpenAd) {
|
||||
self.requestStatAd(type: "close", errorMsg: nil)
|
||||
|
||||
appOpenAd = nil
|
||||
isShowingAd = false
|
||||
|
||||
self.delegate?.appOpenAdManagerDidDismiss?(manager: self)
|
||||
}
|
||||
///广告被点击
|
||||
func appOpenAdDidClick(ad: SPAppOpenAd) {
|
||||
self.requestStatAd(type: "click", errorMsg: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- 统计 --------------
|
||||
extension SPAppOpenAdManager {
|
||||
|
||||
private func requestStatAd(type: String, errorMsg: String?) {
|
||||
guard let appOpenAd = appOpenAd else { return }
|
||||
|
||||
let model = SPStatAdModel()
|
||||
model.type = type
|
||||
model.ads_id = appOpenAd.adUnitID
|
||||
model.ad_platform_key = SPAdPlatformKey(rawValue: appOpenAd.adPlatformKey)
|
||||
model.error_msg = errorMsg
|
||||
model.scene = .splash
|
||||
|
||||
SPStatAPI.requestStatAd(model: model)
|
||||
}
|
||||
|
||||
|
||||
@objc private func didEnterBackgroundNotification() {
|
||||
if !self.isShowingAd { return }
|
||||
|
||||
self.requestStatAd(type: "Interrupt", errorMsg: nil)
|
||||
}
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
//
|
||||
// SPApplovinAppOpenAd.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AppLovinSDK
|
||||
|
||||
class SPApplovinAppOpenAd: NSObject, SPAppOpenAd {
|
||||
|
||||
private lazy var appOpenAd = MAAppOpenAd(adUnitIdentifier: adUnitID)
|
||||
|
||||
var delegate: (any SPAppOpenAdDelegate)?
|
||||
|
||||
var adPlatformKey: String {
|
||||
return SPAdPlatformKey.applovin.rawValue
|
||||
}
|
||||
|
||||
var adUnitID: String {
|
||||
return SPAdManager.manager.applovin_appOpenAdUnitID
|
||||
}
|
||||
|
||||
var isReady: Bool {
|
||||
if ALSdk.shared().isInitialized && appOpenAd.isReady {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func loadAd() {
|
||||
SPAdManager.manager.initialize_applovinSdk { [weak self] in
|
||||
guard let self = self else { return }
|
||||
appOpenAd.delegate = self
|
||||
appOpenAd.load()
|
||||
}
|
||||
}
|
||||
|
||||
func showAd() {
|
||||
guard isReady else { return }
|
||||
appOpenAd.show()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- MAAdDelegate --------------
|
||||
extension SPApplovinAppOpenAd: MAAdDelegate {
|
||||
func didLoad(_ ad: MAAd) {
|
||||
self.delegate?.appOpenAdDidLoadFinish?(ad: self)
|
||||
}
|
||||
|
||||
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
|
||||
let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||
self.delegate?.appOpenAd?(ad: self, didLoadFail: nsError)
|
||||
}
|
||||
|
||||
func didDisplay(_ ad: MAAd) {
|
||||
self.delegate?.appOpenAdDidShow?(ad: self)
|
||||
}
|
||||
|
||||
func didHide(_ ad: MAAd) {
|
||||
self.delegate?.appOpenAdDidDismiss?(ad: self)
|
||||
}
|
||||
|
||||
func didClick(_ ad: MAAd) {
|
||||
self.delegate?.appOpenAdDidClick?(ad: self)
|
||||
}
|
||||
|
||||
func didFail(toDisplay ad: MAAd, withError error: MAError) {
|
||||
let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||
self.delegate?.appOpenAd?(ad: self, didDisplayFail: nsError)
|
||||
}
|
||||
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
//
|
||||
// SPAdmobBannerAd.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/15.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GoogleMobileAds
|
||||
|
||||
class SPAdmobBannerAd: NSObject, SPBannerAd {
|
||||
|
||||
|
||||
var delegate: (any SPBannerAdDelegate)?
|
||||
|
||||
|
||||
let size = CGSize.init(width: kSPScreenWidth, height: 59)
|
||||
|
||||
private lazy var _adView: BannerView = {
|
||||
let view = BannerView()
|
||||
view.adUnitID = self.adUnitID
|
||||
view.adSize = inlineAdaptiveBanner(width: size.width, maxHeight:size.height)
|
||||
view.delegate = self
|
||||
return view
|
||||
}()
|
||||
|
||||
var adView: UIView {
|
||||
return _adView
|
||||
}
|
||||
|
||||
var adPlatformKey: String {
|
||||
return SPAdPlatformKey.google.rawValue
|
||||
}
|
||||
|
||||
var adUnitID: String {
|
||||
return SPAdManager.manager.admob_bannerAdUnitID
|
||||
}
|
||||
|
||||
|
||||
|
||||
func loadAd() {
|
||||
_adView.load(Request())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- BannerViewDelegate --------------
|
||||
extension SPAdmobBannerAd: BannerViewDelegate {
|
||||
|
||||
func bannerViewDidReceiveAd(_ bannerView: BannerView) {
|
||||
self.delegate?.bannerAdDidLoadFinish?(bannerAd: self)
|
||||
}
|
||||
|
||||
func bannerView(_ bannerView: BannerView, didFailToReceiveAdWithError error: Error) {
|
||||
self.delegate?.bannerAd?(bannerAd: self, didLoadFail: error)
|
||||
}
|
||||
|
||||
func bannerViewDidRecordClick(_ bannerView: BannerView) {
|
||||
self.delegate?.bannerAdDidClick?(ad: self)
|
||||
}
|
||||
|
||||
func bannerViewDidRecordImpression(_ bannerView: BannerView) {
|
||||
}
|
||||
|
||||
func bannerViewWillPresentScreen(_ bannerView: BannerView) {
|
||||
self.delegate?.bannerAdDidShow?(bannerAd: self)
|
||||
}
|
||||
|
||||
func bannerViewWillDismissScreen(_ bannerView: BannerView) {
|
||||
}
|
||||
|
||||
func bannerViewDidDismissScreen(_ bannerView: BannerView) {
|
||||
self.delegate?.bannerAdDidDismiss?(bannerAd: self)
|
||||
}
|
||||
}
|
@ -1,91 +0,0 @@
|
||||
//
|
||||
// SPApplovinBannerAd.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import AppLovinSDK
|
||||
|
||||
class SPApplovinBannerAd: NSObject, SPBannerAd {
|
||||
|
||||
let size = CGSize.init(width: kSPScreenWidth, height: 59)
|
||||
|
||||
var delegate: (any SPBannerAdDelegate)?
|
||||
|
||||
///是否加载过
|
||||
private var isLoaded = false
|
||||
|
||||
private(set) lazy var _adView: MAAdView = {
|
||||
let view = MAAdView(adUnitIdentifier: adUnitID)
|
||||
view.frame = .init(x: 0, y: 0, width: size.width, height: size.height)
|
||||
view.delegate = self
|
||||
return view
|
||||
}()
|
||||
|
||||
var adView: UIView {
|
||||
return _adView
|
||||
}
|
||||
|
||||
var adPlatformKey: String {
|
||||
return SPAdPlatformKey.applovin.rawValue
|
||||
}
|
||||
|
||||
var adUnitID: String {
|
||||
return SPAdManager.manager.applovin_bannerAdUnitID
|
||||
}
|
||||
|
||||
func loadAd() {
|
||||
_adView.loadAd()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- MAAdViewAdDelegate --------------
|
||||
extension SPApplovinBannerAd: MAAdViewAdDelegate {
|
||||
func didExpand(_ ad: MAAd) {
|
||||
|
||||
}
|
||||
|
||||
func didCollapse(_ ad: MAAd) {
|
||||
|
||||
}
|
||||
|
||||
func didLoad(_ ad: MAAd) {
|
||||
if !isLoaded {
|
||||
isLoaded = true
|
||||
self.delegate?.bannerAdDidLoadFinish?(bannerAd: self)
|
||||
}
|
||||
}
|
||||
|
||||
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError) {
|
||||
if !isLoaded {
|
||||
isLoaded = true
|
||||
let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||
self.delegate?.bannerAd?(bannerAd: self, didLoadFail: nsError)
|
||||
}
|
||||
}
|
||||
|
||||
func didDisplay(_ ad: MAAd) {
|
||||
self.delegate?.bannerAdDidShow?(bannerAd: self)
|
||||
}
|
||||
|
||||
func didHide(_ ad: MAAd) {
|
||||
self.delegate?.bannerAdDidDismiss?(bannerAd: self)
|
||||
}
|
||||
|
||||
func didClick(_ ad: MAAd) {
|
||||
self.delegate?.bannerAdDidClick?(ad: self)
|
||||
}
|
||||
|
||||
func didFail(toDisplay ad: MAAd, withError error: MAError) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -1,139 +0,0 @@
|
||||
//
|
||||
// SPBannerAdManager.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GoogleMobileAds
|
||||
|
||||
|
||||
|
||||
@objc protocol SPBannerAdManagerDelegate: NSObjectProtocol {
|
||||
///广告加载失败
|
||||
@objc optional func bannerAdManager(adManager: SPBannerAdManager, didLoadFail error: Error)
|
||||
///广告加载成功
|
||||
@objc optional func bannerAdManagerDidLoadFinish(adManager: SPBannerAdManager)
|
||||
///广告被展示
|
||||
@objc optional func bannerAdManagerDidShow(adManager: SPBannerAdManager)
|
||||
///广告被关闭
|
||||
@objc optional func bannerAdManagerDidDismiss(adManager: SPBannerAdManager)
|
||||
}
|
||||
|
||||
|
||||
@objc protocol SPBannerAdDelegate: NSObjectProtocol {
|
||||
///广告加载失败
|
||||
@objc optional func bannerAd(bannerAd: SPBannerAd, didLoadFail error: Error)
|
||||
///广告加载成功
|
||||
@objc optional func bannerAdDidLoadFinish(bannerAd: SPBannerAd)
|
||||
///广告被展示
|
||||
@objc optional func bannerAdDidShow(bannerAd: SPBannerAd)
|
||||
///广告被关闭
|
||||
@objc optional func bannerAdDidDismiss(bannerAd: SPBannerAd)
|
||||
///广告被点击
|
||||
@objc optional func bannerAdDidClick(ad: SPBannerAd)
|
||||
}
|
||||
|
||||
@objc protocol SPBannerAd: NSObjectProtocol {
|
||||
|
||||
weak var delegate: SPBannerAdDelegate? { get set }
|
||||
|
||||
var adView: UIView { get }
|
||||
|
||||
var adPlatformKey: String { get }
|
||||
|
||||
var adUnitID: String { get }
|
||||
|
||||
func loadAd()
|
||||
|
||||
}
|
||||
|
||||
class SPBannerAdManager: NSObject {
|
||||
|
||||
let adUnitID = SPAdManager.manager.admob_bannerAdUnitID
|
||||
|
||||
let size = CGSize.init(width: kSPScreenWidth, height: 59)
|
||||
|
||||
weak var delegate: SPBannerAdManagerDelegate?
|
||||
|
||||
var videoInfo: SPVideoInfoModel?
|
||||
|
||||
private lazy var bannerAd: SPBannerAd = {
|
||||
let ad = SPAdmobBannerAd()
|
||||
ad.delegate = self
|
||||
return ad
|
||||
}()
|
||||
|
||||
var view: UIView {
|
||||
return bannerAd.adView
|
||||
}
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
|
||||
bannerAd.loadAd()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- SPBannerAdDelegate --------------
|
||||
extension SPBannerAdManager: SPBannerAdDelegate {
|
||||
|
||||
///广告加载失败
|
||||
func bannerAd(bannerAd: SPBannerAd, didLoadFail error: Error) {
|
||||
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||
self.delegate?.bannerAdManager?(adManager: self, didLoadFail: error)
|
||||
}
|
||||
///广告加载成功
|
||||
func bannerAdDidLoadFinish(bannerAd: SPBannerAd) {
|
||||
self.requestStatAd(type: "start", errorMsg: nil)
|
||||
self.delegate?.bannerAdManagerDidLoadFinish?(adManager: self)
|
||||
}
|
||||
///广告被展示
|
||||
func bannerAdDidShow(bannerAd: SPBannerAd) {
|
||||
self.delegate?.bannerAdManagerDidShow?(adManager: self)
|
||||
}
|
||||
///广告被关闭
|
||||
func bannerAdDidDismiss(bannerAd: SPBannerAd) {
|
||||
self.requestStatAd(type: "close", errorMsg: nil)
|
||||
self.delegate?.bannerAdManagerDidDismiss?(adManager: self)
|
||||
}
|
||||
|
||||
func bannerAdDidClick(ad: any SPBannerAd) {
|
||||
self.requestStatAd(type: "click", errorMsg: nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//MARK: -------------- 统计 --------------
|
||||
extension SPBannerAdManager {
|
||||
|
||||
func requestStatAd(type: String, errorMsg: String?) {
|
||||
guard self.view.superview != nil else { return }
|
||||
|
||||
let model = SPStatAdModel()
|
||||
model.type = type
|
||||
model.ads_id = adUnitID
|
||||
model.ad_platform_key = SPAdPlatformKey(rawValue: bannerAd.adPlatformKey)
|
||||
model.error_msg = errorMsg
|
||||
model.scene = .banner
|
||||
model.short_play_id = self.videoInfo?.short_play_id
|
||||
model.short_play_video_id = self.videoInfo?.short_play_video_id
|
||||
|
||||
SPStatAPI.requestStatAd(model: model)
|
||||
}
|
||||
|
||||
|
||||
@objc private func didEnterBackgroundNotification() {
|
||||
|
||||
self.requestStatAd(type: "Interrupt", errorMsg: nil)
|
||||
}
|
||||
}
|
||||
|
@ -1,141 +0,0 @@
|
||||
//
|
||||
// SPAdManager+admob.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/9.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GoogleMobileAds
|
||||
|
||||
extension SPRewardedAdManager {
|
||||
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var admob_rewardedAd: Int?
|
||||
static var admob_needShowRewardedAd: Int?
|
||||
static var admob_isLoadingRewardedAd: Int?
|
||||
}
|
||||
|
||||
var admob_rewardedAd: RewardedAd? {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.admob_rewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &AssociatedKeys.admob_rewardedAd) as? RewardedAd
|
||||
}
|
||||
}
|
||||
///广告是否在加载中
|
||||
var admob_isLoadingRewardedAd: Bool {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.admob_isLoadingRewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return (objc_getAssociatedObject(self, &AssociatedKeys.admob_isLoadingRewardedAd) as? Bool) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
///是否需要展示广告,true广告加载完成会直接展示广告
|
||||
private var admob_needShowRewardedAd: Bool {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.admob_needShowRewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return (objc_getAssociatedObject(self, &AssociatedKeys.admob_needShowRewardedAd) as? Bool) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
func admob_isReady() -> Bool {
|
||||
return admob_rewardedAd != nil ? true : false
|
||||
}
|
||||
|
||||
///加载并展示广告
|
||||
func admob_loadAndShowRewardedAd(adInfo: SPAdInfo) {
|
||||
self.admob_needShowRewardedAd = true
|
||||
|
||||
if self.admob_isLoadingRewardedAd {
|
||||
return
|
||||
}
|
||||
|
||||
if self.admob_rewardedAd != nil {
|
||||
self.admob_show()
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
admob_loadRewardedAd(adInfo: adInfo)
|
||||
}
|
||||
|
||||
func admob_loadRewardedAd(adInfo: SPAdInfo) {
|
||||
guard !self.admob_isLoadingRewardedAd else { return }
|
||||
|
||||
#if DEBUG
|
||||
adInfo.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
|
||||
#endif
|
||||
|
||||
let adUnitID = adInfo.ads_id ?? ""
|
||||
|
||||
|
||||
let request = Request()
|
||||
|
||||
self.admob_isLoadingRewardedAd = true
|
||||
RewardedAd.load(with: adUnitID, request: request) { [weak self] rewardedAd, error in
|
||||
guard let self = self else { return }
|
||||
self.admob_isLoadingRewardedAd = false
|
||||
|
||||
if let error = error {
|
||||
self.admob_needShowRewardedAd = false
|
||||
self.loadFailHandler(error: error)
|
||||
return
|
||||
}
|
||||
self.loadFinishHandler()
|
||||
|
||||
self.admob_rewardedAd = rewardedAd
|
||||
self.admob_rewardedAd?.fullScreenContentDelegate = self
|
||||
|
||||
if self.admob_needShowRewardedAd {
|
||||
self.admob_show()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///展示广告
|
||||
private func admob_show() {
|
||||
guard let rewardedAd = admob_rewardedAd, self.admob_needShowRewardedAd else {
|
||||
return
|
||||
}
|
||||
self.admob_needShowRewardedAd = false
|
||||
|
||||
// The UIViewController parameter is an optional.
|
||||
rewardedAd.present(from: nil) { [weak self] in
|
||||
self?.userDidEarnRewardHandler()
|
||||
// TODO: Reward the user.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension SPRewardedAdManager: FullScreenContentDelegate {
|
||||
|
||||
/// Tells the delegate that the ad failed to present full screen content.
|
||||
func ad(_ ad: FullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
|
||||
self.admob_rewardedAd = nil
|
||||
self.admob_needShowRewardedAd = false
|
||||
self.displayFailHandler(error: error)
|
||||
}
|
||||
|
||||
/// Tells the delegate that the ad will present full screen content.
|
||||
func adWillPresentFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||
self.didShowHandler()
|
||||
}
|
||||
|
||||
/// Tells the delegate that the ad dismissed full screen content.
|
||||
func adDidDismissFullScreenContent(_ ad: FullScreenPresentingAd) {
|
||||
self.admob_rewardedAd = nil
|
||||
self.didDismissHandler()
|
||||
|
||||
}
|
||||
|
||||
func adDidRecordClick(_ ad: any FullScreenPresentingAd) {
|
||||
self.didClickHandler()
|
||||
}
|
||||
}
|
@ -1,155 +0,0 @@
|
||||
//
|
||||
// SPAdManager+AppLovin.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/10.
|
||||
//
|
||||
|
||||
#if canImport(AppLovinSDK)
|
||||
import AppLovinSDK
|
||||
#endif
|
||||
|
||||
|
||||
extension SPRewardedAdManager {
|
||||
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var appLovin_rewardedAd: Int?
|
||||
static var appLovin_needShowRewardedAd: Int?
|
||||
static var appLovin_isLoadingRewardedAd: Int?
|
||||
}
|
||||
|
||||
#if canImport(AppLovinSDK)
|
||||
private var appLovin_rewardedAd: MARewardedAd? {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.appLovin_rewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return objc_getAssociatedObject(self, &AssociatedKeys.appLovin_rewardedAd) as? MARewardedAd
|
||||
}
|
||||
}
|
||||
|
||||
///是否需要展示广告,true广告加载完成会直接展示广告
|
||||
private var appLovin_needShowRewardedAd: Bool {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.appLovin_needShowRewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return (objc_getAssociatedObject(self, &AssociatedKeys.appLovin_needShowRewardedAd) as? Bool) ?? false
|
||||
}
|
||||
}
|
||||
|
||||
///广告是否在加载中
|
||||
var appLovin_isLoadingRewardedAd: Bool {
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.appLovin_isLoadingRewardedAd, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
get {
|
||||
return (objc_getAssociatedObject(self, &AssociatedKeys.appLovin_isLoadingRewardedAd) as? Bool) ?? false
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
func appLovin_isReady() -> Bool {
|
||||
#if canImport(AppLovinSDK)
|
||||
return appLovin_rewardedAd?.isReady ?? false
|
||||
#else
|
||||
return false
|
||||
#endif
|
||||
}
|
||||
|
||||
///加载激励广告
|
||||
func appLovin_loadRewardedAd(adInfo: SPAdInfo) {
|
||||
|
||||
#if canImport(AppLovinSDK)
|
||||
if self.appLovin_isLoadingRewardedAd { return }
|
||||
self.appLovin_isLoadingRewardedAd = true
|
||||
|
||||
|
||||
self.appLovin_rewardedAd = MARewardedAd.shared(withAdUnitIdentifier: adInfo.ads_id ?? "")
|
||||
self.appLovin_rewardedAd?.delegate = self
|
||||
self.appLovin_rewardedAd?.load()
|
||||
#endif
|
||||
}
|
||||
|
||||
///加载并展示广告
|
||||
func appLovin_loadAndShowRewardedAd(adInfo: SPAdInfo) {
|
||||
#if canImport(AppLovinSDK)
|
||||
self.appLovin_needShowRewardedAd = true
|
||||
|
||||
if appLovin_rewardedAd?.isReady == true {
|
||||
self.appLovin_show()
|
||||
} else {
|
||||
appLovin_loadRewardedAd(adInfo: adInfo)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
///展示广告
|
||||
private func appLovin_show() {
|
||||
#if canImport(AppLovinSDK)
|
||||
if appLovin_rewardedAd?.isReady == true, self.appLovin_needShowRewardedAd {
|
||||
self.appLovin_needShowRewardedAd = false
|
||||
appLovin_rewardedAd?.show()
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#if canImport(AppLovinSDK)
|
||||
//MARK: -------------- MARewardedAdDelegate --------------
|
||||
extension SPRewardedAdManager: MARewardedAdDelegate {
|
||||
|
||||
func didLoad(_ ad: MAAd)
|
||||
{
|
||||
self.appLovin_isLoadingRewardedAd = false
|
||||
|
||||
loadFinishHandler()
|
||||
|
||||
appLovin_show()
|
||||
|
||||
}
|
||||
|
||||
func didFailToLoadAd(forAdUnitIdentifier adUnitIdentifier: String, withError error: MAError)
|
||||
{
|
||||
self.appLovin_isLoadingRewardedAd = false
|
||||
|
||||
let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||
loadFailHandler(error: nsError)
|
||||
}
|
||||
|
||||
func didDisplay(_ ad: MAAd) {
|
||||
self.didShowHandler()
|
||||
}
|
||||
|
||||
func didClick(_ ad: MAAd) {
|
||||
self.didClickHandler()
|
||||
}
|
||||
|
||||
func didHide(_ ad: MAAd)
|
||||
{
|
||||
self.didDismissHandler()
|
||||
}
|
||||
|
||||
func didFail(toDisplay ad: MAAd, withError error: MAError)
|
||||
{
|
||||
// Rewarded ad failed to display. AppLovin recommends that you load the next ad.
|
||||
self.appLovin_isLoadingRewardedAd = false
|
||||
// appLovin_loadRewardedAd()
|
||||
|
||||
let nsError = NSError(domain: error.message, code: error.code.rawValue)
|
||||
displayFailHandler(error: nsError)
|
||||
}
|
||||
|
||||
|
||||
func didRewardUser(for ad: MAAd, with reward: MAReward)
|
||||
{
|
||||
// Rewarded ad was displayed and user should receive the reward
|
||||
self.userDidEarnRewardHandler()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
#endif
|
@ -1,321 +0,0 @@
|
||||
//
|
||||
// SPRewardedAdManager.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc protocol SPRewardedAdManagerDelegate: NSObjectProtocol {
|
||||
///发放奖励
|
||||
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, userDidEarnReward adInfo: SPAdInfo)
|
||||
///广告加载失败
|
||||
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didLoadFail error: Error)
|
||||
///广告加载成功
|
||||
@objc optional func rewardedAdManagerDidLoadFinish(manager: SPRewardedAdManager)
|
||||
///广告展示失败
|
||||
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didDisplayFail error: Error)
|
||||
///广告被展示
|
||||
@objc optional func rewardedAdManagerDidShow(manager: SPRewardedAdManager)
|
||||
///广告被关闭
|
||||
@objc optional func rewardedAdManager(manager: SPRewardedAdManager, didDismiss adInfo: SPAdInfo)
|
||||
}
|
||||
|
||||
class SPRewardedAdManager: NSObject {
|
||||
|
||||
static let manager = SPRewardedAdManager()
|
||||
|
||||
weak var delegate: SPRewardedAdManagerDelegate?
|
||||
|
||||
private(set) var isLoadingRewardedAd = false
|
||||
|
||||
///重试等待时长
|
||||
private var retryAttempt = 0.0
|
||||
///重试次数
|
||||
private var retryCount = 0
|
||||
///最大重试次数
|
||||
private let retryMaxCount = 1
|
||||
///广告激活状态
|
||||
private(set) var isEnable = true
|
||||
|
||||
private(set) var adInfo: SPAdInfo?
|
||||
|
||||
private(set) var isShowLoading = false
|
||||
private(set) var isShowToast = false
|
||||
|
||||
private var adsDate: Date?
|
||||
///统计场景
|
||||
var statScene: SPStatAdModel.AdScene?
|
||||
var videoInfo: SPVideoInfoModel?
|
||||
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(didEnterBackgroundNotification), name: UIApplication.didEnterBackgroundNotification, object: nil)
|
||||
}
|
||||
|
||||
func isAdAvailable() -> Bool {
|
||||
guard let adInfo = adInfo else { return false }
|
||||
if adInfo.platform_key == .google {
|
||||
return admob_isReady()
|
||||
} else if adInfo.platform_key == .applovin {
|
||||
return appLovin_isReady()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
///加载并展示激励广告
|
||||
func loadAndShowRewardedAd(isShowLoading: Bool = false, isShowToast: Bool = true) {
|
||||
guard isEnable else {
|
||||
let text = "movia_no_ads_tip".localized
|
||||
if isShowToast {
|
||||
self.showToast(text: text)
|
||||
}
|
||||
self.isShowToast = false
|
||||
self.isShowLoading = false
|
||||
let error = NSError(domain: text.localized, code: -1)
|
||||
loadFailHandler(isStat: false, error: error)
|
||||
return
|
||||
}
|
||||
|
||||
self.isShowLoading = isShowLoading
|
||||
self.isShowToast = isShowToast
|
||||
|
||||
if self.isShowLoading {
|
||||
SPHUD.show()
|
||||
}
|
||||
|
||||
guard !isLoadingRewardedAd else { return }
|
||||
if !isAdAvailable() {
|
||||
self.isLoadingRewardedAd = true
|
||||
}
|
||||
|
||||
self.requestAdInfo { [weak self] adInfo in
|
||||
guard let self = self else { return }
|
||||
|
||||
if adInfo.platform_key == .google {
|
||||
self.admob_loadAndShowRewardedAd(adInfo: adInfo)
|
||||
} else if adInfo.platform_key == .applovin {
|
||||
self.appLovin_loadAndShowRewardedAd(adInfo: adInfo)
|
||||
} else {
|
||||
self.isLoadingRewardedAd = false
|
||||
self.adInfo = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///预加载一个广告
|
||||
func preloadRewardedAd() {
|
||||
guard isEnable else { return }
|
||||
guard !isLoadingRewardedAd else { return }
|
||||
|
||||
isShowLoading = false
|
||||
isShowToast = false
|
||||
|
||||
self.isLoadingRewardedAd = true
|
||||
|
||||
self.requestAdInfo { [weak self] adInfo in
|
||||
guard let self = self else { return }
|
||||
if adInfo.platform_key == .google {
|
||||
self.admob_loadRewardedAd(adInfo: adInfo)
|
||||
} else if adInfo.platform_key == .applovin {
|
||||
self.appLovin_loadRewardedAd(adInfo: adInfo)
|
||||
} else {
|
||||
self.isLoadingRewardedAd = false
|
||||
self.adInfo = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///重试加载广告
|
||||
private func retryLoadAd() {
|
||||
guard isEnable else { return }
|
||||
|
||||
guard retryCount < retryMaxCount else {
|
||||
retryCount = 0
|
||||
retryAttempt = 0
|
||||
return
|
||||
}
|
||||
|
||||
retryCount += 1
|
||||
retryAttempt += 1
|
||||
let delaySec = pow(2.0, min(6.0, retryAttempt))
|
||||
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + delaySec) { [weak self] in
|
||||
self?.preloadRewardedAd()
|
||||
}
|
||||
}
|
||||
|
||||
private func clean() {
|
||||
self.statScene = nil
|
||||
self.videoInfo = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//MARK: -------------- 广告内部调用(事件回调) --------------
|
||||
extension SPRewardedAdManager {
|
||||
|
||||
///奖励发放回调
|
||||
func userDidEarnRewardHandler() {
|
||||
guard let adInfo = adInfo else { return }
|
||||
self.delegate?.rewardedAdManager?(manager: self, userDidEarnReward: adInfo)
|
||||
self.requestStatAd(type: "reward", errorMsg: nil)
|
||||
}
|
||||
|
||||
///广告加载失败
|
||||
func loadFailHandler(isStat: Bool = true, error: Error) {
|
||||
|
||||
if isShowLoading {
|
||||
SPHUD.dismiss()
|
||||
}
|
||||
if isShowToast {
|
||||
self.showToast()
|
||||
}
|
||||
self.isLoadingRewardedAd = false
|
||||
self.delegate?.rewardedAdManager?(manager: self, didLoadFail: error)
|
||||
if isStat {
|
||||
self.requestStatAd(type: "load_failed", errorMsg: error.localizedDescription)
|
||||
}
|
||||
|
||||
self.clean()
|
||||
|
||||
if self.adInfo?.platform_key != .google {//谷歌广告兜底
|
||||
self.isLoadingRewardedAd = true
|
||||
let adInfo = SPAdInfo()
|
||||
adInfo.platform_key = .google
|
||||
adInfo.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
|
||||
self.adInfo = adInfo
|
||||
self.admob_loadRewardedAd(adInfo: adInfo)
|
||||
|
||||
} else {
|
||||
self.isEnable = false
|
||||
self.retryLoadAd()
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
///广告加载成功
|
||||
func loadFinishHandler() {
|
||||
self.retryAttempt = 0
|
||||
self.retryCount = 0
|
||||
self.isLoadingRewardedAd = false
|
||||
self.delegate?.rewardedAdManagerDidLoadFinish?(manager: self)
|
||||
}
|
||||
|
||||
///广告展示失败
|
||||
func displayFailHandler(error: Error) {
|
||||
if isShowLoading {
|
||||
SPHUD.dismiss()
|
||||
}
|
||||
if isShowToast {
|
||||
self.showToast()
|
||||
}
|
||||
self.delegate?.rewardedAdManager?(manager: self, didDisplayFail: error)
|
||||
self.requestStatAd(type: "show_failed", errorMsg: error.localizedDescription)
|
||||
|
||||
self.clean()
|
||||
}
|
||||
|
||||
///广告被展示
|
||||
func didShowHandler() {
|
||||
self.adsDate = Date()
|
||||
|
||||
if isShowLoading {
|
||||
SPHUD.dismiss()
|
||||
}
|
||||
self.delegate?.rewardedAdManagerDidShow?(manager: self)
|
||||
|
||||
self.requestStatAd(type: "start", errorMsg: nil)
|
||||
}
|
||||
///广告被关闭
|
||||
func didDismissHandler() {
|
||||
let adInfo = self.adInfo
|
||||
|
||||
var seconds = 0
|
||||
if let adsDate = self.adsDate {
|
||||
seconds = Int(Date().timeIntervalSince(adsDate))
|
||||
}
|
||||
|
||||
self.requestStatAd(type: "close", seconds: seconds, errorMsg: nil) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
if let adInfo = adInfo {
|
||||
self.delegate?.rewardedAdManager?(manager: self, didDismiss: adInfo)
|
||||
}
|
||||
|
||||
}
|
||||
self.clean()
|
||||
self.preloadRewardedAd()
|
||||
|
||||
}
|
||||
|
||||
///广告被点击
|
||||
func didClickHandler() {
|
||||
var seconds = 0
|
||||
if let adsDate = self.adsDate {
|
||||
seconds = Int(Date().timeIntervalSince(adsDate))
|
||||
}
|
||||
|
||||
self.requestStatAd(type: "click", seconds: seconds, errorMsg: nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPRewardedAdManager {
|
||||
|
||||
private func requestStatAd(type: String, seconds: Int = 0, errorMsg: String?, completer: (() -> Void)? = nil) {
|
||||
guard let adInfo = adInfo else { return }
|
||||
|
||||
let model = SPStatAdModel()
|
||||
model.type = type
|
||||
model.ads_id = adInfo.ads_id
|
||||
model.view_seconds = seconds
|
||||
model.ad_platform_key = adInfo.platform_key
|
||||
model.error_msg = errorMsg
|
||||
model.scene = self.statScene
|
||||
model.short_play_id = self.videoInfo?.short_play_id
|
||||
model.short_play_video_id = self.videoInfo?.short_play_video_id
|
||||
|
||||
SPStatAPI.requestStatAd(model: model, completer: completer)
|
||||
}
|
||||
|
||||
|
||||
@objc private func didEnterBackgroundNotification() {
|
||||
if self.statScene == nil { return }
|
||||
|
||||
self.requestStatAd(type: "Interrupt", seconds: 0, errorMsg: nil)
|
||||
}
|
||||
|
||||
func showToast(text: String? = "movia_no_ads_tip".localized) {
|
||||
SPToast.show(text: text)
|
||||
}
|
||||
|
||||
|
||||
private func requestAdInfo(completer: ((_ adInfo: SPAdInfo) -> Void)?) {
|
||||
|
||||
if let adInfo = self.adInfo {
|
||||
completer?(adInfo)
|
||||
return
|
||||
}
|
||||
SPAdAPI.requestShowAdInfo { [weak self] adInfo in
|
||||
guard let self = self else { return }
|
||||
|
||||
if let adInfo = adInfo {
|
||||
self.adInfo = adInfo
|
||||
} else {
|
||||
self.adInfo = SPAdInfo()
|
||||
self.adInfo?.platform_key = .google
|
||||
self.adInfo?.ads_id = SPAdManager.manager.admob_rewardedAdUnitID
|
||||
}
|
||||
completer?(self.adInfo!)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
//
|
||||
// SPAdInfo.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/9.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
|
||||
enum SPAdPlatformKey: String, SmartCaseDefaultable {
|
||||
case google = "google"
|
||||
case applovin = "applovin"
|
||||
}
|
||||
|
||||
class SPAdDataModel: SPModel, SmartCodable {
|
||||
var ad: SPAdInfo?
|
||||
}
|
||||
|
||||
class SPAdInfo: SPModel, SmartCodable {
|
||||
|
||||
|
||||
var id: String?
|
||||
var platform_name: String?
|
||||
var ads_id: String?
|
||||
var status: String?
|
||||
var platform_key: SPAdPlatformKey?
|
||||
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
//
|
||||
// SPAdManager.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/9.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import GoogleMobileAds
|
||||
#if canImport(AppLovinSDK)
|
||||
import AppLovinSDK
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
class SPAdManager: NSObject {
|
||||
|
||||
static let manager = SPAdManager()
|
||||
|
||||
/// AppLovinSDK 初始化完成回调
|
||||
private var appLovininitializeCompleter: (() -> Void)?
|
||||
|
||||
func start() {
|
||||
//初始化admob
|
||||
MobileAds.shared.start()
|
||||
|
||||
|
||||
initialize_applovinSdk(completer: nil)
|
||||
}
|
||||
|
||||
///初始化AppLovinSDK
|
||||
func initialize_applovinSdk(completer: (() -> Void)? = nil) {
|
||||
if completer != nil {
|
||||
self.appLovininitializeCompleter = completer
|
||||
}
|
||||
#if canImport(AppLovinSDK)
|
||||
if !ALSdk.shared().isInitialized {
|
||||
//初始化
|
||||
let initConfig = ALSdkInitializationConfiguration(sdkKey: "XW2aulJv9urKD4MIIFT1xcSCuyTHaDZ9qUbDqygnTLS04GkdX7WMQJviGP5vDRWGsk4OJJIyLGRV3mbLqOWx0W") { builder in
|
||||
builder.mediationProvider = ALMediationProviderMAX
|
||||
//#if DEBUG
|
||||
// builder.testDeviceAdvertisingIdentifiers = [JXUUID.idfa()]
|
||||
//#endif
|
||||
}
|
||||
|
||||
ALSdk.shared().initialize(with: initConfig) { sdkConfig in
|
||||
// Start loading ads
|
||||
self.appLovininitializeCompleter?()
|
||||
}
|
||||
} else {
|
||||
self.appLovininitializeCompleter?()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- 单元ID --------------
|
||||
extension SPAdManager {
|
||||
|
||||
///谷歌激励广告单元ID
|
||||
var admob_rewardedAdUnitID: String {
|
||||
//#if DEBUG
|
||||
// return "ca-app-pub-3940256099942544/1712485313"
|
||||
//#else
|
||||
//#endif
|
||||
return "ca-app-pub-5209443898911659/3535954087"
|
||||
}
|
||||
|
||||
///开屏广告的单元ID
|
||||
var admob_appOpenAdUnitID: String {
|
||||
//#if DEBUG
|
||||
// return "ca-app-pub-3940256099942544/5575463023"
|
||||
//#else
|
||||
//#endif
|
||||
return "ca-app-pub-5209443898911659/3886651330"
|
||||
}
|
||||
///横幅广告单元ID
|
||||
var admob_bannerAdUnitID: String {
|
||||
//#if DEBUG
|
||||
// return "ca-app-pub-3940256099942544/2435281174"
|
||||
//#else
|
||||
//#endif
|
||||
return "ca-app-pub-5209443898911659/8858726666"
|
||||
}
|
||||
|
||||
///开屏广告的单元ID
|
||||
var applovin_appOpenAdUnitID: String {
|
||||
return ""
|
||||
}
|
||||
///横幅广告单元ID
|
||||
var applovin_bannerAdUnitID: String {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,29 +0,0 @@
|
||||
//
|
||||
// SPStatAdModel.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class SPStatAdModel: SPModel, SmartCodable {
|
||||
|
||||
enum AdScene: String, SmartCaseDefaultable {
|
||||
case detail = "detail"
|
||||
case me = "me"
|
||||
case reward = "reward"
|
||||
case splash = "splash"
|
||||
case banner = "banner"
|
||||
}
|
||||
|
||||
var type: String? //start click error click show_failed load_failed Interrupt(退到后台) close
|
||||
var ads_id: String?
|
||||
var view_seconds: Int?
|
||||
var ad_platform_key: SPAdPlatformKey?
|
||||
var scene: AdScene? // splash reward banner detail me turntable
|
||||
var short_play_id: String?
|
||||
var short_play_video_id: String?
|
||||
var error_msg: String?
|
||||
}
|
@ -1,169 +0,0 @@
|
||||
//
|
||||
// SPVersionUpdateAlertView.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/6/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class SPVersionUpdateAlertView: SPAlertView {
|
||||
|
||||
private var model: SPVersionUpdateModel
|
||||
|
||||
private lazy var bgImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "alert_bg_image_03"))
|
||||
imageView.isUserInteractionEnabled = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var closeButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "close_icon_02"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleCloseButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var versionContainerView: UIView = {
|
||||
let view = UIView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var versionTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 18)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.text = "movia_updatenowtitle".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var versionBgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = .colorFF3232()
|
||||
view.layer.cornerRadius = 9
|
||||
view.layer.masksToBounds = true
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var versionLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 12)
|
||||
label.textColor = .colorFFFFFF()
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var desLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 14)
|
||||
label.textColor = .colorA8B8C3()
|
||||
label.numberOfLines = 0
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var button: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.backgroundColor = .colorFF3232()
|
||||
button.setTitle("movia_updatenow".localized, for: .normal)
|
||||
button.setTitleColor(.colorFFFFFF(), for: .normal)
|
||||
button.titleLabel?.font = .fontMedium(ofSize: 16)
|
||||
button.layer.cornerRadius = 21
|
||||
button.layer.masksToBounds = true
|
||||
button.addTarget(self, action: #selector(handleButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
init(model: SPVersionUpdateModel) {
|
||||
self.model = model
|
||||
super.init(frame: .zero)
|
||||
versionLabel.text = "v\(model.version_name ?? "")"
|
||||
desLabel.text = model.des?.localized
|
||||
|
||||
sp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func handleCloseButton() {
|
||||
self.dismiss()
|
||||
}
|
||||
|
||||
@objc private func handleButton() {
|
||||
self.dismiss()
|
||||
guard let url = URL(string: kSPAppleDownloadPath) else { return }
|
||||
let application = UIApplication.shared
|
||||
if application.canOpenURL(url) {
|
||||
application.open(url)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPVersionUpdateAlertView {
|
||||
|
||||
private func sp_setupUI() {
|
||||
self.addSubview(contentView)
|
||||
contentView.addSubview(bgImageView)
|
||||
contentView.addSubview(closeButton)
|
||||
contentView.addSubview(versionContainerView)
|
||||
versionContainerView.addSubview(versionTitleLabel)
|
||||
versionContainerView.addSubview(versionBgView)
|
||||
versionBgView.addSubview(versionLabel)
|
||||
bgImageView.addSubview(desLabel)
|
||||
bgImageView.addSubview(button)
|
||||
|
||||
contentView.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
}
|
||||
|
||||
bgImageView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(-24)
|
||||
// make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
closeButton.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalTo(bgImageView.snp.bottom).offset(22)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
versionContainerView.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(80)
|
||||
}
|
||||
|
||||
versionTitleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview()
|
||||
}
|
||||
|
||||
versionBgView.snp.makeConstraints { make in
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.height.equalTo(18)
|
||||
make.left.equalTo(versionTitleLabel.snp.right).offset(6)
|
||||
make.right.equalToSuperview()
|
||||
}
|
||||
|
||||
versionLabel.snp.makeConstraints { make in
|
||||
make.center.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(8)
|
||||
}
|
||||
|
||||
desLabel.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.right.lessThanOrEqualToSuperview().offset(-20)
|
||||
make.centerY.equalToSuperview().offset(5 + 12)
|
||||
}
|
||||
|
||||
button.snp.makeConstraints { make in
|
||||
make.centerX.equalToSuperview()
|
||||
make.width.equalTo(243)
|
||||
make.height.equalTo(42)
|
||||
make.bottom.equalToSuperview().offset(-32)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -12,10 +12,9 @@ class SPHUD: NSObject {
|
||||
SVProgressHUD.setDefaultMaskType(.clear)
|
||||
}
|
||||
|
||||
static func show(status: String? = nil, containerView: UIView? = nil) {
|
||||
SVProgressHUD.setContainerView(containerView)
|
||||
static func show() {
|
||||
SVProgressHUD.setDefaultMaskType(.clear)
|
||||
SVProgressHUD.show(withStatus: status)
|
||||
SVProgressHUD.show()
|
||||
}
|
||||
|
||||
static func dismiss() {
|
||||
|
@ -87,7 +87,6 @@ class SPLoginManager: NSObject {
|
||||
SPStatAPI.requestEnterApp()
|
||||
SPStatAPI.requestStatOnLine()
|
||||
completer?(true)
|
||||
NotificationCenter.default.post(name: SPLoginManager.userInfoUpdateNotification, object: nil)
|
||||
NotificationCenter.default.post(name: SPLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
} else {
|
||||
completer?(false)
|
||||
@ -108,7 +107,6 @@ class SPLoginManager: NSObject {
|
||||
SPStatAPI.requestEnterApp()
|
||||
SPStatAPI.requestStatOnLine()
|
||||
completer?(true)
|
||||
NotificationCenter.default.post(name: SPLoginManager.userInfoUpdateNotification, object: nil)
|
||||
NotificationCenter.default.post(name: SPLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
} else {
|
||||
completer?(false)
|
||||
@ -124,7 +122,6 @@ class SPLoginManager: NSObject {
|
||||
if let userInfo = userInfo {
|
||||
self.userInfo = userInfo
|
||||
UserDefaults.jx_setObject(userInfo, forKey: kSPLoginUserInfoDefaultsKey)
|
||||
NotificationCenter.default.post(name: SPLoginManager.userInfoUpdateNotification, object: nil)
|
||||
}
|
||||
completer?()
|
||||
}
|
||||
@ -169,7 +166,6 @@ extension SPLoginManager {
|
||||
SPStatAPI.requestEnterApp()
|
||||
SPStatAPI.requestStatOnLine()
|
||||
completer?(true)
|
||||
NotificationCenter.default.post(name: SPLoginManager.userInfoUpdateNotification, object: nil)
|
||||
NotificationCenter.default.post(name: SPLoginManager.loginStateDidChangeNotification, object: nil)
|
||||
}
|
||||
|
||||
@ -181,7 +177,5 @@ extension SPLoginManager {
|
||||
|
||||
///登录状态发生变化
|
||||
@objc static let loginStateDidChangeNotification = NSNotification.Name(rawValue: "SPLoginManager.loginStateDidChangeNotification")
|
||||
///用户信息更新
|
||||
@objc static let userInfoUpdateNotification = NSNotification.Name(rawValue: "SPLoginManager.userInfoUpdateNotification")
|
||||
|
||||
}
|
||||
|
@ -58,8 +58,6 @@ class SPPlayer: NSObject {
|
||||
weak var delegate: SPPlayerDelegate?
|
||||
|
||||
private(set) lazy var isPlaying = false
|
||||
///系统原因导致的暂停(来电话)
|
||||
private(set) lazy var systemPause = false
|
||||
private(set) lazy var playState: PlayState = .unknown
|
||||
private(set) lazy var loadState: LoadState = .unknown
|
||||
|
||||
@ -170,7 +168,6 @@ class SPPlayer: NSObject {
|
||||
}
|
||||
|
||||
func start() {
|
||||
self.systemPause = false
|
||||
self.isPlaying = true
|
||||
// if self.interruptionType != .began {
|
||||
// }
|
||||
@ -227,7 +224,7 @@ extension SPPlayer {
|
||||
guard let self = self else { return }
|
||||
if playState == .playStatePlaying && !isPlaying {
|
||||
self.pause()
|
||||
} else if playState == .playStatePaused, isPlaying, !self.systemPause {
|
||||
} else if playState == .playStatePaused, isPlaying, self.interruptionType != .began {
|
||||
self.start()
|
||||
}
|
||||
switch playState {
|
||||
@ -254,7 +251,7 @@ extension SPPlayer {
|
||||
guard let self = self else { return }
|
||||
if loadState == .playable && !isPlaying {
|
||||
self.pause()
|
||||
} else if loadState == .playable, isPlaying, self.player.playState != .playStatePlaying, !self.systemPause {
|
||||
} else if loadState == .playable, isPlaying, self.player.playState != .playStatePlaying, self.interruptionType != .began {
|
||||
self.start()
|
||||
}
|
||||
|
||||
@ -317,11 +314,9 @@ extension SPPlayer {
|
||||
guard let interruptionType = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt else { return }
|
||||
|
||||
self.interruptionType = AVAudioSession.InterruptionType(rawValue: interruptionType)
|
||||
if self.interruptionType == .began, self.isPlaying {
|
||||
self.systemPause = true
|
||||
if self.interruptionType == .began {
|
||||
self.player.pause()
|
||||
} else if self.interruptionType == .ended {
|
||||
self.systemPause = false
|
||||
} else {
|
||||
if self.isPlaying {
|
||||
self.player.play()
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SPIAPManager: NSObject {
|
||||
typealias CompletionHandler = ((_ finish: Bool) -> Void)
|
||||
@ -19,8 +18,6 @@ class SPIAPManager: NSObject {
|
||||
///成功回调
|
||||
private var completionHandler: CompletionHandler?
|
||||
|
||||
private var productListHandler: ((_ products: [SKProduct]) -> Void)?
|
||||
|
||||
private lazy var iapManager: JXIAPManager = {
|
||||
let manager = JXIAPManager()
|
||||
manager.delegate = self
|
||||
@ -122,17 +119,6 @@ class SPIAPManager: NSObject {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func requestProductList(productIdArr: [String], completer: ((_ products: [SKProduct]) -> Void)?) {
|
||||
self.productListHandler = completer
|
||||
self.iapManager.requestProductList(productIdArr: productIdArr)
|
||||
}
|
||||
|
||||
|
||||
func getProductId(templateId: String?) -> String? {
|
||||
guard let templateId = templateId else { return nil }
|
||||
return SPIAPManager.IAPPrefix + templateId
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -------------- JXIAPManagerDelegate --------------
|
||||
@ -196,13 +182,6 @@ extension SPIAPManager: JXIAPManagerDelegate {
|
||||
self.completionHandler?(false)
|
||||
}
|
||||
|
||||
func jx_iapPayGotProducts(products: [SKProduct]) {
|
||||
|
||||
self.productListHandler?(products)
|
||||
|
||||
self.productListHandler = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SPIAPManager {
|
||||
|
@ -1,101 +0,0 @@
|
||||
//
|
||||
// SPPayTemplateRequest.swift
|
||||
// ThimraTV
|
||||
//
|
||||
// Created by 长沙佳儿 on 2025/7/19.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import StoreKit
|
||||
|
||||
class SPPayTemplateRequest: NSObject {
|
||||
|
||||
private var oldTemplateModel: SPPayTemplateModel?
|
||||
|
||||
private var completerBlock: ((_ model: SPPayTemplateModel?) -> Void)?
|
||||
|
||||
private var isLoding = false
|
||||
private var isToast = false
|
||||
|
||||
|
||||
func requestProducts(isLoding: Bool = false, isToast: Bool = true, completer: ((_ model: SPPayTemplateModel?) -> Void)?) {
|
||||
self.completerBlock = completer
|
||||
self.isLoding = isLoding
|
||||
self.isToast = isToast
|
||||
|
||||
if isLoding {
|
||||
SPHUD.show()
|
||||
}
|
||||
|
||||
SPWalletAPI.requestPayTemplate(isToast: isToast) { [weak self] model in
|
||||
guard let self = self else { return }
|
||||
guard let model = model else {
|
||||
if isLoding {
|
||||
SPHUD.dismiss()
|
||||
}
|
||||
self.completerBlock?(nil)
|
||||
return
|
||||
}
|
||||
self.oldTemplateModel = model
|
||||
|
||||
var productIdArr: [String] = []
|
||||
model.list_sub_vip?.forEach { item in
|
||||
productIdArr.append(SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
model.list_coins?.forEach { item in
|
||||
productIdArr.append(SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? "")
|
||||
}
|
||||
|
||||
let set = Set(productIdArr)
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -------------- SKProductsRequestDelegate --------------
|
||||
extension SPPayTemplateRequest: SKProductsRequestDelegate {
|
||||
|
||||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||
if isLoding {
|
||||
SPHUD.dismiss()
|
||||
}
|
||||
|
||||
guard let templateModel = self.oldTemplateModel else { return }
|
||||
let products = response.products
|
||||
|
||||
var newCoinList: [SPPayTemplateItem] = []
|
||||
var newVipList: [SPPayTemplateItem] = []
|
||||
|
||||
templateModel.list_coins?.forEach { item in
|
||||
let productId = SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||
for product in products {
|
||||
if productId == product.productIdentifier {
|
||||
item.price = product.price.stringValue
|
||||
item.currency = product.priceLocale.currencySymbol
|
||||
newCoinList.append(item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
templateModel.list_sub_vip?.forEach { item in
|
||||
let productId = SPIAPManager.manager.getProductId(templateId: item.ios_template_id) ?? ""
|
||||
for product in products {
|
||||
if productId == product.productIdentifier {
|
||||
item.price = product.price.stringValue
|
||||
item.currency = product.priceLocale.currencySymbol
|
||||
newVipList.append(item)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
templateModel.list_coins = newCoinList
|
||||
templateModel.list_sub_vip = newVipList
|
||||
|
||||
DispatchQueue.main.async {
|
||||
self.completerBlock?(templateModel)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,11 +10,6 @@ import SmartCodable
|
||||
|
||||
class SPUserInfo: SPModel, SmartCodable, NSSecureCoding {
|
||||
|
||||
enum UserLevel: String, SmartCaseDefaultable {
|
||||
case normal = "normal"
|
||||
case ad = "ad"
|
||||
}
|
||||
|
||||
|
||||
var id: String?
|
||||
var customer_id: String?
|
||||
@ -33,7 +28,7 @@ class SPUserInfo: SPModel, SmartCodable, NSSecureCoding {
|
||||
var third_access_platform: String?
|
||||
var ip_address: String?
|
||||
var country_code: String?
|
||||
var user_level: UserLevel?
|
||||
var user_level: String?
|
||||
var avator: String?
|
||||
var sign_in_status: String?
|
||||
var registered_days: String?
|
||||
@ -51,28 +46,23 @@ class SPUserInfo: SPModel, SmartCodable, NSSecureCoding {
|
||||
|
||||
|
||||
func encode(with coder: NSCoder) {
|
||||
coder.encode(id, forKey: "id")
|
||||
coder.encode(customer_id, forKey: "customer_id")
|
||||
coder.encode(user_level?.rawValue, forKey: "user_level")
|
||||
coder.encode(is_vip, forKey: "is_vip")
|
||||
coder.encode(family_name, forKey: "family_name")
|
||||
coder.encode(giving_name, forKey: "giving_name")
|
||||
// coder.encode(id, forKey: "id")
|
||||
// coder.encode(phone, forKey: "phone")
|
||||
// coder.encode(userToken, forKey: "userToken")
|
||||
// coder.encode(ipAddress, forKey: "ipAddress")
|
||||
// coder.encode(audioNum, forKey: "audioNum")
|
||||
// coder.encode(audioSeconds, forKey: "audioSeconds")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init()
|
||||
|
||||
id = coder.decodeObject(of: NSString.self, forKey: "id") as? String
|
||||
customer_id = coder.decodeObject(of: NSString.self, forKey: "customer_id") as? String
|
||||
if let user_level = coder.decodeObject(of: NSString.self, forKey: "user_level") as? String {
|
||||
self.user_level = UserLevel(rawValue: user_level)
|
||||
}
|
||||
is_vip = coder.decodeObject(of: NSNumber.self, forKey: "is_vip")?.boolValue
|
||||
family_name = coder.decodeObject(of: NSString.self, forKey: "family_name") as? String
|
||||
giving_name = coder.decodeObject(of: NSString.self, forKey: "giving_name") as? String
|
||||
|
||||
// id = coder.decodeObject(of: NSString.self, forKey: "id") as? String
|
||||
// phone = coder.decodeObject(of: NSString.self, forKey: "phone") as? String
|
||||
// userToken = coder.decodeObject(of: NSString.self, forKey: "userToken") as? String
|
||||
// ipAddress = coder.decodeObject(of: NSString.self, forKey: "ipAddress") as? String
|
||||
// audioNum = coder.decodeObject(of: NSNumber.self, forKey: "audioNum")?.intValue
|
||||
// audioSeconds = coder.decodeObject(of: NSNumber.self, forKey: "audioSeconds")?.intValue
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 779 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.4 KiB |
@ -5,12 +5,10 @@
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.0 KiB |
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 658 B |
Before Width: | Height: | Size: 961 B |
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Vector@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Vector@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 331 B |
Before Width: | Height: | Size: 438 B |
@ -1,22 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "配图@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "配图.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 686 KiB |
Before Width: | Height: | Size: 326 KiB |
@ -29,628 +29,13 @@
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>FirebaseAppDelegateProxyEnabled</key>
|
||||
<false/>
|
||||
<key>GADApplicationIdentifier</key>
|
||||
<string>ca-app-pub-5209443898911659~1849745003</string>
|
||||
<key>ITSAppUsesNonExemptEncryption</key>
|
||||
<false/>
|
||||
<key>LSApplicationQueriesSchemes</key>
|
||||
<array>
|
||||
<string>fbapi</string>
|
||||
<string>fb-messenger-share-api</string>
|
||||
</array>
|
||||
<key>SKAdNetworkItems</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>22mmun2rn5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>238da6jt44.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>24t9a8vw3c.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>24zw6aqk47.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>252b5q8x7y.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>275upjj5gd.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>294l99pt4k.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>2fnua5tdw4.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>2u9pt9hc89.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>32z4fx6l9h.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>3l6bd9hu43.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>3qcr597p9d.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>3qy4746246.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>3rd42ekr43.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>3sh42y64q3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>424m5254lk.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4468km3ulz.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>44jx6755aq.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>44n7hlldy6.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>47vhws6wlr.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>488r3q3dtq.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4dzt52r2t5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4fzdc2evr5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4mn522wn87.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4pfyvq9l8r.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>4w7y6s5ca2.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>523jb4fst2.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>52fl2v3hgk.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>54nzkqm89y.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>578prtvx9j.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>5a6flpkh64.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>5l3tpt7t6e.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>5lm9lj6jb7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>5tjdwbrq8w.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>6964rsfnh4.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>6g9af3uyq4.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>6p4ks3rnbw.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>6v7lgmsu45.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>6xzpu9s2p8.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>737z793b9f.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>74b6s63p6l.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>79pbpufp6p.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>7fmhfwg9en.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>7rz58n8ntl.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>7ug5zh24hu.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>84993kbrcf.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>89z7zv988g.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>8c4e2ghe7u.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>8m87ys6875.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>8r8llnkz5a.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>8s468mfl3y.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>97r2b46745.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9b89h5y424.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9nlqeag3gk.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9rd848q2bz.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9t245vhmpl.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9vvzujtq5s.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>9yg77x724h.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>a2p9lx4jpn.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>a7xqa6mtl2.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>a8cz6cu7e5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>av6w8kgt66.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>b9bk5wbcq9.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>bxvub5ada5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>c3frkrj4fj.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>c6k4g5qg8m.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>cg4yq2srnc.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>cj5566h2ga.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>cp8zw746q7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>cs644xg564.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>cstr6suwn9.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>dbu4b84rxf.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>dkc879ngq3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>dzg6xy7pwj.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>e5fvkxwrpn.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ecpz2srf59.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>eh6m2bh4zr.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ejvt5qm6ak.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>f38h382jlk.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>f73kdq92p3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>f7s53z58qe.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>feyaarzu9v.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>g28c52eehv.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>g2y4y55b64.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>g6gcrrvk4p.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ggvn48r87g.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>glqzh8vgby.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>gta8lk7p23.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>gta9lk7p23.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>hb56zgv37p.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>hdw39hrw9y.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>hs6bdukanm.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>k674qkevps.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>kbd757ywx3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>kbmxgpxpgc.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>klf5c3l5u5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>krvm3zuq6h.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>lr83yxwka7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ludvb6z3bs.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>m297p6643m.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>m5mvw97r93.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>m8dbw4sv7c.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mj797d8u6f.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mlmmfzh3r3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mls7yz5dvl.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mp6xlyr22a.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mqn7fxpca7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>mtkv5xtk9e.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>n38lu8286q.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>n66cz3y3bx.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>n6fk4nfna4.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>n9x2a789qt.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ns5j362hk7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>nzq8sh4pbs.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>p78axxw29g.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ppxm28t8ap.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>prcb7njmu6.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>pwa73g5rt2.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>pwdxu55a5a.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>qqp299437r.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>qu637u8glc.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>r45fhb6rf7.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>rvh3l7un93.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>rx5hdcabgc.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>s39g8k73mm.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>s69wq72ugq.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>su67r6k2v3.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>t38b2kh725.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>tl55sbb4fm.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>u679fj5vs4.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>uw77j35x4d.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>v4nxqhlyqp.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>v72qych5uu.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>v79kvwwj4g.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>v9wttpbfk9.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>vcra2ehyfk.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>vhf287vqwu.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>vutu7akeur.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>w9q455wk68.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>wg4vff78zm.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>wzmmz9fp6w.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>x44k69ngh6.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>x5l83yy675.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>x8jxxk4ff5.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>x8uqf25wch.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>xga6mpmplv.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>xy9t38ct57.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>y45688jllp.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>y5ghdn5j9k.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>yclnxrl5pm.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>ydx93a7ass.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>zmvfpc5aq8.skadnetwork</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>SKAdNetworkIdentifier</key>
|
||||
<string>zq492l623r.skadnetwork</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>UIAppFonts</key>
|
||||
<array>
|
||||
<string>Inter-ExtraBold-5.otf</string>
|
||||
|
@ -87,7 +87,6 @@
|
||||
"movia_purchase_VIP" = "Purchase VIP";
|
||||
"movia_video_lock_tip_01" = "This episode is locked";
|
||||
"movia_video_lock_tip_02" = "Please unlock the previous episode";
|
||||
"movia_video_lock_tip_03" = "Unlock watching an ad";
|
||||
"movia_unlock_now_for" = "Unlock now for";
|
||||
"movia_Purchase_Single_Episode" = "Purchase Single Episode";
|
||||
"movia_Retry" = "Retry";
|
||||
@ -123,10 +122,6 @@
|
||||
"quarter_short_type" = "Quarterly ";
|
||||
"year_short_type" = "Yearly";
|
||||
"movia_profile_Bonus" = "Bonus";
|
||||
"movia_updatenowtitle" = "Discover a new version";
|
||||
"movia_updatenow" = "Update Now";
|
||||
"movia_no_short_found" = "No Short Found";
|
||||
"movia_no_ads_tip" = "Ad is on the way";
|
||||
|
||||
|
||||
"movia_vip_alert_text_01" = "Short Drama VIP Exclusive";
|
||||
|
105
ThimraTV/Thirdparty/JXIAPManager/JXIAPManager.swift
vendored
@ -10,7 +10,7 @@ import StoreKit
|
||||
|
||||
@objc protocol JXIAPManagerDelegate {
|
||||
/// 获取到可购买商品列表
|
||||
@objc optional func jx_iapPayGotProducts(products: [SKProduct])
|
||||
@objc optional func jx_iapPayGotProducts(productIds: [String])
|
||||
/// 购买成功
|
||||
@objc optional func jx_iapPaySuccess(productId: String, receipt: String, transactionIdentifier: String?)
|
||||
/// 购买失败
|
||||
@ -34,29 +34,19 @@ import StoreKit
|
||||
case cancelled
|
||||
///没有商品
|
||||
case noProduct
|
||||
|
||||
}
|
||||
|
||||
class JXIAPManager: NSObject {
|
||||
|
||||
enum OperationType {
|
||||
case idle
|
||||
case buy
|
||||
case request
|
||||
}
|
||||
|
||||
static let manager: JXIAPManager = JXIAPManager()
|
||||
|
||||
weak var delegate: JXIAPManagerDelegate?
|
||||
|
||||
///当前操作状态
|
||||
private var operationType = OperationType.idle
|
||||
|
||||
private var payment: SKPayment?
|
||||
|
||||
private var product: SKProduct?
|
||||
private var productId: String?
|
||||
|
||||
private var discount: SKPaymentDiscount?
|
||||
private var orderId: String?
|
||||
private var applicationUsername: String? {
|
||||
get {
|
||||
@ -90,47 +80,10 @@ class JXIAPManager: NSObject {
|
||||
SKPaymentQueue.default().add(self)
|
||||
}
|
||||
|
||||
func showCodeRedemption() {
|
||||
SKPaymentQueue.default().presentCodeRedemptionSheet()
|
||||
}
|
||||
|
||||
func requestProductList(productIdArr: [String]) {
|
||||
// guard self.operationType == .idle else { return }
|
||||
self.operationType = .request
|
||||
|
||||
let set = Set(productIdArr)
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
productsRequest.delegate = self
|
||||
productsRequest.start()
|
||||
}
|
||||
|
||||
// ///发起购买
|
||||
// func buyProduct(product: SKProduct, orderId: String, discount: SKPaymentDiscount? = nil) {
|
||||
// guard self.operationType == .idle else { return }
|
||||
// self.operationType = .buy
|
||||
//
|
||||
// self.product = product
|
||||
// self.orderId = orderId
|
||||
//
|
||||
// // 要购买商品,开个小票
|
||||
// let payment = SKMutablePayment(product: product)
|
||||
// payment.applicationUsername = applicationUsername
|
||||
// if let discount = discount {
|
||||
// payment.paymentDiscount = discount
|
||||
// }
|
||||
//
|
||||
// // 去收银台排队,准备购买
|
||||
// SKPaymentQueue.default().add(payment)
|
||||
// }
|
||||
|
||||
func start(productId: String, orderId: String, discount: SKPaymentDiscount? = nil) {
|
||||
guard self.operationType == .idle else { return }
|
||||
self.operationType = .buy
|
||||
|
||||
func start(productId: String, orderId: String) {
|
||||
self.product = nil
|
||||
self.productId = productId
|
||||
self.orderId = orderId
|
||||
self.discount = discount
|
||||
|
||||
let set = Set([productId])
|
||||
let productsRequest = SKProductsRequest(productIdentifiers: set)
|
||||
@ -145,13 +98,9 @@ class JXIAPManager: NSObject {
|
||||
// 要购买商品,开个小票
|
||||
let payment = SKMutablePayment(product: product)
|
||||
payment.applicationUsername = applicationUsername
|
||||
if let discount = self.discount {
|
||||
payment.paymentDiscount = discount
|
||||
self.discount = nil
|
||||
}
|
||||
spLog(message: payment.applicationUsername)
|
||||
|
||||
self.payment = payment
|
||||
|
||||
// 去收银台排队,准备购买
|
||||
SKPaymentQueue.default().add(payment)
|
||||
}
|
||||
@ -161,27 +110,18 @@ class JXIAPManager: NSObject {
|
||||
//MARK: -------------- SKProductsRequestDelegate --------------
|
||||
extension JXIAPManager: SKProductsRequestDelegate {
|
||||
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
|
||||
if self.operationType == .request {
|
||||
guard let product = response.products.first else {
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.jx_iapPayGotProducts?(products: response.products)
|
||||
}
|
||||
self.operationType = .idle
|
||||
} else if self.operationType == .buy {
|
||||
|
||||
guard let product = response.products.first else {
|
||||
DispatchQueue.main.async {
|
||||
if let productId = self.productId {
|
||||
self.productId = nil
|
||||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct)
|
||||
}
|
||||
if let productId = self.productId {
|
||||
self.productId = nil
|
||||
self.delegate?.jx_iapPayFailed?(productId: productId, code: .noProduct)
|
||||
}
|
||||
return
|
||||
}
|
||||
self.product = product
|
||||
|
||||
self.buyProduct()
|
||||
return
|
||||
}
|
||||
self.product = product
|
||||
|
||||
self.buyProduct()
|
||||
}
|
||||
}
|
||||
|
||||
@ -191,6 +131,7 @@ extension JXIAPManager: SKPaymentTransactionObserver {
|
||||
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
|
||||
|
||||
for transaction in transactions {
|
||||
spLog(message: "transactionState = \(transaction.transactionState)")
|
||||
switch transaction.transactionState {
|
||||
case .purchased:
|
||||
DispatchQueue.main.async {
|
||||
@ -230,21 +171,33 @@ extension JXIAPManager: SKPaymentTransactionObserver {
|
||||
|
||||
extension JXIAPManager {
|
||||
private func completeTransaction(transaction: SKPaymentTransaction) {
|
||||
//自动续费
|
||||
// if let _ = transaction.original, transaction.payment.applicationUsername == nil {
|
||||
// return
|
||||
// }
|
||||
//重新开通自动续费
|
||||
// if let _ = transaction.original, transaction.payment.applicationUsername != nil {
|
||||
// self.delegate?.jx_iapPayFailed?(productId: productId, code: .unknown)
|
||||
// return
|
||||
// }
|
||||
|
||||
spLog(message: "transactionDate = \(String(describing: transaction.transactionDate))")
|
||||
spLog(message: "nowDate = \(Date())")
|
||||
spLog(message: "productIdentifier = \(transaction.payment.productIdentifier)")
|
||||
|
||||
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
|
||||
self.productId = nil
|
||||
|
||||
guard let receiptURL = Bundle.main.appStoreReceiptURL else { return }
|
||||
let receiptData = NSData(contentsOf: receiptURL)
|
||||
guard let encodeStr = receiptData?.base64EncodedString(options: .endLineWithLineFeed) else { return }
|
||||
guard let transactionIdentifier = transaction.transactionIdentifier else { return }
|
||||
|
||||
|
||||
guard let productId = self.productId, productId == transaction.payment.productIdentifier else { return }
|
||||
self.operationType = .idle
|
||||
self.productId = nil
|
||||
self.delegate?.jx_iapPaySuccess?(productId: productId, receipt: encodeStr, transactionIdentifier: transactionIdentifier)
|
||||
|
||||
}
|
||||
|
||||
private func failedTransaction(transaction: SKPaymentTransaction) {
|
||||
self.operationType = .idle
|
||||
let error = transaction.error as? SKError
|
||||
guard let productId = self.productId else { return }
|
||||
self.productId = nil
|
||||
|
2
ThimraTV/Thirdparty/JXUUID/JXUUID.h
vendored
@ -15,6 +15,6 @@
|
||||
/**
|
||||
重新安装app后,会发生变化
|
||||
*/
|
||||
+ (nonnull NSString *)idfv;
|
||||
+ (nonnull NSString *)systemUUID;
|
||||
|
||||
@end
|
||||
|
2
ThimraTV/Thirdparty/JXUUID/JXUUID.m
vendored
@ -39,7 +39,7 @@ static NSString *const uuidKey = @"com.JXUUID";
|
||||
return idfa;
|
||||
}
|
||||
|
||||
+ (nonnull NSString *)idfv
|
||||
+ (nonnull NSString *)systemUUID
|
||||
{
|
||||
return [UIDevice currentDevice].identifierForVendor.UUIDString;
|
||||
}
|
||||
|