Live Streaming Kit
  • iOS
  • Android
  • Web
  • Flutter : Dart
  • React Native
  • Overview
  • Quick start
    • Quick start
    • Quick start (with cohosting)
  • Tutorial navigator
  • Enhance the livestream
    • PK battles
    • Screen sharing
    • Advanced beauty effects
    • Minimize livestream window
    • Send virtual gifts
    • Integrate Minigame
  • Customize the livestream
    • Set avatar for users
    • Hide components
    • Customize the preview page
    • Set a leave confirmation dialog
    • Customize the background
    • Add custom UI components
    • Customize the text message UI
    • Customize the member list view
    • Modify User Interface text
    • Customize the menu bar
    • Implement an audio-only live
    • Forcefully end a livestream room
    • Turn off camera during co-hosting
    • Set video resolution
    • Limit the maximum number of co-hosts
    • Host Avatar
    • Calculate live duration
    • Customize The CoHosting
    • Swipe Live Streaming
    • Customize the layout
  • FAQs
  • API Reference
    • API
    • Event
  • Migration guide
  • Documentation
  • Live Streaming Kit
  • Enhance the livestream
  • PK battles

PK battles

Last updated:2024-02-26 15:05

1. Prerequisites

Before you begin, make sure you complete the following:

  • Follow the integration steps by referring to the Quick start with co-hosting.

  • Please contact technical support to activate the Stream Mixing service.

2. What’s PK battles?

A multi-player PK is a friendly competition where audiences can witness the engaged interactions among multiple hosts in two or more live streams.

The buttons on the video view are completely customizable. The example buttons added in the demo are shown in the image below.

3. Quick Start

Hosts can send a PK battle request to the host they want to connect with after they started their own live streams. And both live streams will be connected upon the PK battle request being accepted.

3.1 send PK battle request

ZegoUIKitPrebuiltLiveStreamingController().pk.sendRequest(
    targetHostIDs: [anotherHostUserID],
);

3.2 agree the PK battle request

  ZegoUIKitPrebuiltLiveStreamingEvents(
    pk: ZegoLiveStreamingPKEvents(
      onIncomingRequestReceived: (event, defaultAction) {
        ZegoUIKitPrebuiltLiveStreamingController().pk.acceptRequest(
          requestID: event.requestID,
          targetHost: ZegoUIKitPrebuiltLiveStreamingPKUser(
            userInfo: event.fromHost,
            liveID: event.fromLiveID,
          ),
        );
      },
    ),
  );

3.3 quit pk battle

ZegoUIKitPrebuiltLiveStreamingController().pk.quit();

For a detailed demo source code, click here.

4. APIs

To customize your own PK battle logic and process as needed, the ZegoUIKitPrebuiltLiveStreamingController().pk contains a bunch of methods for you to do further customizations.

Before you make your customization, check the following APIs first.

4.1 APIs of PK inviter:

func name params description
sendRequest required List targetHostIDs

int timeout

String customData

bool isAutoAccept
inviting hosts for a PK.

you will need to specify the [targetHostIDs] you want to connect with.

Remember the hosts you invite must has started a live stream,otherwise, an error will return via the method you called.

you can used [timeout] to set the timeout duration of the PK battle request you sent. After it timed out, the host who sent the request will receive a callback notification via the [ZegoUIKitPrebuiltLiveStreamingPKEvents.onOutgoingRequestTimeout].

if you want to customize the info that you want the host you invited to receive, you can set [customData], and the invited host will receive via [ZegoUIKitPrebuiltLiveStreamingPKEvents.onIncomingRequestReceived].

If you want the remote host to directly accept without a confirmation dialog before entering the PK, you can set [isAutoAccept] to true.
Please note that within the same PK session, this value ONLY takes effect the FIRST time it is set (after the first acceptance of the invitation), subsequent invitations will use the value set during the first acceptance.
cancelRequest required List targetHostIDs

String customData
Cancel the PK invitation to [targetHostIDs].

You can provide your reason by attaching [customData].

If the PK has already started (and any invited host has accepted), the PK invitation cannot be cancelled.
stop Stop PK to all pk-hosts, only the PK Initiator can stop it.

The PK is over and all participants have exited the PK View.
quit Quit PK on your own.

only pop the PK View on your own end, other PK participants decide on their own.
muteAudios required List targetHostIDs

required bool isMute
Silence the [targetHostIDs] in PK, local host and audience in the live streaming won't hear the muted host's voice.

If you want to cancel mute, set [isMute] to false.

4.2 APIs of PK invitee:

func name params description
acceptRequest required String requestID

required ZegoUIKitPrebuiltLiveStreamingPKUser targetHost

int timeout

String customData
Accept the PK invitation from the [targetHost], which invitation ID is [requestID].

If exceeds [timeout] seconds, the accept will be considered timed out.

You can provide your reason by attaching [customData].
rejectRequest required String requestID

required String targetHostID

int timeout

String customData
Rejects the PK invitation from the [targetHost], which invitation ID is [requestID].

If the rejection exceeds [timeout] seconds, the rejection will be considered timed out.

You can provide your reason by attaching [customData].
quit Quit PK on your own.

only pop the PK View on your own end, other PK participants decide on their own.
muteAudios required List targetHostIDs

required bool isMute
Silence the [targetHostIDs] in PK, local host and audience in the live streaming won't hear the muted host's voice.

If you want to cancel mute, set [isMute] to false.

5. Events

Each event has its own event and defaultAction. The defaultAction refers to the default popup behavior within the event.

You can invoke defaultAction.call() to execute the default behavior internally.

During a PK lifecycle, the events thrown by both sides are as follows:

5.1 Events of PK inviter:

func name description
onOutgoingRequestAccepted The PK invitation to [event.fromHost] has been accepted.
onOutgoingRequestRejected The PK invitation to [event.fromHost] has been rejected.
onOutgoingRequestTimeout Your PK invitation has been timeout
onEnded PK invitation had been ended by [event.fromHost]
onUserOffline PK host offline
onUserQuited PK host quit

5.2 Events of PK invitee:

func name description
onIncomingRequestReceived Received a PK invitation from [event.fromHost], with the ID [event.requestID].
onIncomingRequestCancelled The received PK invitation has been canceled by the inviting host [event.fromHost].
onIncomingRequestTimeout The received PK invitation has timed out.
onEnded PK invitation had been ended by [event.fromHost]
onUserOffline PK host offline
onUserQuited PK host quit

6. Customize

6.1 UI

If you want to customize the PK interface, we currently provide the following options:

  • pKBattleViewTopPadding: You can use this to set the top padding for the toolbar in the PK interface.
  • hostReconnectingBuilder: This allows you to set the UI effect for when a PK user temporarily goes offline.
  • pkBattleViewForegroundBuilder: You can use this to add additional custom views or controls to the foreground of the PK interface.
  • pkBattleViewTopBuilder: This allows you to add custom views or controls to the top of the PK interface.
  • pkBattleViewBottomBuilder: You can use this to add custom views or controls to the bottom of the PK interface.

These options provide flexibility for customizing various aspects of the PK interface according to your requirements.

Among these, the definition of the `ZegoLiveStreamingPKBattleHostReconnectingBuilder` and the `ZegoLiveStreamingPKBattleViewBuilder` are as follows:
typedef ZegoLiveStreamingPKBattleHostReconnectingBuilder = Widget Function(
  BuildContext context,
  ZegoUIKitUser? host,
  Map<String, dynamic> extraInfo,
);

typedef ZegoLiveStreamingPKBattleViewBuilder = Widget Function(
  BuildContext context,
  List<ZegoUIKitUser?> hosts,
  Map<String, dynamic> extraInfo,
);

To be specific, if you want to place custom views above, below, and on top of PKView, you can check the following sample code as a reference:

// ZegoUIKitPrebuiltLiveStreamingConfig
config.pkBattleConfig.pkBattleViewBottomBuilder = (
  BuildContext context,
  List<ZegoUIKitUser?> hosts,
  Map<String, dynamic> extraInfo,
) {
  return Container(
    color: Colors.red,
    child: const Center(
      child: Text('pkBattleViewBottomBuilder'),
    ),
  );
};

// ZegoUIKitPrebuiltLiveStreamingConfig
config.pkBattleConfig.pkBattleViewTopBuilder = (
  BuildContext context,
  List<ZegoUIKitUser?> hosts,
  Map<String, dynamic> extraInfo,
) {
  return Container(
    color: Colors.red,
    child: const Center(
      child: Text('pkBattleViewTopBuilder'),
    ),
  );
};

// ZegoUIKitPrebuiltLiveStreamingConfig
config.pkBattleConfig.pkBattleViewForegroundBuilder = (
  BuildContext context,
  List<ZegoUIKitUser?> hosts,
  Map<String, dynamic> extraInfo,
) {
  return Positioned(
    bottom: 80,
    left: 0,
    right: 0,
    child: Container(
      color: Colors.red,
      child: const Center(
        child: Text('pkBattleViewForegroundBuilder'),
      ),
    ),
  );
};

The effect will be like this:

6.2 configs

  • userReconnectingSecond: If the connection with a PK user is lost for a userReconnectingSecond period of time, it will trigger hostReconnectingBuilder, which waits for the user to reconnect.

  • userDisconnectedSecond: When a PK user loses connection for more than userDisconnectedSecond, they will be automatically kicked out of the PK.

7. Migration Guide

Starting from version v2.23, we have introduced support for multiplayer PK(Certainly, the old version of two-player PK is still compatible).

If you wish to migrate from the old version of two-player PK to the new version of multiplayer PK, please refer to the following:

7.1 APIs

The methods in ZegoUIKitPrebuiltLiveStreamingPKService can be replaced with the methods in ZegoUIKitPrebuiltLiveStreamingController().pk.

ZegoUIKitPrebuiltLiveStreamingPKService ZegoUIKitPrebuiltLiveStreamingController().pk description
sendPKBattleRequest sendRequest The requestID is the ID of the current PK session.
cancelPKBattleRequest cancelRequest
acceptIncomingPKBattleRequest acceptRequest The requestID is the event.requestID that you received in the onIncomingRequestReceived event.
rejectIncomingPKBattleRequest rejectRequest The requestID is the same as the event.requestID that you received in the onIncomingRequestReceived event.
stopPKBattle stop The requestID is the result.requestID returned by the sendRequest function.
muteAnotherHostAudio muteAudios
startPKBattleWith none After accepting the PK invitation, the interface will automatically switch to the PK screen, and no further action is required.

If you want the other party to directly enter the PK after the invitation is sent, you can set the isAutoAccept parameter to true in the sendRequest function.

for example, if you previously used ZegoUIKitPrebuiltLiveStreamingService().sendPKBattleRequest(anotherHostUserID) to send a PK invitation, now you should use ZegoUIKitPrebuiltLiveStreamingController().pk.sendRequest([hostUserID]).

7.2 Events

The events in ZegoUIKitPrebuiltLiveStreamingConfig.pkBattleEvents can be replaced with the events in ZegoUIKitPrebuiltLiveStreamingEvents.pk.

ZegoUIKitPrebuiltLiveStreamingConfig.pkBattleEvents ZegoUIKitPrebuiltLiveStreamingEvents.pk description
onIncomingPKBattleRequestReceived onIncomingRequestReceived The requestID parameter from the event will be required when using the acceptRequest or rejectRequest functions.
onIncomingPKBattleRequestCancelled onIncomingRequestCancelled
onIncomingPKBattleRequestTimeout onIncomingRequestTimeout
onOutgoingPKBattleRequestAccepted onOutgoingRequestAccepted
onOutgoingPKBattleRequestRejected onOutgoingRequestRejected
onOutgoingPKBattleRequestTimeout onOutgoingRequestTimeout
onPKBattleEndedByAnotherHost onEnded

8. FAQ

8.1 Server Matching

If you want users to automatically enter a PK after server matching, you can do the following

Let's say you have matched three users with IDs 1001, 1002, and 1003 for the PK.

You should select one of the users, for example, 1001, and call ZegoUIKitPrebuiltLiveStreamingController().pk.sendRequest as follows:

ZegoUIKitPrebuiltLiveStreamingController().pk.sendRequest(
    targetHostIDs: ["1002", "1003"],
    isAutoAccept: true,
);

In this case, when users 1002 and 1003 receive the PK invitation, they will automatically enter the PK without the need for manual acceptance.

8.2 Custom Layout

The default layouts for different numbers of participants are as follows
  • When there are two PK users:

  • When there are three PK users:

  • When there are four PK users:

  • When there are five PK users:

  • When there are six PK users:

  • When there are more than six PK users:

How to customize the pk layout?

If you want to customize the layout for PK, you just need to inherit from ZegoPKMixerLayout and override two methods: getResolution and getRectList.

  • getResolution: should return the width and height of the entire canvas for the streams.
  • getRectList: should return the coordinates of the hostCount users on the canvas.

Here's an example using a simple 1x2, 2x2, 3x3 grid layout:


/// two:
/// ┌───┬────┐
/// │???? │ ???? │
/// └───┴────┘
/// four:
/// ┌───┬───┐
/// │???? │???? │
/// ├───┼───┤
/// │???? │   │
/// └───┴───┘
/// nine:
/// ┌───┬───┬───┐
/// │???? │???? │???? │
/// ├───┼───┼───┤
/// │???? │???? │???? │
/// ├───┼───┼───┤
/// │???? │???? │   │
/// └───┴───┴───┘
class PKGridLayout extends ZegoPKMixerLayout {
  @override
  Size getResolution() => const Size(1080, 960);

  @override
  List<Rect> getRectList(
    int hostCount, {
    double scale = 1.0,
  }) {
    final resolution = getResolution();
    final rowCount = getRowCount(hostCount);
    final columnCount = getColumnCount(hostCount);
    final itemWidth = resolution.width / columnCount;
    final itemHeight = resolution.height / rowCount;

    final rectList = <Rect>[];
    var hostRowIndex = 0;
    var hostColumnIndex = 0;
    for (var hostIndex = 0; hostIndex < hostCount; ++hostIndex) {
      if (hostColumnIndex == columnCount) {
        hostColumnIndex = 0;
        hostRowIndex++;
      }

      rectList.add(
        Rect.fromLTWH(
          itemWidth * hostColumnIndex * scale,
          itemHeight * hostRowIndex * scale,
          itemWidth * scale,
          itemHeight * scale,
        ),
      );

      ++hostColumnIndex;
    }

    return rectList;
  }

  int getRowCount(int hostCount) {
    if (hostCount > 6) {
      return 3;
    }
    if (hostCount > 2) {
      return 2;
    }
    return 1;
  }

  int getColumnCount(int hostCount) {
    if (hostCount > 4) {
      return 3;
    }
    return 2;
  }
}

9. Demo

For a detailed demo source code, click here.

Page Directory