Skip to content

Android


Download the InvestSuite SDK from your Codemagic dashboard

The InvestSuite team will provide you with a Codemagic dashboard where you can download (new) versions of the SDK as we release them. Download the latest one and store it in a convenient location where you can easily access it later.

Unzip the "artifacts" file you downloaded from Codemagic. This should give you a .zip file.

The version number will of course vary based on which version you're loading.

If you unzip this file you'll not only find the SDK packages, but also a fully working example Android project that embeds the InvestSuite SDK and gives you a nice boilerplate.

Example app

Each SDK embedding module ships with a functional example app that shows how to use the SDK. You can find this by unzipping the .zip file you downloaded from Codemagic inside the example folder.

In order to use this app you should cd into the example folder. Run ./gradlew assembleDebug or run it from Android Studio. This will resolve all dependencies for the example app, all packages are based on path.

Changes to your Android project

Set the minSdkVersion to at least 22 in build.gradle:

minSdkVersion = 22

Install the SDK as a dependency

Add the repositories to your app/build.gradle.kts file:

repositories {
    maven {
        // Path to the SDK repo folder
        url = uri("../../sdk/host/outputs/repo")
    }
    maven {
        val storageUrl = System.getenv("FLUTTER_STORAGE_BASE_URL") ?: "https://storage.googleapis.com"
        url = uri("$storageUrl/download.flutter.io")
    }
}

Add the dependency to your app/build.gradle.kts file. Replace white_label with the name of the SDK you're using (check the repo/com/investsuite/ folder for the available SDK):

dependencies {
    // Flutter dependencies
    debugImplementation("com.investsuite.white_label:flutter_debug:1.0.0")
    profileImplementation("com.investsuite.white_label:flutter_profile:1.0.0")
    releaseImplementation("com.investsuite.white_label:flutter_release:1.0.0")
}

Usage of the add-to-app SDK

Implementing the HandoversToHostService

Before starting the engine, you need to implement the HandoversToHostService which handles callbacks from Flutter to your app. This is a gRPC-based service that uses protobuf messages:

import HandoversToHostServiceGrpc
import HandoversToHostServiceOuterClass
import io.grpc.stub.StreamObserver

private fun createHandoversToHostService(): HandoversToHostServiceGrpc.HandoversToHostServiceImplBase {
    return object : HandoversToHostServiceGrpc.HandoversToHostServiceImplBase() {

        override fun provideAccessToken(
            request: HandoversToHostServiceOuterClass.ProvideAccessTokenRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.ProvideAccessTokenResponse?>?
        ) {
            // Return the current access token
            val response = HandoversToHostServiceOuterClass.ProvideAccessTokenResponse.newBuilder()
                .setAccessToken(currentAccessToken)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun provideAnonymousAccessToken(
            request: HandoversToHostServiceOuterClass.ProvideAnonymousAccessTokenRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.ProvideAnonymousAccessTokenResponse?>?
        ) {
            val response = HandoversToHostServiceOuterClass.ProvideAnonymousAccessTokenResponse.newBuilder()
                .setAnonymousAccessToken("")
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun onExit(
            request: HandoversToHostServiceOuterClass.OnExitRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.OnExitResponse?>?
        ) {
            // Handle exit from Flutter app - close the Flutter view/activity
            runOnUiThread {
                handleFlutterExit()
            }
            val response = HandoversToHostServiceOuterClass.OnExitResponse.newBuilder().build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun receiveAnalyticsEvent(
            request: HandoversToHostServiceOuterClass.ReceiveAnalyticsEventRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.ReceiveAnalyticsEventResponse?>?
        ) {
            // Log analytics events to your analytics service
            Log.d("Analytics", "Event: ${request?.name} at ${request?.eventLocation}")
            val response = HandoversToHostServiceOuterClass.ReceiveAnalyticsEventResponse.newBuilder().build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun receiveDebugLog(
            request: HandoversToHostServiceOuterClass.ReceiveDebugLogRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.ReceiveDebugLogResponse?>?
        ) {
            Log.d("FlutterSDK", "[${request?.level}] ${request?.message}")
            val response = HandoversToHostServiceOuterClass.ReceiveDebugLogResponse.newBuilder().build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun receiveError(
            request: HandoversToHostServiceOuterClass.ReceiveErrorRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.ReceiveErrorResponse?>?
        ) {
            Log.e("FlutterSDK", "Error: ${request?.errorCode}")
            val response = HandoversToHostServiceOuterClass.ReceiveErrorResponse.newBuilder().build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startFaq(
            request: HandoversToHostServiceOuterClass.StartFaqRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartFaqResponse?>?
        ) {
            // Navigate to your FAQ screen
            val response = HandoversToHostServiceOuterClass.StartFaqResponse.newBuilder().build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startOnboarding(
            request: HandoversToHostServiceOuterClass.StartOnboardingRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartOnboardingResponse?>?
        ) {
            // Start your onboarding flow
            val response = HandoversToHostServiceOuterClass.StartOnboardingResponse.newBuilder()
                .setSuccess(true)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startFundPortfolio(
            request: HandoversToHostServiceOuterClass.StartFundPortfolioRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartFundPortfolioResponse?>?
        ) {
            // Start your funding flow
            val response = HandoversToHostServiceOuterClass.StartFundPortfolioResponse.newBuilder()
                .setSuccess(true)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startAddMoney(
            request: HandoversToHostServiceOuterClass.StartAddMoneyRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartAddMoneyResponse?>?
        ) {
            // Start your add money flow
            val response = HandoversToHostServiceOuterClass.StartAddMoneyResponse.newBuilder()
                .setSuccess(true)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startAuthorization(
            request: HandoversToHostServiceOuterClass.StartAuthorizationRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartAuthorizationResponse?>?
        ) {
            // Perform authorization (e.g., biometric, PIN)
            val response = HandoversToHostServiceOuterClass.StartAuthorizationResponse.newBuilder()
                .setSuccess(true)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }

        override fun startTransactionSigning(
            request: HandoversToHostServiceOuterClass.StartTransactionSigningRequest?,
            responseObserver: StreamObserver<HandoversToHostServiceOuterClass.StartTransactionSigningResponse?>?
        ) {
            // Perform transaction signing
            val response = HandoversToHostServiceOuterClass.StartTransactionSigningResponse.newBuilder()
                .setSuccess(true)
                .build()
            responseObserver?.onNext(response)
            responseObserver?.onCompleted()
        }
    }
}

Creating StartParams

Create the start parameters with language, theme mode, and environment:

import HandoversToFlutterServiceOuterClass

fun createStartParams(): HandoversToFlutterServiceOuterClass.StartParams {
    return HandoversToFlutterServiceOuterClass.StartParams.newBuilder()
        .setEnvironment("TST") // "MOCK", "TST", "UAT", "PROD"
        .setLanguage(HandoversToFlutterServiceOuterClass.Language.LANGUAGE_EN)
        .setThemeMode(HandoversToFlutterServiceOuterClass.ThemeMode.THEME_MODE_SYSTEM)
        .build()
}

Available Languages: - LANGUAGE_EN - English - LANGUAGE_NL - Dutch - LANGUAGE_FR - French - LANGUAGE_AR - Arabic - LANGUAGE_TR - Turkish

Available Theme Modes: - THEME_MODE_LIGHT - THEME_MODE_DARK - THEME_MODE_SYSTEM

Starting the Flutter engine

Before using the SDK, you need to start the engine:

import com.investsuite.plugins.embedding.InvestSuiteEmbedding
import be.krispypen.plugins.flutter_embedding.CompletionHandler

val startParams = createStartParams()
val handoversToHostService = createHandoversToHostService()

InvestSuiteEmbedding.instance().startEngine(
    this, // Activity context
    startParams = startParams,
    handoversToHostService = handoversToHostService,
    object : CompletionHandler<Boolean> {
        override fun onSuccess(data: Boolean?) {
            Log.d("MainActivity", "Successfully started engine")
            // Engine is ready, you can now show the Flutter UI
        }

        override fun onFailure(e: Exception) {
            Log.e("MainActivity", "Error when starting engine: $e")
        }
    }
)

Showing the Flutter SDK as a full-screen Activity

InvestSuiteEmbedding.instance().startScreen(this)

Embedding the Flutter SDK in a Fragment/View

You can also embed the Flutter SDK within a container in your layout:

val containerId = R.id.flutter_container // Your FrameLayout container
val flutterFragment = InvestSuiteEmbedding.instance().getOrCreateFragment(this, containerId)

if (flutterFragment != null) {
    Log.d("MainActivity", "Flutter fragment added to view")
}

To remove the Flutter fragment:

InvestSuiteEmbedding.instance().clearFragment(this)

Communicating with the Flutter SDK (HandoversToFlutterService)

Once the engine is started, you can call methods on the Flutter SDK:

Change Language

val request = HandoversToFlutterServiceOuterClass.ChangeLanguageRequest.newBuilder()
    .setLanguage(HandoversToFlutterServiceOuterClass.Language.LANGUAGE_FR)
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().changeLanguage(request)

Change Theme Mode

val request = HandoversToFlutterServiceOuterClass.ChangeThemeModeRequest.newBuilder()
    .setThemeMode(HandoversToFlutterServiceOuterClass.ThemeMode.THEME_MODE_DARK)
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().changeThemeMode(request)

Reset the SDK

// Reset to initial state (home screen)
val request = HandoversToFlutterServiceOuterClass.ResetRequest.newBuilder()
    .setClearData(false)
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().reset(request)

// Reset and clear all cached data
val requestWithClear = HandoversToFlutterServiceOuterClass.ResetRequest.newBuilder()
    .setClearData(true)
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().reset(requestWithClear)
val request = HandoversToFlutterServiceOuterClass.NavigateToRequest.newBuilder()
    .setDeeplink("/self/portfolio/DEMO/more")
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().navigateTo(request)

Handle a notification

val notificationData = HandoversToFlutterServiceOuterClass.InvestSuiteNotificationData.newBuilder()
    .setId("notification-123")
    .setTitle("Deposit Received")
    .setBody("Your deposit has been processed")
    .setType("CASH_DEPOSIT_EXECUTED")
    .setModule("SELF")
    .setCreatedAt(System.currentTimeMillis())
    .putData("portfolio_id", "DEMO")
    .build()

val request = HandoversToFlutterServiceOuterClass.HandleNotificationRequest.newBuilder()
    .setNotificationData(notificationData)
    .build()

InvestSuiteEmbedding.instance().handoversToFlutterService().handleNotification(request)

Stop the Flutter engine

After using the SDK, you can stop the engine to free up resources:

InvestSuiteEmbedding.instance().stopEngine()

Handling notifications

See notifications

See deeplinks

Analytics Events

See analytics

Handovers

See handovers