Appearance
廣場與直播
最後更新:2026-04-09
功能說明
廣場 Tab 是 App 的社群與直播中心,提供使用者觀看主播直播、聊天互動、送禮物、領紅包、參與競猜投票、查看活動等功能。支援全螢幕直播(娛樂主播)與賽事嵌入直播(體育直播)兩種模式。廣場本身是 H5 網頁,所有主播列表、活動、資訊流均由後台維護,點擊互動後跳轉至原生頁面。
使用者流程
廣場主頁
- 點擊「廣場」Tab → 載入 H5 URL 到
STBridgeH5WebView - H5 頁面顯示主播列表、活動、資訊流
- 點擊主播卡片 → JS Bridge 通知原生端跳轉至
StreamerViewController
進入主播直播間
- 點擊主播卡片(需登入)→
StreamerViewController - 直播房間載入主播影片流
- 聊天區顯示即時訊息
- 可操作:送禮物、搶紅包、參與競猜、轉動轉盤
- 點擊小化按鈕 → 浮動小窗
- 投屏(AirPlay):
AirPlayAlertView
送禮流程
- 點擊禮物按鈕 → 開啟
STGiftListViewController - 載入禮物列表(
STAPI+LiveGiftListRequest)與錢包餘額 - 選擇禮物 → 選擇數量 → 點擊送出
- 呼叫
STAPI+SendGiftRequest送出禮物 - 成功:播放禮物動畫(全螢幕禮物播
GiftFullScreenView) - 金幣不足(code 300000):回傳不足額,提示充值
- 充值跳轉:全螢幕模式先收回 Sheet → 跳轉
RechargeViewController
頁面跳轉
- 點擊「廣場」Tab → H5 廣場主頁(
BBMineNewsViewController) - 廣場 H5 點擊主播 →
StreamerViewController(需登入) - 廣場 H5 點擊充值 →
RechargeViewController - 廣場 H5 點擊客服 → 客服選擇器
- H5 → H5 內部跳轉 →
BBMineNewsViewController(push 新 WebView) - 主播直播間小化 → 浮動小窗
- 全螢幕模式 →
STFullAmuseHostViewController
技術視角(開發看這裡)
相關檔案
| 類型 | 檔案路徑 |
|---|---|
| ViewController(廣場主頁 H5 容器) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/C/BBMineNewsViewController.swift |
| WebView(H5 Bridge 核心) | /Users/user/Work/bbsport-new/BBSport/Tools/STWebViewManager/STBridgeH5WebView.swift |
| Bridge API(JS→原生跳轉) | /Users/user/Work/bbsport-new/BBSport/Tools/STWebViewManager/STWebviewBridgeApi.swift |
| ViewController(主播直播) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/StreamerViewController.swift |
| ViewModel(主播直播) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/StreamerViewModel/StreamerViewModel.swift |
| ViewController(全螢幕) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STFullAmuseHostViewController.swift |
| ViewModel(全螢幕) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/VM/STFullAmuseHostViewModel.swift |
| ViewController(活動) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/C/BBActivityViewController.swift |
| ViewModel(禮物列表) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/Gift/VM/STGiftListViewModel.swift |
| ViewController(禮物列表) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/Gift/STGiftListViewController.swift |
| View(禮物列表) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/Gift/STGiftListView.swift |
| ViewModel(直播競猜) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/LiveBetGame/LiveBetGameViewModel.swift |
| ViewModel(聊天) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STChatView/VM/STChatViewModel.swift |
| Manager(聊天 Socket) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STChatView/STChatManager.swift |
| API(聊天相關) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STChatView/STChatAPI.swift |
| Model(直播資訊) | /Users/user/Work/bbsport-new/BBSport/Tab/体育/Sport/EventDetail/Views/VideoAndStream/Models/LiveInfoMessageModel.swift |
| 播放器管理 | /Users/user/Work/bbsport-new/BBSport/Tools/AVPlayerManager/STAVPlayerManager.swift |
| 播放器 View | /Users/user/Work/bbsport-new/BBSport/Tools/AVPlayerManager/STAVPlayerView.swift |
| 播放器 Item | /Users/user/Work/bbsport-new/BBSport/Tools/AVPlayerManager/STPlayerItem.swift |
| 播放器影片層 View | /Users/user/Work/bbsport-new/BBSport/Tools/AVPlayerManager/STVideoPlayerLayerView.swift |
| 直播資料元件 | /Users/user/Work/bbsport-new/BBSport/STUIKit/STFoundation/Live/LiveComponent.swift |
| 全螢幕背景 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseBGView.swift |
| 全螢幕聊天 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseChatView.swift |
| 全螢幕更多功能 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseMoreFeaturesView.swift |
| 全螢幕主播資訊 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseHostInfoView.swift |
| 全螢幕引導 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseGuideView.swift |
| 全螢幕 AirPlay 狀態 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseAirPlayStatusView.swift |
| 全螢幕入場動畫 View | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/STFullAmuseEntryAnimationView.swift |
| 全螢幕轉盤遊戲 | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STFullAmuseHostViewController+TurnTableGame.swift |
| 全螢幕更多直播 | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STFullAmuseHostViewController+MoreLive.swift |
| 全螢幕紅包小球 | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/STFullAmuseHostViewController+BallView.swift |
| 紅包雨 ViewModel | /Users/user/Work/bbsport-new/BBSport/Tools/RainRedPacket/RainRedPacketViewModel.swift |
| Model(活動) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/M/BBActivityModel.swift |
| Cell(活動) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/V/BBActivityCell.swift |
| View(導航選擇) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/V/BBNavSelectionView.swift |
| View(用戶導航選擇) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Activity/V/BBUserNavSelectionView.swift |
| View(主播標題) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/Header/StreamerTitleView.swift |
| Model(快速遊戲) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/QuickGame/QuickGameModel.swift |
| View(快速遊戲) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/QuickGame/QuickGameView.swift |
| ViewModel(快速遊戲) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/QuickGame/QuickGameViewModel.swift |
| View(開始遊戲按鈕) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/QuickGame/StartGameButton.swift |
| Extension(直播紅包小球) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/StreamerViewController+BallView.swift |
| Extension(直播更多直播) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/StreamerViewController+MoreLive.swift |
| Extension(直播轉盤遊戲) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/Stream/StreamerViewController+TurnTableGame.swift |
| Model(主播類型) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/M/STHostType.swift |
| View(更多直播新版) | /Users/user/Work/bbsport-new/BBSport/Tab/广场/FullScreenLive/V/NewFullAmuseMoreLiveView.swift |
| API(爆料論壇) | /Users/user/Work/bbsport-new/BBSport/API/STAPI/STAPI+DisclosureForumRequest.swift |
API
| 功能說明 | Endpoint | Method | 主要參數 |
|---|---|---|---|
| 聊天舉報列表 | api/forehead/live/chat/report/cate | POST | 無參數 |
| 大額曬單設定 | api/forehead/live/showorder/config | POST | 無參數 |
| 直播訂閱資訊 | api/forehead/live/user/subscribe/info | POST | 無參數 |
| 紅包查詢(主播房間) | api/forehead/live/get/room/redEnvelope | POST | LiveRoomId: Int — 直播間 ID |
| 領取紅包 | api/forehead/live/submit/receive/redEnvelope | POST | LiveRoomId: Int — 直播間 ID, sendRecordId: String — 紅包發送記錄 ID |
| 金幣商城餘額 | api/forehead/activity/goldmall/balance | POST | 無參數(需 Authorization) |
| 禮物列表 | api/forehead/live/load/gift | POST | matchType: String — 直播類型(體育/娛樂) |
| 送禮物 | api/forehead/live/submit/gift/present | POST | liveRoomId: String — 直播間 ID, giftId: String — 禮物 ID, giftCount: String — 數量。成功 code=1/429,金幣不足 code=300000(data 回傳不足額) |
| 禮物排行榜 Top5 | api/forehead/live/room/gift/top5 | POST | liveRoomId: Int — 直播間 ID |
資料模型
LivePrivilegeType(特權主播類型)
swift
enum LivePrivilegeType: Int, Codable {
case None = 0 // 無特權
case WhiteList = 1 // 白名單(一般特權)
case Proxy = 2 // 代理特權
}特權主播完整判斷邏輯(LiveComponent.filterLanguage):
- 排除已下播(
liveStatus == .Finish)的主播 - 依語言分組:
-1(無語言)、0(普通話)、1(粵語) - 每個語言組內按
sort升序排列 - 判斷特權:若
liveUserGroupId > 0或liveGroupUserType > 0,代表該主播為特權/樂享主播 - 檢查使用者是否在特權名單:讀取
IFUserModel.sharedInstance().liveRoomIdSpecial(逗號分隔的房間 ID 字串),比對liveRoomId - 排序優先級:樂享主播(
liveGroupUserType > 0)排最前 > 純特權主播(liveUserGroupId > 0 && liveGroupUserType == 0)> 一般主播 - 訪客或無特權權限的使用者只能看到一般主播
getLiveStatus 特權判斷(LiveComponent.getLiveStatus):
- 單主播時:直接取第一順位主播的
privilegeType(因篩選已將特權排前) - 多主播時:遍歷所有
liveUserGroupId > 0 || liveGroupUserType > 0的主播,Proxy優先於WhiteList
MatchType(直播類型)
swift
enum MatchType: Int, Codable {
case Sport = 0 // 賽事
case Entertainment = 1 // 娛樂
}LiveStreamStatus(直播狀態)
swift
enum LiveStreamStatus: Int, Codable {
case UnStream = 0 // 未開始
case Streaming = 1 // 直播中
case Finish = 2 // 已結束
}LiveStreamShowType(直播展示類型)
swift
enum LiveStreamShowType: String, Codable {
case Sport = "体育赛事直播"
case Vip = "高V私密直播"
case Tutorial = "官方新手教学"
case TransferTutorial = "客服充提直播"
case Welfare = "彩蛋福利直播"
case Excellent = "精彩集锦直播"
case Other = "其他娱乐直播"
case Proxy = "专线独享直播"
}LiveInfoMessageModel 完整欄位
| 屬性 | 型別 | 預設值 | 說明 |
|---|---|---|---|
hostId | Int | 0 | 主播 ID |
hostName | String | "" | 主播名稱 |
hostPhotoId | String | "" | 主播頭像 ID |
liveRoomId | Int | 0 | 直播間 ID |
liveStatus | LiveStreamStatus | .UnStream | 直播狀態(0: 未開始, 1: 直播中, 2: 已結束) |
matchId | String | "" | 賽事 ID |
videoSource | [String: String] | [:] | 視訊源地址(key 如 "m3u8"、"rtmp") |
hostLanguage | Int | -1 | 主播語言(0: 普通話, 1: 粵語, -1: 未設定) |
activityStatus | Int | 0 | 活動狀態(0: 正常, 1: 禁用, 2: 刪除) |
benefitsScenesId | Int | 0 | 直播間專屬客服場景代碼 |
sort | Int | -1 | 排序(由小到大) |
liveUserGroupId | Int | 0 | 使用者是否在特權主播名單內 |
liveGroupUserType | Int | 0 | 直播間代理類型(0: 會員, 1: 特權主播/代理) |
privilegeType | LivePrivilegeType | .None | 特權顯示類型 |
benefitsAssistantSwitch | Int | 0 | 是否顯示專屬客服(0: 否) |
liveHostTypeShow | LiveStreamShowType | .Other | 顯示特權字段 |
liveHostType | Int | 0 | 特權類型(用於聊天室) |
hostPictureId | String | "" | 主播場次圖 |
league | String | "" | 聯賽名 |
startDate | Int | 0 | 開播時間 |
subscribeStatus | Int | 0 | 訂閱狀態(0: 未訂閱, 1: 已訂閱) |
liveStreamId | String | "" | 直播流 ID |
masterTeamName | String | "" | 主隊名 |
guestTeamName | String | "" | 客隊名 |
matchType | String | "" | 判斷來源(簡體字串:"体育"、"娱乐") |
watcherCount | Int | 0 | 觀看人數 |
hostTags | String | "" | 主播標籤 |
backgroundImage | String | "" | 背景圖 |
ext | String | "" | 擴展 JSON 字串(含 marquee 跑馬燈、bennefitsAssistantWord 客服提示、isHorizontalScreen 橫豎屏) |
popupMatch | Bool | false | 是否彈出賽事 |
languageStr | String? | 計算屬性 | 語言字串("普通话"/"粤语"/nil) |
voidSourceUrl | String | 計算屬性 | 取 videoSource["m3u8"],優先 M3U8 |
ext JSON 解析方法:
getExtDictionary()→ 解析 ext 為[String: Any]getAnnounceWord()→ 取marquee跑馬燈文字getBennefitsAssistantWord()→ 取專屬客服提示文字isHorizontalScreen()→ 是否橫屏(TransferTutorial強制橫屏;其餘讀 ext 的isHorizontalScreen,0=豎屏/1=橫屏,預設豎屏)
StreamerViewModel 完整屬性
| 屬性 | 型別 | 說明 |
|---|---|---|
goBackChangeToView | (() -> Void)? | 返回事件回呼 |
privilegeType | LivePrivilegeType | 特權主播類型,didSet 觸發 privilegeTypeDidChangeToView |
subscribeHostSatusHandler | (() -> Void)? | 主播狀態變更回呼 |
subscribeEntertainmentHandler | (([LiveInfoMessageModel]) -> Void)? | 娛樂主播列表更新回呼 |
subscribLiveInfoHandeler | (() -> Void)? | 訂閱主播資訊回呼 |
videoUrlString | String | 影片 URL,didSet 驅動播放器 |
fetchGiftRankListHandler | ((STGiftRankListModel) -> Void)? | 禮物排行榜回呼 |
didReceivedNewMessage | (([STChatMessageModel]) -> Void)? | 收到新訊息回呼 |
didReceivedGiftList | (() -> Void)? | 收到禮物列表回呼 |
didReceivedEmojiList | (() -> Void)? | 收到表情列表回呼 |
didReceivedAutoMessage | (([ChatMessageModel]) -> Void)? | 收到系統訊息回呼 |
didCustomService | ((String?) -> Void)? | 點擊客服回呼 |
showRedPacket | ((STRedPacketInfoModel) -> Void)? | 紅包小球顯示回呼 |
shouldDisplayRainRedPacket | ((STRedPacketInfoModel) -> Void)? | 紅包雨顯示回呼 |
shouldDisplayLuckyDraw | ((STLuckDrawModel?) -> Void)? | 抽獎顯示回呼 |
shouldDisplayVote | ((ChatVoteModel?) -> Void)? | 投票顯示回呼 |
liveBetGameViewModel | LiveBetGameViewModel | 主播競猜 ViewModel(lazy) |
hotInPlayRankViewModel | STHotInPlayRankViewModel | 熱門投注排行 ViewModel |
chatViewModel | STChatViewModel | 聊天 ViewModel(lazy) |
clearScreenClosure | (() -> Void)? | 清屏回呼 |
matchId | Int | 賽事 ID |
hostId | Int | 主播 ID |
isH5OpenLive | Bool | 是否從 H5 開啟 |
toastOpenLive | Bool | 開播推送 Toast |
sendRecordId | Int | 紅包發送記錄 ID |
liveInfoModels | [LiveInfoMessageModel]? | 當前娛樂主播 model 列表 |
subscribeInfoData | SubscribeInfoData? | 訂閱資訊(已訂閱的主播/賽事 ID 集合) |
chatEvents | STBindingVariable<[STChatEventModel]> | 活動列表綁定變數 |
chatEventBallHideStatus | (Bool, Bool) | 活動小球隱藏狀態 |
streamerModels | [LiveInfoMessageModel] | 其他主播列表(排除當前主播) |
currentStreamer | LiveInfoMessageModel? | 當前主播,didSet 更新聊天室與競猜 |
openChatRoomAccesstime | Date? | 開啟聊天室時間 |
chatManager | STChatManager | 聊天 Socket 管理器(private(set)) |
rainRedPacketViewModel | RainRedPacketViewModel | 紅包雨 ViewModel(lazy) |
chId | String | 頻道 ID(計算屬性) |
chatGiftList | [STGiftModel] | 禮物列表,didSet 觸發 didReceivedGiftList |
chatEmojiList | [[STEmojiModel]] | 表情列表,didSet 觸發 didReceivedEmojiList |
JS Bridge 支援的 NativeType
| type | 跳轉目標 |
|---|---|
funAnchor | 主播直播間(需登入) |
sportDetail | 賽事詳情 |
rechargeIndex | 充值頁 |
welfareCenter | 福利中心 |
openCustomerService | 客服 |
播放器技術細節
播放器架構
App 使用 Apple AVPlayer(AVFoundation)作為唯一的播放器框架,無 IJKPlayer 或其他第三方播放器。
| 元件 | 說明 |
|---|---|
STAVPlayerManager | 全域單例播放器管理器,管理 AVPlayer 實例、AirPlay、重試、前後景切換 |
STAVPlayerView | 播放器 UI View,承載影片圖層和動畫圖層 |
STPlayerItem | 繼承 AVPlayerItem,監聽 status 變化通知 delegate |
STVideoPlayerLayerView | 影片圖層 View |
VideoSourceType(播放源類型)
swift
enum VideoSourceType {
case live // 賽事主播
case video // 賽事視頻
case animation // 動畫
case entertainment // 全螢幕娛樂主播
case shortVideo // 短視頻
case hostLive // 主播視頻
case noneSource // 不明
}串流協議
- HLS(M3U8):主要使用。
LiveInfoMessageModel.getVoidSourceUrl()優先取videoSource["m3u8"] - RTMP:程式碼中已被註解掉(
// if let rtmp = self.videoSource["rtmp"]),目前不使用 - 視頻源 URL 由
videoSource字典提供,key 對應協議名
播放器生命週期
- 初始化:
setupPlayer()設定 URL、來源類型、佈局方向等參數 - 影片播放:建立
AVURLAsset→STPlayerItem→AVPlayer→ 添加至STAVPlayerView - 重試機制:5 秒為週期,最多重試 3 次。若仍失敗顯示播放錯誤
- 前後景處理:進背景暫停(AirPlay 除外);回前景自動播放
- 循環播放:短視頻/主播視頻
isLoopPlay = true時,播完回到開頭重播 - AirPlay 投屏:監聽
AVAudioSession.routeChangeNotification,偵測.airPlay設備 - 浮動小窗:
isFloating = true時,播放器 View 移至UIApplication.currentWindow上方 - 關閉:取消 pending seeks、停止播放、清除 UI 和狀態
視頻 Referer 處理
賽事視頻(sourceType == .video)會在 AVURLAsset 的 HTTP Header 加入 Referer 欄位。
直播源取得策略(getUrl)
- 賽事主播:從
SportDataManager取得正在直播的主播列表,優先選樂享(liveGroupUserType > 0)→ 特權(liveUserGroupId > 0)→ 一般 - 賽事視頻:從
LiveComponent.getVideoSource()取得,支援多線路切換 - 動畫:從
LiveComponent.getAnimationUrlString()或SportDataManager的 eventInfo
LiveComponent 輪詢服務
LiveComponent.registerLiveServices() 啟動兩個輪詢:
streamer:定期呼叫EventDetailChatService.fetchStreamerList()更新主播列表sportEventLiveInfo:定期呼叫STAPI.VideoUrlRequest()更新視頻/動畫源
視頻源支援最多 4 組(videoSource1~videoSource4),動畫源支援 2 組(animateSource1~animateSource2),每組依 fbId、obId、upId 分平台儲存。
送禮流程技術細節
STGiftListViewModel
| 屬性/方法 | 說明 |
|---|---|
models: [STGiftModel] | 禮物列表 |
currentModel: STGiftModel? | 當前選中的禮物 |
isRecharge / isGoRecharge | 充值狀態標記 |
paycheckBlock | 餘額不足回呼(需要金額) |
paycheckCoinBlock | 金幣不足回呼(需要金額) |
didSendGiftBlock | 送禮成功回呼(含是否全螢幕) |
sendGiftHandler | 送禮動作回呼 |
updateGoldBalance | 金幣餘額更新回呼 |
updateBalance | 錢包餘額更新回呼 |
refreshGoldBeanBalance() | 呼叫 GoldMallBalanceRequest 刷新金幣 |
refreshBeanBalance() | 透過 MGJRouter 取得所有錢包餘額 |
rechargeBalance(direction:) | 跳轉充值頁(全螢幕先收 Sheet 再跳轉) |
送禮調用鏈
使用者選禮 → STGiftListView.sendGift
→ STChatInputView → STChatViewModel.sendGift
→ StreamerViewModel.sendGift(STGiftModel)
→ STChatManager.sendGift(STGiftModel)
→ STAPI.SendGiftRequest(liveRoomId, giftId, giftCount)全螢幕模式相關
STFullAmuseHostViewController
滿屏娛樂主播控制器,包含:
bigViewModel: STFullAmuseHostViewModel— 全螢幕 ViewModelbgVideoView: STFullAmuseBGView— 背景播放器 View(點擊觸發清屏)guideView: STFullAmuseGuideView— 新手引導giftFullScreenView: GiftFullScreenView?— 全螢幕禮物動效customServiceView: EventDetailCustomServiceView— 專屬客服chatEventEntryView/chatEventSmallButton— 活動入口與小球
Extension 拆分:
+TurnTableGame:轉盤遊戲互動+MoreLive:更多直播間切換+BallView:紅包小球 UI
STFullAmuseHostViewModel 關鍵屬性
| 屬性 | 說明 |
|---|---|
avatarUrlString | 主播頭像 URL |
hostIsStreaming | 主播是否直播中 |
privilegeType | 特權主播類型 |
titleString / subTitleString | 主播資訊卡標題/副標題 |
marqueeList | 跑馬燈文字列表 |
videoUrlString | 影片播放 URL |
giftLiveAnimationHandler | 禮物動畫訊息回呼 |
shouldDisplayRainRedPacket | 紅包雨顯示回呼 |
didShowActivityMarquee | 活動中獎跑馬燈 |
實作重點
廣場本質是 H5:廣場 Tab 載入
IFMainSwitch.getSportInformationUrl()的 H5 頁面,非原生列表JS Bridge 兩條路徑:H5→H5(
jumpToH5Page)push 新BBMineNewsViewController;H5→原生(jumpToNativePage)依 NativeType 分流主播類型分支:娛樂主播(
StreamerViewController)全螢幕 + 聊天 + 禮物;體育直播嵌入STEventDetailViewController廣場 Tab icon 動畫:選中時播放 Transition 動畫;Loop 圖示依「是否直播中」選擇
_livevs_no_live紅包雨機制:Socket 通知 → 生成
STBallItemViewProtocol小球 UI → 點擊搶紅包播放器為 AVPlayer 單例:
STAVPlayerManager.shared全域管理,支援浮動小窗、AirPlay、5 秒重試(最多 3 次)影片源優先 M3U8:
getVoidSourceUrl()只取videoSource["m3u8"],RTMP 已停用特權主播排序:樂享 > 純特權 > 一般。使用者需在
liveRoomIdSpecial名單內才可見特權主播送禮金幣不足處理:
SendGiftRequest回傳 code 300000 時,data 為不足金額,觸發充值提示橫豎屏判斷:
TransferTutorial(客服充提直播)強制橫屏;其餘由ext.isHorizontalScreen決定
API 呼叫流程
進入廣場 Tab
StreamerViewController.viewDidLoad
├─ [API 1] GET ssapi/anchor/search {pid:"bb", matchSource:"all"}
│ → 回傳主播列表 [LiveInfoMessageModel]
│
└─ [並行] POST api/forehead/live/user/subscribe/info
→ 回傳已關注主播清單點擊主播進入全屏直播
STFullAmuseHostViewController.init(hostId, matchId)
│
├─ [API 1] GET api/forehead/user/chat/token/v2 {liveHostType}
│ → 回傳 chatToken, chatBanInfo, chatRule
│ (失敗重試 3 次)
│
├─ WebSocket 連線
│ └─ BBSocketServices.openSocket(url: getChatSocketUrl2())
│ └─ 連線成功 → 訂閱歷史訊息 (cmd: L01)
│ └─ 送出進場動畫 (cmd: P02)
│ └─ 啟動心跳 (每 30 秒 ping)
│
└─ [並行載入] fetchChatData()
├─ POST api/forehead/common/pic/load {categoryId:"20104"} → 公告跑馬燈
├─ POST api/forehead/live/match/message/select → 自動訊息
├─ POST api/forehead/live/load/gift {matchType} → 禮物列表
├─ POST api/forehead/live/emoji/list {matchType} → 表情包
├─ POST api/forehead/live/get/room/redEnvelope {liveRoomId} → 紅包狀態
├─ POST api/forehead/live/get/room/redEnvelope/template → 紅包雨
├─ POST api/forehead/live/activity/lottery/start/info → 抽獎資訊
├─ POST api/forehead/live/activity/select {liveRoomId} → 活動列表
└─ POST api/forehead/common/pic/load {categoryId:"40101,40102"} → 聊天設定觀看直播中 (持續)
├─ WebSocket 接收即時訊息 (M01/G01/G02/G06/G07/P001/P002/P003)
├─ 心跳: 每 30 秒 ping
└─ [API] POST api/forehead/live/submit/watch {liveRoomId, matchId} → 回報觀看關注 / 取消關注
關注: [API] POST api/forehead/live/subscribe {hostId}
取消: [API] POST api/forehead/live/unsubscribe {hostId}
└─ 完成後 → POST api/forehead/live/user/subscribe/info 刷新狀態送禮
用戶選禮物 → 確認
└─ [API] POST api/forehead/live/submit/gift/present
{liveRoomId, giftId, giftCount}
├─ code 1/429 → 成功
└─ code 300000 → 餘額不足 (data = 差額)