Device-side player SDK for DOOH (Digital Out-of-Home) digital signage on Android.
The SDK handles everything below the display layer: playlist fetching, media caching, heartbeat reporting, emergency broadcast overrides, and remote device commands — so your app only needs to render what it receives.
| Artifact | What it does |
|---|---|
squarescreen-player |
Core engine — flows, background workers, foreground service |
squarescreen-ui |
Jetpack Compose player and emergency overlay (optional) |
squarescreen-core |
Shared models and contracts (transitive) |
squarescreen-network |
Retrofit network layer (transitive) |
squarescreen-cache |
Room metadata cache + disk media cache (transitive) |
Add to your module's build.gradle.kts:
dependencies {
// Core player (required)
implementation("io.squarescreen:squarescreen-player:0.1.0")
// Jetpack Compose UI components (optional)
implementation("io.squarescreen:squarescreen-ui:0.1.0")
}Minimum SDK: API 29 (Android 10)
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
SquareScreen.init(
context = this,
config = SquareScreenConfig(
deviceId = credentialStore.deviceId,
deviceToken = credentialStore.deviceToken,
foregroundNotification = ForegroundNotificationConfig(
title = "Display active",
iconResId = R.drawable.ic_player
),
logger = if (BuildConfig.DEBUG) SquareScreenDebugLogger() else null
)
)
}
}Security: never hardcode
deviceToken. Store it inEncryptedSharedPreferencesand retrieve it after the device pairing flow.
@Composable
fun PlayerScreen() {
val squareScreen = SquareScreen.getInstance()
SquareScreenDisplay(
squareScreen = squareScreen,
modifier = Modifier.fillMaxSize()
)
}SquareScreenDisplay renders the active playlist, overlays emergency alerts, and automatically reports proof-of-play after each item.
SquareScreenConfig(
deviceId = "...", // required — X-Device-Id header
deviceToken = "...", // required — X-Device-Token header
heartbeatIntervalSeconds = 60L, // min 30, default 60
emergencyPollIntervalSeconds = 30L, // min 15, default 30
cacheTtlSeconds = 3600L, // default 1 hour
foregroundNotification = ForegroundNotificationConfig(
title = "Display active",
iconResId = R.drawable.ic_player
),
logger = SquareScreenDebugLogger() // null = silent (recommended for production)
)The API base URL is managed internally by the SDK — debug builds target staging, release builds target production. Integrators do not set it.
The SDK exposes four Kotlin Flows on the SquareScreen instance:
val squareScreen = SquareScreen.getInstance()
// Active playlist — emits on every schedule change or manual refresh
squareScreen.nowPlaying.collect { result ->
when (result) {
is SquareScreenResult.Success -> render(result.data)
is SquareScreenResult.Error -> showError(result.error)
}
}
// Emergency alert — emits null when no broadcast is active
squareScreen.emergencyAlert.collect { alert ->
if (alert != null) showEmergencyOverlay(alert) else hideOverlay()
}
// Device connectivity and sync state
squareScreen.deviceStatus.collect { status ->
when (status) {
DeviceStatus.ONLINE -> hideOfflineBadge()
DeviceStatus.OFFLINE -> showOfflineBadge()
DeviceStatus.SYNCING -> showSpinner()
DeviceStatus.CONNECTING -> Unit
}
}
// Remote commands issued by the management console
squareScreen.commands.collect { commands ->
commands.forEach { command ->
when (command.toCommandType()) {
is CommandType.SetVolume -> setVolume((command.toCommandType() as CommandType.SetVolume).volume)
is CommandType.Unknown -> { /* ignore unknown commands */ }
}
squareScreen.acknowledgeCommand(command.id, status = "completed")
}
}For code that can't use collect, all flows have callback wrappers:
val job = squareScreen.nowPlayingCallback(
scope = lifecycleScope,
onSuccess = { playlist -> render(playlist) },
onError = { error -> showError(error) }
)
// Cancel when done
job.cancel()Emergency broadcasts automatically override the playlist UI when using SquareScreenDisplay. The overlay renders the alert's title, message, backgroundColor, and textColor as provided by the server.
If you are not using squarescreen-ui, subscribe to squareScreen.emergencyAlert and implement your own overlay.
SquareScreenDisplay reports playback automatically. If you use SquareScreenPlayerView directly, wire the onItemCompleted callback:
SquareScreenPlayerView(
nowPlaying = squareScreen.nowPlaying,
onItemCompleted = { item, startedAt, endedAt ->
scope.launch {
squareScreen.reportPlayback(
PlaybackReport(
mediaUuid = item.id,
playlistUuid = currentPlaylist?.playlist?.uuid,
scheduleUuid = currentPlaylist?.schedule?.uuid,
startedAt = formatIso8601(startedAt),
endedAt = formatIso8601(endedAt),
durationSeconds = item.duration,
completed = true
)
)
}
}
)The squarescreen-player module has no UI dependency. Use it headlessly — collect nowPlaying and render however you like:
// Add only the player, skip the UI module
implementation("io.squarescreen:squarescreen-player:0.1.0")squareScreen.nowPlaying.collect { result ->
val playlist = result.getOrNull() ?: return@collect
myCustomRenderer.show(playlist.items)
}Provide your own implementation of CacheProvider or NetworkDataSource in SquareScreenConfig:
SquareScreenConfig(
...
cacheProvider = MyCustomCacheProvider()
)// Force a playlist refresh (bypasses TTL)
val result = squareScreen.refresh()
// Force an emergency status check
val alert = squareScreen.checkEmergency()
// Stop the foreground service and cancel all background workers
squareScreen.shutdown()The SDK never calls android.util.Log directly. All internal logs route through SquareScreenLogger.
// Development — writes to Logcat
logger = SquareScreenDebugLogger()
// Production — silent (recommended)
logger = null
// Custom — e.g. forward to Crashlytics
logger = object : SquareScreenLogger {
override fun debug(tag: String, message: String) {}
override fun info(tag: String, message: String) {}
override fun warn(tag: String, message: String) {}
override fun error(tag: String, message: String, throwable: Throwable?) {
FirebaseCrashlytics.getInstance().recordException(throwable ?: Exception(message))
}
}- Android API 29+
- Kotlin 2.0+
- Jetpack Compose (only if using
squarescreen-ui)
Copyright 2024 SquareScreen
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.