This guide shows the fastest path to a working Android integration:
SportSdkReference implementation:
androidApp/src/main/java/ag/sportradar/mobile/sdk/sport/android/ui/SampleActivity.ktandroidApp/src/main/java/ag/sportradar/mobile/sdk/sport/android/viewmodel/Add the dependency, call SportSdk.init(...) once, wait for it to finish, and verify the setup with SportControllers.sportsController.getAllSports().
dependencies {
implementation("ag.sportradar.mobile.sdk.sport:sport-sdk:<version>")
}
val initialized = SportSdk.init(
applicationContext,
enableAnalytics = true,
clientConfig = ClientConfig(
clientId = YOUR_CLIENT_ID,
appKey = "YOUR_APP_KEY",
logger = if (BuildConfig.DEBUG) DebugAntilog
Use Maven Central in consumer apps, or depend on :sport-sdk locally while developing in this repository.
Call SportSdk.init(...) before any controller usage and gate your UI until it completes.
Use getAllSports() as your first request to confirm credentials and connectivity.
From sports, move to categories, seasons, fixtures, standings, lineups, timeline events, and squads.
Replace <version> with the released SDK version your team is onboarding to. Until the Maven Central listing URL is finalized, the artifact coordinates above are the important part.
Add the required network permissions to your AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
</manifest>Initialize the SDK before you use any controller.
Do not call SportControllers.* until initialization completes.
throwErrorOnInit defaults to false and should only be enabled for testing failure handling.
Start with getAllSports().
suspend fun loadSports() {
val result = SportControllers.sportsController.getAllSports()
if (result.isSuccess) {
val sports = result.data.orEmpty()
println("Loaded ${sports.size} sports")
} else {
println("Failed to load sports: ${result.errorMessage}")
}
}Android APIs return CommonResult<T> or typed aliases built on top of it.
Some typed aliases also expose convenience accessors backed by data, for example result.sports, result.matches, result.events, or result.teamSquad.
result.isSuccessresult.dataresult.errorMessageSportsResult = CommonResult<List<Sport>>SeasonsResult = CommonResult<List<Season>>StandingsResult = CommonResult<Standings>FixturesResult = CommonResult<List<Match>>MatchStatisticsResult = CommonResult<List<MatchStatistics>>SportControllers.sportsControllerSports, categories, dated matches, and tracked category updates.
SportControllers.seasonControllerTournament seasons, tables / standings, and season fixtures.
SportControllers.matchControllerStatistics, lineups, and soccer timeline events.
SportControllers.playerControllerTeam squad data for a specific team + season pair.
| Method | Returns |
|---|---|
getAllSports() | SportsResult |
getSportCategories(sportId) | SportsResult |
getSportMatchesForDate(timestamp) | SportsResult |
trackSportCategories(sportId) | Flow<CommonResult<List<Sport>>> |
class SportsViewModel : ViewModel(), InternalKoinComponent {
private val ioDispatcher: CoroutineDispatcher by inject(qualifier(DispatcherType.IO))
private val sportsController = SportControllers.sportsController
private val _sportsState = MutableStateFlow
sportId: LonguniqueTournamentId: LongseasonId: LongmatchId: LongteamId: Int| Method | Returns |
|---|---|
getMatchStatistics(matchId) | MatchStatisticsResult |
getMatchLineups(matchId) | MatchLineupsResult |
getSoccerMatchTimelineEvents(matchId) | SoccerTimelineResult |
viewModelScope.launch(ioDispatcher) {
coroutineScope {
val statisticsDeferred = async { SportControllers.matchController.getMatchStatistics(matchId) }
val lineupsDeferred = async { SportControllers.matchController.getMatchLineups(matchId) }
val timelineDeferred = async { SportControllers.matchController.getSoccerMatchTimelineEvents(matchId) }
val statistics = statisticsDeferred.await
when (val stat = matchStatistic) {
is MatchStatistics.IntStat -> Unit
is MatchStatistics.DoubleStat -> Unit
is MatchStatistics.TextStat -> Unit
is MatchStatistics.BoolStat -> Unit
}
when (val event = soccerEvent) {
is SoccerEvent.HighlightEvent -> Unit
is SoccerEvent.StatusUpdate -> Unit
}@Composable
fun SportsScreen(viewModel: SportsViewModel = viewModel()) {
val state by viewModel.sportsState.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
viewModel.getAllSports()
}
when (val loadingStatus = state.loadingStatus) {
-keep class ag.sportradar.mobile.sdk.sport.** { *; }
-keep class ag.sportradar.mobile.sdk.sport.model.** { *; }
falseCheck:
clientId is an IntappKey is correctpackageName), which the SDK resolves automaticallyCheck:
result.errorMessageLong vs Int)Usually this means a controller was accessed before SportSdk.init(...) completed.
Attach a logger in ClientConfig:
ClientConfig(
clientId = YOUR_CLIENT_ID,
appKey = "YOUR_APP_KEY",
logger = if (BuildConfig.DEBUG) DebugAntilog() else null,
)clientId, appKeyclientId is an Int on Android.
If appIdentifier is still passed through a shared configuration path, the SDK ignores it on Android and always uses the app packageName.
If your team consumes the published Android artifact from Maven Central, no custom repository URL is required.
Make sure your project resolves dependencies from google() and mavenCentral().
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}Then add the dependency in your app module:
dependencies {
implementation("ag.sportradar.mobile.sdk.sport:sport-sdk:<version>")
}If your project already includes mavenCentral(), you only need the dependency line.
You can also keep the version in a version catalog if that matches your Gradle setup:
[versions]
sportSdk = "<version>"
[libraries]
sport-sdk = { module = "ag.sportradar.mobile.sdk.sport:sport-sdk", version.ref = "sportSdk" }dependencies {
implementation(libs.sport.sdk)
}class SampleActivity : AppCompatActivity() {
private var sdkInitialized by mutableStateOf(false)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val splashScreen = installSplashScreen()
splashScreen.setKeepOnScreenCondition { !sdkInitialized }
lifecycleScope.launch {
val initialized = SportSdk.init(
applicationContext,
enableAnalytics = true,
clientConfig = ClientConfig(
clientId = YOUR_CLIENT_ID,
appKey = "YOUR_APP_KEY",
logger = if (BuildConfig.DEBUG) DebugAntilog() else null,
),
)
sdkInitialized = initialized
}
setContent {
if (sdkInitialized) {
MainScreen()
}
}
}
}Logging is configured through ClientConfig.logger, not a separate enableLogs parameter on Android.
LoadingStatus is provided by the SDK in ag.sportradar.mobile.sdk.sport.state. Reuse it rather than redefining your own loading enum.
| Method | Returns |
|---|---|
getTournamentSeasons(uniqueTournamentId) | SeasonsResult |
getSeasonStanding(seasonId, isCurrentSeason) | StandingsResult |
getSeasonFixtures(seasonId, isCurrentSeason) | FixturesResult |
val seasonsResult = SportControllers.seasonController.getTournamentSeasons(uniqueTournamentId)
val fixturesResult = SportControllers.seasonController.getSeasonFixtures(seasonId, isCurrentSeason = true)
if (seasonsResult.isSuccess) {
val seasons = seasonsResult.data.orEmpty()
}
if (fixturesResult.isSuccess) {
val matches = fixturesResult.data.orEmpty()
}viewModelScopelifecycleScopeSportSdk.shutdown() from a coroutine