Skip to content

Flutter


Setting up your project

There are a few requirements for a flutter project that wants to implement the InvestSuite SDK.

  • Make sure that you are using flutter 3.13 or later (3.16.5 is recommended). If you want to be able to easily manage the flutter versions on your machine we can recommend Flutter Version Manager (fvm).

Creating an example project

A quick example of setting up a project could look something like this. For the name of our project we will choose investsuite_flutter_embedding_example.

  1. Create the directory mkdir investsuite_flutter_embedding_example
  2. Navigate to the directory cd investsuite_flutter_embedding_example
  3. Run your project creation command: fvm use 3.16.5 --force (--force is required because your current directory is no flutter project yet)
  4. Run your project creation command: fvm flutter create .
  5. After creation, verify that your project is setup correctly by running it on both Android and iOS (simulators). If you get errors here (regarding simulator setup, for example) fix these first. Since they have nothing to do with the InvestSuite SDK but might become confusing later.
    • Check for device ids: fvm flutter devices
    • Run on Android: fvm flutter run -d <android_device_id>
    • Run on iOS: fvm flutter run -d <ios_device_id>

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 that looks something like this:

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 flutter project that embeds the InvestSuite SDK and gives you a nice boilerplate to the steps we explain in step 6: Usage of the add-to-app SDK.

In order to continue with this step-by-step guide. We assume you place the unzipped folder here: packages/investsuite_module

Install the SDK as a dependency

Add the following to your pubspec.yaml file in your dependencies:

dependencies:
  #...
  investsuite_module:
    path: ../packages/investsuite_module
  #...    
in order to successfully run the SDK you have to do some extra changes to your iOS and Android projects. We will now do these.

Changes to your iOS project

As of now iOS doesn't require any changes to your project.

Changes to your Android project

Warning

To be completed and updated

Set the mindSdkVersion to at least 22 in build.gradle. minSdkVersion = 22

Usage of the add-to-app SDK

If you have the setup done, it is time to start playing around! The SDK exists out of two main parts:

  • InvestSuiteApp: This is a Flutter widget that renders the application. You can use it in your own application widgets where you wish to render the views of the Add-to-App SDK
  • InvestSuiteEmbeddingController: This is a controller that allows you to interact with the application that is shown in the InvestSuiteApp
  • InvestSuiteEmbeddingHandoverCallbacks: This is a class that receives callbacks when navigation should happen to screen,popup,dialog that is maintained by the SuperApp

We recommend to create a seperate widget to bundle everything together. This widget should contain the InvestSuiteApp and the InvestSuiteEmbeddingController. This widget can then be used in your application.

Minimal example on how to use the sdk
import 'package:flutter/material.dart';
import 'package:investsuite_flutter_embedding_example/example_embedding_controller.dart';
import 'package:investsuite_module/investsuite_module.dart';

class InvestSuiteAppWidget extends StatelessWidget {
final InvestSuiteFlavor flavor;
final ExampleEmbeddingController embeddingController;
final InvestSuiteEmbeddingNavigatorActionController embeddingNavigatorActionController;

const InvestSuiteAppWidget({
    required this.flavor,
    required this.embeddingController,
    required this.embeddingNavigatorActionController,
    super.key,
});

@override
Widget build(BuildContext context) {
    return InvestSuiteApp(
        flavor: flavor,
        embeddingController: embeddingController,
        embeddingNavigatorActionController: embeddingNavigatorActionController,
        loadingPageBuilder: (context) => const Scaffold(
            backgroundColor: Colors.white,
            body: Center(
            child: CircularProgressIndicator(),
            ),
        ),
        );
    }
}
import 'package:flutter/foundation.dart';
import 'package:investsuite_flutter_embedding_example/debug/logger/handover_logger.dart';
import 'package:investsuite_module_cbd/investsuite_module_cbd.dart';

class ExampleEmbeddingController extends InvestSuiteEmbeddingController {
    final AsyncValueGetter<String> accessTokenCallback;
    final AsyncValueGetter<String> anonymousAccessTokenCallback;

    ExampleEmbeddingController({
        required this.accessTokenCallback,
        required this.anonymousAccessTokenCallback,
        required InvestSuiteEmbeddingHandoverCallbacks handoverCallbacks,
    }) {
        init(handoverCallbacks);
    }

    @override
    Future<String?> provideAccessToken() => HandoverLogger.run(
            'provideAccessToken',
            null,
            accessTokenCallback,
        );

    @override
    Future<String> provideAnonymousAccessToken() => HandoverLogger.run(
            'provideAnonymousAccessToken',
            null,
            anonymousAccessTokenCallback,
        );

    @override
    void receiveAnalyticsEvent(AnalyticsEvent event) => HandoverLogger.addHandoverLog(
            'receiveAnalyticsEvent',
            arguments: event,
        );

    @override
    void receiveDebugLog(DebugLogRequest request) => HandoverLogger.addHandoverLog(
            'receiveDebugLog',
            arguments: request,
        );

    @override
    void receiveError(ErrorReqeust request) => HandoverLogger.addHandoverLog(
            'receiveError',
            arguments: request,
        );
}
import 'package:flutter/material.dart';
import 'package:investsuite_flutter_embedding_example/debug/logger/handover_logger.dart';
import 'package:investsuite_flutter_embedding_example/debug/screens/faq_screen.dart';
import 'package:investsuite_flutter_embedding_example/debug/screens/start_funding_portfolio_screen.dart';
import 'package:investsuite_flutter_embedding_example/debug/screens/start_onboarding_screen.dart';
import 'package:investsuite_flutter_embedding_example/debug/screens/start_authorization_screen.dart';
import 'package:investsuite_flutter_embedding_example/debug/screens/start_add_money_screen.dart';
import 'package:investsuite_module_cbd/investsuite_module_cbd.dart';

mixin EmbeddingHandoverCallbacksMixin<T extends StatefulWidget> on State<T> implements InvestSuiteEmbeddingHandoverCallbacks {
    @override
    void onExit() {
        HandoverLogger.addHandoverLog('onExit');
        Navigator.of(context).pop();
    }

    @override
    Future<OnboardingResponse> startOnboarding(OnboardingRequest request) => HandoverLogger.run(
            'startOnboarding',
            request,
            () => _push((context) => StartOnboardingScreen(request: request)),
        );

    @override
    Future<AuthorizationResponse> startAuthorization() => HandoverLogger.run(
            'startAuthorization',
            null,
            () => _push((context) => const StartAuthorizationScreen()),
        );

    @override
    Future<AddMoneyResponse> startAddMoney(
        AddMoneyRequest request,
    ) =>
        HandoverLogger.run(
            'startAddMoney',
            request,
            () => _push(
            (context) => StartAddMoneyScreen(request: request),
            ),
        );

    @override
    Future<FundPortfolioResponse> startFundPortfolio(
        FundPortfolioRequest request,
    ) =>
        HandoverLogger.run(
            'startFundPortfolio',
            request,
            () => _push((context) => StartFundPortfolioScreen(request: request)),
        );

    @override
    Future<void> startFaq(FaqRequest request) async {
        HandoverLogger.addHandoverLog(
        'startFaq',
        arguments: request,
        );
        await _push((context) => FaqScreen(request: request));
    }

    Future<E> _push<E>(WidgetBuilder builder) async {
        final result = await Navigator.of(context).push(MaterialPageRoute(builder: builder));
        if (result == null) {
        throw Exception('Failed to get $E restult');
        }
        return result;
    }
}
class ExampleEmbeddingNavigatorActionController extends InvestSuiteEmbeddingNavigatorActionController
    with InvestSuiteRoboNavigatorActions {}

InvestSuiteApp

Using the InvestSuiteApp should be fairly straightforward since it is a normal Flutter Widget

    InvestSuiteApp(
      flavor: ...,
      embeddingController: ...,
      loadingPageBuilder: (context) => ...,
    );

flavor

The InvestSuiteFlavor is used to determine which environment the SDK should use.

embeddingController

The InvestSuiteEmbeddingController is used to communicate with the SDK.

loadingPageBuilder

The loadingPageBuilder is used to show a loading page while the SDK is starting up. This is a builder function that should return a Widget.

InvestSuiteEmbeddingController

The InvestSuiteEmbeddingController is used to communicate with the SDK. Any method called on the controller should only be called if the InvestSuiteApp is open somewhere in your widget tree.

It has the following methods:

init

void init(InvestSuiteEmbeddingHandoverCallbacks handoverCallbacks); should be called before any other method is called on the controller. It is used to initialize the controller with the InvestSuiteEmbeddingHandoverCallbacks that are used to communicate with the SDK.

provideAccessToken

Future<String?> provideAccessToken(); will be called when an access token is needed. It should return a Future<String?> that contains the access token.

provideAnonymousAccessToken

Future<String> provideAnonymousAccessToken(); will be called when an anonymous access token is needed. It should return a Future<String> that contains the anonymous access token.

receiveAnalyticsEvent

void receiveAnalyticsEvent(AnalyticsEvent event); will be called when an analytics event should be logged by the host app.

receiveDebugLog

void receiveDebugLog(InvestSuiteDebugLogRequest request); will be called when a debug log should be logged by the host app.

receiveError

void receiveError(InvestSuiteErrorRequest request); will be called when an error should be logged by the host app.

changeLanguage

Future<bool> changeLanguage(Locale locale); should be called when you want to change the language of the SDK. It should return a Future<bool> that indicates if the language change was successful.

handleNotification

Future<bool> changeLanguage(Locale locale); should be called when you want to change the language of the SDK. It should return a Future<bool> that indicates if the language change was successful.

reset

Future<void> reset({bool clearData = false}); should be called when you want to reset the SDK.

InvestSuiteEmbeddingHandoverCallbacks

There are multiple ways to implement this and handle HandoverCallbacks. (Navigation to specific screens and return a specific result) We recommend to use a mixin that can directy access the navigator? Or get your navigation instance from somewhere else.

onExit

void onExit() will be called when the SDK wants to exit. This should be used to close the SDK. (In most cases this will be a Navigator.pop())

startOnboarding

Future<InvestSuiteOnboardingResponse> startOnboarding(InvestSuiteOnboardingRequest request) will be called when the SDK wants to start the onboarding flow with an OnboardingRequest. This should be used to navigate to the onboarding flow and return the OnboardingResponse when the flow is finished.

startAuthorization

Future<AuthorizationResponse> startAuthorization() will be called when the SDK wants to start the authorization flow. This should be used to navigate to the authorization flow and return the AuthorizationResponse when the flow is finished.

startFundPortfolio

Future<InvestSuiteAddMoneyResponse> startAddMoney(InvestSuiteAddMoneyRequest request) will be called when the SDK wants to start the add money flow with an AddMoneyRequest. This should be used to navigate to the add money flow and return the AddMoneyResponse when the flow is finished.

startFaq

Future<InvestSuiteFundPortfolioResponse> startFundPortfolio(InvestSuiteFundPortfolioRequest request) will be called when the SDK wants to start the fund portfolio flow with an InvestSuiteFundPortfolioRequest. This should be used to navigate to the fund portfolio flow and return the InvestSuiteFundPortfolioResponse when the flow is finished.

startFaq

Future<void> startFaq(InvestSuiteFaqRequest request) will be called when the SDK wants to start the faq flow with an InvestSuiteFaqRequest. This should be used to navigate to the faq flow and return when the flow is finished.

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 fvm flutter packages get. This will resolve all dependencies for the example app, all packages are based on path.

After this you can run the example app on your device by running fvm flutter run -d <device_id>.

You will now be able to browse a nice example app which looks something like this: