ライブ配信アプリにホストPK機能を追加する方法 ｜ Androidチュートリアル

多くの人気ライブ配信プラットフォームでは、「PK」（「Player Kill」または「対戦バトル」の略）機能を導入しており、配信者同士が視聴者からのギフト数を競い、最も多くのギフトを獲得した側が勝利となります。場合によっては、ファンからの最後の数秒の大型ギフトによって、ほぼ決まっていた勝敗が覆ることもあり、視聴者にとっては非常にスリリングな体験となります。プラットフォームにとっては、PK機能は配信者に高度な権限を付与し、エンゲージメントを高める重要な仕組みです。

本記事では、[**PK機能**](https://trtc.io/document/67283?platform=android&product=live&menulabel=uikit)をAndroidライブ配信アプリに統合する方法を解説します。

![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/fbf517a6-0ba0-480e-85f3-1439974c408b.png)


Tencent RTCの[**TUILiveKitコンポーネント**](https://trtc.io/document/60037?platform=android&product=live&menulabel=uikit)を使用した既存のライブ配信環境をベースに進めます。

## **カスタム機能**

**カスタムバトル待機カウントダウンスタイル**

バトル待機カウントダウンを独自にカスタマイズしたい場合は、以下のパスのコードを参照して変更してください。

```kotlin
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/anchor/component/livestreaming/battle/

├── BattleCountdownBackView.java    // バトル待機カウントダウン背景スタイル
└── BattleCountdownView.java        // バトル待機カウントダウン前景スタイル
```

**カスタム定義デュアルバトルスコアスタイル**

デュアルバトルスコアを独自にカスタマイズしたい場合は、以下のパスのコードを参照して変更してください。

```kotlin
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/SingleBattleScoreView.java

public class SingleBattleScoreView extends FrameLayout {
    ...
}
```

**カスタム定義マルチバトルスコアスタイル**

マルチバトルスコアを独自にカスタマイズしたい場合は、以下のパスのコードを参照して変更してください。

```kotlin
// File location: tuilivekit/src/main/java/com/trtc/uikit/livekit/view/liveroom/view/common/battle/BattleMemberInfoView.java

public class BattleMemberInfoView extends FrameLayout {
    ...
}
```

**カスタム定義バトルスコア結果スタイル**

バトルスコア結果表示を独自にカスタマイズしたい場合は、以下のパスのコードを参照してください。

```kotlin
// 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) {
        // バトル結果表示
    }
}
```

## **主要コード**

**配信者バトル**

[**TUILiveKit**](https://github.com/Tencent-RTC/TUILiveKit) の配信者バトル機能は主に `BattleService` に基づいており、`store.serviceCenter.battleService` を通じてバトル管理オブジェクトを取得し、関連するバトルAPIを呼び出すことでバトル機能を実装します。たとえば、配信者Aと配信者B間のやり取りにおいては、下記のシーケンス図を参考にしてください。

![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/badb1d33-737b-426b-81cd-a76a47301c62.png)


**配信者Aがバトルを開始**

配信者Aは `requestBattle` を呼び出してバトルを開始します。`config` にバトルの最大継続時間を渡し、招待者が承諾/拒否の返答が必要かどうかを指定し、招待する相手である配信者Bの userId を`userIdList`に設定、そしてバトル招待待機時間を `timeout` に設定します。

```kotlin
// 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();
        }
    });
}
```

配信者Aは、`onBattleRequestAccept` を介してリクエスト受諾のコールバックを受け取ります。

**配信者がバトルリクエストを受信**

配信者Bは、`onBattleRequestReceived` を通じてバトルリクエストのコールバックを受け取り、`acceptBattle` を呼び出すことでリクエストを受諾します。

```kotlin
// 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);
}
```

```kotlin
// 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) {

       }
   });
}
```

配信者A、B、およびルーム内の視聴者は `onBattleStarted` を通じてバトル開始コールバックを受け取ります。

```kotlin
// 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);
}
```

**配信者がバトルから退出**

例として、配信者Bがバトルを退出する場合のシーケンス図は下記を参照してください。

![3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3957687/18acee04-55e0-480d-9d6f-781167383de8.png)


配信者Bは `exitBattle` を呼び出すことでバトルを退出します。

```kotlin
// 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) {

        }
    });
}
```

配信者A、B、およびルーム内の視聴者は `onBattleEnded` を通じてバトル終了のコールバックと通知を受け取ります。

```kotlin
// 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);
}
```

これで、ライブ配信アプリに配信者のPK機能を追加できます！詳しい機能については、[**ドキュメント**](https://trtc.io/document/67283?platform=android&product=live&menulabel=uikit) をご参照ください。

私はSusieと申します。ライター兼メディアサービスのプロダクトマネージャーとして、世界中のスタートアップと協力し、SDKやAPIを活用したリアルタイムコミュニケーションソリューションの構築を支援しています。

アプリにフェイスフィルターやその他の特殊効果機能を実装したい場合は、[**ぜひお問い合わせください**](https://sc-rp.tencentcloud.com:8106/t/RA)。