> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gameball.co/llms.txt
> Use this file to discover all available pages before exploring further.

# How Do I Migrate to the iOS SDK v3?

> Migrate from v2 to v3.2.2

This guide walks you through migrating from **Gameball iOS SDK v2** to **v3.2.2**.

## What's New in v3.2.2

<Info>
  **Widget Events, Dismissal & External Links** — v3.2.x keeps all v3.x code compatible. Every new capability is opt-in, so an existing integration keeps working after a version bump.
</Info>

### Highlights in v3.2.2

* **RTL Layout No Longer Leaks**: the widget's right-to-left layout direction is scoped to the widget's own view. Opening the widget in Arabic no longer flips your app's layout.

### Highlights in v3.2.1

* **Vector Close Button**: the close "X" is drawn as a vector tinted by `closeButtonColor` (default `#CECECE`), so it stays crisp at any screen scale.
* **Smaller SDK Footprint**: 70 unused bundled images were removed. No public API or behavior change.

### Highlights in v3.2.0

* **Widget Event Channel**: `widgetEventCallback` on `ShowProfileRequest` receives events posted from the widget, such as `gameCompleted`.
* **Host-Initiated Dismiss**: `GameballApp.getInstance().hideProfile()` dismisses the widget programmatically.
* **Web-Initiated Close**: the widget can dismiss itself via `window.GameballWidget.closeWidget()`.
* **External-Link Handling**: links tagged `gbExternalBrowser=true` open in the system browser, or in your own handler via `externalLinkCallback`.
* **Channel Merging**: `ShowProfileRequest` accepts optional `mobile` and `email`.
* **Diagnostic Logging**: the SDK records internal diagnostic logs to aid troubleshooting. No integration changes required.

### Migrate v3.1.x → v3.2.2 (Non-Breaking)

* Update the SPM dependency to `from: "3.2.2"`.
* No code changes are required. Adopt the new widget capabilities only if you need them — see [Show Profile Widget](/installation-guides/v3/ios/show-profile).

***

### Highlights in v3.1.1

* **Guest Mode Fix**: Profile widget works without a customer ID.
* **Non-Throwing ShowProfileRequest**: Remove the `try` keyword when creating the request.
* **Optional customerId**: Omit for guest experiences.
* **Session Tokens**: Still supported for secure routing to v4.1.

### Migrate v3.1.0 → v3.1.1 (Non-Breaking)

* Update SPM dependency to `from: "3.1.1"`.
* Drop `try` when creating `ShowProfileRequest` (initializer is non-throwing).
* Use guest mode when `customerId` is not available:
  ```swift theme={null}
  let guestRequest = ShowProfileRequest(showCloseButton: true)
  GameballApp.getInstance().showProfile(guestRequest, presentationStyle: .pageSheet)
  ```
* Authenticated mode stays the same:
  ```swift theme={null}
  let profileRequest = ShowProfileRequest(customerId: "customer_123")
  GameballApp.getInstance().showProfile(profileRequest, presentationStyle: .fullScreen)
  ```

***

## What's New in v3.0.0

<CardGroup cols={2}>
  <Card title="Modern Swift API" icon="code">
    Native Swift API with improved type safety and better Swift idioms
  </Card>

  <Card title="Async/Await Support" icon="bolt">
    Full async/await support alongside traditional callback-based APIs
  </Card>

  <Card title="Enhanced Type Safety" icon="shield">
    Stronger typing and better compile-time checks with Swift generics
  </Card>

  <Card title="Improved Performance" icon="gauge-high">
    Optimized SDK initialization and reduced memory footprint
  </Card>
</CardGroup>

***

## Breaking Changes

### 1. SDK Initialization

**v2:**

```swift theme={null}
// v2 constructed a Gameball instance directly
let gameball = Gameball(
    apiKey: "api-key",
    lang: "en",
    shop: "shop-id",
    platform: "ios"
)
```

**v3.2.2:**

```swift theme={null}
let config = GameballConfig(
    apiKey: "api-key",
    lang: "en",
    platform: "ios",
    shop: "shop-id",
    sessionToken: "session-token"  // Optional - New in v3.1.x
)

GameballApp.getInstance().`init`(config: config) { error in
    if let error = error {
        print("SDK init failed: \(error.localizedDescription)")
    }
}
```

***

### 2. Customer Registration

**v2:**

```swift theme={null}
gameball.registerPlayer(
    playerUniqueId: "customer-123",
    referrerCode: "REF123",
    playerAttributes: attributes
) { gameballId, error in
    // Handle response
}
```

**v3.2.2:**

```swift theme={null}
do {
    let request = try InitializeCustomerRequest(
        customerId: "customer-123",
        customerAttributes: attributes,
        referralCode: "REF123",
        isGuest: false
    )

    GameballApp.getInstance().initializeCustomer(request) { response, errorMessage in
        if let errorMessage = errorMessage {
            print("Error: \(errorMessage)")
        } else {
            print("Customer initialized: \(response?.gameballId ?? \"\")")
        }
    }

    // Optional: Override session token for this request
    GameballApp.getInstance().initializeCustomer(
        request,
        sessionToken: "customer-token"
    ) { _, _ in }
} catch {
    print("Validation error: \(error.localizedDescription)")
}
```

***

### 3. Event Tracking

**v2:**

```swift theme={null}
// v2 sent an array of events, and params were [String: String]
let event = Event(eventName: "purchase", params: ["amount": "99.99"])

gameball.sendEvents(
    playerUniqueId: "customer-123",
    events: [event]
) { success, errorDescription in
    // Handle response
}
```

**v3.2.2:**

```swift theme={null}
do {
    let event = try Event(
        events: [
            "purchase": [
                "amount": 99.99
            ]
        ],
        customerId: "customer-123"
    )

    GameballApp.getInstance().sendEvent(event) { success, errorMessage in
        if success {
            print("Event sent")
        } else if let errorMessage = errorMessage {
            print("Error: \(errorMessage)")
        }
    }

    // Optional: Override session token for this request
    GameballApp.getInstance().sendEvent(
        event,
        sessionToken: "customer-token"
    ) { _, _ in }
} catch {
    print("Validation error: \(error.localizedDescription)")
}
```

***

### 4. Method Name Changes

| **v2**                               | **v3.2.2**                                                    |
| :----------------------------------- | :------------------------------------------------------------ |
| `Gameball(apiKey:…)` initializer     | `GameballApp.getInstance().init(config:)`                     |
| `registerPlayer(playerUniqueId:…)`   | `GameballApp.getInstance().initializeCustomer(_:completion:)` |
| `sendEvents(playerUniqueId:events:)` | `GameballApp.getInstance().sendEvent(_:completion:)`          |
| `showProfile(playerUniqueId:…)`      | `GameballApp.getInstance().showProfile(_:presentationStyle:)` |
| `Event(eventName:params:)`           | `Event(events:customerId:)`                                   |
| `playerUniqueId`                     | `customerId`                                                  |
| `playerAttributes`                   | `customerAttributes`                                          |
| `referrerCode`                       | `referralCode`                                                |
| `showCloseBtn`                       | `showCloseButton`                                             |

***

### 5. Show Profile Widget

**v2:**

```swift theme={null}
gameball.showProfile(
    playerUniqueId: "customer-123",
    showCloseBtn: true
) { viewController, errorMessage in
    // v2 handed you the view controller to present yourself
    if let vc = viewController {
        self.present(vc, animated: true)
    }
}
```

**v3.2.2:**

```swift theme={null}
let profileRequest = ShowProfileRequest(
    customerId: "customer-123",
    showCloseButton: true,
    closeButtonColor: "#FF6B6B"
)

GameballApp.getInstance().showProfile(
    profileRequest,
    presentationStyle: .fullScreen
) { _, _ in }

// Optional: Override session token for this request
GameballApp.getInstance().showProfile(
    profileRequest,
    presentationStyle: .fullScreen,
    sessionToken: "customer-token"
) { _, _ in }
```

***

### 6. Error Handling

**v2:**

```swift theme={null}
gameball.sendEvents(playerUniqueId: "customer-123", events: [event]) { success, errorDescription in
    if success != nil {
        // Success
    } else {
        // Error — v2 surfaced it as an untyped `Any?`
    }
}
```

**v3.2.2:**

```swift theme={null}
GameballApp.getInstance().sendEvent(event) { success, errorMessage in
    if success {
        // Success
    } else if let errorMessage = errorMessage {
        print(errorMessage)
    }
}
```

***

### 7. Session Token Authentication (New in v3.1.x)

```bash theme={null}
// Configure with session token
let config = GameballConfig(
    apiKey: "api-key",
    lang: "en",
    sessionToken: "session-token"  // Global token
)
GameballApp.getInstance().`init`(config: config)

// Per-request token override
GameballApp.getInstance().initializeCustomer(
    request,
    sessionToken: "override-token"
) { _, _ in }
```

<Info>
  Session tokens enable automatic v4.1 endpoint routing and enhanced security. The token is stored in memory with thread-safe access.
</Info>

***

### 8. Async/Await Support (New in v3.0.0)

```swift theme={null}
// Traditional callback
GameballApp.getInstance().initializeCustomer(request) { _, _ in }

// Async/await (v3.0.0+)
Task {
    do {
        let response = try await GameballApp.getInstance().initializeCustomer(request)
        // Handle success
    } catch {
        // Handle error
    }
}

// With session token override (v3.1.x+)
Task {
    do {
        let response = try await GameballApp.getInstance().initializeCustomer(
            request,
            sessionToken: "customer-token"
        )
        // Handle success
    } catch {
        // Handle error
    }
}
```

***

## Migration Steps

### From v3.x to v3.2.2 (No Breaking Changes)

<Info>
  v3.2.x is fully backward compatible with earlier v3 releases. Simply update the dependency version. Session Token support and the new widget capabilities are optional.
</Info>

<Steps>
  <Step title="Update Dependency">
    Update your Swift Package Manager dependency to **3.2.2**.
  </Step>

  <Step title="(Optional) Add Session Token">
    If you need enhanced security, add a session token to your configuration:

    ```swift theme={null}
    let config = GameballConfig(
        apiKey: "api-key",
        lang: "en",
        sessionToken: "your-session-token"
    )
    ```
  </Step>

  <Step title="Test">
    Test your integration. All existing v3.0.0 code should work without changes.
  </Step>
</Steps>

***

### From v2.x to v3.2.2

<Steps>
  <Step title="Update Dependency">
    Update your Swift Package Manager dependency to **3.2.2**.
  </Step>

  <Step title="Update Initialization">
    Replace the `Gameball(apiKey:…)` initializer with `GameballConfig` + `GameballApp.getInstance().init(config:)`.
  </Step>

  <Step title="Update Customer Registration">
    Replace `registerPlayer()` with `initializeCustomer()` using the new request type `InitializeCustomerRequest`.
  </Step>

  <Step title="Update Event Tracking">
    Update event creation to use the `Event` model and pass it to `sendEvent`.
  </Step>

  <Step title="Update Error Handling">
    Replace boolean success handlers with Result-based completion handlers to access detailed error information.
  </Step>

  <Step title="Update Show Profile">
    Use the non-throwing `ShowProfileRequest` (guest mode optional) for displaying the profile widget.
  </Step>

  <Step title="Test Thoroughly">
    Test all Gameball functionality (registration, events, profile, notifications, etc.) to ensure the migration is successful.
  </Step>
</Steps>

***

## Compatibility

* **Minimum iOS**: iOS 12.0+
* **Xcode**: 12.0+
* **Swift**: 5.0+

***

## Additional Resources

* **GitHub Repository:** [https://github.com/gameballers/gameball-ios](https://github.com/gameballers/gameball-ios)
* **Release history:** see the [gameball-ios releases page](https://github.com/gameballers/gameball-ios/releases)
* **Developer Docs:** [https://docs.gameball.co](https://docs.gameball.co)

<Tip>
  If you encounter issues during migration, check the GitHub repository for known issues and solutions, or contact Gameball support.
</Tip>
