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)
Navigate to a specific screen (Deep linking)¶
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
Deeplinks¶
See deeplinks
Analytics Events¶
See analytics
Handovers¶
See handovers