Docs03 / 06

Android SDK

The Bildirim Android SDK is the shortest way to add push notifications to your app: you set up Firebase Cloud Messaging, and the SDK takes care of device registration, rendering the notification, click tracking and user tagging. It is written in Kotlin and callable from Java; its only dependency is firebase-messaging.

This page describes version 1.0.1 of the SDK — published on Maven Central. An app that already has a Firebase/APNs integration can also be connected without the SDK, over REST; both routes use the same endpoints.

Do not use 1.0.0: that package has no login(externalId, identityHash); the call will not compile once you turn on identity verification.

#Prerequisites

  1. A Firebase project — your app has to be connected to Firebase: google-services.json in the app module, the com.google.gms.google-services plugin applied. The "Add Firebase to your Android app" flow in the Firebase console does this.
  2. An FCM service account in the panel — in the Firebase console go to Project settings → Service accounts → Generate new private key, then paste the downloaded JSON under Settings → Mobile Push in the panel and press Verify. Without verification, device registration returns 403; that is deliberate — you could not have sent anything without credentials anyway.
  3. minSdk 21 (Android 5.0). A device with Play Services, or an emulator with a Google Play image.

#Installation

build.gradle.kts (app module):

dependencies {
    implementation("io.bildirim:bildirim-android:1.0.1")
    implementation("com.google.firebase:firebase-messaging:24.0.0") // leave it if you already have it
}

The SDK declares firebase-messaging as compileOnly; you choose the version. That way it never clashes with your app's Firebase version. Anything from 23.0.0 upwards works.

In your Application class:

class YourApp : Application() {
    override fun onCreate() {
        super.onCreate()
        Bildirim.initialize(this, "pk_your_key")
    }
}

The pk_ key is under Settings → API keys in the panel; the Settings → Mobile Push screen gives you this snippet with your key already filled in. It is a public key (the same key sits inside a <script> tag on your website), so embedding it in the APK is fine.

For a self-hosted Bildirim:

Bildirim.initialize(this, "pk_...", BildirimConfig(apiBase = "https://api.yourcompany.com"))

You do not need to add anything to the manifest: the SDK's FirebaseMessagingService subclass is merged in from the library manifest. If you have your own service, see I have my own FirebaseMessagingService below.

#Ask for permission

From Android 13 (API 33) the POST_NOTIFICATIONS permission is required to show notifications; below that there is no permission and notifications are shown directly. The SDK reduces both to a single call:

Bildirim.requestPermission { granted ->
    // granted=true: the device is registered (or already was)
}

When to ask: not the moment the app opens — after the user has seen some value (read their first story, added something to the basket). On Android, a declined permission is not easily asked for a second time. Our experience on the web is the same: a contextual request is accepted about twice as often.

When permission is granted the SDK collects the FCM token and registers it with POST /v1/subscribe. If the token changes (onNewToken) the registration refreshes itself; thanks to a persistent install id generated by the SDK, the old token is replaced by the new one and the same device is never counted as two subscribers.

That is all. Your device appears on the Subscribers screen with an Android badge; send the first notification with Create notification → Send to my test device.

#How the notification is rendered

Bildirim sends a data-only message to Android; the SDK renders it, not the system. The reason is that messages with a notification block are drawn by the system while the app is in the background, and in that case the image, action buttons and impression tracking are all lost. With data-only, all three work in every case.

The SDK creates a notification channel called bildirim_default (shown to the user as "Notifications"). To change its name and importance:

BildirimConfig(
    channelName = "Breaking news",
    smallIcon = R.drawable.ic_stat_bildirim, // default: the app icon
    accentColor = R.color.brand,
)

The small icon (smallIcon) is the single-colour icon shown in the status bar; without one, the app icon is used and on some devices it appears as a white square. Draw one and pass it.

While the app is in the foreground the notification is still shown by default. To decide yourself:

Bildirim.setForegroundHandler { notification ->
    // true → let the SDK draw it; false → handle it yourself (e.g. an in-app banner)
    notification.campaignId != currentPageCampaign
}

When the user taps a notification, the SDK opens its address (url) by default: https:// in the browser, your own scheme (myapp://news/42) in your app. To route it yourself:

Bildirim.setNotificationOpenedHandler { notification ->
    // notification.url, notification.campaignId, notification.actionId (if a button was pressed)
    startActivity(Intent(this, NewsActivity::class.java).putExtra("url", notification.url))
    true // true = do not let the SDK do its default open
}

The click is reported to the server by the SDK; the click counts on the notification screen show web and mobile events together. You do not need to do anything by hand.

Action buttons (actions in the panel or the API) are drawn as up to 3 buttons on the notification. If a button has its own address that is opened, otherwise the notification's address; which button was pressed arrives as notification.actionId and is counted per button on the notification screen.

#Identify, tag and measure users

The same names as in the web SDK:

Bildirim.login("user-42")                // on sign-in — targetable from your server via externalIds
Bildirim.login("user-42", identityHash = signature)  // required if the project asks for identity verification
Bildirim.logout()                        // on sign-out — the device stays, the user link is cut
Bildirim.setTags(mapOf("city" to "istanbul", "plan" to "premium"))
Bildirim.setTags(mapOf("plan" to null))  // a null value deletes the tag
Bildirim.track("purchase", mapOf("value" to 149.9, "currency" to "TRY"))
Bildirim.unsubscribe()                   // the user turned notifications off
  • login — from your server you can send to all of this user's devices (web + mobile) with POST /v1/push and "externalIds": ["user-42"]. If Settings → Keys → Identity verification is on in the panel, the second parameter is required: HMAC-SHA256(the project identity secret, externalId) in hex, generated on your server — never embed the secret in the app. An unsigned call gets 403 identity_verification_required and the user identity is not recorded; detail: Mobile integration → Identity verification.
  • setTags — tags are merged; you do not need to send all of them on every call. Segment rules read these tags.
  • track — an event is attributed to a campaign clicked in the last 24 hours and appears as revenue on the notification screen (value + currency).

These calls are not lost when the network is down: the SDK keeps them in an ordered queue and flushes it when the connection returns. After logout, a queued older setTags is not written to the new user.

#I have my own FirebaseMessagingService

If your app already has a FirebaseMessagingService subclass (another notification provider, your own messaging), two services clash in the manifest and only one runs. Forward to the SDK from your own service in two lines:

class MyService : FirebaseMessagingService() {
    override fun onNewToken(token: String) {
        Bildirim.onNewToken(token)
        // your own work
    }
    override fun onMessageReceived(message: RemoteMessage) {
        if (Bildirim.onMessageReceived(message)) return // it came from Bildirim, the SDK drew it
        // your own message
    }
}

onMessageReceived only takes over messages carrying a data.bildirim key and returns true; it does not touch the rest. In that case, remove the SDK's own service from the manifest:

<service android:name="io.bildirim.sdk.internal.MessagingService" tools:node="remove" />

#ProGuard / R8

The library ships with its own consumer-rules.pro; no extra rules are needed.

#Play Data Safety declaration

What the SDK collects: the FCM device token, a random install id generated by the SDK, the OS version, the app version, the SDK version, language and time zone; plus the externalId, tags and track events you provide. No advertising ID (AAID) is collected, and no location. On the declaration form it is enough to tick "App interactions" and "Device or other IDs"; ready-made wording is in DATA-SAFETY.md in the SDK repository.

#Troubleshooting

403 — "FCM is not configured for this project" — enter the service account JSON under Settings → Mobile Push in the panel and press Verify.

The device does not register, the Bildirim log says "could not get token" — the device has no Play Services (Huawei HMS devices, an emulator without a Play image), or google-services.json does not match the application id. Check the package name in the Firebase console.

Notifications arrive, but not while the app is closed — on Xiaomi/Oppo/Vivo/Huawei, battery optimisation kills the app and FCM cannot deliver even a high-priority message. Bildirim messages are sent with high priority; even so, on these devices the user may need to add the app to "auto-start". In the panel these devices show as delivered (FCM accepted them) — the device was never woken.

The small icon is a white square — pass a smallIcon (single colour, transparent background).

Notifications arrive twice — both the SDK's service and yours are running. Add the tools:node="remove" line from the I have my own FirebaseMessagingService section above.

The test device is not in the list — was permission granted (requestPermission called and granted=true), is FCM verified, does the device have internet? In Logcat, the Bildirim tag prints the result of the registration request.

More: Troubleshooting. Server-side detail and the REST route: Mobile integration.

Did not find what you were looking for? [email protected] and we will help — these pages grow with the questions we receive.Next: iOS SDK