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 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)

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

MethodDescription
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(): BooleanChecks if the SDK is initialized
suspend fun currentUsername(): StringRetrieves the current username
suspend fun hasRequiredPermissions(): BooleanChecks if required permissions are granted
fun isLocalzFirebaseMessage(data: Map<String, String>): BooleanChecks 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.

ValueDescription
UNINITIALIZEDInitial state before initialization
INITIALIZEDSDK is initialized but no user is logged in
LOGGED_INUser is logged in but not actively on duty
ON_DUTYUser is logged in and actively on duty (sharing location)

Exceptions

ExceptionDescription
BackgroundSdkExceptionBase exception for the Background SDK
BackgroundSdkNotConfiguredExceptionThrown when a method is called before configuring the SDK
BackgroundSdkInvalidStateExceptionThrown when an operation is attempted in an invalid state
BackgroundSdkInvalidPayloadExceptionThrown when an invalid payload is provided

Packages

Link copied to clipboard
common
Link copied to clipboard
common