播放完成统计,播放时长上报,推动提示

This commit is contained in:
zeng 2025-05-09 10:09:10 +08:00
parent 94e047a0e9
commit b78bd95996
15 changed files with 169 additions and 27 deletions

View File

@ -19,12 +19,35 @@ extension AppDelegate {
center.delegate = self center.delegate = self
center.requestAuthorization(options: [.badge, .sound, .alert]) { grant, error in center.requestAuthorization(options: [.badge, .sound, .alert]) { grant, error in
if grant { if !grant {
// SPRewardsAPI.requestUploadOpenNotify(completer: nil) DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
if let date = UserDefaults.standard.object(forKey: kSPApnsAlertDefaultsKey) as? Date {
#if DEBUG
self.showApnsAlert()
#else
if date.sp_isToday {
self.showApnsAlert()
}
#endif
}
UserDefaults.standard.set(Date(), forKey: kSPApnsAlertDefaultsKey)
}
} }
} }
UIApplication.shared.registerForRemoteNotifications() UIApplication.shared.registerForRemoteNotifications()
} }
private func showApnsAlert() {
let alert = UIAlertController(title: nil, message: "kAlertMessage_03".localized, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Affirm".localized, style: .default, handler: { _ in
SPAPPTool.openApnsSetting()
}))
alert.addAction(UIAlertAction(title: "Cancel".localized, style: .cancel))
SPAPPTool.topViewController()?.present(alert, animated: true)
}
} }
extension AppDelegate: UNUserNotificationCenterDelegate { extension AppDelegate: UNUserNotificationCenterDelegate {

View File

@ -40,7 +40,12 @@ extension SceneDelegate {
static var hasOpenMessage = false static var hasOpenMessage = false
func handleOpenAppMessage(webpageURL: URL?) { func handleOpenAppMessage(webpageURL: URL?) {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self._handleOpenAppMessage(webpageURL: webpageURL)
}
}
private func _handleOpenAppMessage(webpageURL: URL?) {
//URL //URL
var statUrlStr: String? var statUrlStr: String?
var data: [String : Any]? var data: [String : Any]?
@ -85,6 +90,7 @@ extension SceneDelegate {
let vc = SPPlayerDetailViewController() let vc = SPPlayerDetailViewController()
vc.shortPlayId = shortPlayId vc.shortPlayId = shortPlayId
SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true) SPAPPTool.topViewController()?.navigationController?.pushViewController(vc, animated: true)
} }
} }

View File

@ -18,20 +18,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
self.registThirdparty(application, didFinishLaunchingWithOptions: launchOptions) self.registThirdparty(application, didFinishLaunchingWithOptions: launchOptions)
self.appConfig() self.appConfig()
///
registerAPNS()
/// ///
SPNetworkReachabilityManager.manager.startMonitoring() SPNetworkReachabilityManager.manager.startMonitoring()
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
let _ = JXIAPManager.manager let _ = JXIAPManager.manager
// SPLoginManager.manager.requestVisitorLogin(completer: nil) // SPLoginManager.manager.requestVisitorLogin(completer: nil)
SPLoginManager.manager.updateUserInfo(completer: nil) SPLoginManager.manager.updateUserInfo(completer: nil)
///
registerAPNS()
return true return true
} }

View File

@ -22,9 +22,9 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
window?.rootViewController = tabBarController window?.rootViewController = tabBarController
window?.makeKeyAndVisible() window?.makeKeyAndVisible()
if let webpageURL = session.stateRestorationActivity?.webpageURL { // if let webpageURL = session.stateRestorationActivity?.webpageURL {
handleOpenAppMessage(webpageURL: webpageURL) // handleOpenAppMessage(webpageURL: webpageURL)
} // }
//线 //线
timer = Timer.scheduledTimer(timeInterval: 60 * 10, target: self, selector: #selector(handleOnLine), userInfo: nil, repeats: true) timer = Timer.scheduledTimer(timeInterval: 60 * 10, target: self, selector: #selector(handleOnLine), userInfo: nil, repeats: true)
@ -40,13 +40,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneDidBecomeActive(_ scene: UIScene) { func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state. // Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
SPStatAPI.requestEnterApp()
handleOpenAppMessage(webpageURL: nil) handleOpenAppMessage(webpageURL: nil)
} }
func sceneWillResignActive(_ scene: UIScene) { func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state. // Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call). // This may occur due to temporary interruptions (ex. an incoming phone call).
SPStatAPI.requestEnterApp()
} }
func sceneWillEnterForeground(_ scene: UIScene) { func sceneWillEnterForeground(_ scene: UIScene) {

View File

@ -17,3 +17,6 @@ let kSPHomeSearchHistoryDefaultsKey = "kSPHomeSearchHistoryDefaultsKey"
/// ///
let kSPWaitRestoreIAPDefaultsKey = "kSPWaitRestoreIAPDefaultsKey" let kSPWaitRestoreIAPDefaultsKey = "kSPWaitRestoreIAPDefaultsKey"
///
let kSPApnsAlertDefaultsKey = "kSPApnsAlertDefaultsKey"

View File

@ -19,6 +19,21 @@ extension Date {
let dateComponents = Calendar.current.dateComponents([.day], from: self, to: date) let dateComponents = Calendar.current.dateComponents([.day], from: self, to: date)
return dateComponents.day ?? 0 return dateComponents.day ?? 0
} }
///
var sp_isToday: Bool {
get {
return Calendar.current.isDateInToday(self)
}
}
///
var sp_isYesterday: Bool {
return Calendar.current.isDateInYesterday(self)
}
///
var sp_isTomorrow: Bool {
return Calendar.current.isDateInTomorrow(self)
}
} }

View File

@ -32,7 +32,7 @@ class SPVideoAPI: NSObject {
} }
/// ///
static func requestRequestVideoPlayHistory(videoId: String, shortPlayId: String) { static func requestCreateVideoPlayHistory(videoId: String, shortPlayId: String) {
var param = SPNetworkParameters(path: "/createHistory") var param = SPNetworkParameters(path: "/createHistory")
param.isLoding = false param.isLoding = false
param.isToast = false param.isToast = false
@ -46,6 +46,39 @@ class SPVideoAPI: NSObject {
} }
} }
///
static func requestViewingFinish(shortPlayId: String, videoId: String, activityId: String) {
var param = SPNetworkParameters(path: "/activeAfterWatchingVideo")
param.isLoding = false
param.isToast = false
param.parameters = [
"short_play_video_id" : videoId,
"short_play_id" : shortPlayId,
"activity_id" : activityId
]
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
///
static func requestUploadPlayTime(shortPlayId: String, videoId: String, seconds: Int) {
var param = SPNetworkParameters(path: "/uploadHistorySeconds")
param.isLoding = false
param.isToast = false
param.parameters = [
"video_id" : videoId,
"short_play_id" : shortPlayId,
"play_seconds" : seconds
]
SPNetwork.request(parameters: param) { (response: SPNetworkResponse<String>) in
}
}
/// ///
static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String?, success: (() -> Void)?, failure: (() -> Void)? = nil) { static func requestCollectShort(isCollect: Bool, shortPlayId: String, videoId: String?, success: (() -> Void)?, failure: (() -> Void)? = nil) {
let path: String let path: String

View File

@ -89,15 +89,7 @@ extension SPWebViewController {
DispatchQueue.main.async { [weak self] in DispatchQueue.main.async { [weak self] in
guard let self = self else { return } guard let self = self else { return }
if settings.authorizationStatus != .authorized {// if settings.authorizationStatus != .authorized {//
if #available(iOS 16.0, *) { SPAPPTool.openApnsSetting()
if let url = URL(string: UIApplication.openNotificationSettingsURLString) {
UIApplication.shared.open(url)
}
} else {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
}
} else {// } else {//
SPRewardsAPI.requestUploadOpenNotify(completer: nil) SPRewardsAPI.requestUploadOpenNotify(completer: nil)
} }

View File

@ -26,6 +26,8 @@ class SPMineWalletView: UIView {
view.backgroundColor = .colorFFFFFF(alpha: 0.06) view.backgroundColor = .colorFFFFFF(alpha: 0.06)
view.layer.cornerRadius = 8 view.layer.cornerRadius = 8
view.layer.masksToBounds = true view.layer.masksToBounds = true
view.layer.borderWidth = 1
view.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.14).cgColor
return view return view
}() }()

View File

@ -25,6 +25,9 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
private var detailModel: SPVideoDetailModel? private var detailModel: SPVideoDetailModel?
///
private var lastUploadTime: Int = 0
//MARK: UI //MARK: UI
/// ///
private weak var episodeView: SPEpisodeView? private weak var episodeView: SPEpisodeView?
@ -63,6 +66,7 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: SPIAPManager.buyVipFinishNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(buyVipFinishNotification), name: SPIAPManager.buyVipFinishNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(reachabilityDidChangeNotification), name: SPNetworkReachabilityManager.reachabilityDidChangeNotification, object: nil)
self.autoNextEpisode = true self.autoNextEpisode = true
self.dataSource = self self.dataSource = self
@ -102,7 +106,31 @@ class SPPlayerDetailViewController: SPPlayerListViewController {
super.play() super.play()
SPVideoAPI.requestRequestVideoPlayHistory(videoId: videoInfo.short_play_video_id ?? "", shortPlayId: videoInfo.short_play_id ?? "") SPVideoAPI.requestCreateVideoPlayHistory(videoId: videoInfo.short_play_video_id ?? "", shortPlayId: videoInfo.short_play_id ?? "")
}
override func currentPlayFinish() {
if let videoInfo = self.viewModel.currentPlayer?.videoInfo, let activityId = self.activityId {
//
SPVideoAPI.requestViewingFinish(shortPlayId: videoInfo.short_play_id ?? "", videoId: videoInfo.short_play_video_id ?? "", activityId: activityId)
}
super.currentPlayFinish()
}
override func currentPlayTimeDidChange(time: Int) {
super.currentPlayTimeDidChange(time: time)
let videoInfo = self.viewModel.currentPlayer?.videoInfo
//5
if (time >= lastUploadTime + 5 || time < lastUploadTime) && time >= 5 {
lastUploadTime = time
guard let shortPlayId = videoInfo?.short_play_id, let videoId = videoInfo?.short_play_video_id else { return }
//
SPVideoAPI.requestUploadPlayTime(shortPlayId: shortPlayId, videoId: videoId, seconds: time)
}
} }
} }
@ -220,6 +248,12 @@ extension SPPlayerDetailViewController {
self?.play() self?.play()
} }
} }
///
@objc private func reachabilityDidChangeNotification() {
if SPNetworkReachabilityManager.manager.isReachable == true && self.detailModel == nil {
self.requestDetailData()
}
}
} }
//MARK: -------------- SPPlayerListViewControllerDataSource -------------- //MARK: -------------- SPPlayerListViewControllerDataSource --------------

View File

@ -217,6 +217,18 @@ class SPPlayerListViewController: SPViewController {
self.collectionView.scrollToItem(at: indexPath, at: .top, animated: animated); self.collectionView.scrollToItem(at: indexPath, at: .top, animated: animated);
CATransaction.commit() CATransaction.commit()
} }
///
func currentPlayFinish() {
if self.autoNextEpisode {
scrollToNextEpisode()
}
}
///
func currentPlayTimeDidChange(time: Int) {
}
} }
extension SPPlayerListViewController { extension SPPlayerListViewController {
@ -242,6 +254,11 @@ extension SPPlayerListViewController {
self?.currentPlayFinish() self?.currentPlayFinish()
} }
self.viewModel.handlePlayTimeDidChange = { [weak self] time in
self?.currentPlayTimeDidChange(time: time)
}
} }
} }
@ -267,12 +284,6 @@ extension SPPlayerListViewController {
} }
} }
///
private func currentPlayFinish() {
guard self.autoNextEpisode else { return }
scrollToNextEpisode()
}
/// ///
private func scrollToNextEpisode() { private func scrollToNextEpisode() {

View File

@ -197,6 +197,7 @@ extension SPPlayerListCell: SPPlayerDelegate {
controlView.progress = CGFloat(currentTime) / CGFloat(duration) controlView.progress = CGFloat(currentTime) / CGFloat(duration)
controlView.currentTime = currentTime controlView.currentTime = currentTime
controlView.durationTime = duration controlView.durationTime = duration
self.viewModel?.handlePlayTimeDidChange?(currentTime)
} }
func sp_firstRenderedStart(_ player: SPPlayer) { func sp_firstRenderedStart(_ player: SPPlayer) {

View File

@ -46,6 +46,8 @@ class SPPlayerListViewModel: NSObject {
var handlePauseOrPlay: (() -> Void)? var handlePauseOrPlay: (() -> Void)?
/// ///
var handlePlayFinish: (() -> Void)? var handlePlayFinish: (() -> Void)?
///
var handlePlayTimeDidChange: ((_ time: Int) -> Void)?
/// ///
var handleEpisode: (() -> Void)? var handleEpisode: (() -> Void)?

View File

@ -94,3 +94,20 @@ extension SPAPPTool {
} }
} }
} }
extension SPAPPTool {
///
static func openApnsSetting() {
if #available(iOS 16.0, *) {
if let url = URL(string: UIApplication.openNotificationSettingsURLString) {
UIApplication.shared.open(url)
}
} else {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
}
}
}

View File

@ -103,6 +103,8 @@
"kAlertMessage_01" = "The previous episode of this series has not been unlocked yet. Please unlock the previous episode first."; "kAlertMessage_01" = "The previous episode of this series has not been unlocked yet. Please unlock the previous episode first.";
///没有找到视频提示 ///没有找到视频提示
"kAlertMessage_02" = "Purchase failed, please try again later!"; "kAlertMessage_02" = "Purchase failed, please try again later!";
///推送消息提示
"kAlertMessage_03" = "Go and enable push messages?";
"kLoginAgreementText" = "By continuing, you agree to the User Agreement and Privacy Policy"; "kLoginAgreementText" = "By continuing, you agree to the User Agreement and Privacy Policy";