AgentforceMobileSDK-Android

Agentforce Mobile SDK - Integration Guide

Note: This documentation reflects the latest SDK version with significant API updates. If you’re migrating from an earlier version, please review the changes carefully.

Full integration guide available in the Agentforce Mobile SDK Developer Guide

Getting Started with Agentforce

The Agentforce Mobile SDK empowers you to integrate Salesforce’s feature-rich, trusted AI platform directly into your native iOS and Android mobile applications. By leveraging the Agentforce Mobile SDK, you can deliver cutting-edge, intelligent, and conversational AI experiences to your mobile users, enhancing engagement and providing seamless access to information and actions.

What is Agentforce?

Agentforce is Salesforce’s platform for building and deploying trusted AI agents. These agents can understand user requests, access relevant data, perform actions across Salesforce and external systems, and generate helpful, conversational responses. The Agentforce Mobile SDK acts as the bridge, allowing your mobile app to communicate directly with these sophisticated agents, bringing the power of generative AI and automated workflows to your users’ fingertips.

Why Use the Agentforce Mobile SDK?

Integrating the Agentforce Mobile SDK into your app offers several key advantages. It allows you to deliver advanced AI experiences that go beyond simple chatbots, providing users with truly agentic capabilities for complex task completion, personalized interactions, and access to generative AI features within your app’s context.

The SDK offers flexible integration options to suit your needs:

We suggest starting with the Full UI Experience unless you need more granular control over the interface.

Core Features

Before You Begin

Before you begin integrating the Agentforce Mobile SDK, you must first configure an agent within your Salesforce organization.

More documentation on configuring your orgs for Agentforce are available at developer.salesforce.com

Implementing Core Service Interfaces

The Agentforce Mobile SDK is designed for flexibility and delegates several core responsibilities to the host application. This is achieved through a set of protocols (interfaces) that your application must implement. This approach allows the SDK to remain lean and lets you use your existing application architecture for handling common tasks.

You will need to create concrete implementations for the following interfaces:

AgentforceSDK Interfaces:

Salesforce Mobile Interfaces:

These are described in more detail in Salesforce Mobile Interfaces

By implementing these interfaces, you provide the “scaffolding” that the Agentforce SDK builds upon, ensuring seamless integration with your app’s existing ecosystem.

Android Integration Guidelines

This guide provides the steps to integrate the Agentforce Mobile SDK into your native Android application using Jetpack Compose.

Prerequisites

Dependencies

Add the Maven Repository

In your top-level settings.gradle.kts file, add the Salesforce Maven URL:

 // settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        maven { url = uri("https://jitpack.io") }
        maven { url = uri("https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository") }
        maven { url = uri("https://s3.amazonaws.com/inapp.salesforce.com/public/android") }
        maven { url = uri("https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android") }
    }
}

Add SDK Dependencies

In your app-level build.gradle.kts file, add the dependencies for the integration path you choose. The agentforcesdk artifact is for the Full UI experience, while agentforce-service is for the Headless approach.

Required Plugin

plugins {
   id("com.android.application")
   id("kotlin-android")
   id("kotlin-kapt")
   id("kotlinx-serialization")
}

Dependencies

Add the following to your module’s build.gradle.kts:

dependencies {
   // Agentforce SDK Dependencies
   api("com.salesforce.android.agentforcesdk:agentforce-sdk:14.146.2")
}
Core Library Desugaring

If your module doesn’t already have core library desugaring configured, add the following to your build.gradle.kts:

android {
    compileOptions {
        isCoreLibraryDesugaringEnabled = true
    }
}

dependencies {
    coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
}

After adding the dependencies, sync your project with the Gradle files.

Implement Core Service Interfaces

The Agentforce Mobile SDK is designed for flexibility and delegates several core responsibilities to the host application. This is achieved through a set of protocols that your application must implement. This approach allows the SDK to remain lean and lets you use your existing application architecture for handling common tasks. You will need to create concrete implementations for the following:

AgentforceSDK Interfaces

-AgentforceAuthCredentialProviding: Supplies the SDK with the authentication token (e.g., OAuth 2.0 access token) required to communicate securely with Salesforce APIs. -AgentforceInstrumentation: A handler for the SDK to emit instrumentation and telemetry data into your app’s analytics system.

AgentforceNetwork Implementation:

import com.salesforce.android.mobile.interfaces.network.Network
import com.salesforce.android.mobile.interfaces.network.NetworkRequest
import com.salesforce.android.mobile.interfaces.network.NetworkResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody

class MyAppNetwork(private val okHttpClient: OkHttpClient) : Network {
   override suspend fun perform(request: NetworkRequest): NetworkResponse {
      return withContext(Dispatchers.IO) {
         val okHttpRequest = Request.Builder().apply {
            url(request.path)
            request.headers.forEach { (key, value) -> addHeader(key, value) }

            when (request.method) {
               NetworkRequest.Method.POST -> {
                  val mediaType = request.contentType?.toMediaType() ?: "application/json".toMediaType()
                  post(request.body?.toRequestBody(mediaType))
               }
               NetworkRequest.Method.GET -> get()
               NetworkRequest.Method.PUT -> {
                  val mediaType = request.contentType?.toMediaType() ?: "application/json".toMediaType()
                  put(request.body?.toRequestBody(mediaType))
               }
               NetworkRequest.Method.DELETE -> delete()
               else -> throw IllegalArgumentException("Unsupported HTTP method: ${request.method}")
            }
         }.build()

         val response = okHttpClient.newCall(okHttpRequest).execute()

         response.use { // Properly close the response
            NetworkResponse(
               body = it.body?.string()?.toByteArray(),
               statusCode = it.code,
               headers = it.headers.toMap()
            )
         }
      }
   }
}

AgentforceAuthCredentialProvider Implementation:

import com.salesforce.android.agentforceservice.AgentforceAuthCredentialProvider
import com.salesforce.android.agentforceservice.AgentforceAuthCredentials
import com.salesforce.android.mobile.interfaces.logging.Logger

class MyAppCredentialProvider(
   private val userSession: UserSession,
   private val logger: Logger? = null
) : AgentforceAuthCredentialProvider {
   override fun getAuthCredentials(): AgentforceAuthCredentials {
      return try {
         val token = userSession.getAuthToken()
         if (token.isBlank()) {
            logger?.e("Auth token is empty")
            throw IllegalStateException("Authentication token is empty")
         }
         AgentforceAuthCredentials(
            authToken = token,
            orgId = userSession.getOrgId(),
            userId = userSession.getUserId()
         )
      } catch (e: Exception) {
         logger?.e("Failed to fetch auth credentials", e)
         throw IllegalStateException("Failed to fetch authentication credentials", e)
      }
   }
}

Option A: Full UI (with AgentforceClient)

This approach is the fastest way to get a complete, out-of-the-box chat interface running in your app. The AgentforceClient manages the session and provides a AgentforceLauncherContainer Composable that presents the chat UI.

1. Create an AgentforceConfiguration Instance

The AgentforceConfiguration object holds the essential settings for connecting to your agent. You’ll need to use the builder pattern to create the configuration.

import com.salesforce.android.agentforcesdkimpl.configuration.AgentforceConfiguration
import com.salesforce.android.agentforceservice.AgentforceAuthCredentialProvider
import com.salesforce.android.agentforceservice.AgentforceInstrumentationHandler
import com.salesforce.android.mobile.interfaces.logging.Logger
import com.salesforce.android.mobile.interfaces.network.Network
import com.salesforce.android.mobile.interfaces.navigation.Navigation

// First, create your implementations of the required interfaces
val authCredentialProvider = MyAppCredentialProvider(userSession)
val network = MyAppNetwork(okHttpClient)
val logger = MyAppLogger() // Your implementation of Logger
val navigation = MyAppNavigation() // Your implementation of Navigation

// Then create the configuration using the builder
val agentforceConfig = AgentforceConfiguration.builder(authCredentialProvider)
   .setSalesforceDomain("https://your-domain.my.salesforce.com")
   .setAgentId("YOUR_AGENT_ID")
   .setNetwork(network)
   .setLogger(logger)
   .setNavigation(navigation)
   // Optional configurations
   .setInstrumentationHandler(myInstrumentationHandler) // Optional: for analytics
   .setViewProvider(myViewProvider) // Optional: for custom UI components
   .build()

The configuration requires several mandatory components:

Optional components include:

2. Initialize the SDK and Build the View

Implement an Auth Credential Provider

Create an implementation of AgentforceAuthCredentialProvider to supply authentication credentials to the SDK.

For Employee Agents (OAuth):

import com.salesforce.android.agentforceservice.AgentforceAuthCredentialProvider
import com.salesforce.android.agentforceservice.AgentforceAuthCredentials

class MyAuthCredentialProvider : AgentforceAuthCredentialProvider {
    override fun getAuthCredentials(): AgentforceAuthCredentials {
        return AgentforceAuthCredentials.OAuth(
            authToken = "your-oauth-token",
            orgId = "your-org-id",
            userId = "your-user-id"
        )
    }
}

For Service Agents (Guest / Unauthenticated):

class MyGuestCredentialProvider : AgentforceAuthCredentialProvider {
    override fun getAuthCredentials(): AgentforceAuthCredentials {
        return AgentforceAuthCredentials.Guest(url = "https://your-instance.salesforce.com")
    }
}
Build the Configuration

Use AgentforceConfiguration.builder() to create a configuration with your auth provider:

import com.salesforce.android.agentforcesdkimpl.configuration.AgentforceConfiguration

val configuration = AgentforceConfiguration.builder(
    authCredentialProvider = myAuthCredentialProvider
)
    .setApplication(application)
    .setSalesforceDomain("https://your-instance.salesforce.com")
    .setThemeManager(createCustomAgentforceThemeManager(themeMode = AgentforceThemeMode.SYSTEM))
    .setLogger(myLogger)           // optional
    .setViewProvider(myViewProvider) // optional: register custom component renderers
    .build()
Create an AgentforceMode

The SDK supports two primary modes:

Employee Agent (FullConfig):

import com.salesforce.android.agentforcesdkimpl.configuration.AgentforceMode

val agentforceMode = AgentforceMode.FullConfig(configuration)

Service Agent:

import com.salesforce.android.agentforcesdkimpl.configuration.AgentforceMode
import com.salesforce.android.agentforcesdkimpl.configuration.ServiceAgentConfiguration
import com.salesforce.android.agentforceservice.miaw.AuthorizationContext
import com.salesforce.android.agentforceservice.miaw.AuthorizationMethod

val serviceAgentConfig = ServiceAgentConfiguration.builder(
    serviceApiURL = "https://your-service-api-url",
    organizationId = "your-org-id",
    esDeveloperName = "your-es-developer-name",
    authorizationContext = AuthorizationContext(
        authorizationMethod = AuthorizationMethod.UNVERIFIED
    )
).build()

val agentforceMode = AgentforceMode.ServiceAgent(
    serviceAgentConfiguration = serviceAgentConfig,
    agentforceConfiguration = configuration // optional: pass configuration for theming, logger, etc.
)
Initialize the Client and Start a Conversation
import com.salesforce.android.agentforcesdkimpl.AgentforceClient

val agentforceClient = AgentforceClient()
agentforceClient.init(
    authCredentialProvider = configuration.authCredentialProvider,
    agentforceMode = agentforceMode,
    application = application
)

// Start a conversation (optionally pass an agentId)
val conversation = agentforceClient.startAgentforceConversation()
// or with a specific agent:
// val conversation = agentforceClient.startAgentforceConversation(agentId = "your-agent-id")
Display the Chat UI

Use the AgentforceConversationContainer Composable provided by AgentforceClient:

import androidx.compose.runtime.Composable
import com.salesforce.android.agentforcesdkimpl.AgentforceClient
import com.salesforce.android.agentforcesdkimpl.AgentforceConversation

@Composable
fun MyChatScreen(
    agentforceClient: AgentforceClient,
    conversation: AgentforceConversation,
    onClose: () -> Unit
) {
    agentforceClient.AgentforceConversationContainer(
        conversation = conversation,
        onClose = onClose
    )
}

The AgentforceConversationContainer Composable renders the full chat interface including the top app bar, message list, and input field. The onClose callback is invoked when the user closes the chat view.

Full Example (Activity)

Below is a minimal Activity that shows/hides the chat UI:

class MyActivity : ComponentActivity() {

    private var agentforceClient: AgentforceClient? = null
    private var conversation: AgentforceConversation? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Initialize the Agentforce client and start a conversation
        initializeAgentforce()

        setContent {
            var showChat by rememberSaveable { mutableStateOf(false) }

            Box(Modifier.fillMaxSize()) {
                // Your app content
                Button(onClick = { showChat = true }) {
                    Text("Open Chat")
                }

                // Show chat overlay
                if (showChat) {
                    conversation?.let { conv ->
                        agentforceClient?.AgentforceConversationContainer(
                            conversation = conv,
                            onClose = { showChat = false }
                        )
                    }
                }
            }
        }
    }

    private fun initializeAgentforce() {
        val authProvider = MyAuthCredentialProvider()

        val configuration = AgentforceConfiguration.builder(
            authCredentialProvider = authProvider
        )
            .setApplication(application)
            .setSalesforceDomain("https://your-instance.salesforce.com")
            .build()

        val mode = AgentforceMode.FullConfig(configuration)

        agentforceClient = AgentforceClient().also {
            it.init(
                authCredentialProvider = authProvider,
                agentforceMode = mode,
                application = application
            )
        }
        conversation = agentforceClient?.startAgentforceConversation()
    }
}
Optional: Customize the Theme

Use createCustomAgentforceThemeManager to customize colors, typography, and theme mode:

import com.salesforce.android.agentforcesdk.components.theme.createCustomAgentforceThemeManager
import com.salesforce.android.agentforcesdk.components.theme.AgentforceThemeMode

val themeManager = createCustomAgentforceThemeManager(
    themeMode = AgentforceThemeMode.SYSTEM  // or LIGHT / DARK
)

// Pass to configuration builder:
// .setThemeManager(themeManager)

Basic Use Cases

Sending a Message

To send a message to the agent programmatically, you can use a method like sendUtterance on your AgentforceConversation object:

// Example: Sending a message with an optional attachment
conversation.sendUtterance(
   utterance = "Hello, world!",
   attachment = null // or provide an AgentforceAttachment object
)

Receiving Messages

To receive messages from the agent, you can use the conversationManager property on the AgentforceConversation object and its sendMessage method which returns a ReceiveChannel<AgentforceComponent>:

// Example: Using conversationManager to send and receive messages
val responseChannel = conversation.conversationManager.sendMessage(
   inputRepresentation = ConversationInputRepresentation("Hello, world!"),
   agentforceAttachment = null, // Optional attachment
   file = null // Optional file
)

Handling UI Events

To handle UI events, you can implement the AgentforceUIDelegate interface. This interface has the following methods:

class YourActivity : AgentforceUIDelegate {
   override suspend fun modifyUtteranceBeforeSending(utterance: AgentforceUtterance): AgentforceUtterance {
      // Modify the utterance if needed
      return utterance
   }

   override fun didSendUtterance(utterance: AgentforceUtterance) {
      // Handle sent utterance
   }

   override fun userDidSwitchAgents(newConversation: AgentforceConversation) {
      // Handle agent switch
   }
}

Option B: Headless (with AgentforceService)

This approach is for developers who want to build a completely custom UI or run agent interactions in the background. The AgentforceService handles the communication and state, emitting events via Kotlin Flows that your app uses to update its own UI or trigger logic.

1. Instantiate AgentforceService

Use the AgentforceServiceProvider to create an AgentforceService instance for a specific agent.

import com.salesforce.android.agentforceservice.AgentforceServiceProvider
import com.salesforce.android.agentforceservice.AgentforceService
import com.salesforce.android.agentforceservice.AgentforceServerSentEvents
import com.salesforce.android.mobile.interfaces.logging.Logger
import com.salesforce.android.mobile.interfaces.network.Network
import java.util.Locale

// Create the service provider with required dependencies
val serviceProvider = AgentforceServiceProvider(
   configurationLocale = Locale.getDefault(), // Optional: Your app's locale
   domain = "https://your-domain.my.salesforce.com", // Your Salesforce domain
   network = MyAppNetwork(okHttpClient), // Your Network implementation
   credentialProvider = MyAppCredentialProvider(userSession), // Your credential provider
   instrumentationHandler = myInstrumentationHandler, // Optional: For analytics
   logger = myLogger // Optional: For logging
)

// Get the service for your specific agent
val agentId = "YOUR_AGENT_ID"
val agentforceService: AgentforceService = serviceProvider.getAgentforceService(agentId)

2. Start a Session and Handle Events

Start a session by calling startSession() and then use sendMessageAndStartStreaming() to send messages and receive streaming responses. You’ll need to handle the streaming responses in your UI.

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.salesforce.android.agentforceservice.AgentforceService
import com.salesforce.android.agentforceservice.conversationservice.data.AgentforceResponse
import com.salesforce.android.agentforceservice.conversationservice.data.StreamingCapabilities
import com.salesforce.android.agentforceservice.conversationservice.data.StreamingRequest
import com.salesforce.android.agentforceservice.conversationservice.data.ChunkType
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch

class ChatViewModel(private val agentforceService: AgentforceService) : ViewModel() {
   private var currentSessionId: String? = null
   private val _messages = MutableStateFlow<List<ChatMessage>>(emptyList())
   val messages = _messages.asStateFlow()

   fun startSession() {
      viewModelScope.launch {
         try {
            // Configure streaming capabilities
            val streamingCapabilities = StreamingCapabilities(
               chunkTypes = mutableListOf(ChunkType.TEXT.type).apply {
                  if (AgentforceClient.agentforceFeatureFlagSettings.enableLightningTypeStreaming) {
                     add(ChunkType.LIGHTNING.type)
                  }
               }
            )

            // Start the session
            val session = agentforceService.startSession(streamingCapabilities)
            currentSessionId = session.sessionId

            // Handle initial messages if any
            session.messages.forEach { message ->
               processMessage(message)
            }
         } catch (e: Exception) {
            // Handle session start error
         }
      }
   }

   fun sendMessage(text: String) {
      val sessionId = currentSessionId ?: return
      viewModelScope.launch {
         try {
            // Create streaming request
            val streamingRequest = StreamingRequest(
               message = text,
               // Add any additional request parameters
            )

            // Send message and start streaming
            val responseChannel = agentforceService.sendMessageAndStartStreaming(
               sessionId = sessionId,
               inputRepresentation = streamingRequest
            )

            // Process streaming responses
            for (response in responseChannel) {
               processMessage(response.message)
            }
         } catch (e: Exception) {
            // Handle message sending error
         }
      }
   }

   private fun processMessage(message: AgentforceMessage) {
      // Process different message types
      when (message.type) {
         "progressindicator" -> {
            // Handle progress indicator
         }
         "inform" -> {
            // Handle informational message
         }
         "inquire" -> {
            // Handle inquiry message
         }
         // Handle other message types...
      }
   }

   override fun onCleared() {
      super.onCleared()
      // Cancel any ongoing streaming
      agentforceService.cancelCurrentStreaming()
   }
}

The session flow works as follows:

  1. Call startSession() to initialize a new session with the agent
  2. The session response includes a sessionId and any initial messages
  3. Use sendMessageAndStartStreaming() to send messages and receive streaming responses
  4. Process the streaming responses in your UI, handling different message types:
    • progressindicator: Shows that the agent is processing
    • inform: Contains information or responses from the agent
    • inquire: Contains questions or requests from the agent
  5. Use cancelCurrentStreaming() to stop any ongoing streaming when needed

Advanced Topics

Custom View Providers

The AgentforceViewProvider interface allows you to provide your own custom views for the different components that are displayed in the chat interface. This is useful if you want to replace the default implementation of a component with your own.

To provide your own views, you must create a class that implements the AgentforceViewProvider interface and implement the following methods:

Here is an example of how you can provide a custom view for the AF_RICH_TEXT component:

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.sp
import com.salesforce.android.agentforcesdk.components.models.AgentforceComponent
import com.salesforce.android.agentforcesdk.components.models.AgentforceViewProvider

class CustomViewProvider : AgentforceViewProvider {
   override fun canHandle(definition: String): Boolean {
      return definition == "AF_RICH_TEXT"
   }

   @Composable
   override fun GetView(modifier: Modifier, view: AgentforceComponent) {
      // Access component data from the view parameter
      val value = view.data["value"] as? String ?: ""
      androidx.compose.material3.Text(
         text = value,
         fontSize = 16.sp,
         fontWeight = FontWeight.Normal,
         modifier = modifier
      )
   }
}

Once you have created your custom view provider, you can register it with a ViewProviderService and pass it to the AgentforceConfiguration when you initialize it:

// Create and register your view provider
val viewProviderService = DemoViewProviderServiceImpl()
viewProviderService.register(CustomViewProvider())

val agentforceConfig = AgentforceConfiguration.builder(authCredentialProvider)
   .setSalesforceDomain("https://your-domain.my.salesforce.com")
   .setAgentId("YOUR_AGENT_ID")
   .setNetwork(network)
   .setLogger(logger)
   .setNavigation(navigation)
   .setViewProvider(viewProviderService) // Add your view provider service
   .build()

Instrumentation

The Agentforce SDK provides a detailed instrumentation framework for monitoring performance and usage. To receive instrumentation events, you can provide an implementation of the AgentforceInstrumentationHandler interface in your AgentforceConfiguration.

import com.salesforce.android.agentforceservice.AgentforceInstrumentationHandler
import com.salesforce.android.agentforceservice.AgentforceInstrumentationEvent
import com.salesforce.android.mobile.interfaces.logging.Logger

class MyInstrumentationHandler(private val logger: Logger? = null) : AgentforceInstrumentationHandler {
   override fun recordEvent(event: AgentforceInstrumentationEvent) {
      // Handle instrumentation events
      logger?.d("Instrumentation event: $event")

      // You can send events to your analytics service here
      // For example, using Firebase Analytics, Mixpanel, etc.
      when (event) {
         is AgentforceInstrumentationEvent.MessageSent -> {
            // Track message sent events
            logger?.d("Message sent: ${event.messageType}")
         }
         is AgentforceInstrumentationEvent.MessageReceived -> {
            // Track message received events
            logger?.d("Message received: ${event.messageType}")
         }
         is AgentforceInstrumentationEvent.SessionStarted -> {
            // Track session start events
            logger?.d("Session started: ${event.sessionId}")
         }
         is AgentforceInstrumentationEvent.SessionEnded -> {
            // Track session end events
            logger?.d("Session ended: ${event.sessionId}")
         }
         is AgentforceInstrumentationEvent.Error -> {
            // Track error events
            logger?.e("Agentforce error: ${event.error}")
         }
         else -> {
            // Handle other event types
            logger?.d("Other event: $event")
         }
      }
   }
}

Include the instrumentation handler in your configuration:

val agentforceConfig = AgentforceConfiguration.builder(authCredentialProvider)
   .setSalesforceDomain("https://your-domain.my.salesforce.com")
   .setAgentId("YOUR_AGENT_ID")
   .setNetwork(network)
   .setLogger(logger)
   .setNavigation(navigation)
   .setInstrumentationHandler(MyInstrumentationHandler(logger)) // Add your instrumentation handler
   .build()

Support and Resources

For additional documentation, examples, and support:

Contributing

See CONTRIBUTING.md

License

This project is licensed under the terms specified in the LICENSE.txt file.