Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
pidan
/
FuSiLive
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
caafca38
authored
Mar 16, 2026
by
suolong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
添加倒计时 付费屋
parent
7175d0cc
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
308 additions
and
144 deletions
FuSiLive.xcworkspace/xcuserdata/server.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController.m
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.h
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m
FuSiLive.xcworkspace/xcuserdata/server.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
View file @
caafca38
...
...
@@ -19,128 +19,16 @@
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"
39FF1C38-2542-4416-A8C4-0315968F39
41"
uuid =
"
557ED31B-F4DE-4254-9E50-0D51EFABE2
41"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"
DevelopmentPods/FUSFoundation/FUSFoundation/Classes/FUSFoundation/Views/ActionSheet/FUSActionSheetView
.m"
filePath =
"
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController
.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"149"
endingLineNumber =
"149"
landmarkName =
"-showAcionSheetWithTitle:cancelTitle:enterTitle:otherTitles:buttonColors:clickBlock:"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"1E153074-605C-4A42-B48F-38DF7C360A71"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"DevelopmentPods/FUSFoundation/FUSFoundation/Classes/FUSFoundation/Views/StreamView/LiveStreamView/Push/Capture/ByteRTC/FUSByteRTCPKStreamCaptureHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"405"
endingLineNumber =
"405"
landmarkName =
"-fus_restartStreamPush"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"88E06B63-A6EE-4AA2-97A3-2DD86F138229"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"DevelopmentPods/FUSFoundation/FUSFoundation/Classes/FUSFoundation/Views/StreamView/LiveStreamView/Push/Capture/ByteRTC/FUSByteRTCPKStreamCaptureHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"191"
endingLineNumber =
"191"
landmarkName =
"-fus_endLivePush"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"2178470A-240F-4C11-802C-507A47CD6F3D"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/LinkMicro/Other/FUSAgoraHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"592"
endingLineNumber =
"592"
landmarkName =
"-fus_switchAgoraLinkMicMode:"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"A06C7465-3FBC-4337-ADC2-4320EA06A76B"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/FunctionView/LinkMicro/Other/FUSAgoraHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"180"
endingLineNumber =
"180"
landmarkName =
"-fus_enableVideo:"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"4F5B7872-1C1A-4EA0-911F-1A4E6EFDF43E"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"DevelopmentPods/FUSFoundation/FUSFoundation/Classes/FUSFoundation/Views/StreamView/LiveStreamView/Push/Capture/TTSDK/Base/FUSStreamCatureHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"626"
endingLineNumber =
"626"
landmarkName =
"-fus_setupCaptureEnable:"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"4B4C9D12-5F36-4B96-BE77-C1250DFEBE1B"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/View/Push/LiveStartView/FUSLiveStartSetPrivacyView.swift"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"355"
endingLineNumber =
"355"
landmarkName =
"fus_requestLiveBeforeReadyIfNeeded(completion:)"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID =
"Xcode.Breakpoint.FileBreakpoint"
>
<BreakpointContent
uuid =
"47DDFACE-B633-4A68-B5D3-CC4B6253CB4F"
shouldBeEnabled =
"Yes"
ignoreCount =
"0"
continueAfterRunningActions =
"No"
filePath =
"Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m"
startingColumnNumber =
"9223372036854775807"
endingColumnNumber =
"9223372036854775807"
startingLineNumber =
"954"
endingLineNumber =
"954"
landmarkName =
"-joinRoomFailuerWithErrorDict:code:msg:currentRoomId:password:behaviorSrc:otherInfo:"
startingLineNumber =
"1648"
endingLineNumber =
"1648"
landmarkName =
"-payRoomSwitch:"
landmarkType =
"7"
>
</BreakpointContent>
</BreakpointProxy>
...
...
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Controller/FUSLiveMainViewController.m
View file @
caafca38
...
...
@@ -1404,6 +1404,8 @@ typedef NS_ENUM(NSInteger, FUSStreamState) {
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
liveStatus
:
)
name
:
STR
(
ROOM_CID_LIVE_STATU
)
object
:
nil
];
// 被踢出直播
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
forceKick
:
)
name
:
STR
(
ROOM_CID_FORCEKICK_NOTICE
)
object
:
nil
];
// 付费房模式切换
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
payRoomSwitch
:
)
name
:
STR
(
ROOM_CID_PAYROOM_SWITCH
)
object
:
nil
];
// 包房重连
[[
NSNotificationCenter
defaultCenter
]
addObserver
:
self
selector
:
@selector
(
roomReconnected
:
)
name
:
FUSLiveNotificationKeys
.
fus_Baofang_Socket_Reconnected
object
:
nil
];
// 5555 回调
...
...
@@ -1602,6 +1604,13 @@ typedef NS_ENUM(NSInteger, FUSStreamState) {
FUSSocketMessageModel
*
messageModel
=
noti
.
object
;
NSDictionary
*
dict
=
[
messageModel
fus_getJsonDict
];
if
([
dict
[
@"exitType"
]
integerValue
]
==
1
)
{
NSString
*
roomId
=
[
FUSLiveHelper
shareInstance
].
roomInfoModel
.
roomId
;
[[
FUSLiveHelper
shareInstance
]
fus_endPayRoomPreviewWithRoomId
:
roomId
];
[
FUSDialogView
fus_showDialog
:[
FUSFormatContentHelper
fus_getContentFromArr
:
dict
[
@"multiContents"
]]];
return
;
}
if
([[
FUSLiveHelper
shareInstance
]
liveType
]
==
FUSLiveTypeAudience
)
{
// 播放
[
_streamView
.
playView
fus_stopALLPlayer
];
...
...
@@ -1634,6 +1643,26 @@ typedef NS_ENUM(NSInteger, FUSStreamState) {
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}
-
(
void
)
payRoomSwitch
:
(
NSNotification
*
)
noti
{
FUSSocketMessageModel
*
messageModel
=
noti
.
object
;
NSDictionary
*
dict
=
[
messageModel
fus_getJsonDict
];
NSString
*
roomId
=
[[
dict
[
@"roomId"
]
description
]
length
]
?
[
dict
[
@"roomId"
]
description
]
:
[
dict
[
@"roomid"
]
description
];
if
([
NSString
isNull
:
roomId
])
{
roomId
=
[
NSString
stringWithFormat
:
@"%d"
,
messageModel
.
extend1
];
}
if
(
!
[
roomId
isEqualToString
:[
FUSLiveHelper
shareInstance
].
roomInfoModel
.
roomId
])
{
return
;
}
if
([
dict
[
@"mode"
]
integerValue
]
!=
0
)
{
return
;
}
[[
FUSLiveHelper
shareInstance
]
fus_handlePayRoomSwitchToNormalPlayWithRoomId
:
roomId
];
}
-
(
void
)
recieveScreenCaptureNotification
:
(
NSNotification
*
)
notification
{
if
([
FUSConfig
sharedInstanced
].
devConfigs
.
appStatus
==
NO
)
{
...
...
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.h
View file @
caafca38
...
...
@@ -274,6 +274,12 @@ typedef NS_ENUM(NSInteger,FUSLiveRoomScopeType) {
+
(
void
)
fus_quitLiveWithCompletion
:(
void
(
^
_Nullable
)(
void
))
completion
animated
:(
BOOL
)
animated
;
/// 结束付费房试看:停止拉流并回到付费入口磨砂弹层
-
(
void
)
fus_endPayRoomPreviewWithRoomId
:(
NSString
*
)
roomId
;
/// 付费房模式切到非付费(mode=0):恢复正常UI并重置播放
-
(
void
)
fus_handlePayRoomSwitchToNormalPlayWithRoomId
:(
NSString
*
)
roomId
;
// 最小化直播间
+
(
void
)
fus_minimizeLiveCompletion
:
(
void
(
^
__nullable
)(
void
))
completion
;
...
...
Modules/FUSShowRoomModule/FUSShowRoomModule/Features/NewLive/Main/Other/FUSLiveHelper.m
View file @
caafca38
...
...
@@ -61,6 +61,13 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
/// 是否关闭主播推流的声音
@property
(
nonatomic
,
assign
)
BOOL
audioMute
;
/// 付费房试看倒计时定时器(GCD timer,运行在主队列,避免 runloop 模式导致 UI 不刷新)
@property
(
nonatomic
,
strong
)
dispatch_source_t
payRoomPreviewCountdownTimer
;
/// 付费房试看倒计时按钮(展示右上角剩余秒数,并提供点击退出入口)
@property
(
nonatomic
,
strong
)
UIButton
*
payRoomPreviewCountdownButton
;
/// 付费房试看剩余秒数(用于驱动按钮文案与自动结束)
@property
(
nonatomic
,
assign
)
NSInteger
payRoomPreviewCountdownSeconds
;
@end
@implementation
FUSLiveHelper
...
...
@@ -954,8 +961,54 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Did_End_Live_Notification
object
:
currentRoomId
];
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Refresh
object
:
nil
];
}
else
if
(
code
==
-
20065
)
{
FUSStreamPlayStatus
status
=
[
self
.
liveVC
.
playView
fus_statusForUID
:
currentRoomId
];
if
(
status
==
FUSStreamPlayStatusPlaying
||
status
==
FUSStreamPlayStatusLoading
||
status
==
FUSStreamPlayStatusPause
)
{
[
self
.
liveVC
.
playView
fus_stopWithUID
:
currentRoomId
];
[
self
.
liveVC
.
playView
fus_destroyAllPlayer
];
[
self
.
liveVC
fus_stopPlay
];
[
self
.
liveVC
destroyPlayPictureInPicture
];
}
[
self
fus_handlePayRoomFrostedGlassWithRoomId
:
currentRoomId
];
return
;
}
else
if
(
code
==
-
20060
)
{
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Refresh
object
:
nil
];
// V6.1.0 改成直接退出toast提示
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
[
FUSDialogView
fus_showDialog
:[
NSString
fus_localString
:
@"您已被踢出房间,暂时不能进入"
]];
// // 您已被移除直播,暂时不能进入
}
else
if
(
code
==
-
20080
)
{
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Refresh
object
:
nil
];
// 没有私密房权限
[
self
.
currentFunctionView
fus_hideAllFunctionLayers
];
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
errorDict
[
@"msg"
]
cancelButtonTitle
:
[
NSString
fus_localString
:
@"确定"
]
otherButtonTitles
:
nil
clickBlock
:^
(
NSInteger
buttonIndex
)
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}];
}
else
{
// 其他情况
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
msg
cancelButtonTitle
:
nil
otherButtonTitles
:
@[[
NSString
fus_localString
:
@"确定"
],
[
NSString
fus_localString
:
@"退出"
]]
clickBlock
:^
(
NSInteger
buttonIndex
)
{
if
(
buttonIndex
==
0
)
{
[
self
fus_audienceJoinRoomWithRoomId
:
currentRoomId
password
:
password
behaviorSrc
:
behaviorSrc
otherInfo
:
otherInfo
];
}
else
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}
}];
}
if
(
self
.
enterRoomFailureBlock
){
self
.
enterRoomFailureBlock
();
}
}
/**
付费房磨砂弹层(-20065)处理:拉取磨砂数据并展示付费入口视图
*/
-
(
void
)
fus_handlePayRoomFrostedGlassWithRoomId
:
(
NSString
*
)
roomId
{
NSString
*
uid
=
[[
FUSCacheDataShare
shareStore
].
userVerifyInfo
.
uid
description
]
?:
@""
;
NSString
*
roomId
=
[
currentRoomId
description
]
?:
@""
;
__weak
typeof
(
self
)
weakSelf
=
self
;
[
FUSLiveHttpHelper
fus_requestGetPayRoomFrostedGlassDataWithUid
:
uid
RoomId
:
roomId
succeed
:^
(
NSDictionary
*
dataDict
)
{
...
...
@@ -1009,7 +1062,8 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
NSString
*
roundId
=
[
dataModel
.
roomData
.
roundId
description
]
?:
@""
;
__weak
typeof
(
strongSelf
)
weakStrongSelf
=
strongSelf
;
[
FUSPayRoomEntryMainView
fus_showOnView
:
rootView
viewModel
:
viewModel
actionHandler
:^
(
FUSPayRoomEntryMainViewAction
action
)
{
__block
__weak
FUSPayRoomEntryMainView
*
weakEntryView
=
nil
;
FUSPayRoomEntryMainView
*
entryView
=
[
FUSPayRoomEntryMainView
fus_showOnView
:
rootView
viewModel
:
viewModel
actionHandler
:^
(
FUSPayRoomEntryMainViewAction
action
)
{
__strong
typeof
(
weakStrongSelf
)
strongSelf
=
weakStrongSelf
;
if
(
!
strongSelf
)
{
return
;
...
...
@@ -1019,51 +1073,110 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
return
;
}
if
(
action
==
FUSPayRoomEntryMainViewActionTrial
)
{
[
strongSelf
fus_requestPayRoomPreviewWithUid
:
uid
roomId
:
roomId
channelId
:
channelId
roundId
:
roundId
];
[
strongSelf
fus_requestPayRoomPreviewWithUid
:
uid
roomId
:
roomId
channelId
:
channelId
roundId
:
roundId
entryView
:
weakEntryView
];
return
;
}
}];
weakEntryView
=
entryView
;
});
}
failure
:^
(
NSString
*
msg
,
NSInteger
code
)
{
}];
return
;
}
else
if
(
code
==
-
20060
)
{
}
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Refresh
object
:
nil
];
// V6.1.0 改成直接退出toast提示
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
[
FUSDialogView
fus_showDialog
:[
NSString
fus_localString
:
@"您已被踢出房间,暂时不能进入"
]];
// // 您已被移除直播,暂时不能进入
}
else
if
(
code
==
-
20080
)
{
[[
NSNotificationCenter
defaultCenter
]
postNotificationName
:
FUSLiveNotificationKeys
.
fus_BaoFang_Refresh
object
:
nil
];
// 没有私密房权限
[
self
.
currentFunctionView
fus_hideAllFunctionLayers
];
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
errorDict
[
@"msg"
]
cancelButtonTitle
:
[
NSString
fus_localString
:
@"确定"
]
otherButtonTitles
:
nil
clickBlock
:^
(
NSInteger
buttonIndex
)
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
}];
}
else
{
// 其他情况
[
FUSAlertView
showAlertWithTitle
:
nil
message
:
msg
cancelButtonTitle
:
nil
otherButtonTitles
:
@[[
NSString
fus_localString
:
@"确定"
],
[
NSString
fus_localString
:
@"退出"
]]
clickBlock
:^
(
NSInteger
buttonIndex
)
{
/**
结束付费房试看:清理倒计时并停止拉流,然后复用 -20065 的磨砂弹层流程
*/
-
(
void
)
fus_endPayRoomPreviewWithRoomId
:
(
NSString
*
)
roomId
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
self
fus_stopPayRoomPreviewCountdown
];
[
self
.
liveVC
fus_showLiveLoadingViewWithType
:
liveLoadingDismiss
];
[
self
.
liveVC
.
playView
fus_stopWithUID
:
roomId
];
[
self
.
liveVC
.
playView
fus_destroyAllPlayer
];
[
self
.
liveVC
fus_stopPlay
];
[
self
.
liveVC
destroyPlayPictureInPicture
];
self
.
hiddenBackgroundImage
=
NO
;
self
.
liveVC
.
backgroundImageView
.
hidden
=
NO
;
self
.
liveVC
.
liveFunctionView
.
hidden
=
NO
;
self
.
liveVC
.
scrollEnableCount
=
0
;
[
self
.
currentFunctionView
fus_showAllFunctionLayers
];
[
self
fus_handlePayRoomFrostedGlassWithRoomId
:
roomId
];
});
}
if
(
buttonIndex
==
0
)
{
[
self
fus_audienceJoinRoomWithRoomId
:
currentRoomId
password
:
password
behaviorSrc
:
behaviorSrc
otherInfo
:
otherInfo
];
}
else
{
[
FUSLiveHelper
fus_quitLiveWithCompletion
:
nil
];
-
(
void
)
fus_handlePayRoomSwitchToNormalPlayWithRoomId
:
(
NSString
*
)
roomId
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
self
fus_stopPayRoomPreviewCountdown
];
UIView
*
rootView
=
self
.
liveVC
.
view
?:
[
UIViewController
fus_topViewController
].
view
;
for
(
UIView
*
subview
in
rootView
.
subviews
.
copy
)
{
if
([
subview
isKindOfClass
:
FUSPayRoomEntryMainView
.
class
])
{
[(
FUSPayRoomEntryMainView
*
)
subview
fus_dismissAnimated
:
YES
];
}
}];
}
if
(
self
.
enterRoomFailureBlock
){
self
.
enterRoomFailureBlock
();
self
.
hiddenBackgroundImage
=
NO
;
self
.
liveVC
.
backgroundImageView
.
hidden
=
NO
;
self
.
liveVC
.
liveFunctionView
.
hidden
=
NO
;
self
.
liveVC
.
scrollEnableCount
=
0
;
[
self
.
currentFunctionView
fus_showAllFunctionLayers
];
[
self
.
liveVC
fus_showLiveLoadingViewWithType
:
liveLoadingDismiss
];
NSString
*
mainRoomId
=
(
roomId
?:
self
.
roomInfoModel
.
roomId
);
if
([
NSString
isNull
:
mainRoomId
])
{
return
;
}
[
self
.
liveVC
initPlayView
];
[
self
.
liveVC
.
playView
fus_stopWithUID
:
mainRoomId
];
[
self
.
liveVC
.
playView
fus_destroyWithUID
:
mainRoomId
];
NSString
*
streamUrl
=
self
.
streamModel
.
url
;
if
([
NSString
isNull
:
streamUrl
])
{
streamUrl
=
self
.
roomInfoModel
.
publishUrl
;
}
if
([
NSString
isNull
:
streamUrl
])
{
return
;
}
[
self
.
liveVC
.
playView
fus_playWithUID
:
mainRoomId
Url
:
streamUrl
];
});
}
-
(
void
)
fus_requestPayRoomPreviewWithUid
:
(
NSString
*
)
uid
roomId
:
(
NSString
*
)
roomId
channelId
:
(
NSString
*
)
channelId
roundId
:
(
NSString
*
)
roundId
entryView
:
(
FUSPayRoomEntryMainView
*
)
entryView
{
/**
付费房试看:请求 /payRoom/preview,拿到 pullUrl 后切换到“纯播放”模式。
约束与约定:
- 该方法只负责:请求 -> 成功后驱动 UI(关闭入口弹窗、进入试看播放)-> 失败弹 toast。
- pullUrl 由服务端下发,属于临时拉流地址,直接交给播放层播放即可。
- 成功/失败回调都在主线程收口 UI 相关操作,避免跨线程触碰 UIKit。
注意:
- entryView 通过弱引用传入,避免强引用链导致入口视图无法释放。
*/
__weak
typeof
(
self
)
weakSelf
=
self
;
__weak
FUSPayRoomEntryMainView
*
weakEntryView
=
entryView
;
[
FUSLiveHttpHelper
fus_requestPayRoomPreviewWithUid
:(
uid
?:
@""
)
RoomId
:(
roomId
?:
@""
)
previewType
:
@"1"
channelId
:
(
channelId
?:
@""
)
roundId
:
(
roundId
?:
@""
)
succeed
:^
(
NSDictionary
*
dataDict
)
{
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
NSDictionary
*
payload
=
([
dataDict
[
@"data"
]
isKindOfClass
:
NSDictionary
.
class
]
?
dataDict
[
@"data"
]
:
dataDict
);
NSDictionary
*
userData
=
([
payload
[
@"userData"
]
isKindOfClass
:
NSDictionary
.
class
]
?
payload
[
@"userData"
]
:
nil
);
NSString
*
pullUrl
=
[(
userData
?:
payload
)[
@"pullUrl"
]
description
];
if
([
NSString
isNull
:
pullUrl
])
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
FUSDialogView
fus_showDialog
:[
NSString
fus_localString
:
@"拉流地址为空"
]];
});
return
;
}
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
weakEntryView
fus_dismissAnimated
:
YES
];
[
strongSelf
fus_playPayRoomPreviewWithPullUrl
:
pullUrl
];
});
}
failure
:^
(
NSString
*
msg
,
NSInteger
code
)
{
dispatch_async
(
dispatch_get_main_queue
(),
^
{
[
FUSDialogView
fus_showDialog
:(
msg
?:
@""
)];
...
...
@@ -1072,6 +1185,133 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
}
/**
将直播间切换为“试看播放态”:
- 使用 preview 接口返回的 pullUrl 播放
- 隐藏所有业务/互动 UI,仅保留视频播放画面
- 右上角展示 20 秒倒计时,并提供点击退出
*/
-
(
void
)
fus_playPayRoomPreviewWithPullUrl
:
(
NSString
*
)
pullUrl
{
FUSLiveMainViewController
*
liveVC
=
self
.
liveVC
;
if
(
!
liveVC
)
{
return
;
}
[
liveVC
initPlayView
];
[
liveVC
fus_setupScrollEnable
:
NO
];
[
liveVC
fus_showLiveLoadingViewWithType
:
liveLoadingDismiss
];
liveVC
.
backgroundImageView
.
hidden
=
YES
;
[
self
.
currentFunctionView
fus_hideAllFunctionLayers
];
liveVC
.
liveFunctionView
.
hidden
=
YES
;
[
liveVC
fus_playStreamWithUrl
:(
pullUrl
?:
@""
)];
[
self
fus_startPayRoomPreviewCountdownSeconds
:
20
];
}
/**
开始试看倒计时(GCD Timer)
- 使用 dispatch_source_t,避免 NSTimer 依赖 runloop mode 导致滑动/交互时不触发
- 计时与 UI 更新都在主队列执行,保证按钮文案与布局安全更新
*/
-
(
void
)
fus_startPayRoomPreviewCountdownSeconds
:
(
NSInteger
)
seconds
{
[
self
fus_stopPayRoomPreviewCountdown
];
self
.
payRoomPreviewCountdownSeconds
=
MAX
(
0
,
seconds
);
UIView
*
hostView
=
self
.
liveVC
.
view
?:
[
UIViewController
fus_topViewController
].
view
;
if
(
!
hostView
)
{
return
;
}
UIButton
*
button
=
[
UIButton
buttonWithType
:
UIButtonTypeCustom
];
button
.
backgroundColor
=
[[
UIColor
blackColor
]
colorWithAlphaComponent
:
0
.
4
];
[
button
setTitleColor
:
UIColor
.
whiteColor
forState
:
UIControlStateNormal
];
button
.
titleLabel
.
font
=
[
UIFont
boldSystemFontOfSize
:
13
];
button
.
clipsToBounds
=
YES
;
button
.
layer
.
cornerRadius
=
12
;
button
.
autoresizingMask
=
UIViewAutoresizingFlexibleLeftMargin
|
UIViewAutoresizingFlexibleBottomMargin
;
[
button
addTarget
:
self
action
:
@selector
(
fus_onPayRoomPreviewCountdownButtonTap
)
forControlEvents
:
UIControlEventTouchUpInside
];
[
hostView
addSubview
:
button
];
self
.
payRoomPreviewCountdownButton
=
button
;
[
self
fus_updatePayRoomPreviewCountdownButton
];
__weak
typeof
(
self
)
weakSelf
=
self
;
dispatch_source_t
timer
=
dispatch_source_create
(
DISPATCH_SOURCE_TYPE_TIMER
,
0
,
0
,
dispatch_get_main_queue
());
dispatch_source_set_timer
(
timer
,
dispatch_time
(
DISPATCH_TIME_NOW
,
(
int64_t
)
NSEC_PER_SEC
),
(
uint64_t
)
NSEC_PER_SEC
,
(
uint64_t
)(
0
.
1
*
NSEC_PER_SEC
));
dispatch_source_set_event_handler
(
timer
,
^
{
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
if
(
!
strongSelf
)
{
return
;
}
strongSelf
.
payRoomPreviewCountdownSeconds
=
MAX
(
0
,
strongSelf
.
payRoomPreviewCountdownSeconds
-
1
);
if
(
strongSelf
.
payRoomPreviewCountdownSeconds
<=
0
)
{
[
strongSelf
fus_endPayRoomPreviewWithRoomId
:
strongSelf
.
roomInfoModel
.
roomId
];
return
;
}
[
strongSelf
fus_updatePayRoomPreviewCountdownButton
];
});
dispatch_resume
(
timer
);
self
.
payRoomPreviewCountdownTimer
=
timer
;
}
/// 点击右上角倒计时按钮:弹窗二次确认结束试看(仅清理倒计时,不退出直播间)
-
(
void
)
fus_onPayRoomPreviewCountdownButtonTap
{
__weak
typeof
(
self
)
weakSelf
=
self
;
[
FUSAlertView
showAlertWithTitle
:
@""
message
:[
NSString
fus_localString
:
@"结束试看"
]
cancelButtonTitle
:
[
NSString
fus_localString
:
@"取消"
]
otherButtonTitles
:
@[[
NSString
fus_localString
:
@"结束"
]]
clickBlock
:^
(
NSInteger
buttonIndex
)
{
if
(
buttonIndex
!=
1
)
{
return
;
}
__strong
typeof
(
weakSelf
)
strongSelf
=
weakSelf
;
if
(
!
strongSelf
)
{
return
;
}
[
strongSelf
fus_endPayRoomPreviewWithRoomId
:
strongSelf
.
roomInfoModel
.
roomId
];
}];
}
/// 刷新倒计时按钮文案与位置(右上角,考虑 safeArea)
-
(
void
)
fus_updatePayRoomPreviewCountdownButton
{
UIButton
*
button
=
self
.
payRoomPreviewCountdownButton
;
UIView
*
hostView
=
button
.
superview
?:
(
self
.
liveVC
.
view
?:
[
UIViewController
fus_topViewController
].
view
);
if
(
!
button
||
!
hostView
)
{
return
;
}
[
button
setTitle
:[
NSString
stringWithFormat
:
@"%@:%lds"
,
[
NSString
fus_localString
:
@"试看"
],(
long
)
self
.
payRoomPreviewCountdownSeconds
]
forState
:
UIControlStateNormal
];
CGFloat
topInset
=
20
;
if
(
@available
(
iOS
11
.
0
,
*
))
{
topInset
=
MAX
(
topInset
,
hostView
.
safeAreaInsets
.
top
);
}
CGFloat
height
=
24
;
CGFloat
maxWidth
=
MAX
(
52
,
hostView
.
bounds
.
size
.
width
-
24
);
CGFloat
width
=
MIN
(
MAX
(
52
,
[
button
sizeThatFits
:
CGSizeMake
(
CGFLOAT_MAX
,
height
)].
width
+
16
),
maxWidth
);
CGFloat
x
=
MAX
(
0
,
hostView
.
bounds
.
size
.
width
-
width
-
12
);
CGFloat
y
=
topInset
+
8
;
button
.
frame
=
CGRectMake
(
x
,
y
,
width
,
height
);
}
/// 停止倒计时并移除按钮,释放 timer 资源(避免页面退出后仍回调导致异常)
-
(
void
)
fus_stopPayRoomPreviewCountdown
{
if
(
self
.
payRoomPreviewCountdownTimer
)
{
dispatch_source_cancel
(
self
.
payRoomPreviewCountdownTimer
);
self
.
payRoomPreviewCountdownTimer
=
nil
;
}
[
self
.
payRoomPreviewCountdownButton
removeFromSuperview
];
self
.
payRoomPreviewCountdownButton
=
nil
;
self
.
payRoomPreviewCountdownSeconds
=
0
;
}
/**
结束观看直播
*/
+
(
void
)
fus_quitLiveWithCompletion
:
(
void
(
^
)(
void
))
completion
animated
:
(
BOOL
)
animated
{
...
...
@@ -2040,6 +2280,7 @@ static NSString *const KLiveDataCenter_store_liveRTCData = @"LiveDataCenter_stor
#pragma mark - Other
-
(
void
)
dealloc
{
[
self
fus_stopPayRoomPreviewCountdown
];
[[
NSNotificationCenter
defaultCenter
]
removeObserver
:
self
];
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment