このページは現在英語版のみで提供されており、日本語版も近日中に提供される予定です。ご利用いただきありがとうございます。

Anchor Battle

Note:
New Battle Arrivals, Limited Time Free Trial Available.

Component Introduction

Battle feature is an intense and entertaining real-time interactive feature designed for anchors and the audience. It allows anchors from different rooms to engage in real-time confrontations, enhancing the competitiveness and entertainment value of live streaming.TUILiveKit's battle feature supports up to 9 anchors participating simultaneously, providing a platform for anchors to showcase their talents and charisma, while offering an exciting viewing experience for the audience. Whether it's a talent competition, knowledge Q&A, or gaming sports, the battle feature creates more interactive opportunities for anchors and the audience, stimulating audience enthusiasm, enhancing the entertainment value and attraction of live streaming, thus bringing more surprises and value to both sides and promoting the diversified development of live streaming content.
In Dual Battle
Dual Battle results
In Multi-player Battle
Multi-player Battle results













Instructions for Use

Note:
Before you initiate or accept a PK, please ensure that you are in a connected state.

Anchor initiates battle

Click the Battle button
Stop Waiting for battle
Exit Battle










Anchor receives battle

Anchor receives Battle invitation
Anchor accepts Battle







Custom Functionality

Custom Battle waiting countdown style

If you need the custom battle waiting countdown style, please refer to the following path for changes:
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/anchor/component/livestreaming/battle/

├── BattleCountdownBackView.java // Battle waiting countdown background style
└── BattleCountdownView.java // Battle waiting countdown foreground style
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/View

View
├── BattleCountDownBackgroundView.swift // Battle waiting countdown background style
└── BattleCountDownView.swift // Battle waiting countdown foreground style

Custom Definition Dual Battle Score Style

If you need the custom Definition Dual battle score style, please refer to the following path for changes:
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/SingleBattleScoreView.java

public class SingleBattleScoreView extends FrameLayout {
...
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/View/SingleBattleScoreView.swift

class SingleBattleScoreView: UIView {
...
func constructViewHierarchy() {
// View Hierarchy Construction
}

func activateConstraints() {
// View Layout
}
}

Custom Definition Multi Battle Score Style

If you need the custom Definition Multi Battle score style, please refer to the following path for changes:
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/BattleMemberInfoView.java

public class BattleMemberInfoView extends FrameLayout {
...
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/View/BattleMemberInfoView.swift

class BattleMemberInfoView: UIView {
...
func constructViewHierarchy() {
// View Hierarchy Construction
}

func activateConstraints() {
// View Layout
}
}

Custom Definition Battle Score Result Style

If you need a Custom Definition Battle Score Result Style, please refer to the following path for changes:
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/BattleInfoView.java

public class BattleInfoView extends BasicView {
...
private void showBattleResult(int type) {
// Battle Result Display
}
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/View/BattleInfoView.swift

class BattleInfoView: UIView {
...
func showBattleResult(store: LiveStore) {
// Battle Result Display
}
}

Key code

Anchor Battle

TUILiveKit Anchor battle feature is mainly based on BattleService. You can obtain the battle management object through store.serviceCenter.battleService and call the relevant battle API functions to implement the battle feature. For example, in the interaction between Anchor A and B, refer to the diagram below for the specific interaction sequence.



Note:
When inviting multiple participants to the battle, if any invitee accepts the battle, only the battle initiator, the battle invitee who accepted, and the audience in the corresponding rooms will receive the onBattleStarted callback.

Anchor A initiates Battle

Anchor A initiates a battle by calling requestBattle, passing the maximum Battle duration in parameter config, whether the inviter needs to reply with accept/reject, and passing anchor B's userId in parameter userIdList, and passing the battle invitation wait duration in parameter timeout.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java

public void requestBattle(List<String> roomIdList, int timeout) {
TUILiveBattleManager.BattleConfig config = new TUILiveBattleManager.BattleConfig();
config.duration = BattleState.BATTLE_DURATION;
config.needResponse = mBattleState.mNeedResponse;
config.extensionInfo = "";
mLiveService.requestBattle(config, roomIdList, timeout, new TUILiveBattleManager.BattleRequestCallback() {
@Override
public void onSuccess(TUILiveBattleManager.BattleInfo battleInfo,
Map<String, TUILiveBattleManager.BattleCode> map) {
mBattleState.mBattleId = battleInfo.battleId;
mBattleState.mBattleConfig.copy(config);
List<BattleState.BattleUser> sendRequests = mBattleState.mSentBattleRequests.get();
for (Map.Entry<String, TUILiveBattleManager.BattleCode> entry : map.entrySet()) {
String key = entry.getKey();
TUILiveBattleManager.BattleCode code = entry.getValue();
if (code == TUILiveBattleManager.BattleCode.SUCCESS) {
for (ConnectionState.ConnectionUser user : mConnectionState.connectedUsers.get()) {
if (TextUtils.equals(user.userId, key)) {
sendRequests.add(new BattleState.BattleUser(user));
break;
}
}
} else {
notifyToast(convertCodeToString(entry.getValue()));
}
}
mBattleState.mSentBattleRequests.set(sendRequests);
}

@Override
public void onError(TUICommonDefine.Error error, String s) {
ErrorHandler.onError(error);
mBattleState.mSentBattleRequests.clear();
}
});
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/API/LSBattleService.swift

func requestBattle(config: TUIBattleConfig, userIdList: [String], timeout: TimeInterval) async throws -> (battleInfo: TUIBattleInfo, resultMap: [String : TUIBattleCode]) {
return try await withCheckedThrowingContinuation { [weak self] continuation in
guard let self = self else { return }
battleManager.requestBattle(config: config, userIdList: userIdList, timeout: timeout) { battleInfo, resultMap in
var battleResult: [String: TUIBattleCode] = [:]
resultMap.forEach { (key: String, value: NSNumber) in
battleResult[key] = TUIBattleCode(rawValue: value.intValue) ?? .unknown
}
continuation.resume(returning: (battleInfo, battleResult))
} onError: { err, message in
let error = InternalError(error: err, message: message)
continuation.resume(throwing: error)
}
}
}
Anchor A can receive the request acceptance callback via onBattleRequestAccept.

Anchor receives a battle request

Anchor B receives the battle request callback via onBattleRequestReceived.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleRequestReceived(BattleInfo battleInfo, BattleUser inviter, BattleUser invitee) {
LiveKitLog.info(mTag + " onBattleRequestReceived:[battleInfo:" + new Gson().toJson(battleInfo)
+ ", inviter:" + new Gson().toJson(inviter) + ", invitee:" + new Gson().toJson(invitee) + "]");
mBattleController.onBattleRequestReceived(battleInfo, inviter);
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/Module/LSBattleManagerObserver
func onBattleRequestReceived(battleInfo: TUIBattleInfo, inviter: TUIBattleUser, invitee: TUIBattleUser) {
manager?.onBattleRequestReceived(battleInfo: battleInfo, inviter: inviter, invitee: invitee)
}
Anchor B accepts the battle request by calling acceptBattle.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java
public void accept() {
mLiveService.acceptBattle(mBattleState.mBattleId, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {

}

@Override
public void onError(TUICommonDefine.Error error, String s) {

}
});
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/API/LSBattleService.swift

func acceptBattle(battleId: String) async throws {
return try await withCheckedThrowingContinuation { [weak self] continuation in
guard let self = self else { return }
battleManager.acceptBattle(battleId: battleId) {
continuation.resume()
} onError: { err, message in
let error = InternalError(error: err, message: message)
continuation.resume(throwing: error)
}
}
}

Anchors A, B, and the audience in the room can receive the battle start callback through onBattleStarted.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleStarted(BattleInfo battleInfo) {
LiveKitLog.info(mTag + " onBattleStarted:[battleInfo:" + new Gson().toJson(battleInfo) + "]");
mBattleController.onBattleStarted(battleInfo);
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/Module/LSBattleManagerObserver
func onBattleStarted(battleInfo: TUIBattleInfo) {
manager?.onBattleStarted(battleInfo: battleInfo)
}

The anchor exits the battle

For example, when anchor B exits the battle, the interaction sequence can be referenced from the diagram below.



Note:
During multi-anchor Battle:
When a anchor exits the battle, the remaining anchors and corresponding room audience will receive the onUserExitBattle callback.
When the battle reaches the preset battle time, the anchors and corresponding room audience will receive the onBattleEnded callback.
When there are two anchors in the battle and one exits, the anchors and corresponding room audience will receive the onBattleEnded callback.
Anchor B calls exitBattle to exit the battle.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/controller/BattleController.java
public void exitBattle() {
mLiveService.exitBattle(mBattleState.mBattleId, new TUIRoomDefine.ActionCallback() {
@Override
public void onSuccess() {
mBattleState.mSentBattleRequests.clear();
mBattleState.mBattledUsers.clear();
removeBattleRequestReceived();
}

@Override
public void onError(TUICommonDefine.Error error, String s) {

}
});
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/API/LSBattleService.swift
func exitBattle(battleId: String) async throws {
return try await withCheckedThrowingContinuation { [weak self] continuation in
guard let self = self else { return }
battleManager.exitBattle(battleId: battleId) {
continuation.resume()
} onError: { err, message in
let error = InternalError(error: err, message: message)
continuation.resume(throwing: error)
}
}
}
Anchors A, B, and the room audience receive the onBattleEnded callback and the battle end notification.
Android
iOS
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/manager/observer/LiveBattleManagerObserver.java
@Override
public void onBattleEnded(BattleInfo battleInfo, BattleStoppedReason reason) {
LiveKitLog.info(mTag + " onBattleEnded:[battleInfo:"
+ new Gson().toJson(battleInfo) + ", reason:" + reason + "]");
mBattleController.onBattleEnded(battleInfo);
}
// File location: iOS/TUILiveKit/Sources/LiveStream/HostBattle/Module/LSBattleManagerObserver

func onBattleEnded(battleInfo: TUIBattleInfo, reason: TUIBattleStoppedReason) {
manager?.onBattleEnded(battleInfo: battleInfo, reason: reason)
}