Name Engine Allowlist Interval Devices Blocked
Loading…

Loading…

SpeedTester SDK

Run speed tests, monitor network status, and manage Wi-Fi — all through the SpeedTester TV app, with a clean Kotlin API. No AIDL. No service binding. No boilerplate.

Android 7.0+ Kotlin Coroutines Flow

Overview

The SpeedTester SDK wraps the IPC layer between your app and the SpeedTester TV service. Under the hood it uses AIDL, but you never touch it — the SDK handles service binding, reconnection, and marshalling automatically.

Your App
consumer
SpeedTester SDK
AAR
AIDL / Binder IPC
hidden
SpeedTester App
tv.threess.speedtester
RequirementMinimum
Android SDK24 (Android 7.0)
Kotlin1.9+
Coroutines1.7+
SpeedTester TV appInstalled on device

Authentication

Every call into the SpeedTester service is authorised. Two mechanisms are available — whichever passes first is used.

📦 Package allowlist

Register your app's package name via this portal (Tenants → Allowed Packages). The service verifies the calling UID automatically — no code needed on your side.

🔑 Tenant API key

Request a key from 3SS and pass it to SpeedTesterSdk.init(). Useful for multi-app or white-label scenarios where package registration isn't practical.

Dev mode: If the SpeedTester app has no allowlist or keys configured (fresh dev install), all callers are permitted — no credentials needed for local development.

Setup

Add the dependency

// settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        maven { url = uri("https://maven.3ss.tv/releases") }
    }
}
// app/build.gradle.kts
dependencies {
    implementation("tv.threess:speedtest-sdk:1.0.0")
}

Declare package visibility (Android 11+)

<!-- AndroidManifest.xml -->
<queries>
    <package android:name="tv.threess.speedtester" />
</queries>

Initialise the SDK

class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        SpeedTesterSdk.init(
            context = this,
            apiKey  = "YOUR_TENANT_API_KEY"  // omit if using package allowlist
        )
    }
}
Important: Creating a client before calling init() throws an IllegalStateException at runtime.

Speed test

Use SpeedTestClient to trigger a test and observe progress as a Flow. Cancelling the coroutine automatically cancels the test.

val client = SpeedTestClient(context)

client.startTest().collect { event ->
    when (event) {
        is SpeedTestClient.Event.Progress   -> showProgress(event.downloadMbps, event.percent)
        is SpeedTestClient.Event.Completed -> showResult(event.result)
        is SpeedTestClient.Event.Error     -> showError(event.message)
    }
}

client.release() // call in onDestroy / onCleared

Network status

Observe live network conditions as a Flow. Emits immediately with the current state, then on every change.

val client = NetworkStatusClient(context)

client.networkStatus().collect { status ->
    println("${status.connectionType} — ${status.ssid} (${status.signalStrengthDbm} dBm)")
}

Wi-Fi

val client = WifiClient(context)

when (val result = client.connect("MyNetwork", "password123")) {
    is WifiConnectResult.Connected -> println("Connected to ${result.ssid}")
    is WifiConnectResult.Failed    -> println("Failed: ${result.reason}")
}

Data models

SpeedTestResult

FieldTypeDescription
sessionIdStringUnique test identifier
engineString"ookla" or "librespeed"
timestampEpochMsLongCompletion time (Unix ms)
downloadMbpsFloatDownload speed
uploadMbpsFloatUpload speed
pingMsFloatLatency
jitterMsFloatJitter
packetLossPercentFloatPacket loss %
networkNetworkStatusNetwork context at test time

NetworkStatus

FieldTypeDescription
connectionTypeConnectionTypeWIFI, CELLULAR, ETHERNET, UNKNOWN
ssidString?Wi-Fi SSID (null on cellular)
bssidString?Access point MAC address
signalStrengthDbmIntSignal in dBm
linkSpeedMbpsIntPHY link speed
ipAddressString?IPv4 address
visibleSsidsList<String>Nearby network names

Error reference

ErrorCauseFix
"Not authorised" Package not on allowlist; API key missing or invalid Add package in Tenants → Allowed Packages, or pass a valid API key
IllegalStateException: init()… Client created before SpeedTesterSdk.init() Move init() to Application.onCreate()
Bind never completes SpeedTester app not installed or not running Ensure SpeedTester app is installed and has been launched at least once

Permissions

All sensitive permissions are held by the SpeedTester app. Your AndroidManifest.xml does not need ACCESS_FINE_LOCATION, ACCESS_WIFI_STATE, CHANGE_WIFI_STATE, or INTERNET. You only need the <queries> entry from step 2.

For API key requests, package registration, or support: sdk@3ss.tv

Devices

Loading…