Android Beginners Guide 

Intro sentence 

This guide is for developers and integrators who want to integrate the DC SDK into an Android application.

Overview 

DC SDK is a modular identity platform for Android apps. It provides the building blocks to:

  • onboard users through identity enrollment,
  • issue and manage credentials in an on-device wallet,
  • handle online authentication and request-driven flows,
  • share identity attributes in person (ISO 18013 scenarios),
  • maintain credential trust over time with update and lifecycle operations.

1. Get Started 

Prerequisites 

Before integrating the SDK, make sure your development environment meets the following requirements.

Supported CPU architectures (required by the Capture SDK):

  • armeabi-v7a (32-bit ARM devices)
  • arm64-v8a (64-bit ARM devices)

NOTE: The SDK does not support x86/x64 architecture. Android Emulators on Intel-based machines are not supported. A physical Android device is required. Emulators running on Apple Silicon (M-series Macs) works due to ARM64 compatibility.

Skills Required 

You must have working knowledge of:

  • Android Studio
  • Kotlin
  • Android SDK
  • Maven/Gradle dependency management
  • Kotlin Coroutines

Resources Required 

Android integration may be performed on macOS, Linux, or Windows with the following tools:

  • Android Studio
  • JDK: preferred the latest version (17 or above) — Android Studio includes a bundled JDK
  • Android SDK tools: preferred the latest version (API level 29 or above)
  • Minimum Android SDK version: 29 (Android 10.0)
  • Physical Android device (emulator is not supported)

Access to Artifactory 

SDK artefacts are published to a dedicated Maven repository. You will need:

  • Access credentials (artifactoryUser / artifactoryPassword) — provided together with the licenses and SDK configuration file
  • Access to SDK dependencies - available from Artifactory
  • Access to the sample app: mobileid-sdk-sample-app-XX.XX.XX.zip — available from Artifactory
  • Access to SDK KDoc: sdk-api-kdoc-XX.XX.XX.zip- available from Artifactory

Sample Application 

A Sample Application is available alongside the SDK package. It demonstrates the recommended SDK integration flow, provides examples of using the SDK APIs, and can be used to validate the configuration provided for your environment.

The Sample Application also allows you to explore and test features available through the Digital Credentials Platform before integrating them into your own application.


2. Project Configuration 

Before configuring your project manually, it is recommended to download the sample app from Artifactory and import it into Android Studio. The sample app contains the most up-to-date working configuration as a reference.

Credentials DC repositories 

Define in your ~/.gradle/gradle.properties following properties credentials to required repositories

Properties
1mobileIdArtifactoryUser=
2mobileIdArtifactoryPassword=
3artifactoryUserMI=
4artifactoryPasswordMI=

Repositories required to build DC SDK and Sample App are defined in gradle.properites.

Properties
1idemiaRepositoryUrl=
2remoteRepositoryUrl=
3mobileIdSdkRepositoryUrl=

NOTE: The username and password are provided together with the licenses and SDK configuration file.

Dependencies 

Add the required SDK dependencies in your application build.gradle file. Repository URLs and exact version numbers are available in the sample app (mobileid-sdk-sample-app/app/build.gradle).

Groovy
1dependencies {
2 // sdk api library
3 implementation "com.idemia.mid.sdk:sdk-api:${Versions.mobileIdSdkVersion}"
4 implementation "com.idemia.mid.sdk:unlock:${Versions.mobileIdSdkVersion}"
5 implementation "com.idemia.mid.sdk:remote-face-liveness-plugin:${Versions.idemiaMobileIdSdkVersion}"
6 implementation "com.idemia.mid.sdk:document-capture-plugin:${Versions.idemiaMobileIdSdkVersion}"
7
8 // Kotlin Coroutines
9 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${Versions.coroutines}"
10 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${Versions.coroutines}"
11}

NOTE: The SDK does not support app data backup after uninstall. If you generate a new project from Android Studio, it adds android:allowBackup="true" to the application tag by default. You must either remove this attribute or explicitly set it to false.

App Name 

The SDK requires the integrator to provide the application name via the R.string.app_name string resource:

XML
1<string name="app_name">Your App Name</string>

This value is used by the SDK in the following ways:

  1. As part of the User-Agent header sent to backend services:
    Language not specified
    1User-Agent: Your App Name/XX.XX.XX SDK/XX.XX.XX Android
  2. To customize messages shown to the end user, for example on error screens.

3. SDK Integration 

Overview 

The SDK must be initialized during application startup before any SDK APIs can be accessed. The recommended approach is to perform initialization from a custom Application class and expose a shared MobileIDHolder instance for the rest of the application.

Terminology

Term
Description
MobileIDThe main SDK API used by the application.
MobileIDProviderFactory responsible for creating a MobileID instance.
MobileIDHolderLifecycle-aware container that manages SDK initialization and provides access to the initialized MobileID instance. This is an example code to initialize MobileID
MobileIDConfigurationConfiguration object containing all SDK settings and backend information.
TrackerOptional analytics interface used to receive SDK events.

Prerequisites 

Before initializing the SDK, ensure that:

  • The SDK dependencies are added to your project.
  • A valid SDK configuration is available
  • Sample Application was build with the configuration
  • Sample Applicaiton was launched on your phone

1. Create a Custom Application Class 

Create a custom Application class responsible for SDK initialization.

Kotlin
1class MyApplication : Application(), MobileIDHolderProvider, CoroutineScope by CoroutineScope(Dispatchers.IO) {
2
3 private val configuration = MobileIDConfiguration()
4 private lateinit var mobileIDHolder: MobileIDHolder
5
6 override fun getMobileIDHolder(): MobileIDHolder = mobileIDHolder
7
8 override fun onCreate() {
9 super.onCreate()
10
11 val mobileIDProvider = createMobileIdProvider()
12 registerActivityLifecycleCallbacks(MyActivityLifecycleCallbacks())
13 mobileIDHolder = MobileIDHolder(
14 application = this,
15 mobileIDProvider = mobileIDProvider
16 )
17
18 launch {
19 mobileIDHolder.createMobileId()
20 }
21 }
22
23 private fun createMobileIdProvider(): MobileIDProvider {
24 val configuration : MobileIDConfiguration = ConfigurationProvider().get()
25
26 return MobileID.initialize(
27 application = this,
28 configuration = configuration,
29 analyticsTracker = MyTracker(),
30 analyticsOptOut = false
31 )
32 }
33}

2. SDK Configuration 

Provide the configuration before initializing the SDK.

There are two approaches to provide configuration. The first is creating an instance of MobileIDConfiguration, fill out all properties and this is recommended. Another is to load for example Json file from assets. This approach you will find in Sample App but it is not recommended and it is used just only for presentation. In general you should receive all properties from us to fill out configuration. To get more info about configuration file, you can download sdk-api-kdoc-${version}.zip file from artifactory and find out its KDoc.

Kotlin
1val configuration = ConfigurationProvider().get()

Security Recommendation

We strongly recommend creating the MobileIDConfiguration object programmatically rather than loading it from application assets or resources.

The configuration contains backend endpoints and API keys used to communicate with Digital Credential services. Resource and asset files can be easily extracted from a packaged APK. While tools such as R8 provide code obfuscation, they do not protect static configuration files.

For production deployments, store configuration values in application code and apply standard Android code obfuscation and hardening techniques.

3. Initialize MobileID 

Create a MobileIDProvider using the MobileID.initialize() API.

Kotlin
1val mobileIDProvider = MobileID.initialize(
2 application = this,
3 configuration = configuration,
4 analyticsTracker = FirebaseTracker(Firebase.analytics),
5 analyticsOptOut = false
6)

Parameters:

Parameter
Type
Required
Description
applicationApplicationYesThe Android Application instance.
configurationMobileIDConfigurationYesThe SDK configuration object delivered in the SDK package. Do not modify values other than colors and appInfo.
analyticsTrackerTracker?NoAn optional implementation of the Tracker interface. Provide this to receive and handle SDK analytics events in your app.
analyticsOptOutBooleanNoSet to true to opt the user out of analytics tracking. Defaults to false.

NOTE: Code examples are available in mid-sdk-sample-app — see SplashScreenActivity.

4. Register Activity Lifecycle Callbacks 

Register the provided activity lifecycle callbacks to allow the SDK to observe Android activity state changes and create MobileID instance if previous attempts failed.

Kotlin
1registerActivityLifecycleCallbacks(MyActivityLifecycleCallbacks())
2
3// where
4
5class MyActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks, CoroutineScope by CoroutineScope(Dispatchers.IO) {
6
7 override fun onActivityStarted(activity: Activity) {
8 if (activity is MobileIDInitializationFailed) {
9 return
10 }
11
12 val mobileIDHolder = activity.mobileIDHolder()
13 launch {
14 if (mobileIDHolder.getMobileIDState() == MobileIDState.NotInitialized) {
15 mobileIDHolder.createMobileId()
16 }
17 }
18 }
19 ...
20}

5. Create a MobileIDHolder 

Creating a MobileID instance involves remote configuration download and SDK initialization, which are asynchronous operations. MobileIDHolder acts as a lifecycle-aware container that:

  • Maintains the initialization state.
  • Exposes the initialized MobileID instance.
  • Allows consumers to wait until initialization is completed.
  • Recovers from initialization failures.
Kotlin
1mobileIDHolder = MobileIDHolder(application = this, mobileIDProvider = mobileIDProvider)

6. Create the MobileID Instance 

Initialize MobileID asynchronously on a background thread.

Kotlin
1launch {
2 mobileIDHolder.createMobileId()
3}

This ensures that SDK initialization does not block the application's main thread.

7. Expose the MobileIDHolder 

Implement the MobileIDHolderProvider interface to provide global access to the SDK holder.

Kotlin
1interface MobileIDHolderProvider {
2 fun getMobileIDHolder(): MobileIDHolder
3}

Implementation:

Kotlin
1override fun getMobileIDHolder(): MobileIDHolder = mobileIDHolder

Usage from an Activity or Fragment:

Kotlin
1suspend fun Context.mobileID(): MobileID {
2 return (applicationContext as MobileIDHolderProvider).getMobileIDHolder().waitForMobileIdInitialization()
3}
4
5suspend fun Activity.mobileID(): MobileID {
6 return (application as MobileIDHolderProvider).getMobileIDHolder().waitForMobileIdInitialization()
7}
8
9suspend fun Fragment.mobileID(): MobileID {
10 return requireActivity().mobileID()
11}

Consumers should always obtain the SDK instance through waitForMobileIdInitialization(). This method suspends until initialization completes successfully and guarantees that a valid MobileID instance is returned.

8. Using MobileID 

After initialization, obtain the MobileID instance from any Android component.

Kotlin
1class MainActivity : AppCompatActivity() {
2
3 override fun onCreate(savedInstanceState: Bundle?) {
4 super.onCreate(savedInstanceState)
5
6 lifecycleScope.launch {
7 val mobileID = mobileID()
8
9 // Use MobileID APIs
10 }
11 }
12}

9. AndroidManifest Configuration 

Register the custom application class in AndroidManifest.xml.

XML
1<application
2 android:name=".MyApplication"
3 ... />

10. Initialization Flow 

Text
1Application Startup
2
3
4Instantiate Configuration
5
6
7MobileID.initialize()
8
9
10Register Lifecycle Callbacks
11
12
13Create MobileIDHolder
14
15
16mobileIDHolder.createMobileId()
17
18
19MobileID Ready

11. Verifying the Integration 

After integrating the SDK, verify that the initialization process completes successfully.

Prerequisites

  • The device or emulator has an active Internet connection.
  • The application starts without initialization errors.
  • Logging is enabled (e.g., Timber.DebugTree in debug builds).

Validation Steps

  1. Launch the application.
  2. Ensure the device is connected to the Internet.
  3. Monitor application logs using Android Studio Logcat.
  4. Search for SDK log entries during startup.

Successful Initialization

The SDK is considered ready when:

  • The Wallet Configuration has been downloaded.
  • The MobileIDHolder state transitions to Ready.
  • No initialization exceptions are reported.
  • MobileID APIs can be accessed through waitForMobileIdInitialization().

Expected Result

During initialization, the SDK should connect to backend services and download the Wallet Configuration.

Verify that logs do not contain entries indicating failed configuration retrieval.

Troubleshooting

If the Wallet Configuration is not downloaded:

  • Verify Internet connectivity.
  • Confirm the SDK configuration is correct.
  • Check that the backend environment endpoints are reachable.
  • Review Logcat for networking or SDK initialization errors.
  • Ensure that mobileIDHolder.createMobileId() is executed successfully.

Integration Success Criteria

A successful integration should produce the following sequence:

✅ Application starts successfully.

✅ MobileIDHolder is created.

✅ SDK initialization completes without errors.

✅ Wallet Configuration is downloaded successfully.

✅ MobileIDState transitions to Ready.

✅ Calls to waitForMobileIdInitialization() return successfully.

✅ No SDK-related exceptions are reported in Logcat.

12. Complete Example 

Kotlin
1class MyApplication : Application(), MobileIDHolderProvider, CoroutineScope by CoroutineScope(Dispatchers.IO) {
2
3 private lateinit var mobileIDHolder: MobileIDHolder
4
5 override fun getMobileIDHolder(): MobileIDHolder = mobileIDHolder
6
7 override fun onCreate() {
8 super.onCreate()
9
10 val mobileIDProvider = createMobileIdProvider()
11 registerActivityLifecycleCallbacks(MyActivityLifecycleCallbacks())
12 mobileIDHolder = MobileIDHolder(
13 application = this,
14 mobileIDProvider = mobileIDProvider
15 )
16
17 launch {
18 mobileIDHolder.createMobileId()
19 }
20 }
21
22 private fun createMobileIdProvider(): MobileIDProvider {
23 val configuration : MobileIDConfiguration = ConfigurationProvider().get()
24
25 return MobileID.initialize(
26 application = this,
27 configuration = configuration,
28 analyticsTracker = MyTracker(),
29 analyticsOptOut = false
30 )
31 }
32}
33
34interface MobileIDHolderProvider {
35 fun getMobileIDHolder() : MobileIDHolder
36}
37
38data class MobileIDConfiguration(
39 val enrollment: EnrollmentServiceConfiguration,
40 val authServer: AuthServerConfiguration,
41 val notifications: NotificationsConfiguration,
42 val captureSdkConfiguration: CaptureSdkConfiguration,
43 val appInfo: AppInfo,
44 val eventEmitterConfiguration: EventEmitterConfiguration? = null,
45 val walletConfiguration: WalletDownloadConfiguration? = WalletDownloadConfiguration(),
46)
47
48interface Tracker {
49 fun onScreenDisplayed(screenName: String, correlationId: String)
50 fun onEvent(event: String, correlationId: String, params: Map<String, String>)
51}
52
53class MyActivityLifecycleCallbacks : Application.ActivityLifecycleCallbacks, CoroutineScope by CoroutineScope(Dispatchers.IO) {
54
55 override fun onActivityStarted(activity: Activity) {
56 if (activity is MobileIDInitializationFailed) {
57 return
58 }
59
60 val mobileIDHolder = activity.mobileIDHolder()
61 launch {
62 if (mobileIDHolder.getMobileIDState() == MobileIDState.NotInitialized) {
63 mobileIDHolder.createMobileId()
64 }
65 }
66 }
67 ...
68}
69
70class MobileIDHolder(private val context: Context, private val mobileIDProvider: MobileIDProvider) {
71
72 private val _instanceFlow = MutableStateFlow<MobileIDState>(MobileIDState.NotInitialized)
73
74 suspend fun waitForMobileIdInitialization(): MobileID = withContext(Dispatchers.Default) {
75 _instanceFlow.filterIsInstance<MobileIDState.Ready>().first().mobileID
76 }
77
78 suspend fun getMobileIDState(): MobileIDState = withContext(Dispatchers.Default) {
79 _instanceFlow.first()
80 }
81
82 suspend fun createMobileId(){
83 try {
84 setMobileIdState(MobileIDState.InProgress)
85 val mobileID = mobileIDProvider.create()
86 MobileIdEventsListeners(context, Navigator(context.applicationContext)).setupListeners(mobileID)
87 setMobileIdState(MobileIDState.Ready(mobileID))
88 } catch (e: Exception) {
89 setMobileIdState(MobileIDState.NotInitialized)
90 }
91 }
92
93 private suspend fun setMobileIdState(mobileIDState: MobileIDState) = withContext(Dispatchers.Default) {
94 _instanceFlow.emit(mobileIDState)
95 }
96}