---
title: Account sharing on mobile
description: Move the v2 iOS and Android account-sharing integration onto v3. Which SDK events were renamed, which were dropped, and the step-by-step swap for each platform.
---

# Account sharing on iOS and Android

The shift is the same as [on web](/docs/v3/migration/account-sharing-on-web): `attach` becomes `evaluate` with the `access` action. The bigger change on mobile is how challenges are shown and which callbacks exist. Three changes apply on both platforms:

1. **One entry point.** Configuring the client, setting the user, and attaching collapse into a single `evaluate` call that takes `user`, `email`, and `phone` inline.
2. **Challenges render through a container.** You add `RuptContainerView` (iOS) or `RuptContainer` (Android) to your UI and it observes `redirectURL`. The SDK no longer pushes its own view controller or activity, so the "should present" hooks are gone.
3. **The callback set is smaller.** The device-limit and pre-challenge callbacks are dropped, and two challenge-button callbacks are added.

::alert{type="warning"}
This is a breaking upgrade. Every app needs code changes, and there is no compatibility shim. The steps below are the full swap.
::

## iOS (3.8.1 to 4.0.0)

### Step 1: Replace the framework

Download the new `RuptClient.xcframework` and replace the old binary in your project.

### Step 2: Create the client, then evaluate

```swift
// v2
let rupt = Rupt(clientID: "your_client_id", useViewController: true)
rupt.onLogoutCurrentDevice = {
    // Clear your session and sign the user out locally.
}
rupt.setUserID(user.id)
rupt.setEmail(user.email)
rupt.attach()
```

```swift
// v4
let rupt = Rupt(clientID: "your_client_id")
rupt.onLogout = {
    // Fires when this session is logged out remotely. Clear your local session.
}

// Same call site as attach: once per protected screen, for paying users.
try await rupt.evaluate(
    action: "access",
    user: user.id,
    email: user.email,
    phone: user.phone
)
```

`setUserID`, `setEmail`, `setPhone`, `identify`, and `getHash` are gone. Pass the user inline to `evaluate` instead.

### Step 3: Show challenges through the container

Wrap your root view so the challenge can overlay it:

```swift
RuptContainerView(rupt: rupt) {
    // your app content
}
```

UIKit hosts skip the container, observe `$redirectURL`, and present the challenge web view themselves.

### iOS events

| v2 (3.8.1)                             | v4 (4.0.0)         | What changed                                          |
| -------------------------------------- | ------------------ | ---------------------------------------------------- |
| `onLogoutCurrentDevice`                | `onLogout`         | Renamed                                              |
| `onChallengeCompleted`                 | `onComplete`       | Renamed                                              |
| `onBackButtonPressed`                  | `onBackButtonPressed` | Unchanged                                         |
| `onLimitExceeded`                      | Removed            | Cap devices with a `device_count` policy             |
| `onChallenge`                          | Removed            | The SDK surfaces the challenge via `redirectURL`      |
| `onCreateNewAccount`                   | Removed            | Conversion is handled by the challenge Success URL    |
| `shouldPresentChallengeViewController` | Removed            | Use `RuptContainerView`                              |
| Added                                  | `onPrimaryCta`     | Fires when the challenge primary button is tapped     |
| Added                                  | `onSecondaryCta`   | Fires when the challenge secondary button is tapped   |

## Android (2.1.0 to 4.0.0)

### Step 1: Swap the dependency

Move from JitPack to Maven Central:

```groovy
// v2
implementation 'com.github.getrupt:kotlin:2.1.0'

// v4
implementation 'dev.rupt.android:rupt-android:4.0.0'
```

Make sure `mavenCentral()` is in your repositories.

### Step 2: Create the client, then evaluate

v2 was a `configure` plus `attach` on the `Rupt` singleton. v4 is an instance you create with your client ID.

```kotlin
// v2
Rupt.configure(clientId = "your_client_id", account = user.id)
Rupt.onLogoutCurrentDevice = {
    // Clear your session and sign the user out locally.
}
Rupt.attach(context = this)
```

```kotlin
// v4
val rupt = Rupt(context = this, clientId = "your_client_id")
rupt.onLogout = {
    // Fires when this session is logged out remotely. Clear your local session.
}

// Same call site as attach: once per protected screen, for paying users.
lifecycleScope.launch {
    rupt.evaluate(
        action = "access",
        user = user.id,
        email = user.email,
        phone = user.phone,
    )
}
```

`detach`, `identify`, and `getHash` are gone, and there is no longer a separate `attach` call to repeat on resume.

### Step 3: Show challenges through the container

```kotlin
setContent {
    RuptContainer(rupt = rupt) {
        // your app content
    }
}
```

View-system hosts skip the container, collect `rupt.redirectURL` in a lifecycle scope, and launch `ChallengeActivity` with the URL.

### Android events

| v2 (2.1.0)                  | v4 (4.0.0)            | What changed                                       |
| --------------------------- | --------------------- | -------------------------------------------------- |
| `onLogoutCurrentDevice`     | `onLogout`            | Renamed                                            |
| `onChallengeCompleted`      | `onComplete`          | Renamed                                            |
| `onBackButtonCallback`      | `onBackButtonPressed` | Renamed, and no longer passed the back state       |
| `onLimitExceeded`           | Removed               | Cap devices with a `device_count` policy           |
| `onChallenge`               | Removed               | The SDK surfaces the challenge via `redirectURL`   |
| `onCreateNewAccount`        | Removed               | Conversion is handled by the challenge Success URL  |
| `shouldStartChallengeActivity` | Removed            | Use `RuptContainer`                                |
| Added                       | `onPrimaryCta`        | Fires when the challenge primary button is tapped   |
| Added                       | `onSecondaryCta`      | Fires when the challenge secondary button is tapped |

## Where the dropped events went

The renamed callbacks are a straight swap. The dropped ones moved out of the client on purpose:

- **Device limits** (`onLimitExceeded`) are now a policy on the access event. Set a `device_count` cap in the dashboard and the device-limit challenge does the capping. There is no client callback to wire.
- **The pre-challenge hook** (`onChallenge`) is gone because the SDK surfaces the challenge itself through `redirectURL`. There is nothing to intercept.
- **The new-account hook** (`onCreateNewAccount`, and the `new_account` web view message) is gone because conversion is handled by the challenge's Success URL. Point it at your signup page.
- **The presentation hooks** (`shouldPresentChallengeViewController`, `shouldStartChallengeActivity`) are replaced by the container. Adopt `RuptContainerView` or `RuptContainer`, or observe `redirectURL` and present it yourself.

`onPrimaryCta` and `onSecondaryCta` are optional. Use them only if you want to react when the user taps a button on the challenge.

## Policies and challenge URLs

The client swap above only wires up detection. What actually triggers a challenge is your policies, and those live in the dashboard, the same across every platform. Recreate the three default account-sharing checks (device limits, impossible travel, concurrency) and set the Success and Logout URLs by following Steps 3 and 4 of the [web migration](/docs/v3/migration/account-sharing-on-web). The Logout URL is where a device lands when the user logs it out from the challenge; `onLogout` is the callback that fires when this session is logged out remotely.

## Related

- [Access protection](/docs/v3/fundamentals/access-protection): the account-sharing fundamental in full.
- [Account sharing on web](/docs/v3/migration/account-sharing-on-web): the web version of this migration.
