Using Behavioral Module with Dynamic Feature

The Behavioral Module in the Credolab SDK enables passive, privacy-compliant behavioral events collection used for risk assessment and scoring. Proper initialization is required to ensure reliable data collection, especially when the module is packaged in a dynamic feature module (DFM) rather than the base APK.

Initialization Flow Diagram

Determine if manual initialization is required for your app

Auto Initialization

When the Behavioral Module is bundled into the base APK, it is initialized automatically via a ContentProvider declared in the SDK. In this setup, no action is required from your side. Initialization occurs early in the application lifecycle and is safe to use immediately.

Auto-init is on if:

  • The SDK is included directly in the base APK
  • You don’t load the module conditionally at runtime

Dynamic Feature Modules

If the Behavioral Module is delivered as a dynamic feature module, auto-initialization will not work. Android does not process the ContentProvider defined in the module’s manifest unless it is installed at app startup. As a result, the module must be initialized manually.

Use manual initialization if:

  • The module is installed at runtime (e.g., via Play Feature Delivery)
  • You want to defer initialization until a specific point

Manual Initialization

Manual initialization support was introduced in BehavioralModule version 4.13.0.

Step 1

To avoid compiling errors, ignore Behavioral Module's Content Provider from your app's AndroidManifest.

<application>
    <!-- ignore Behavioral Module's ContentProvider if using manual init -->
    <provider
        android:authorities="${applicationId}.credoapp.behavioral.provider"
        android:name="credoapp.module.behavioral.BehavioralProvider"
        tools:node="remove"
        tools:ignore="MissingClass" />
</application>

Step 2

CallBehavioralModule.init(context) method

override fun onStateUpdate(state: SplitInstallSessionState) {
    if (state.sessionId() == mySessionId) {
        when (state.status()) {
            SplitInstallSessionStatus.INSTALLED -> {
                try {
                    // Load the BehavioralModule class
                    val clazz = Class.forName("credoapp.module.behavioral.BehavioralModule")
                    // init
                    clazz.getMethod("init", Context::class.java).invoke(null, applicationContext)

                    val intent =
                        Intent().setClassName("com.example", "com.example.dynamic.FeatureActivity")
                    startActivity(intent)
                } catch (e: Exception) {
                    Log.e("SplitInstallManager", "Failed to initialize BehavioralModule", e)
                }
            }
        }
    }
}
class ExampleApp : SplitCompatApplication() {

    override fun onCreate() {
        super.onCreate()
        initBehavioralModule(applicationContext)
    }

    private fun initBehavioralModule(context: Context) {
        CoroutineScope(Dispatchers.Default).launch {
            try {
                val clazz = Class.forName("credoapp.module.behavioral.BehavioralModule")
                // init
                clazz.getMethod("init", Context::class.java).invoke(null, context)
                Log.d("ExampleApp", "BehavioralModule initialized successfully")
            } catch (e: ClassNotFoundException) {
                Log.d("ExampleApp", "BehavioralModule not found")
            } catch (e: Exception) {
                Log.e("ExampleApp", "init() failed", e)
            }
        }
    }
}
👍

Initialize early

Call init(context) method early, before transitioning to any activity expected to be tracked.

Step 3

Now you can safely callstartTracking() method later in your code. Just make sure to call init before starting that Activity or any other user flow.

class FeatureActivity : AppCompatActivity() {

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

        BehavioralModule.startTracking()
    }
}

FAQ

Can I call startTracking() before init() method?

No. The SDK requires successful initialization first.

Is init() thread-safe?

Yes. Parallel calls are safely handled.