This document extends the shared build guide with Android-specific details.
Read the shared guide first: https://raw.githubusercontent.com/OneSignal/sdk-shared/refs/heads/main/demo/build.md
Replace {{PLATFORM}} with Android everywhere in that guide. Everything below either overrides or supplements sections from the shared guide.
- Language: Kotlin with Coroutines (
Dispatchers.IO,Dispatchers.Main) - UI: Jetpack Compose with Material3
- Architecture: MVVM (
MainViewModelwithLiveData) - Build system: Gradle Kotlin DSL with inline dependency versions (no
buildSrc, so it works when included from the SDK project) - Product flavors: Google FCM and Huawei HMS (matching existing OneSignalDemo setup)
- Package name:
com.onesignal.sdktest(must matchgoogle-services.jsonandagconnect-services.json) - App bar:
CenterAlignedTopAppBar(Material3)
build.gradle.kts (app):
plugins {
id("org.jetbrains.kotlin.plugin.compose") version "2.2.0"
}
buildFeatures { compose = true }Dependencies (via BOM 2024.02.00):
composeUi,composeUiGraphics,composeUiToolingPreviewcomposeMaterial3composeMaterialIconsExtended(for IAM type icons)composeRuntime,composeRuntimeLivedataactivityComposelifecycleViewModelCompose,lifecycleRuntimeCompose
Register Android-specific listener interfaces:
IInAppMessageLifecycleListener(onWillDisplay,onDidDisplay,onWillDismiss,onDidDismiss)IInAppMessageClickListenerINotificationClickListenerINotificationLifecycleListener(withpreventDefault()for async display testing)IUserStateObserver(log when user state changes)
Initialization order:
OneSignal.consentRequired = SharedPreferenceUtil.getCachedConsentRequired(context)
OneSignal.consentGiven = SharedPreferenceUtil.getUserPrivacyConsent(context)
OneSignal.initWithContext(this, appId)
OneSignal.InAppMessages.paused = SharedPreferenceUtil.getCachedInAppMessagingPausedStatus(context)
OneSignal.Location.isShared = SharedPreferenceUtil.getCachedLocationSharedStatus(context)
SDK log capture:
OneSignal.Debug.addLogListener { event ->
LogManager.log("SDK", event.entry, level)
}IPushSubscriptionObserver— react to push subscription changesIPermissionObserver— react to notification permission changesIUserStateObserver— callfetchUserDataFromApi()when user changes
loadInitialState() reads from the SDK (not SharedPreferences):
_consentRequiredfromrepository.getConsentRequired()(readsOneSignal.consentRequired)_privacyConsentGivenfromrepository.getPrivacyConsent()(readsOneSignal.consentGiven)_inAppMessagesPausedfromrepository.isInAppMessagesPaused()(readsOneSignal.InAppMessages.paused)_locationSharedfromrepository.isLocationShared()(readsOneSignal.Location.isShared)_externalUserIdfromOneSignal.User.externalId(empty string = no user logged in)_appIdfromSharedPreferenceUtil(app-level config, no SDK getter)
Stored in SharedPreferences:
- OneSignal App ID
- Consent required status
- Privacy consent status
- External user ID (for login state restoration)
- Location shared status
- In-app messaging paused status
Auto-request via LaunchedEffect(Unit) { viewModel.promptPush() } in MainScreen composable.
Use kotlinx.coroutines.delay(100) after setting all LiveData values before dismissing the loader.
Use JSONObject to parse Track Event properties and convert to Map<String, Any?>.
MainViewModelexposestoastMessage: LiveData<String?>MainActivityobserves and shows AndroidToastLaunchedEffecttriggers ontoastMessagechange
- Pass-through to Android
logcatAND UI display - Thread-safe (posts to main thread for Compose state)
- API:
LogManager.d/i/w/e(tag, message)mimicsandroid.util.Log
TooltipHelperis a Kotlinobject(singleton)- Fetches on
CoroutineScope(Dispatchers.IO)to avoid blocking startup - Uses
HttpURLConnectionfor the network request init(context: Context)takes AndroidContext
vine_boom.wavplaced inres/raw/NotificationType.WITH_SOUNDsends withandroid_channel_idin the REST API payload- The OneSignal SDK handles channel creation when the notification is received
examples/demo/
├── app/
│ ├── src/main/
│ │ ├── java/com/onesignal/sdktest/
│ │ │ ├── application/
│ │ │ │ └── MainApplication.kt
│ │ │ ├── data/
│ │ │ │ ├── model/
│ │ │ │ │ ├── NotificationType.kt
│ │ │ │ │ └── InAppMessageType.kt
│ │ │ │ ├── network/
│ │ │ │ │ └── OneSignalService.kt
│ │ │ │ └── repository/
│ │ │ │ └── OneSignalRepository.kt
│ │ │ ├── ui/
│ │ │ │ ├── components/
│ │ │ │ │ ├── SectionCard.kt
│ │ │ │ │ ├── ToggleRow.kt
│ │ │ │ │ ├── ActionButton.kt
│ │ │ │ │ ├── ListComponents.kt
│ │ │ │ │ ├── LoadingOverlay.kt
│ │ │ │ │ ├── LogView.kt
│ │ │ │ │ └── Dialogs.kt
│ │ │ │ ├── main/
│ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ ├── MainScreen.kt
│ │ │ │ │ ├── Sections.kt
│ │ │ │ │ └── MainViewModel.kt
│ │ │ │ ├── secondary/
│ │ │ │ │ └── SecondaryActivity.kt
│ │ │ │ └── theme/
│ │ │ │ └── Theme.kt
│ │ │ └── util/
│ │ │ ├── SharedPreferenceUtil.kt
│ │ │ ├── LogManager.kt
│ │ │ └── TooltipHelper.kt
│ │ └── res/
│ │ ├── raw/
│ │ │ └── vine_boom.wav
│ │ └── values/
│ │ ├── strings.xml
│ │ ├── colors.xml
│ │ └── styles.xml
│ └── src/huawei/
│ └── java/com/onesignal/sdktest/notification/
│ └── HmsMessageServiceAppLevel.kt
├── google-services.json
├── agconnect-services.json
└── build.md (this file)
<string name="onesignal_app_id">77e32082-ea27-42e3-a898-c72e141824ef</string>The package name MUST be com.onesignal.sdktest to work with the existing google-services.json (Firebase) and agconnect-services.json (Huawei). Changing it requires updating those files with your own project configuration.