# iOS native

You can use this plugin for all ios games.

## Connecting plugin to your project manually

To obtain the plugin please connect with us.

Link it manually to your project. To do that, go to your Target's `General` tab in Xcode and under section "`Frameworks, Libraries and Embedded Content`" press `+`, then locate downloaded framework and add it. Don't forget to choose "embed & sign". Also, you will need to load and link manually <https://github.com/SDWebImage/SDWebImageWebPCoder> and it's dependencies too, because we use it internally. Once you finish, that's it!

## Connecting plugin to your project using CocoaPods (recommended)

Add escs pod in Podfile

and then run `pod update`

And that's it! Now you are ready to use it

## Removing unused targets

Because provided framework is a "fat framework" you may run into issues when uploading to Appstore because apple rejects simulator architectures in binaries. To remedy this issue, you need to add script action which will remove it upon build.

Under “Build Phases” select “Add Run Script” and copy the contents of below script

```bash
echo "Target architectures: $ARCHS"

APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"

find "$APP_PATH" -name '*.framework' -type d | while read -r FRAMEWORK
do
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

FRAMEWORK_TMP_PATH="$FRAMEWORK_EXECUTABLE_PATH-tmp"

# remove simulator's archs if location is not simulator's directory
case "${TARGET_BUILD_DIR}" in
*"iphonesimulator")
    echo "No need to remove archs"
    ;;
*)
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "i386") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "i386" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "i386 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    if $(lipo "$FRAMEWORK_EXECUTABLE_PATH" -verify_arch "x86_64") ; then
    lipo -output "$FRAMEWORK_TMP_PATH" -remove "x86_64" "$FRAMEWORK_EXECUTABLE_PATH"
    echo "x86_64 architecture removed"
    rm "$FRAMEWORK_EXECUTABLE_PATH"
    mv "$FRAMEWORK_TMP_PATH" "$FRAMEWORK_EXECUTABLE_PATH"
    fi
    ;;
esac

echo "Completed for executable $FRAMEWORK_EXECUTABLE_PATH"
echo $(lipo -info "$FRAMEWORK_EXECUTABLE_PATH")

done
```

## Integrating plugin into your game.

It is very easy to integrate ESCS plugin into your game code

First you need to initialize your plugin.&#x20;

### Initialization

To start using your plugin you need first initialize it:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
#import <EscsIosPluginFramework/EscsIosPluginFramework-Swift.h>

EscsService* service;
service = [[EscsService alloc] init];

EscsServiceConfigObjC* config = [[EscsServiceConfigObjC alloc] init];
config.publicKey = @"public_key";
config.playerBaseUrl = @"player_base_url";
config.baseUrl = @"base_url";
config.autoReconnect = true/false;
    
UIViewController* serviceController = [service initializeWithConfig:config 
callback:^(BOOL status, NSString * _Nonnull gameId, NSString * _Nonnull tournamentId) {
    NSLog(@"%@", gameId);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
import EscsIosPluginFramework

let service = EscsService()
let config = EscsServiceConfig(publicKey: "public_key", 
    baseUrl: "base_url",
    playerBaseUrl: "player_base_url",
    autoReconnect: true/false) //default: true

let controller = service.initialize(
    config) { 
        status, gameid, tournamentid in
            print(status)
        }
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **`public_key`**- a key that you've obtained in the step 1 of the integration guide, like `"fee91a27-2b87-45f8-8ca4-0b317707806q"`
* **`base_url`** - url for the core ESCS service. It is <https://api.escs.io> for production environment and [https://api.demo.escs.io](https://api.demo.escs.io/) for demo environment.
* **`player_base_url`** - the URL for the view you created in the [first step of the integration](https://docs.escs.io/integration-step-1), like this one `https://37b35a72-f8d9-48ca-8cd1-e6690c23637c.player.demo.escs.io`  (without "demo" on production)
* **`autoReconnect` -** tells plugin whether you want to wait for network connection to become available if it isn't, or return with failed initialization immediately; default is **true** - i.e. plugin will try to initialize until network is available
* **`callback`** - callback when init is completed; you can omit it.&#x20;

Callback parameters are following:

* `status`  - boolean: true for successfully initialized escs or false otherwise
* `gameId` - gameId string of configured game or empty string
* `tournamentId` - tournamentId string of current active tournament or empty string

After this you need to attach this ViewController to your view hierarchy:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[[self view] addSubview: serviceController.view];
[self addChildViewController: serviceController];
[serviceController didMoveToParentViewController: self];
```

{% endtab %}

{% tab title="Swift" %}

```swift
view.addSubview(controller.view)
addChild(controller)
controller.didMove(toParent: self)
```

{% endtab %}
{% endtabs %}

### Start/End Game

After that you are all set and ready to use ESCS functionality. To start a game's round, just call `startGameWithCallback`:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
 [service startGameWithCallback:^(NSString * _Nonnull roundId, NSString * _Nonnull tournamentId, NSString * _Nonnull status, NSString * _Nonnull playerId) {
     NSLog(@"%@", roundId);
 }];

```

{% endtab %}

{% tab title="Swift" %}

```swift
service.startGame { roundId, tournamentId, status, playerId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* `roundId`  - roundId of just started game round
* `tournamentId`- tournamentId of active tournament for which the round was created for
* `status`- round status. "active" for just created round
* `playerId`- escs playerId

When the round of your game has ended, just call  `endGameWithScore` with score parameter:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
NSDictionary<NSString *, NSNumber *> *result = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithDouble:[input.text doubleValue]], @"points1", nil];

[service endGameWithScore: result callback:^(NSString * _Nonnull roundId, NSString * _Nonnull tournamendId, NSString * _Nonnull status, NSString * _Nonnull playerId) {
    NSLog(@"ended round: %@ playerId: %@ status:%@", roundId, playerId, status);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
//score takes double as parameter
service.endGame(score: ["points1": 150.0]) { roundId, tournamentId, status, playerId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`result`** - game score parameter - game score parameter - accepts a dictionary of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)

and callback:

* `roundId`  - roundId of just ended game round
* `tournamentId`- tournamentId of active tournament for which the round was ended&#x20;
* `status`- round status. "ended" for just ended round
* `playerId`- escs playerId

## Optional steps

### ESCS ready callback

When you get the callback from [initialize](#initialization), this means that plugin is ready to work and can show UI. But this does not mean that you can already use every ESCS feature, as some components require more time to hook up. Most of the time you don't need to worry about it, but in some cases it is not what you want (e.g. your game loads from deep link and you want to show tournament/wager inside ESCS, so you might want to disable your game UI until ESCS is able to show full info). To remedy this problem, we provide additional callback:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnEscsReadyCallbackWithCallback:^(BOOL ready) {
        NSLog(@"escs is ready!");
    }];
```

{% endtab %}

{% tab title="Swift" %}

```kotlin
service?.registerOnEscsReadyCallback { s in //s: boolean
            print("escs is ready!: ", s)
        }
```

{% endtab %}
{% endtabs %}

Receiving this callback means that ESCS is fully ready to receive and perform any supported actions.

### Hiding ESCS button

### Sending Game Progress

If you want send game score as your player progresses through game, for example in case gameplay is abruptly stopped or you want to see score progression graphs when players are streaming their gameplay, just call  `progressGame()` with score parameter:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
NSDictionary<NSString *, NSNumber *> *result = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithDouble:[input.text doubleValue]], @"points1", nil];

[service progressGameWithScore: progress callback:^(NSString * _Nonnull roundId, NSString * _Nonnull progressId) {
    NSLog(@"progressed round: %@ progressId: %@", roundId, progressId);
}];
```

{% endtab %}

{% tab title="Swift" %}

```swift
//progressId score takes double as parameter
service.progressGame(score: ["points1": 150.0]) { roundId, progressId in
    print(roundId)
}
```

{% endtab %}
{% endtabs %}

where&#x20;

* **`progress`**- game score parameter - game score parameter - accepts a dictionary of string key and double value; the names of keys should be defined in game dashboard at [client.escs.io](https://client.escs.io)

and callback:

* `progressId` - id of just sent progress object
* `roundId`-  roundId of just progressed game round

### Hiding ESCS button

Most of the time you will not want to show the ESCS button during the actual game, to not mess with the gameplay, for example user can accidentally touch it and almost full-screen webview will show up. To hide or show button you can use following call:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonVisibilityWithVisible: visible ];  //visible: BOOL
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonVisibility(visible: false) //or true
```

{% endtab %}
{% endtabs %}

### Opening ESCS view programmatically

Sometimes you might prefer to implement you own customized button for opening Escs in style of your game and with full control of its position. For such cases you can hide Escs button altogether (like shown above) and open Escs with your own button using following method:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service openEscsView]; 
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.openEscsView()
```

{% endtab %}
{% endtabs %}

### Notifications/Announcements

There are situations, when ESCS needs to show announcements or notifications - for example to promote your game's upcoming championship, or ask user to add credit card, because his/her trial is about to expire. ESCS will open its full WebView automatically to show notification's content, if it's needed. To be able to show these, not interrupting your gameplay and at the times that are not interruptive for user, please call:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service maybeShowNotifications];
[service maybeShowAnnouncemens];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.maybeShowAnnouncemens()
service.maybeShowNotifications()
```

{% endtab %}
{% endtabs %}

There's internal logic in the plugin to decide whether it needs to show actual notification and announcement, but you should place these calls whenever you feel that interruption with ESCS WebView window is okay for user experience.&#x20;

***Please note*** that it does **not** mean that user will see notification or announcement **every time** you call these methods. We are trying for those to be as subtle and fluent as possible for end user. Their names imply that notification/announcement just **maybe** will be shown.

### Changing default button position

There are situations when it is not suitable for your UI to have our ESCS button at  default top center area. Then you can change that (remember, that user actually can drag the button anywhere on the screen he wants)

`setButtonDefaultPositionAbsoluteWithX` will set button position in absolute coordinates from left upper corner of the app.

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonDefaultPositionAbsoluteWithX:x y:y];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonDefaultPositionAbsolute(x: 50.0, y: 50.0)
```

{% endtab %}
{% endtabs %}

where

* x - x coordinate (float)
* y - y coordinate (float)

`setButtonDefaultPositionRelativeWithXPart`will set button position in relative coordinates from center horizontally and top vertically of the app. That is, if you set **0, 0** coordinates the button will be shown in the **x: (device width)/2  y: 0.**&#x20;

The coordinate system here is from **-0.5 to 0.5** for `xPart` : where **-0.5** means most left side of device and **0.5** - right side and **0** is dead center. For `yPart` it is from **0 to 1** where **0** is top of the screen and **1** is the bottom.

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service setButtonDefaultPositionRelativeWithXPart:xPart yPart:yPart]; 
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.setButtonDefaultPositionRelative(xPart: 0.5, yPart: 0.5)
```

{% endtab %}
{% endtabs %}

### Getting in-game rewards

To receive the list of in-game rewards that particular player has (you can set those rewards as string fields in your game dashboard - for winning matches and so on) you can use the following method:

{% tabs %}
{% tab title="Objective-C" %}

```bash
[service getIngameRewardsObjCWithCallback:^(NSInteger count, NSArray<RewardPayloadObjC *> * _Nonnull rewards) {
    //...your callback code here
}];
```

where:&#x20;

* **count** - amount of rewards player has (***integer***)
* **rewards** - array of **RewardPayloadObjC** objects:
  * **\_id** - id of reward (***string***)
  * **rewardData** - ***string*** representation of rewards (which you set in the dashboard)
  * **tournamentId** - id of tournamnt it was received by player (***string***)
    {% endtab %}

{% tab title="Swift" %}

```
service.getIngameRewards(callback: { rewards in
    print(rewards)
})
```

where:

* **rewards** - **InGameRewards** struct, which has fields:
  * **count** - amount of rewards player has (***Int***)
  * **data** - array of **RewardPayload**s, which consists of:
    * **\_id** - id of reward (***String***)
    * **rewardData** - representation of rewards (which you set in the dashboard) (***string***)
    * **tournamentId** - id of tournamnt it was received by player (***String***)
      {% endtab %}
      {% endtabs %}

### Supporting video chat and streaming

In order to support escs video chat and streaming capabilities, you need to add two keys to I**nfo.plist** of your app, for user's prompts when requesting camera and mic recording:

![](https://3853901254-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAfYp0johoPRZW2PhVp%2F-MjEuZDAXKtSY4NRcno7%2F-MjF9OYrYDRE_2DWD_e0%2Fimage.png?alt=media\&token=82f71a1c-11ca-43c2-89f0-56a479429463)

## Deeplink integration

Deeplink integration allows you to process ESCS-related deeplinks in your app. We provide wagers integration, and for them to work this step is required.

ESCS will generate deep links using provided url scheme and domain, i.e.:  [gamescheme://some/path/?escsplayer](gamescheme://some/path/?escsplayer=)[=%escs-specific-urlencoded-part%](https://yourgame.com/some/path/?escsplayer=%escs-specific-urlencoded-part%). This also could be your ios universal link. So when creating a link for tournaments/wagers inside your game, ESCS will just append the "?escsplayer=" parameter to the url you have entered in escs dev console in your app settings.

<figure><img src="https://3853901254-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MAfYp0johoPRZW2PhVp%2Fuploads%2FXK5p7C9J7dUFB6ZJIGna%2Fimage.png?alt=media&#x26;token=a2f653a3-bae8-45fd-b0c9-a679a59eca1b" alt=""><figcaption><p>Deep link setting in ESCS dashboard's Advanced options</p></figcaption></figure>

In the field you should enter something like [gamescheme://some/path](gamescheme://some/path/?escsplayer=) for simple deeplink or <https://yourgame.com/some/path> for universal link - where the **some/path** is any path inside your application that you can process. After this setup, you can use&#x20;

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service followDeepLinkWithLink:param];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.followDeepLink(link:param)
```

{% endtab %}
{% endtabs %}

method to pass the value of url parameter called "**escsplayer**" ([%escs-specific-urlencoded-part%](https://yourgame.com/some/path?escsplayer=%escs-specific-urlencoded-part%) in the example above). You can provide it in urlencoded format, i.e. raw string that is passed in escsplayer param, escs will decode it correctly. How you extract the parameter value from the url is left to your game's implementation detail, but that should be fairly easy.

{% hint style="info" %}
Note that still have to manually implement the iOS deeplink/universal link handling. Please refer to docs: <https://developer.apple.com/documentation/xcode/defining-a-custom-url-scheme-for-your-app>
{% endhint %}

This will trigger escs service to process that deeplink and automatically show relevant info in our overlay. If the user decides to take action with shown info, your game will receive the data about the match it needs to create using our standard APIs described in previous sections  (i.e. **OnGameSetStart** and other relevant callbacks) and no additional implementation is required

## Multiplayer

### Overview

We support multiplayer games with different types of matches, matchmaking and so on. To be able to use this feature, you need to follow these steps:&#x20;

* Create multiplayer tournament in the game dashboard
* Implement several callbacks in you game, which will be called in response to player's engagement with multiplayer tournament

Currently we provide 4 such callbacks:

* **OnGameSetStart** callback - is called when a game set is started by escs backend. This is moment when you should start your game or create lobby and await for players to join it. What is a "set"? It's just one multiplayer game that several players are playing simultaneously. It can be real multiplayer (e.g. they, for example, race each other on track in a racing game or are participating in a deathmatch 1vs1 or 2vs2 and so on), or even "singleplayer", meaning that they all play their own singleplayer game (like solving puzzles and the one who solves it faster is the winner). In this callback you will receive information about players that are playing this set, teams that players are in (i.e. 2vs2 game), metadata that is supplied with the player (supplied by **registerInGamePlayerId**) and global metadata that is set in the game dashboard
* **OnGameSetEnd** callback - is called when each player in the set has finished their game. this might be not necessary the same moment you end your multiplayer game - it is called when the escs backend processed all game end events from each participating player and saved their corresponding scores. You will receive **matchId** and **setId** as parameters
* **OnMatchStart** callback - is called when multiplayer match has started. Usually you will get this event right before getting **OnGameSetStart**. Each match consists of several game sets. You will receive **matchId** as parameter of this callback.
* **OnMatchEnd** callback - is called when multiplayer match has ended. That is when all the sets in the match has been played or timeout occurred. You will receive **matchId** as parameter of this callback

The following diagram may be helpful for understanding about aforementioned events:

![](https://3853901254-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MAfYp0johoPRZW2PhVp%2F-MMGKFBYBvgpRAu5mOpi%2F-MMHglMU0wyrPPD2Fb_z%2FUntitled%20Diagram%20\(1\).svg?alt=media\&token=269d7151-8e6a-4a42-8336-60efbb937a8c)

To utilize these events you should call following methods after initializing escs service:

### Registering in-game player id and metadata:

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerInGamePlayerIdWithId:playerId ingameMetadata:ingameMetadata];
```

{% endtab %}

{% tab title="Swift" %}

```swift
service.registerInGamePlayerId(id: playerId,ingameMetadata: ingameMetadata)
```

{% endtab %}
{% endtabs %}

where:&#x20;

* **playerId** - your ingame player id (**string**). It will be passed along with OnGameSetStart callback when the game set will start
* **ingameMetadata** - your ingame metadata for this player (**string**)

### Register OnGameSetStart event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameSetStartCallbackObjCWithCallback:
                    ^(NSString * _Nonnull setId, 
                    NSString * _Nonnull tournamentId, 
                    NSString * _Nonnull matchId, 
                    NSString * _Nonnull roundId, 
                    NSString * _Nonnull globalMetadata, 
                    NSArray<NSArray<ParticipantObjC *> *> * _Nonnull participants
                    NSInteger setEndTimeUnix) { 
              //... your callback code here
 }];
```

where:

* **setId** - setId of started set (**string**)
* **tournamentId** - tournamentId of the set (**string**)
* **matchId** - matchId of the set (**string**)
* **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)
* **globalMetadata** - metadata string that can be set in the game dashboard (**string**)
* **pariticipants** - array of arrays of **ParticipantObjC.** *Each sub-array is considered a "team". So if the game is 2vs2, then you will get array of 2 arrays, each having 2 objects inside. Those 2 arrays are 2 teams with 2 players each. In case of 1vs1 game, you will receive an array of 2 arrays, each having 1 object inside - thus the team contains only one player.* **ParticipantObjC** object consists of:
  * **playerId** - escs player id (**string**)
  * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
  * **username** - user's escs username (**string**)
  * **firstName** - user's escs first name (**string**)
  * **lastName** - user's escs last name (**string**)
  * **avatar** - user's escs avatar image url (**string**)
  * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)
* **setEndTimeUnix** - latest end time of the set in unix time (**NSInteger**)
  {% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameSetStartCallback(callback: { payload in
            print(payload)
})
```

where:&#x20;

* **payload** - **OnGameSetStartPayload** struct which contains:
  * **setId** - setId of started set (**string**)

  * **tournamentId** - tournamentId of the set (**string**)

  * **matchId** - matchId of the set (**string**)

  * **roundId** - roundId of the set (this is in fact id of the set "results") (**string**)

  * **globalMetadata** - metadata string that can be set in the game dashboard (**string**)

  * **pariticipants** - array of arrays of **Participant** structs( i.e. `[[Participant]?]?`)

    *Each sub-array is considered a "team". So if the game is 2vs2, then you will get array of 2 arrays, each having 2 objects inside (i.e.* `[ [ participant1, participant2] , [participant3, participant4] ]`*). Those 2 arrays are 2 teams with 2 players each. In case of 1vs1 game, you will receive an array of 2 arrays, each having 1 object inside (i.e.* `[ [ participant1] , [participant2] ]`*- thus the team contains only one player.*

    &#x20;Each **Participant** struct consists of:

    * **playerId** - escs player id (**string**)
    * **ingamePlayerId** - registered in-game player id via **registerInGamePlayerId** (**string**)
    * **username** - user's escs username (**string**)
    * **firstName** - user's escs first name (**string**)
    * **lastName** - user's escs last name (**string**)
    * **avatar** - user's escs avatar image url (**string**)
    * **ingameMetadata** - in-game metadata that was registered via registerInGamePlayerId (**string**)

  * **setEndTimeUnix** - latest end time of the set in unix time (**int**)
    {% endtab %}
    {% endtabs %}

### Register OnGameSetEnd event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameSetEndCallbackObjCWithCallback:
^(NSString * _Nonnull setId, 
NSString * _Nonnull matchId) {
    // ... your callback code here
    }]; 
```

where:&#x20;

* **setId** - setId of finished set (**string**)
* **matchId** - matchId of the set (**string**)
  {% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameSetEndCallback { payload in
    print(payload)           
}
```

where **payload** is **OnGameSetEndPayload** struct containing follwing fields:

* **setId** - setId of finished set (**string**)
* **matchId** - matchId of the set (**string**)
  {% endtab %}
  {% endtabs %}

### Register OnMatchStart event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameMatchStartCallbackObjCWithCallback:
                                ^(NSString * _Nonnull matchId) {
        // ... your callback code here
    }];
```

where **matchId** - is **matchId** of the match that started (**string**)
{% endtab %}

{% tab title="Swift" %}

```
service.registerOnGameMatchStartCallback { payload in
        print(payload)
}
```

where **payload** is **OnMatchStartPayload** struct, containing just one field - **matchId** of the match that started (**string**)
{% endtab %}
{% endtabs %}

### Register OnMatchEnd event callback

{% tabs %}
{% tab title="Objective-C" %}

```objectivec
[service registerOnGameMatchEndCallbackObjCWithCallback:
                ^(NSString * _Nonnull matchId) {
    // ... your callback code here
}]; 
```

where **matchId** - is **matchId** of the match that ended (**string**)
{% endtab %}

{% tab title="Swift" %}

```swift
service.registerOnGameMatchEndCallback { payload in
        print(payload)
}
```

where **payload** is **OnMatchEndPayload** struct, containing just one field - **matchId** of the match that ended (**string**)
{% endtab %}
{% endtabs %}
