Skip to main content

Android Integration

Device Intel SDK Documentation · Version 1.5 · October 2026

This guide covers the integration of Device Intel SDK into Android applications.

Overview​

Device Intel is a lightweight library for Android device identification and risk detection. The SDK provides:

  • Persistent Device ID — Unique identifier that persists across app reinstalls
  • Risk Detection — Detection of emulators, rooted devices, VPNs, and other security signals
  • Minimal Footprint — No required permissions for core functionality

Prerequisites​

RequirementVersion
Minimum SDKAndroid 7.0 (API 24)
Target SDKAndroid 14+ (API 34+)
Java17+

Installation​

Add the dependency to your app's build.gradle.kts:

app/build.gradle.kts
dependencies {
implementation("ai.mubeen:deviceintel-lib:1.7.3")
}
tip

1.7.3 was the latest release at the time of writing. Check Maven Central for the most recent version before integrating.


Quick Start​

1. Import the SDK​

import ai.mubeen.deviceintel.MB_DeviceConfig
import ai.mubeen.deviceintel.MB_DeviceIntel
import ai.mubeen.deviceintel.ErrorCallback
import ai.mubeen.deviceintel.DeviceIntelError
import org.json.JSONObject

2. Initialize the SDK​

Initialize the SDK once during application startup, typically in your Application class.

The example below sets every option explicitly. In Kotlin you can omit any field to fall back to its default and use named arguments, so a minimal setup can be as short as MB_DeviceConfig(apiKey = "public_your_key").

MyApp.kt
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
val config = MB_DeviceConfig(
apiKey = "public_your_key",
uploadOnGetId = true,
debugMode = false,
collectionTimeoutMs = 5000L,
retryCount = 3,
baseUrl = "https://fp.sa.mubeen.ai/",
compressEnabled = true,
errorCallback = object : ErrorCallback {
override fun onError(error: DeviceIntelError) {
Log.e("DeviceIntel", "Error: ${error.type} - ${error.message}")
}
},
collectLocation = false,
locationMaxAgeMs = 1_800_000L,
collectAdvancedSignals = true,
collectAdvertisingId = false
)
MB_DeviceIntel.init(this, config)
}
}
Java requires every parameter

MB_DeviceConfig is a Kotlin data class. Its per-parameter defaults are only available to Kotlin callers — from Java you must pass all constructor arguments in order, as shown above. Kotlin callers can use named arguments and omit any field they want to leave at its default.

3. Retrieve the Device ID​

val deviceId = MB_DeviceIntel.getDeviceId()
Log.d("DeviceIntel", "Device ID: $deviceId")
info

When uploadOnGetId is true (the default), each call to getDeviceId() also triggers a full fingerprint collection and background upload. It is not a cheap getter — call it deliberately rather than in hot paths.

When to send a fingerprint​

Send a fingerprint with uploadFingerprint() to gather up-to-date data about the device:

  • Once when the app is opened — on launch / foreground.
  • Once per significant event — such as sign-in, registration, checkout, or any other high-value action you want scored.
// On app launch
MB_DeviceIntel.uploadFingerprint()

// Again at each significant event (sign-in, registration, checkout, …)
MB_DeviceIntel.uploadFingerprint()

Manual Fingerprint Upload​

Call uploadFingerprint() to collect a fresh fingerprint and upload it on demand, without going through getDeviceId(). This is the recommended trigger when uploadOnGetId = false, or when you want to send a fingerprint for an event without re-reading the device ID.

Collection and upload both run asynchronously on a background thread, so the call returns immediately and never blocks the caller. Failed uploads are queued for retry according to your retryCount configuration.

// Collects a fresh fingerprint and uploads it in the background.
MB_DeviceIntel.uploadFingerprint()
info

uploadFingerprint() must be called after MB_DeviceIntel.init(), otherwise it throws IllegalStateException. To inspect the fingerprint locally instead of uploading it, use getFingerprint(), which returns the fingerprint as a JSONObject (synchronous and blocking — call it off the main thread).


Configuration​

Basic Configuration​

Configuration Example
val config = MB_DeviceConfig(
apiKey = "public_your_key",
uploadOnGetId = true,
debugMode = false,
collectionTimeoutMs = 5000L,
retryCount = 3,
compressEnabled = true,
errorCallback = object : ErrorCallback {
override fun onError(error: DeviceIntelError) {
Log.e("DeviceIntel", "Error: ${error.type} - ${error.message}")
}
}
)
MB_DeviceIntel.init(this, config)

Configuration Parameters​

ParameterTypeDefaultDescription
apiKeyString""API key for authentication (e.g. public_...). Required if uploads are enabled.
uploadOnGetIdBooleantrueAutomatically collect and upload a fingerprint when getDeviceId() is called.
debugModeBooleanfalseEnable verbose logcat logging. Enable only for debugging.
collectionTimeoutMsLong5000Timeout for data collection, in milliseconds.
retryCountInt3Number of retry attempts for failed uploads. Set to 0 to disable retries.
baseUrlString"https://fp.sa.mubeen.ai/"Base URL of the fingerprint collection API.
compressEnabledBooleantrueEnable gzip compression for network uploads (reduces payload by 30–50%).
errorCallbackErrorCallback?nullCallback for error notifications. When null, failures are silent.
collectLocationBooleanfalseOpt-in. Include the device's last-known cached location. See Optional Data Collection.
locationMaxAgeMsLong1800000Max acceptable age (ms) of a cached location fix; older fixes report as null. 30 minutes by default.
collectAdvancedSignalsBooleanfalseOpt-in. Include permission-gated WiFi SSID/BSSID, Bluetooth name + paired-device count, phone number, and data-network type. Each field degrades to null unless the host app already holds the matching permission.
collectAdvertisingIdBooleanfalseOpt-in. Include the Google Advertising ID (GAID).

Optional Data Collection​

The following fields are permission-gated. The SDK never requests runtime permissions itself — each field is read only when the host app already holds the matching permission, and degrades gracefully to null otherwise. Whenever a field is actually collected, the host app is responsible for the runtime permission request, the Google Play Data Safety disclosure, and privacy-policy / consent coverage.

Defaults: collectAdvancedSignals, collectLocation and collectAdvertisingId are all false (opt-in). Set a flag to true to enable that group; a flag left false disables it entirely regardless of granted permissions.

Location (collectLocation)​

Reads only a cached last-known fix and never blocks. Requires the host app to already hold ACCESS_FINE_LOCATION or ACCESS_COARSE_LOCATION. Tune freshness with locationMaxAgeMs.

Advanced signals (collectAdvancedSignals)​

Gates these permission-sensitive fields (each degrades to null without the matching permission):

  • WiFi SSID / BSSID — ACCESS_FINE_LOCATION (plus ACCESS_WIFI_STATE) and location services enabled.
  • Bluetooth name + paired-device count — BLUETOOTH_CONNECT on Android 12+, or install-time BLUETOOTH below 12.
  • Phone number — READ_PHONE_NUMBERS / READ_PHONE_STATE (often still null on apps targeting API 30+ unless the app is the default SMS/dialer or has carrier privileges).
  • Data-network type — READ_PHONE_STATE, or READ_BASIC_PHONE_STATE on Android 12+.
note

Carrier / SIM / network metadata and adapter on/off state are collected regardless of this flag; only the identity-revealing fields above are gated by it.

Advertising ID (collectAdvertisingId)​

Includes the Google Advertising ID at device_detail.gaid. Read via the official AdvertisingIdClient, so it honors the user's "Limit Ad Tracking" / opt-out setting (returns null when opted out) and degrades to null when Google Play services are unavailable. When enabling it, the host app must:

  1. Add the com.google.android.gms:play-services-ads-identifier dependency.
  2. Declare the com.google.android.gms.permission.AD_ID permission (required on apps targeting API 33+).
  3. Disclose advertising-ID collection in its Google Play Data Safety form and privacy policy.

Permissions​

The SDK declares no permissions in its own manifest and operates without any for core functionality.

Required for network uploads:

AndroidManifest.xml
<uses-permission android:name="android.permission.INTERNET" />

Optional for enhanced detection:

AndroidManifest.xml
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
info

The ACCESS_NETWORK_STATE permission enables the connectivity signals (wifiEnabled, network transport, metered state). VPN detection does not require it — it works via network-interface enumeration with no permission. See Optional Data Collection for the additional permissions needed by opt-in signals.


Troubleshooting​

Debug Logging​

Enable debug mode to capture detailed logs:

MB_DeviceConfig(apiKey = "public_your_key", debugMode = true)

View logs using:

adb logcat | grep "MB_DeviceIntel"

Common Issues​

getDeviceId() throws IllegalStateException

MB_DeviceIntel.init() must be called before any other SDK method. Initialize in Application.onCreate(). If storage is temporarily unavailable, getDeviceId() does not throw or return null — it returns a process-stable, non-persistent fallback ID and reports the fault through errorCallback.

Network upload failures
  1. Verify the INTERNET permission is declared in the manifest
  2. Confirm network connectivity on the device
  3. Validate the API key is correct and active
Risk signals not detected

Certain signals have specific requirements:

  • Connectivity signals (wifiEnabled, network transport, metered state) require ACCESS_NETWORK_STATE
  • adb_enabled detection is limited to debug builds or rooted devices
  • Opt-in signals require the matching collect* flag and the corresponding host permission — see Optional Data Collection