Background SDK
The Background SDK provides developers with tools to implement automated location sharing for field operatives, enabling real-time position tracking and status management. This guide explains how to integrate and use the Background SDK in your mobile applications.
Table of Contents
Getting Started
Installation
Configuration
Required Permissions
Core Features
Authentication
State Management
Permissions
Location Tracking
Push Notifications
Error Handling
Logging
Background Processing
Other Sections
Sample Code
API Reference
Getting Started
Installation
To use the Background SDK in your project, include it as a dependency:
dependencies {
implementation("com.localz:background-sdk:1.1.10")
}
Configuration
Before using the SDK, you need to configure it with your Localz SDK key:
import com.localz.backgroundsdk.LocalzBackgroundSDK
import com.localz.common.LocalzEnvironment
import kotlinx.coroutines.launch
// Configure the SDK
coroutineScope.launch {
LocalzBackgroundSDK.configure(
key = "your-localz-sdk-key",
environment = LocalzEnvironment.PROD,
appVersion = "1.0.0"
)
}
Required Permissions
The Background SDK requires specific permissions to function correctly, especially for location tracking. You need to add the following permissions to your AndroidManifest.xml
:
<!-- Location permissions -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- Background processing permissions -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- Internet permissions -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Core Features
Authentication
The Background SDK provides multiple authentication methods.
Initializing the SDK
Before authenticating, you need to initialize the SDK:
import com.localz.backgroundsdk.BackgroundSdkState
import com.localz.common.LocalzResult
import kotlinx.coroutines.launch
coroutineScope.launch {
val result: LocalzResult<BackgroundSdkState> = LocalzBackgroundSDK.initialize()
when (result) {
is LocalzResult.Success -> {
val state = result.payload
// SDK initialized successfully
}
is LocalzResult.Error -> {
val errorMessage = result.message
// Handle initialization error
}
}
}
Basic Authentication
To authenticate with username and password:
coroutineScope.launch {
val result = LocalzBackgroundSDK.loginBasicAuth(
username = "driver_username",
password = "driver_password"
)
when (result) {
is LocalzResult.Success -> {
val state = result.payload
// User logged in successfully
}
is LocalzResult.Error -> {
val errorMessage = result.message
// Handle login error
}
}
}
MDLP SSO Authentication
To authenticate with MDLP SSO:
coroutineScope.launch {
val result = LocalzBackgroundSDK.loginMDLPSSO(
idToken = "your-sso-id-token"
)
when (result) {
is LocalzResult.Success -> {
val state = result.payload
// User logged in successfully with SSO
}
is LocalzResult.Error -> {
val errorMessage = result.message
// Handle login error
}
}
}
Logging Out
To log out the current user:
coroutineScope.launch {
val result = LocalzBackgroundSDK.logout()
when (result) {
is LocalzResult.Success -> {
val state = result.payload
// User logged out successfully
}
is LocalzResult.Error -> {
val errorMessage = result.message
// Handle logout error
}
}
}
Getting Current Username
You can retrieve the username of the currently logged-in user:
coroutineScope.launch {
try {
val username = LocalzBackgroundSDK.currentUsername()
// Use the username
} catch (e: Exception) {
// Handle error (e.g., user not logged in)
}
}
State Management
The Background SDK manages several states that your application can observe and interact with.
SDK States
The SDK can be in one of the following states:
UNINITIALIZED
: Initial state before initializationINITIALIZED
: SDK is initialized but no user is logged inLOGGED_IN
: User is logged in but not actively on dutyON_DUTY
: User is logged in and actively on duty (sharing location)
Observing State Changes
You can observe state changes in the SDK:
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
// Observe state changes
coroutineScope.launch {
LocalzBackgroundSDK.stateFlow().collect { state ->
when (state) {
BackgroundSdkState.UNINITIALIZED -> {
// SDK is not initialized
}
BackgroundSdkState.INITIALIZED -> {
// SDK is initialized but no user is logged in
}
BackgroundSdkState.LOGGED_IN -> {
// User is logged in but not on duty
}
BackgroundSdkState.ON_DUTY -> {
// User is logged in and on duty (sharing location)
}
}
}
}
Checking SDK Initialization
You can check if the SDK has been initialized:
coroutineScope.launch {
val isInitialized = LocalzBackgroundSDK.isInitialized()
if (isInitialized) {
// SDK is initialized
} else {
// SDK is not initialized
}
}
Permissions
The Background SDK requires specific permissions to function correctly, especially for location tracking.
Checking Required Permissions
You can check if all required permissions are granted:
coroutineScope.launch {
val hasPermissions = LocalzBackgroundSDK.hasRequiredPermissions()
if (hasPermissions) {
// All required permissions are granted
} else {
// Some permissions are missing
// Prompt the user to grant permissions
}
}
Location Tracking
The primary purpose of the Background SDK is to enable automated location tracking.
On Duty / Off Duty
When a user is "on duty," their location is automatically tracked and shared according to the configured settings. When they go "off duty," location tracking stops.
The SDK automatically manages the transition between these states based on authentication state and server-driven events.
Push Notifications
The Background SDK can integrate with Firebase Cloud Messaging (FCM) to receive server-driven events for location tracking control, but Firebase integration is optional. The SDK includes an internal fallback mechanism that maintains the proper functionality even without Firebase.
Handling Firebase Messages (Optional)
If you choose to use Firebase, you should configure your application to forward relevant Firebase messages to the Background SDK:
import com.google.firebase.messaging.RemoteMessage
// In your Firebase Messaging Service
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val data = remoteMessage.data
// Check if the message is from Localz
if (LocalzBackgroundSDK.isLocalzFirebaseMessage(data)) {
// Process with Background SDK
coroutineScope.launch {
LocalzBackgroundSDK.handleLocalzFirebaseMessage(data)
}
} else {
// Handle other Firebase messages
}
}
Note: Firebase integration is completely optional. The Background SDK includes an internal state synchronization mechanism that will maintain proper device state through periodic checks and API calls, ensuring reliable operation even without push notifications.
Error Handling
The SDK uses LocalzResult
to represent operation outcomes:
when (result) {
is LocalzResult.Success -> {
// Handle success case
val data = result.payload
}
is LocalzResult.Error -> {
// Handle error case
val errorMessage = result.message
val exception = result.throwable
when (exception) {
is BackgroundSdkNotConfiguredException -> {
// SDK not configured
}
is BackgroundSdkInvalidStateException -> {
// Invalid state transition
}
is BackgroundSdkInvalidPayloadException -> {
// Invalid payload
}
is BackgroundSdkException -> {
// General SDK exception
}
else -> {
// Other exceptions
}
}
}
}
Logging
The SDK provides built-in logging that you can observe:
import com.localz.common.logging.LogReport
import com.localz.common.logging.LogLevel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
// Observe log reports
coroutineScope.launch {
LocalzBackgroundSDK.logReportFlow().collect { logReport ->
// Process log report
val tag = logReport.tag
val message = logReport.message
val logLevel = logReport.logLevel
// Example: Forward to your logging system
when (logLevel) {
LogLevel.DEBUG -> Log.d(tag, message)
LogLevel.INFO -> Log.i(tag, message)
LogLevel.WARNING -> Log.w(tag, message)
LogLevel.ERROR -> Log.e(tag, message)
LogLevel.VERBOSE -> Log.v(tag, message)
LogLevel.FATAL -> Log.wtf(tag, message)
}
}
}
Background Processing
The Background SDK is designed to work effectively in the background. It uses platform-specific mechanisms to ensure reliable location tracking even when the app is not in the foreground.
Sample Code
Here's a sample demonstrating how to use the Background SDK in an Android app:
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.localz.backgroundsdk.BackgroundSdkState
import com.localz.backgroundsdk.LocalzBackgroundSDK
import com.localz.common.LocalzEnvironment
import com.localz.common.LocalzResult
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class MainActivity : ComponentActivity() {
private val requiredPermissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
)
private val permissionLauncher = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
val allGranted = permissions.all { it.value }
if (allGranted) {
initializeSDK()
} else {
showPermissionError()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Check permissions
if (hasAllPermissions()) {
configureSDK()
} else {
requestPermissions()
}
}
private fun hasAllPermissions(): Boolean {
return requiredPermissions.all {
ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
}
}
private fun requestPermissions() {
permissionLauncher.launch(requiredPermissions)
}
private fun showPermissionError() {
// Show error that permissions are required
}
private fun configureSDK() {
lifecycleScope.launch {
try {
LocalzBackgroundSDK.configure(
key = "your-localz-sdk-key",
environment = LocalzEnvironment.PROD,
appVersion = "1.0.0"
)
// Observe SDK state
LocalzBackgroundSDK.stateFlow().collect { state ->
updateUI(state)
}
// Observe logs
LocalzBackgroundSDK.logReportFlow().collect { logReport ->
// Process logs
}
initializeSDK()
} catch (e: Exception) {
// Handle configuration error
}
}
}
private fun initializeSDK() {
lifecycleScope.launch {
val initResult = LocalzBackgroundSDK.initialize()
when (initResult) {
is LocalzResult.Success -> {
// SDK initialized successfully
login()
}
is LocalzResult.Error -> {
// Handle initialization error
}
}
}
}
private fun login() {
lifecycleScope.launch {
val loginResult = LocalzBackgroundSDK.loginBasicAuth(
username = "driver_username",
password = "driver_password"
)
when (loginResult) {
is LocalzResult.Success -> {
// User logged in successfully
}
is LocalzResult.Error -> {
// Handle login error
}
}
}
}
private fun updateUI(state: BackgroundSdkState) {
when (state) {
BackgroundSdkState.UNINITIALIZED -> {
// Update UI for uninitialized state
}
BackgroundSdkState.INITIALIZED -> {
// Update UI for initialized state
}
BackgroundSdkState.LOGGED_IN -> {
// Update UI for logged in state
}
BackgroundSdkState.ON_DUTY -> {
// Update UI for on duty state
}
}
}
fun onLogoutClicked() {
lifecycleScope.launch {
val logoutResult = LocalzBackgroundSDK.logout()
when (logoutResult) {
is LocalzResult.Success -> {
// User logged out successfully
}
is LocalzResult.Error -> {
// Handle logout error
}
}
}
}
}
API Reference
LocalzBackgroundSDK
Main object for interacting with the Background SDK.
Methods
Method | Description |
---|---|
suspend fun configure(key: String, environment: LocalzEnvironment, appVersion: String) | Configures the SDK |
suspend fun initialize(): LocalzResult<BackgroundSdkState> | Initializes the SDK |
suspend fun loginBasicAuth(username: String, password: String): LocalzResult<BackgroundSdkState> | Logs in with username and password |
suspend fun loginMDLPSSO(idToken: String): LocalzResult<BackgroundSdkState> | Logs in with MDLP SSO |
suspend fun logout(): LocalzResult<BackgroundSdkState> | Logs out the current user |
suspend fun isInitialized(): Boolean | Checks if the SDK is initialized |
suspend fun currentUsername(): String | Retrieves the current username |
suspend fun hasRequiredPermissions(): Boolean | Checks if required permissions are granted |
fun isLocalzFirebaseMessage(data: Map<String, String>): Boolean | Checks if a Firebase message is from Localz |
suspend fun handleLocalzFirebaseMessage(data: Map<String, String>) | Handles a Localz Firebase message |
fun stateFlow(): StateFlow<BackgroundSdkState> | Provides a flow of SDK states |
fun logReportFlow(): Flow<LogReport> | Provides a flow of log reports |
BackgroundSdkState
Enum representing the state of the Background SDK.
Value | Description |
---|---|
UNINITIALIZED | Initial state before initialization |
INITIALIZED | SDK is initialized but no user is logged in |
LOGGED_IN | User is logged in but not actively on duty |
ON_DUTY | User is logged in and actively on duty (sharing location) |
Exceptions
Exception | Description |
---|---|
BackgroundSdkException | Base exception for the Background SDK |
BackgroundSdkNotConfiguredException | Thrown when a method is called before configuring the SDK |
BackgroundSdkInvalidStateException | Thrown when an operation is attempted in an invalid state |
BackgroundSdkInvalidPayloadException | Thrown when an invalid payload is provided |