👩🏽‍💻

Bunch Party Kit Integration Guide

This guide explains the steps required to integrate Bunch Party Kit into your game.

Step by Step Bunch Party Kit integration guide:

Sign Bunch Developer Platform Terms of Service

Before starting the integration work, make sure you've signed Bunch Developer Platform Terms of Service. If you didn't sign it yet, or are not sure, contact us on the shared Slack channel, or email developers@bunch.live.

Get your API Key

Once you've signed the Bunch Developer Platform ToS we will issue an APIKey for each of the games you're planning to integrate with the Bunch Party Kit. Together with the APIKey, you will receive a gameKey for your game. A gameKey is a unique identifier of your game in the Bunch system. Again, if you don't have the APIKey yet, or you're not sure, contact us on the shared Slack channel, or email developers@bunch.live.

Setup URI Scheme

When Bunch sends players from the Bunch app to your game, it uses a URI scheme defined by your game to open it directly. Each mobile app chooses their URI scheme and sets it up in the app configuration. Typically the URI scheme reflects the app name, for example for the Bunch app it's simply bunch:// For the purpose of this document we will use yourgame:// as a placeholder for your game's custom URI scheme.

💡
To learn more about setting up deep linking URI scheme for your app, see the developer documentation for iOS and Android.
Register Your Developers and Testers

Registering your developers and testers with the access to the Bunch integration is a three step process:

  1. First we will need a list of email addresses for all the developers and testers. We will invite people on this list to our Test Flight / App Tester to give them access to a special build of the Bunch App.
  2. Once they accept the invite and download the special build of the Bunch App, they will need to create Bunch accounts on that app. Those accounts will be able to access developer functions in the Bunch app, which will enable them to set up and test game integration.
  3. Then we will need a list of GitHub accounts of all developers who will be working on the integration - as we're using GitHub authentication to grant access to our SDK (build artifacts and repository)

To set up the integration please contact us on the shared Slack channel, or email at developers@bunch.live. At this point typically we are able to set up a zoom call with your team working on the integration to answer any questions and make sure everything is set up correctly.

🔧
In the future we will offer a web based developer portal, which will allow self-serve set up and management of the Bunch integration.
Add Bunch SDK to your project

After everything is set up, it's time to add Bunch SDK (a.k.a Bunch Party Kit) to your game's project. Bunch SDK supports standard dependency management and build systems: Cocoapods for iOS and Gradle for Android.

On Android, add Bunch to the dependencies section of the build.gradle and file and include jitpack as a repository for the project:

dependencies {
    ...
		implementation com.github.BunchLive:bunch-sdk:SDK_VERSION
    ...
}
...
repositories {
    maven {
			  url "https://jitpack.io"
    }
}
⚠️
The minimum version required by the Bunch SDK is Android 5.0 (API Level 21)

On iOS, add Bunch pod dependency:

platform :ios, '9.0'

target 'YOUR_GAME' do
...
  pod 'Bunch/BunchSDK', 'SDK_VERSION'
...
end
⚠️
The minimum version required by the Bunch SDK is iOS 9.0.
💡
The current version of the Bunch SDK is 1.1.0
Configure your project

Then you need to ensure that the permissions required by the Bunch SDK.

There is no extra steps for Android, but on iOS there are two permissions (camera and microphone), so the following keys need to be included in the Info.plist

<key>NSCameraUsageDescription</key>
<string>This game needs Camera permission to enable in-game video chat.</string>
<key>NSMicrophoneUsageDescription</key>
<string>This game needs Microphone permission to enable voice and video chat.</string> 

Additionally you need to include bunchin your game's Info.plist file's LSApplicationQueriesSchemes key.

<key>LSApplicationQueriesSchemes</key>
<array>
...
	<string>bunch</string>
...
</array>

This will allow Bunch SDK to detect whether the Bunch app is installed on the device, so that it can optimize the experience for players who already have Bunch account and app. To learn more about LSApplicationQueriesSchemes check Apple's documentation here.

Initialization

Once Bunch SDK is added to your game, the first step is to initialize it. This is done by calling static initialize() function on BunchClient. The initialization requires two components:

  • BunchClientConfig object which stores your Bunch APIKey and your gameKey (see Get your API Key section of this guide for more details)
  • Implementation of a BunchClientInterface (a listener on Android and a delegate on iOS) with specific callbacks so that the game behaves correctly in reaction to certain events originating from Bunch. You will learn more about implementing those callbacks in Player Matching and Custom Player Dialogs sections of this guide.
Code Sample - Kotlin
class MainActivity : AppCompatActivity(), BunchClientDelegate {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //...
				BunchClient.apply {
				          initialize(
				              BunchClientConfig(
				                  apiKey = API_KEY,
				                  gameId = GAME_ID,
				                  buildType = BunchClientConfig.BuildType.Beta
											),
				              this@MainActivity,
				              this@MainActivity
				          )
				      }
		}
		//...
		override fun startGameSessionForBunch(party: BunchParty) {
       
    }

    override fun joinGameSessionForBunch(sessionId: String) {
        
    }

    override fun playerDidJoinBunchParty(party: BunchParty) {
        
    }

    override fun playerDidLeaveBunchParty(party: BunchParty) {
       
    }

    override fun anotherPlayerDidJoinBunchParty(userName: String) {
       
    }
}
Code Sample - Swift
@main
class AppDelegate: UIResponder, UIApplicationDelegate {

    func application(_ application: UIApplication,
                     didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

	      //...
        let bunchConfig = BunchClientConfig(apiKey: API_KEY,
                                            gameId: GAME_ID,
                                            buildType: .beta)
        BunchClient.initialize(config: bunchConfig, delegate: self)
				//...
				return true
    }
		//...
extension AppDelegate: BunchClientDelegate {
    func startGameSessionForBunch(client: BunchClient, party: BunchParty) {
        
    }

    func joinSessionForBunch(client: BunchClient, sessionId: String) {
        
    }

    func playerDidJoinBunchParty(party: BunchParty) {
        
    }

    func playerDidLeaveBunchParty() {
        
    }

    func anotherPlayerDidJoinBunchParty(userName: String) {
        
    }
}
  • Optional completion parameter. The callback allows the game to be notified when the initialization process if completed and all methods on the SDK interface are ready to be called.
Player Matching

Player Matching is a system which ensures that players who open your game from a specific Bunch party end up playing together in the same associated multiplayer session in your game. It uses deep linking protocol to ensure players arriving in your game can be taken to the right place. To learn more about how it works see product documentation.

From the implementation perspective, the Player Matching system has 3 parts:

  • Deep link handling to correctly recognize players opening the game from Bunch
  • Callbacks to direct the game to let the player start or join a multiplayer game session
  • API calls linking party and game session

Combined, they form the system illustrated in the following diagram:

image

In the diagram above gameSessionId is a unique identifier of the multiplayer game session the player is in. Other players need to be able to join the same session using this id.

When a Bunch user selects to play your game in the Bunch app, the game will be opened with a specific deep link. As soon as the game is launched, and the Bunch SDK is initialized the game should call the handleDeepLink() function of the BunchClient instance passing on the entire deep link as the parameter. It's safe to call the function even if the game was opened with a non-Bunch specific deep link (e.g. an ad, game invite link, etc.). In such case, the function will ignore the deep link and return false. If it recognizes the deep link as a valid Bunch deep link it will process it and return true.

Code Sample - Kotlin
BunchClient.instance.handleDeeplink(uri)
Code Sample - Swift
BunchClient.instance().handleDeeplink(url: url)

Depending on what deep link Bunch App used to open your game (which was then passed to handleDeepLink() function) one of the two callbacks will be triggered: startSessionForBunch() or joinSessionForBunch() - so implementing those callbacks correctly is critical to making the Bunch integration work correctly.

startSessionForBunch() should result in the new multiplayer game session being created with the player opening the game being present in that session. This can be very different, depending on the game:

  • in some games, this can be done instantly if the game is able to create a multiplayer session without player input. If that's the case, the game should call linkGameSessionId() passing the game session id, and if necessary, take player to the right place (screen) in the game, where they can wait for other players to join them.
  • Code Sample - Kotlin
    override fun startGameSessionForBunch(party: BunchParty) {
            updateDemoFragment()
    	BunchClient.instance.party?.linkGameSessionId(gameSessionId) {
    		// handle exceptions here		
      }
    }
    Code Sample - Swift
    func startGameSessionForBunch(client: BunchClient, party: BunchParty) {
    	BunchClient.instance().getParty()?.linkGameSessionId(gameSessionId: text) { isSuccessful, error in
    	  // handle exceptions here         
    	}
    }
  • In some games, a user interaction (such as choosing a map to play on) is required before a game session can be started. In such case, startSessionForBunch() implementation should take the player to the appropriate destination in the game to set up the multiplayer session with as little steps as possible. Once the user has completed the set up, and the new session is started and available for other players to join, the game should call linkGameSessionId() then.

Once the game session is successfully linked to the party, other participants of that Bunch party will open your game from the Bunch app to play together with the host who's already in the game. For those players a different deep link will be used, so that when they start the game, calling handleDeepLink() will result in joinSessionForBunch() callback being triggered.

joinSessionForBunch() should result in the player joining the specified game session, which was previously linked to the party. Bunch enables it by passing through the same game session id, which was previously provided in the linkGameSessionId() by the host player's game client.

Code Sample - Kotlin
override fun joinGameSessionForBunch(sessionId: String) {
	// add this player to the specified game session
	// similar to how you would handle opening an invite link to this game session
}
Code Sample - Swift
func joinSessionForBunch(client: BunchClient, sessionId: String) {
	// add this player to the specified game session
	// similar to how you would handle opening an invite link to this game session
}

Finally, the last step is to unlink the game session once it's no longer available, i.e. no new players can join it using the same game session id. Depending on the game, this can be the case if the game lobby is full or the game session has ended. Before unlinking the game session, it's important to check that:

  • the party still exists (the player may have left the party)
  • the game session id currently assigned to the party still matches the one which just became unavailable (another player may have linked a different game session with the party).
Code Sample - Kotlin
BunchClient.instance.party?.unlinkGameSessionId() {
	// handle exceptions here		
}
Code Sample - Swift
BunchClient.instance().getParty()?.unlinkGameSessionId() { isSuccessful, error in
  // handle exceptions here         
}
Party Reservation

While Player Matching makes it easy for people who are in the same Bunch party to play your game together, Party Reservation is designed to make it easy for people who play together to join the same Bunch Party to chat directly in your game. To learn more about how it works see product documentation.

The most important concept of the Party Reservation system is gameSessionId - a game generated unique identifier which all people who play together share - depending on the game it could be an id of room, lobby, session, match etc. It enables your game to reserve a party in the Bunch system such that all players in the same game session can join the same Bunch party. As such, party reservation should be called when a player enters a multiplayer session, ideally with at least one other player (e.g. when entering a match lobby).

The following diagram illustrates how Party Reservation works:

image

Couple important things to note:

  • promptToJoinParty() requires the game to pass gameSessionId - so that all players who are in the same game session can be directed by Bunch to the same party. This means that when multiple game clients call promptToJoinParty() on behalf of different players who are in the same game session, only one party will be reserved and they all will be prompted to join it.
  • The game won't be able to reserve a new party, if the player already participates in another party. This can be the case for example, if the player opened the game directly from Bunch App, as described in the Player Matching section of this guide.
  • When reserving a party, the game can choose between Voice & Video, or Voice-Only party types. In the first case players who join the party will be able to turn their camera on and video chat, while the latter will result in voice chat only.
  • ⚠️
    In some cases, the party returned through the party reservation system can be voice & video type, even if voice-only type was specified when calling promptToJoinParty(). This is possible in two cases: - the game client reserved a party for the same game session id as the one passed to promptToJoinParty() with voice & video type earlier (this should never happen if the game is consistent with the party type when using party reservation) - a party created in Bunch App earlier was associated with the same game session id as the one passed to promptToJoinParty() through Player Matching system.
  • promptToJoinParty() shows a built-in platform dialog to the player. To learn how you can use your own custom dialogs instead, see Customizing Player Dialogs section below.
Code Sample - Kotlin
if (BunchClient.instance.bunchUser.isInParty) {
	// is user already participates in a party, link game session instead 
	// of using party reservation system   
	BunchClient.instance.party?.linkGameSessionId(gameSessionId) {
		// handle exceptions here		
  }
} else {
	// prompt player to join the party reserved for the specific gameSessionId
	BunchClient.instance.promptToJoinParty(
            gameSessionId,
            BunchPartyType.VOICE_AND_VIDEO,
					//BunchPartyType.VOICE_ONLY,
  )
}
Code Sample - Swift
if BunchClient.instance().getUser().isInParty() {
	// is user already participates in a party, link game session instead 
	// of using party reservation system  
	BunchClient.instance().getParty()?.linkGameSessionId(sessionId: text) { isSuccessful, error in
	  // handle exceptions here         
	}
} else {
	// prompt player to join the party reserved for the specific gameSessionId
	BunchClient.instance().promptToJoinParty(
						gameSessionId: text,
						BunchParty.BunchPartyType.voiceAndVideo
					//BunchParty.BunchPartyType.voiceOnly                                                    
	)
}

One thing to keep in mind is that, when the player reacts to the prompting dialog and decides to join party for the first time they will be asked to quickly create a guest Bunch account before they can participate in the party - see Guest Experience section of the product documentation.

As part of the guest account creation, the player is asked to create a Bunch user name; this name is used across Bunch surfaces to make the user experience more intuitive. To speed up the guest account creation process, it's possible for the game to pass on the name the player uses in the game to prefill the user name in the guest account creation form, saving players from typing it in. So if your game displays player names (a game handle, a gamer tag etc) , set the default name on the BunchUser object before using promptToJoinParty()

Code Sample - Kotlin
// if isAuthenticated is true, user already has an account and won't be asked 
// to create a new one - so no need to prefill the user name then.
if (!BunchClient.instance.bunchUser.isAuthenticated) {
	BunchClient.instance.bunchUser.userNameDefaultValue = PLAYER_NAME
}
Code Sample - Swift
// if isAuthenticated is true, user already has an account and won't be asked 
// to create a new one - so no need to prefill the user name then.
if BunchClient.instance().getUser().isAuthenticated() {
	BunchClient.instance().getUser().setUserNameDefaultValue(PLAYER_NAME)		
}
Leaving Party

Once players join the party they have access to controls allowing them to leave the party at any time they want. For most games leaving the full control over when to leave the party to the player works just fine, but there may be cases, where games want to prompt the user to leave the party or allow them to leave it without interacting with Bunch Overlay UI (for example by having a permanent “leave party” button on the game’s UI. To facilitate it, BunchParty has two relevant methods:

  • promptToLeave() which shows the dialog asking user to confirm if they want to leave the party.
  • leave() which gets the user to leave the party immediately. The game should only call this function after showing a custom UI asking or at least informing the user about leaving the party. Otherwise it can result in a user leaving the party abruptly, which is a confusing experience for the user.
Code Sample - Kotlin
if (BunchClient.instance.bunchUser.isInParty) {
		// use one of the calls below as required
		BunchClient.instance.party?.promptToLeave()	
		BunchClient.instance.party?.leave()	
} else {
	// user is currently not in a party
}
Code Sample - Swift
if BunchClient.instance().getUser().isInParty() {
	// use one of the calls below as required
	BunchClient.instance().getParty()?.promptToLeave()
	BunchClient.instance().getParty()?.leave()
} else {
	// user is currently not in a party
}
Customizing Player Dialogs

Party Reservation system relies heavily on player-facing dialogs - a notification-like UI which guides players through process of partying up in your game. There are two such dialogs to help players up:

  • Start party dialog - shown to all players in the game session when the party is reserved for that game session. The objective is to encourage all of the players to join the party and chat while they play together. This dialog is shown by calling promptToJoinParty() function as explained in Party Reservation section of this guide.
  • Join party dialog - shown to players who dismissed the "start party dialog" after at least one other player did start a party. The objective is to bring the remaining players into the party. This dialog is shown automatically by the SDK.

While Bunch SDK provides the built-in dialogs, it's possible to build custom dialogs which better fit the look and feel of your game. To use your custom dialogs for:

  • Start party dialog - First, simply show your custom built dialog instead of calling promptToJoinParty() function. Such custom dialog should encourage the player to start a voice chat for the game. It's a good practice to include names of other players in the game session to make the dialog more personal. For example, if you want to reserve a party for game session with 3 players: Adam, Kate and Mike, each player should see a message encouraging them to start the party to chat with the other 2 players - "Start a voice party to chat with Kate and Mike" shown to Adam, "Start a voice party to chat with Adam and Mike" shown to Kate etc.
  • For reference here's how the generic built-in dialog looks like:

    image

    At the same time when showing your own custom dialog you need to call subscribeToParty() passing the game session id that you'd otherwise pass to promptToJoinParty(). This allows the SDK to get notified when certain party events (like other participants joining) occur.

    Code Sample - Kotlin
    if (BunchClient.instance.bunchUser.isInParty) {
    	// is user already participates in a party, link game session instead 
    	// of using party reservation system   
    	BunchClient.instance.party?.linkGameSessionId(gameSessionId) {
    		// handle exceptions here		
      }
    } else {
    	// Show your own custom UI prompting player to join party here
    	// At the same time call subscribeToParty to allow SDK to receive 
    	// relevant party events.
    	BunchClient.instance.subscribeToParty(gameSessionId)
    }
    Code Sample - Swift
    if BunchClient.instance().getUser().isInParty() {
    	// is user already participates in a party, link game session instead 
    	// of using party reservation system  
    	BunchClient.instance().getParty()?.linkGameSessionId(gameSessionId: text) { isSuccessful, error in
    	  // handle exceptions here         
    	}
    } else {
    	// Show your own custom UI prompting player to join party here
    	// At the same time call subscribeToParty to allow SDK to receive 
    	// relevant party events.
    	BunchClient.instance().subscribeToParty(gameSessionId: text)
    }

    When player reacts to your dialog and takes action to start chatting (equivalent to tapping "Let's go!" button in the generic built-in dialog) simply call joinParty() function.

    Code Sample - Kotlin
    BunchClient.instance.joinParty(
                gameSessionId,
                BunchPartyType.VOICE_AND_VIDEO,
    					//BunchPartyType.VOICE_ONLY,
    )
    Code Sample - Swift
    BunchClient.instance().joinParty(
    						gameSessionId: text,
    						BunchParty.BunchPartyType.voiceAndVideo
    					//BunchParty.BunchPartyType.voiceOnly                                                    
    )

    The following diagram shows the sequence of events when using your own custom UI for Start Party dialog:

    image
  • Join Party dialog- If you want to use your own custom Join Party dialog - first, the automatic built-in dialogs need to be disabled. To do it, set the showBuiltInJoinPartyDialog property of the BunchClientConfig when initializing the SDK.
  • Then, show your custom dialog in the implementation of anotherPlayerDidJoinBunchParty() function of BunchClientInterface. When calling this function, the SDK will pass the Bunch userName of the player who joined the party, so that your dialog can be personalized - similar to the build-in default dialog shown below.

    image
    Code Sample - Kotlin
    override fun anotherPlayerDidJoinBunchParty(userName: String) {
    	if (!BunchClient.instance.bunchUser.isInParty) {
    		// show your custom Join Party dialog here. Use userName parameter 
    		// indicating the name of the player who started the party 
    		// to personalize the message. 
    	}   
    }
    
    Code Sample - Swift
    func anotherPlayerDidJoinBunchParty(userName: String) {
    	if BunchClient.instance().getUser().isInParty() {
    		// show your custom Join Party dialog here. Use userName parameter 
    		// indicating the name of the player who started the party 
    		// to personalize the message. 
    	}        
    }

    Lastly, when player reacts to your dialog and takes action to join the party (equivalent to tapping "Join" button in the generic built-in dialog) simply call joinParty() function.

    Code Sample - Kotlin
    BunchClient.instance.joinParty(
                gameSessionId,
                BunchPartyType.VOICE_AND_VIDEO,
    					//BunchPartyType.VOICE_ONLY,
    )
    Code Sample - Swift
    BunchClient.instance().joinParty(
    						gameSessionId: text,
    						BunchParty.BunchPartyType.voiceAndVideo
    					//BunchParty.BunchPartyType.voiceOnly                                                    
    )
    💡
    Keep in mind that anotherPlayerDidJoinBunchParty() will continue to be called whenever other players join the party even after the player did join the party - so you need to take it into account when generating custom notifications. Alternatively you can call unsubscribeFromParty() after player joined the party to stop receiving anotherPlayerDidJoinBunchParty() calls altogether - if generating the join party notification is the only thing you’re using it for.
Overlay Developer Controls

Bunch Overlay is the main UI component of the Bunch SDK. For the most part, it's automatically managed by the SDK and shown automatically when needed (for example when a player decides to join a reserved party). To learn more about how it works see product documentation.

Most of the times when the Overlay is present on the screen, your player will control it, but the SDK also offers a number of Developer Settings to optimize the player experience based on what's happening in the game.

The Developer Controls for the Overlay are:

  • Setting Overlay state
    1. The three Overlay states are:

    2. Expanded - Overlay state showing the expanded UI, with all participants and control panel visible.
    3. Minimized - Overlay state showing a small circle with current speaker's camera view (or profile picture).
    4. Hidden - Overlay state with most UI hidden, reduced to a bookmark.
    5. To learn more about the different states see product documentation.

      Most of the time, the player controls the Overlay and switches between different states depending on current needs, but it's possible to programmatically force the Overlay to a specific state. Doing it however can be disruptive and confusing to the user - as normally they are in control of switching between states and it may prevent them from doing something they wanted to do. As such it should only be used when necessary - for example when having expanded state on the screen could negatively impact user's ability to play the game.

      Code Sample - Kotlin
      val overlay = BunchClient.instance.overlay
      if (overlay.state == BunchOverlay.BunchOverlayState.EXPANDED) {
          overlay.state = BunchOverlay.BunchOverlayState.MINIMIZED
      }
      Code Sample - Swift
      let overlay = BunchClient.instance().getOverlay()
      if overlay.state == .expanded {
      	overlay.state = .minimized
      }
  • Setting default state and position:
  • It's possible to specify the default state and position of the Overlay.

    The default state specifies which state the Overlay first opens to. If no default state is set by the game, the Overlay will open to EXPANDED state. To learn more about the three available Overlay states see the Setting Overlay state in this guide. You can set the default state by changing defaultOverlayState property of BunchClientConfig when initializing the SDK.

    The default position specifies the position on the screen where the Overlay is shown in the MINIMIZED state. If no default position is set by the game, the Overlay will be shown near top right corner of the screen.

  • Showing & dismissing the Overlay
  • The SDK automatically shows the Overlay when it's required by the player to control the party experience. This is the case, for example, if the player opens the game directly from Bunch (as described in Player Matching section) or when they decide to join the party after being prompted to do so (as described in Party Reservation section).

    💡
    The one exception, when the doesn't automatically show the Overlay is on the game startup. In some cases, when SDK is initialized, it will detect that there's an ongoing party which player participated in and can rejoin. If that's the case it will signal it to the game, by calling playerDidJoinBunchParty() The game can then choose the right moment to ask the player if they want to re-join the party by calling show() function on the Overlay object. This will show an alert asking the player if they want to rejoin the party, and shows the Overlay if they choose to rejoin (and signal it to the game through the onComplete callback accordingly. Alternatively the game can choose to not let the user to rejoin the party and have it discarded but calling leave() on the Party object instad.

    The game can also completely dismiss the overlay when it's no longer needed. However, this can only be done if the player is not currently in a party. Otherwise dismissing the Overlay would make controlling the party experience (muting etc.) impossible. For this reason, when the game wants to dismiss Overlay it's highly recommended to set Overlay state to HIDDEN instead of dismissing it completely - as it allows player to bring it back if they want to control the party experience. See the Setting Overlay state in this guide to learn more about the different Overlay states.

  • Pin & Unpin the Overlay
    1. By default, when in minimized state the Overlay is "floating", i.e. it's rendered on top of the game's UI. Because player can freely drag it around the screen or move it off the screen almost entirely (by switching to hidden state), the Overlay doesn't get in the way of the gameplay. It's possible however to incorporate the Overlay directly into game's UI instead. This can be done by pinning the Overlay to a specific point on the screen. When the Overlay is pinned it:

    2. transitions to the minimized state, placing the circle at specified position on the screen
    3. cannot be moved around the screen by the user
    4. cannot be collapsed to the hidden state by the user
    5. can still be tapped on to transition to the expanded state by the user. When minimized by the user, it goes back to the same position it was pinned to.
    6. With the above characteristic, pinned Overlay can be seen as an integral part of the game's UI rather than a floating UI.

  • Overlay State Change Callbacks
    1. As user controls the party experience, the state of the overlay can change at any time. The overlay changes include:

    2. Overlay appearing (when player joins the party)
    3. Overlay disappearing (when player leaves the party)
    4. Overlay transitioning between expanded, minimized and hidden states (when player interacts with it)
    5. If your game needs to react to any of the above state changes (for example adjust in-game UI accordingly) the game can get notified through BunchOverlayDelegate on iOS and BunchOverlayStateListener on Android. To do it, implement the relevant Delegate / Listener and then register it with BunchOverlay:

      Code Sample - Kotlin
      BunchClient.instance.overlay.stateListener = yourOverlayStateListener
      Code Sample - Swift
      BunchClient.instance().getOverlay().delegate = yourOverlayDelegate
      💡
      Please note that while on iOS BunchOverlayDelegate contains separate callbacks for overlayDidAppear overlayDidDisappear overlayStateDidChange events, on Android they are all combined into single onChanged(newState: BunchOverlay.BunchOverlayState) callback.
Join/Leave Party Callbacks

Finally, if your game needs to react to player joining or leaving the party (for example adjust game's UI) you can use the corresponding callbacks included in BunchClientInterface.

💡
It’s highly recommended that the game automatically turns off or reduces the audio volume of in-game music and sound effects when player joins a party. This helps make the conversation easier for all participants - as otherwise the game music and / or sound being picked up by the microphone can make it very hard for the players to hear each other.
Code Sample - Kotlin
override fun playerDidJoinBunchParty(party: BunchParty) {
	// it's safe to call show every time, as it won't have an effect 
	// if there's no ongoing party.
	BunchClient.instance.overlay.show()
	// React to player joining Bunch Party
  // Lower the volume or turn the in-game music and/or sounds off. 
}

override fun playerDidLeaveBunchParty(party: BunchParty) {
	// React to player leaving Bunch Party   
	// Restore the volume of the in-game music and/or sounds.  
}
Code Sample - Swift
func playerDidJoinBunchParty(party: BunchParty) {
	// it's safe to call show every time, as it won't have an effect 
	// if there's no ongoing party.
	BunchClient.instance().getOverlay().show()
	// React to player joining Bunch Party
  // Lower the volume or turn the in-game music and/or sounds off.        
}

func playerDidLeaveBunchParty() {
	// React to player leaving Bunch Party
	// Restore the volume of the in-game music and/or sounds.       
}