Bỏ qua để đến nội dung
VLivev1.1.2

04 — API Reference

Tài liệu tham chiếu đầy đủ các API thuộc module ISdk của SDK Interactive iOS.

Xem Markdown

Toàn bộ API dưới đây thuộc module ISdk (import ISdk).


Lớp điều phối chính — điểm vào của app.

@objc public class InteractiveControllerView : NSObject {
public override init() // tạo SocketIOManagementImpl + OverlayManagementImpl
}
Thuộc tínhKiểuMô tả
overlayManagementOverlayManagement?Manager overlay minigame (gắn delegate qua đây)
predictManagementPredictManagementImpl!Manager nút + dialog predict/lucky
socketIOSocketIOManagement?Đối tượng socket (chỉ đọc thông tin)
interactivePlayerDelegateInteractivePlayerDelegate?Delegate trạng thái player / số người xem
interactiveLoginDelegateInteractiveLoginDelegate?Delegate yêu cầu đăng nhập
interactivePredictDelegateInteractivePredictDelegate?Delegate layout nút predict
HàmMô tả
initOverlay(uiView: UIView, predictView: UIView)Gắn 2 view host (overlay + predict), đăng ký lắng nghe xoay màn hình, tạo PredictManagementImpl
initAuthenToken(authenToken: String, userId: String, bjName: String)Khai báo/xoá phiên đăng nhập. Đăng xuất: truyền chuỗi rỗng. Nếu đang Live → tự vào lại phòng
joinRoom(mediaId: String, type: Int)Bắt đầu phiên. type = 1 LIVE, type = 2 VOD. Tự dọn phiên cũ
getTimeVideo(time: TimeInterval)(VOD) Bơm thời gian phát (giây). So khớp timeShow để hiện overlay
leaveRoom()Emit leave-room cho media hiện tại
releaseAll()Giải phóng: leaveRoom + gỡ delegate + disconnect socket
removeAllView()Gỡ overlay đang hiển thị (không đụng socket)
resizeVideoView(width: CGFloat, height: CGFloat)Cập nhật kích thước khung video cho overlay
fetchInteractiveStatus(mediaId: String, completion: @escaping (Bool) -> Void)Hỏi server media này có tương tác không (lỗi → false)
showChartsInteractive(viewRoot: UIView, mediaId: String, userid: String?, backgroundColorHeaderView: UIColor = #489BE6)Mở bảng xếp hạng (iframe)
setInteractivePlayerDelegate(interactivePlayerDelegate:)Gắn delegate player
setupPredictViewDelegate(interactivePredictDelegate:)Gắn delegate layout predict
setuPredictLoginDelegate(interactiveLoginDelegate:)Gắn delegate login cho predict (lưu ý chính tả setuPredict)
embededInteractiveContentView()Chủ động mở dialog nội dung predict/lucky
setHiddenInteractiveButton(_ isHidden: Bool)Ẩn/hiện nút nổi predict/lucky
leaveRoom() / disconnection()Rời phòng / ngắt socket

Gắn delegate cho overlay minigame qua overlayManagement:

interactive.overlayManagement?.setupDelegate(interactiveViewDelegate: self)
interactive.overlayManagement?.setupDelegate(interactiveLoginDelegate: self)
interactive.overlayManagement?.setupDelegate(fanClubDelegate: self)
interactive.overlayManagement?.setupAnswerDelegate(interactiveAnswerDelegate: self)

@objc public class InteractiveSetting: NSObject {
public static let KEY_ENABLE_PROD_ENV = "KEY_ENABLE_PROD_ENV"
public static let KEY_X_TENANT_ID = "KEY_X_TENANT_ID"
public func setEnableProdEnv(enableProdEnv: String) // Enviroment.rawValue
public func setXTenantId(xTenantId: String) // TenantIdType.rawValue
}

Phải gọi cả hai trước mọi joinRoom. Giá trị lưu vào UserDefaults.standard và được đọc lại (force-unwrap) ở nhiều nơi.

public enum Enviroment: String { case DEV = "dev"; case STG = "stg"; case PROD = "prod" }
public enum TenantIdType: String {
case vtvlive // OnPlus
case onliveLiveStream = "onlivev2" // SOOP
case onliveTV = "onlivetv" // OnLive TV
case VTVprime = "VTVprime" // SeeNow
}

Tất cả (trừ PlayerChangeListener) là @objc public protocol … : AnyObject.

func getPlayerState() -> Int // mã trạng thái player, dùng cho sự kiện ckst
func showLiveView(liveView: Int) // số người xem realtime (ĐÃ cộng +230)
func showInteractiveLogin() // gọi khi user tương tác mà chưa đăng nhập
func showLayoutViewPredictRoot() // hiện vùng chứa nút predict/lucky
func hideLayoutViewPredictRoot()
func endLayoutViewPredictRoot()
func confirmDeduction() // đồng ý trừ OnG
func confirmNotEnoughMoney() // thiếu OnG (PM402)
func confirmAnswerSuccess() // trả lời thành công
func showSubscibeView() // mở màn hình nạp/đăng ký (chính tả "Subscibe")
func shrinkScreenInteractive(show: Bool, direction: Int, withXScale x: CGFloat, withYScale y: CGFloat)
func resetLayoutInteractive()
func preloadVideoActionBranching(url: String, timeToNext: TimeInterval)
func nextVideoActionBranching()
func showLayoutViewRoot()
func hideLayoutViewRoot()
func locationLayoutViewRoot(location: Int, width: CGFloat, height: CGFloat) // vị trí 0..8
func hidePlayerControl()
func showPlayerControl()
func viewForPresentDialogDedution() -> UIView? // có default = nil (tùy chọn)
func btnConfirmFanClub() // user bấm xác nhận vào fanclub
func connectedSocket()
func currentPosition() -> CLong?

location trong locationLayoutViewRoot: 0 LeftTop, 1 CenterTop, 2 RightTop, 3 LeftCenter, 4 Center, 5 RightCenter, 6 LeftBottom, 7 CenterBottom, 8 RightBottom.


@objc public protocol OverlayManagement {
var isReadyToShowVodOverlay: Bool { get set }
func initialization(overlayView: UIOverlay)
func setupDataToPrepareShowVOD(timeLineList: [Timelines])
func prepareShowOverlayForVod(overlayList: [Overlay])
func showOverlayLive(overlay: Overlay, authenToken: String, mediaContentId: String,
socketId: String?, bjName: String, buttonPredict: UIImageView)
func showOverlayVod(overlay: Overlay, authenToken: String, mediaContentId: String)
func stopShowOverlayPlayback()
func hiddenOverlay()
func onDestroy()
func removeAllView()
func setupDelegate(interactiveViewDelegate: InteractiveViewDelegate)
func setupDelegate(interactiveLoginDelegate: InteractiveLoginDelegate?)
func setupAnswerDelegate(interactiveAnswerDelegate: InteractiveAnswerDelegate)
func setupDelegate(fanClubDelegate: FanClubDelegate)
func resizeVideoView(width: CGFloat, height: CGFloat)
func webviewPublic() -> WKWebView?
func killDelegate()
func recallOverlay(timelineId: String)
}

App chủ yếu dùng các setupDelegate*, recallOverlay do SDK gọi nội bộ.


Ứng dụng thường không gọi trực tiếp; SDK điều phối.

func connection(url: String, authenToken: String?)
func addCallback(callBack: @escaping (String, Any) -> ())
func joinRoom(data: JoinRoomData)
func leaveRoom(data: JoinRoomData)
func ckstRoom(data: CkstData)
func sendEmitAck(trackingId: String, event: String, stage: String, clientContext: [String: Any])
func isConnected() -> Bool
func getSocketId() -> String
func disconnection()
func onDestroy()

Tên wireHằng sốXử lý
overlaySocketEvents.OVERLAYOverlay realtime
ex-overlaySocketEvents.EX_OVERLAYOverlay bù
overlay-recallSocketEvents.OVERLAY_RECALLThu hồi overlay theo timelineId
predict-timelineSocketEvents.PREDICT_TIMELINEACTIVE/INACTIVE/POWER/END cho nút predict
lucky-eventSocketEvents.LUCKY_EVENTTương tự cho lucky
predict-resultSocketEvents.PREDICT_RESULTanswer1/answer2
update-resultSocketEvents.UPDATE_RESULTĐẩy xuống web qua UPDATE_DATA_INTERACTIVE
liveviewsSocketEvents.LIVE_VIEWSố người xem
dataSocketEvents.FANCLUBTrạng thái fanclub
ckstSocketEvents.CKSTServer hỏi trạng thái player
branchingSocketEvents.BRANCHINGVideo nhánh (branching)

Sự kiện client nội bộ: .connect → CONNECTED, .disconnect → DISCONNECTED, .reconnect → RECONNECT, .error → ERROR.

TênKhi nàoPayload
join-roomSau khi socket connectJoinRoomData = {deviceId, mediaContentId, os, tenantId, versionSDK}
leave-roomleaveRoom()như trên
receive-messagePayload overlay có traceLock == trueBản nhị phân (ArrayBuffer) của payload gốc
emit-ackCác mốc tracking{trackingId, event, stage, deviceId, clientContext}
ckstTrả lời sự kiện ckstCkstData = {action: "CHECK_PLAYER_STATUS", sessionId, os: {…Ckst}}
HeaderGiá trị
x-tenant-idKEY_X_TENANT_ID
vApiConst.VERSION_SDK ("2025-05-25")
osApiConst.OS ("iphone")
deviceIdUIDevice.identifierForVendor
Authorizationtoken nguyên văn (socket không tự thêm Bearer)

Cấu hình: forceWebsockets(true), compress, reconnects(true), reconnectWait(5), randomizationFactor(0.4).


Base URL chọn theo KEY_ENABLE_PROD_ENV:

EnvREST baseWSK base
DEVhttps://dev-api.onplay.live/https://dev-wsk.onplay.live/
STGhttps://beta-api.onplay.live/https://beta-wsk.onplay.live/
PRODhttps://api.onplay.live/https://wsk.onplay.live/
MethodĐường dẫnHeaderDùng cho
GET/api/ctc/scenario/v2/vod/{mediaId}/{os}X-TENANT-IDTải kịch bản VOD
POST/api/actionsX-TENANT-ID, Authorization (Bearer nếu JWT)Gửi hành động / câu trả lời
GET/api/public/vip-statusX-TENANT-ID, AuthorizationKiểm tra VIP (telco) trước khi trừ OnG
GET/api/media/interactive-status/{mediaId}X-TENANT-IDMedia có tương tác không
GET/api/scenario/getActiveOverlay/{mediaId}—Overlay đang hoạt động (bù) — hàm hiện có lỗi trả về đồng bộ, xem 06

Thân request /api/actions (SDK bổ sung vào JSON web gửi lên):

{
"type": "INTERACTIVE_ACTION_REPORT",
"deviceId": "<identifierForVendor>", // SDK thêm
"os": "iphone", // SDK thêm
"data": {
"answer": ..., // từ template
"content": ..., // từ template
"media": "<mediaId>", // SDK thêm
"socket_id": "<socket id>", // SDK thêm (chỉ Live)
"versionSDK": "2025-05-25" // SDK thêm
// ...các trường khác do template gửi
}
}

Tên interface: IOS (userContentController.add(callBack, name: "IOS")).

window.webkit.messageHandlers.IOS.postMessage(JSON.stringify({ type: "INTERACTIVE_ACTION_REPORT", data: {...} }));
type (TypeInteractive)Ý nghĩa
INTERACTIVE_SHOW_ANALYTICSOverlay hiển thị
INTERACTIVE_HIDE_ANALYTICSOverlay đóng → gỡ WebView
INTERACTIVE_ACTION_REPORTTrả lời / hành động (data.action = "CLICK_ADS" cho quảng cáo, mở urlLinkAds)
INTERACTIVE_OPEN_ANALYTICS / INTERACTIVE_CLOSE_ANALYTICSMở/đóng dialog predict/lucky
INTERACTIVE_PING_ANALYTICSChỉ dùng để lọc
window.addEventListener("message", (e) => { /* e.data chứa key + data */ });
keyNội dung
UPDATE_DATA_INTERACTIVECập nhật kết quả realtime (từ update-result)
UPDATE_COUTER (nguyên văn)Số liệu predict answer1/answer2
UPDATE_NUMBER_LUCKYKết quả số may mắn
UPDATE_CONFIRMXác nhận trả lời thành công (nhánh bet/VIP)

Tham sốKhi nào
&logged=false / &logged=trueTheo trạng thái đăng nhập & allowAnonymous
&fanclub=falseTenant onlivev2, requiredFanClub và chưa là fanclub
&duration=<còn lại>Khi countdown > 0 (tính từ ts)
&u=<userId>Riêng lucky (typeTimeline = 5)
timelineId, tenantId, deviceType=IOSRiêng overlay VOD

TrườngKiểuÝ nghĩa
srcStringURL template
metadataMetadata(size, pos, duration?, targets?)Vị trí + kích thước
tsIntMốc thời gian (ms) để tính duration còn lại
timelineID (timelineId)StringĐịnh danh mốc (chống trùng / chống trả lời lại)
mediaContentID (mediaContentId)StringNội dung áp dụng
targetsStringNền tảng (iphone, all…)
duration, frequencyLimit, countdownInt?Thời lượng / giới hạn tần suất
statusString?ACTIVE / INACTIVE…
typeTimelineInt?3 predict, 5 lucky, 2 (bet), còn lại minigame
allowAnonymous, requiredFanClub, isPopupOverlayBool?Điều kiện hiển thị/trả lời
betAmountInt?Số OnG cược
imageNormal, imagePowerString?Ảnh nút predict/lucky
trackingId (_trackingId), emitTimestamp (_emitTimestamp)Metadata tracking

id, src, ttl, ts, pos: OverlayPosition, size: OverlaySize, isPopupOverlay, allowAnonymous, compensatory: Compensatory, userId, requiredFanClub, betAmount, typeTimeline, imageNormal, imagePower, countdown, và trackingSession (internal).

class OverlayPosition { var x: Int; var y: Int; var alignment: OverlayAlignment? } // x/y ∈ {0,1,2}
class OverlaySize { var w: Float; var h: Float } // tỉ lệ so với khung

x: 0 trái / 1 giữa / 2 phải. y: 0 trên / 1 giữa / 2 dưới. → OverlayAlignment.{LeftTop … RightBottom}.

time: String ("SS"/"MM:SS"/"HH:MM:SS"), interactive: VODInteractive?, showStatus: String?, id (_id), computed timeShow: Int (giây).

id, allowAnonymous, isPopupOverlay, requiredFocus, frequencyLimit, metadata: MetadataVod, betAmount, duration, targets, tenantId, src, timelineId, mediaContentId, ts.

mediaId, duration, frequencyLimit, interactiveId, unlockedTime. Lưu vào UserDefaults(suiteName: "INTERACTIVE_<userId|DEFAULT>") theo key mediaId.

tenantId, timlineId (nguyên văn — thiếu chữ e), data: { answer1: Int?, answer2: Int? }.

roomName, isFanClub?, mediaId?; ghi KEY_FAN_CLUB vào UserDefaults.

  • JoinRoomData: {deviceId, mediaContentId, os, tenantId, versionSDK}.
  • CkstData: action = "CHECK_PLAYER_STATUS", sessionId, data: Ckst (map JSON key os). Ckst: {deviceId, os, mediaContentId, playerStatus: Int?, tenantId}.

ApiConst.TYPE_LIVE // = 1
ApiConst.TYPE_VOD // = 2
ApiConst.OS // = "iphone"
ApiConst.VERSION_SDK // = "2025-05-25"

CDN ảnh nút:

PredictConst.CDN_PREDICT_IDLE // btnpredictidle.gif (động)
PredictConst.CDN_PREDICT_POWER // btnpredictpower.gif (động)
PredictConst.CDN_LUCKY_IDLE // lucky-normal.png (tĩnh)
PredictConst.CDN_LUCKY_POWER // lucky-power.png (tĩnh)

← Luồng hoạt động · Về mục lục · Tiếp: Tracking emit-ack →