Android Quickstart
This page adds Bubbl to a native Android app.
Requirements
- Android API 27 or newer.
- Kotlin or Java Android project.
- AndroidX enabled.
- Firebase configured if you want push notifications.
Install
Add the SDK dependency in your app module:
dependencies {
implementation("tech.bubbl.sdk:bubbl-sdk:4.0.2")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.1")
}
Make sure your project resolves dependencies from Maven Central.
Enable AndroidX in gradle.properties:
android.useAndroidX=true
If you want to keep the API key out of source, expose it through BuildConfig:
android {
buildFeatures {
buildConfig = true
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
defaultConfig {
buildConfigField(
"String",
"BUBBL_API_KEY",
"\"${providers.gradleProperty("BUBBL_API_KEY").orNull ?: ""}\""
)
}
}
If your app uses Kotlin Gradle plugin syntax, align Kotlin to JVM 17 as well:
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
}
}
Then set it in your local Gradle properties or CI secret store:
BUBBL_API_KEY=your-live-bubbl-api-key
Boot the SDK
Install the SDK once in your Application class, then boot it with your API key.
import android.app.Application
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import tech.bubbl.sdk.BubblConfig
import tech.bubbl.sdk.BubblEnvironment
import tech.bubbl.sdk.BubblSdk
class ExampleApp : Application() {
private val bubblScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreate() {
super.onCreate()
BubblSdk.install(this)
bubblScope.launch {
BubblSdk.boot(
BubblConfig(
apiKey = BuildConfig.BUBBL_API_KEY,
environment = BubblEnvironment.Production,
enablePushHandling = true,
enableLocationTracking = false
)
)
}
}
}
Use BubblEnvironment.Production for the live Bubbl environment.
Register your Application class in AndroidManifest.xml:
<application
android:name=".ExampleApp"
...>
...
</application>
Permissions
The SDK declares the permissions it needs, but your app must request runtime permissions from the user:
POST_NOTIFICATIONSon Android 13+ before visible push notifications can appear.- Fine or coarse location before location features can work.
- Background location only if your app needs geofence behavior while not visible.
Ask for permissions in context. For example, ask for notification permission when enabling Bubbl notifications and ask for background location only after explaining why the app needs it.
Firebase token
Add Firebase Messaging if your app does not already have it:
dependencies {
implementation(platform("com.google.firebase:firebase-bom:34.7.0"))
implementation("com.google.firebase:firebase-messaging")
}
When your app receives an FCM token, forward it to Bubbl:
BubblSdk.registerPushToken(token)
One common pattern is a Firebase Messaging service:
import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import tech.bubbl.sdk.BubblSdk
class ExampleMessagingService : FirebaseMessagingService() {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onNewToken(token: String) {
scope.launch {
BubblSdk.registerPushToken(token)
}
}
override fun onMessageReceived(message: RemoteMessage) {
scope.launch {
BubblSdk.handleFirebasePayload(message.data)
}
}
}
Declare the service:
<service
android:name=".ExampleMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
If your app receives Firebase data messages directly, pass the payload to Bubbl:
val payload = BubblSdk.handleFirebasePayload(remoteMessage.data)
If the SDK returns a payload, you can either let Bubbl render it with the default UI or handle it in your own UI, depending on your configuration.
First verification
After boot, call diagnostics:
val diagnostics = BubblSdk.diagnostics()
Expected signs of a healthy setup:
sdkVersionis4.0.2.bootedistrueafter a successful boot.pendingIngestCountreturns a number, even if it is0.