> For the complete documentation index, see [llms.txt](https://docs.payments.thalescloud.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.payments.thalescloud.io/pin-management/integrate-d1-sdk/getting-started/multiplatform-technology/integrate-d1-sdk-using-flutter.md).

# Integrate D1 SDK using Flutter

Flutter is an open source framework by Google for building natively compiled, multi-platform applications from a single codebase.

To integrate D1 SDK using Flutter, refer to the following sections:

* [Integrating a Native SDK to a Flutter Application](#integrating-a-native-sdk-to-a-flutter-application)
* [Integrating D1 SDK to a Flutter Application](#integrating-d1-sdk-to-a-flutter-application)
* [Android platform](#android-platform)
* [iOS platform](#ios-platform)
* [Calling the D1 Plugin API from the Flutter application](#calling-the-d1-plugin-api-from-the-flutter-application)
* [References](#references)

### Integrating a Native SDK to a Flutter application <a href="#integrating-a-native-sdk-to-a-flutter-application" id="integrating-a-native-sdk-to-a-flutter-application"></a>

In Flutter, the Android and iOS platforms are generated only once.

There are two ways to integrate third party SDKs and Native components:

* A simple approach: Update the generated native projects directly.
* A more modular and universal approach: Create a standalone module(plugin), which is then linked and added to the Flutter application.

For simplicity, this guide will focus only on the first option.

### Integrating D1 SDK to a Flutter application <a href="#integrating-d1-sdk-to-a-flutter-application" id="integrating-d1-sdk-to-a-flutter-application"></a>

This guide was tested with:

* D1 SDK
  * 4.0.0 Android
  * 4.0.0 iOS
* Flutter 3.16.9
* Android Studio Giraffe | 2022.3.1
* Xcode 14.3.1

To create a new Flutter application:

{% code overflow="wrap" %}

```
>> flutter create --android-language java --ios-language swift --platforms=ios,android --org com.thalesgroup.gemalto.d1 validation
```

{% endcode %}

To be able to configure the D1 SDK on the Android platform for the Push provisioning use case, the application ID needs to be registered for [Google Pay](https://developer.dbp.thalescloud.io/docs/d1-developer-portal/tpa40s3iff528-d1-push-onboarding-for-wallets#google-pay). Use the application ID `com.thalesgroup.gemalto.d1.validation` for the [sandbox testing environment](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/environments/mobile-sdk-sandbox).

### Android platform <a href="#android-platform" id="android-platform"></a>

{% stepper %}
{% step %}

#### Adding D1 SDK dependencies to the Flutter application.

Add the D1 SDK binaries [dependencies](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/1.-binary-integration/android).

Create the Android modules using D1 SDK.

```
d1plugin-libs-debug/android
├── build.gradle
└── d1-debug.aar

d1plugin-libs-release/android
├── build.gradle
└── d1-release.aar
```

{% code title="d1plugin-libs-debug/android/build.gradle" %}

```
configurations.maybeCreate("default")
artifacts.add("default", file('d1-debug.aar'))
```

{% endcode %}

{% code title="d1plugin-libs-release/android/build.gradle" %}

```
configurations.maybeCreate("default")
artifacts.add("default", file('d1-release.aar'))
```

{% endcode %}
{% endstep %}

{% step %}

#### Add the dependencies to the Flutter application.

{% code title="validation/android/app/build.gradle" %}

```
dependencies {

    debugImplementation project(":d1plugin-libs-debug")
    releaseImplementation project(":d1plugin-libs-release")

    // other dependencies
    implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
    implementation "net.java.dev.jna:jna:5.5.0@aar"
    implementation "com.google.code.gson:gson:2.8.9"
}
```

{% endcode %}

{% code title="validation/android/settings.gradle" overflow="wrap" %}

```
include ':d1plugin-libs-debug'
project(':d1plugin-libs-debug').projectDir = new File('/path/to/d1plugin-libs-debug/android')

include ':d1plugin-libs-release'
project(':d1plugin-libs-release').projectDir = new File('/path/to/sdk/d1plugin-libs-release/android')
```

{% endcode %}
{% endstep %}

{% step %}

#### Update the minimum SDK version supported to 24.

{% code title="validation/android/app/build.gradle" %}

```
defaultConfig {
        minSdkVersion 24
    }
```

{% endcode %}
{% endstep %}

{% step %}

#### Add `'tools:replace="android:label"'` to `<application>` element and `xmlns:tools="http://schemas.android.com/tools"` to `<manifest>` element at `AndroidManifest.xml`.

{% code title="validation/android/app/src/main/Manifest.xml" %}

```
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

        <application
          tools:replace="android:label">
        
        </application>
</manifest>
```

{% endcode %}
{% endstep %}

{% step %}

#### Add the NFC Wallet configuration files.

For more information, see [NFC Wallet configuration files](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/2.-onboarding/nfc-payment/set-up-nfc-payment-on-application).

```
validation/android/app/src/main/assets/
├── gemcbp.properties
├── mobilegateway.properties
└── rages.properties
```

{% endstep %}

{% step %}

#### Update application signing keystore.

To run the NFC Wallet use case on the Android platform, the application needs to be signed with a specific [keystore](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/2.-onboarding/nfc-payment/onboard-nfc-payment#issuer-application-signing-key-app_pk).

```
validation/android/app/keystore/
└── keystore
```

{% code title="validation/android/app/build.gradle" overflow="wrap" expandable="true" %}

```
android {

    signingConfigs {
        debug {
            storeFile file('keystore/keystore')
            storePassword 'storePassword'
            keyAlias 'keyAlias'
            keyPassword 'keyPassword'
        }
        release {
            storeFile file('keystore/keystore')
            storePassword 'storePassword'
            keyAlias 'keyAlias'
            keyPassword 'keyPassword'
        }
    }

    buildTypes {
        debug {
            signingConfig signingConfigs.debug
        }

        release {
            // TODO: Add your own signing config for the release build.
            // Signing with the debug keys for now, so `flutter run --release` works.
            signingConfig signingConfigs.release
        }
    }
}
```

{% endcode %}
{% endstep %}

{% step %}

#### Add Firebase Cloud Messaging (FCM).

As NFC Wallet on the Android platform uses Firebase Cloud Messaging (FCM), Google Messaging Services has to be enabled in the Android application and the `google-services.json` file needs to be added.

{% code title="validation/android/build.gradle" %}

```
buildscript {
    dependencies {
        classpath 'com.google.gms:google-services:4.3.15'
    }
}
```

{% endcode %}

{% code title="validation/android/app/build.gradle" overflow="wrap" expandable="true" %}

```
plugins {
    id "com.android.application"
    id "kotlin-android"
    id "dev.flutter.flutter-gradle-plugin"
    id 'com.google.gms.google-services'
}

android {

    dependencies {
        debugImplementation project(":d1plugin-libs-debug")
        releaseImplementation project(":d1plugin-libs-release")

        implementation "net.java.dev.jna:jna:5.5.0@aar"
        implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
        implementation platform('com.google.firebase:firebase-bom:30.1.0')
        implementation 'com.google.firebase:firebase-messaging'
    }

}
```

{% endcode %}

Add the `google-services.json` to the Android project: `validation/android/app/google-services.json`.
{% endstep %}

{% step %}

#### Add the Host APDU Service Resource File.

For more information, see  [Host APDU service resource file](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/2.-onboarding/nfc-payment/set-up-nfc-payment-on-application).

{% code title="validation/android/app/src/main/res/xml/apduservice.xml" overflow="wrap" expandable="true" %}

```
<?xml version="1.0" encoding="utf-8"?>
<host-apdu-service xmlns:android="http://schemas.android.com/apk/res/android"
    android:apduServiceBanner="@mipmap/ic_launcher"
    android:description="@string/label_payment">
    <aid-group
        android:category="payment"
        android:description="@string/label_d1_pay_description">

        <!-- region MasterCard -->
        <!--Standard MasterCard-->
        <aid-filter android:name="A0000000041010" />

        <!--Mastercard Maestro (Debit)-->
        <aid-filter android:name="A0000000043060" />
        <aid-filter android:name="A0000000042203" />
        <aid-filter android:name="A0000000041010D056" />
        <!-- endregion -->

        <!-- region VISA -->
        <!--VISA Electron-->
        <aid-filter android:name="A0000000032010" />
        <!--VISA Debit/Credit (Classic)-->
        <aid-filter android:name="A0000000031010" />
        <!--Visa payWave for Mobile-->
        <aid-filter android:name="325041592E5359532E4444463031" />
        <!-- endregion -->
    </aid-group>
</host-apdu-service>
```

{% endcode %}

{% code title="validation/android/app/src/main/res/values/strings.xml" overflow="wrap" %}

```
<resources>
    <string name="label_payment">payment</string>
    <string name="label_d1_pay_description">payment description</string>
</resources>
```

{% endcode %}
{% endstep %}

{% step %}

#### Update the [Android manifest file](https://docs.payments.thalescloud.io/pin-management/integrate-d1-sdk/getting-started/multiplatform-technology/spaces/62lLFDcmLCeqqwmy4Fee/pages/szgSW0iOBkDj62qiSupT#androidmanifest.xml).

{% code title="validation/android/app/src/main/Manifest.xml" overflow="wrap" expandable="true" %}

```
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">

    <application
        android:label="validation"
        android:name="${applicationName}"
        tools:replace="android:label"
        android:icon="@mipmap/ic_launcher">

        <service
            android:name="com.thalesgroup.gemalto.d1.d1pay.D1HCEService"
            android:exported="true"
            android:permission="android.permission.BIND_NFC_SERVICE">
            <intent-filter>
                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

            <meta-data
                android:name="android.nfc.cardemulation.host_apdu_service"
                android:resource="@xml/apduservice" />
        </service>

    </application>

    <uses-feature android:name="android.hardware.nfc.hce" />
    <uses-feature android:name="android.hardware.nfc" />
    <uses-permission android:name="android.permission.USE_FINGERPRINT" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.NFC" />
    <uses-permission android:name="android.permission.USE_BIOMETRIC" />
</manifest>
```

{% endcode %}
{% endstep %}

{% step %}

#### Implement the Native Android entry point.

The following code snippet shows how to implement the methods for the [Login ](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/5.-authentication/sdk-login)and [Configure](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/3.-initialization/android-initialization) use cases.

{% code title="validation/android/app/src/main/java/com/thalesgroup/gemalto/d1/validation/MainActivity.java" overflow="wrap" expandable="true" %}

```java
package com.thalesgroup.gemalto.d1.validation;

import com.thalesgroup.gemalto.d1.ConfigParams;
import com.thalesgroup.gemalto.d1.D1Exception;
import com.thalesgroup.gemalto.d1.D1Params;
import com.thalesgroup.gemalto.d1.D1Task;
import com.thalesgroup.gemalto.d1.card.OEMPayType;
import com.thalesgroup.gemalto.d1.d1pay.ContactlessTransactionListener;
import com.thalesgroup.gemalto.d1.d1pay.D1PayConfigParams;
import com.thalesgroup.gemalto.d1.d1pay.VerificationMethod;

import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Locale;

import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class MainActivity extends FlutterActivity {
    private final String CHANNEL = "d1plugin";
    private D1Task mD1Task;

    @Override
    public void configureFlutterEngine(@NonNull final FlutterEngine flutterEngine) {
        super.configureFlutterEngine(flutterEngine);

        new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
                          CHANNEL).setMethodCallHandler((call, result) -> {
            switch (call.method) {
                case "configure":
                    configure(call, result);
                    break;
                case "login":
                    login(call, result);
                    break;
                case "logout":
                    logout(call, result);
                    break;
                default:
                    result.notImplemented();
                    break;
            }
        });
    }

    /**
     * Configures the D1 SDK.
     *
     * @param call   Call.
     * @param result Result.
     */
    private void configure(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        final String consumerId = call.argument("consumerId");
        final String d1ServiceUrl = call.argument("d1ServiceUrl");
        final String digitalCardUrl = call.argument("digitalCardUrl");
        final String issuerId = call.argument("issuerId");
        final String modulus = call.argument("modulus");
        final String exponent = call.argument("exponent");
        final String visaClientId = call.argument("visaClientId");
        final String samsungServiceId = call.argument("samsungServiceId");

        assert consumerId != null;
        assert d1ServiceUrl != null;
        assert digitalCardUrl != null;
        assert issuerId != null;
        assert modulus != null;
        assert exponent != null;

        // D1Core config.
        mD1Task = new D1Task.Builder().setContext(getApplicationContext()).setD1ServiceURL(d1ServiceUrl)
                                      .setIssuerID(issuerId).setD1ServiceRSAExponent(hexStringToByteArray(exponent))
                                      .setD1ServiceRSAModulus(hexStringToByteArray(modulus))
                                      .setDigitalCardURL(digitalCardUrl).build();

        final D1Params coreConfig = ConfigParams.buildConfigCore(consumerId);
        final D1Params cardConfig = ConfigParams.buildConfigCard(this, OEMPayType.NONE, visaClientId, samsungServiceId);

        // D1Pay config.
        final D1PayConfigParams d1PayConfigParams = D1PayConfigParams.getInstance();
        d1PayConfigParams.setContactlessTransactionListener(new D1PayTransactionListener());
        d1PayConfigParams.setReplenishAuthenticationUIStrings("Replenishment Title",
                                                              "Replenishment Subtitle",
                                                              "Replenishment Description",
                                                              "Cancel");

        mD1Task.configure(new D1Task.ConfigCallback<Void>() {
            @Override
            public void onSuccess(final Void unused) {
                result.success(null);
            }

            @Override
            public void onError(@NonNull final List<D1Exception> list) {
                if (!list.isEmpty()) {
                    result.error(String.format(Locale.US, "%d", list.get(0).getCauseErrorCode()),
                                 list.get(0).getLocalizedMessage(),
                                 null);
                }
            }
        }, coreConfig, cardConfig, d1PayConfigParams);
    }

    /**
     * Logs in to D1 services.
     *
     * @param call   Call.
     * @param result Result.
     */
    private void login(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        final String authToken = call.argument("authToken");

        assert authToken != null;

        getD1Task().login(authToken.getBytes(StandardCharsets.UTF_8), new D1Task.Callback<Void>() {
            @Override
            public void onSuccess(final Void unused) {
                result.success(null);
            }

            @Override
            public void onError(@NonNull final D1Exception exception) {
                result.error(String.format(Locale.US, "%d", exception.getCauseErrorCode()),
                             exception.getLocalizedMessage(),
                             null);
            }
        });
    }

    /**
     * Logs out from D1 services.
     *
     * @param call   Call.
     * @param result Result.
     */
    private void logout(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
        getD1Task().logout(new D1Task.Callback<Void>() {
            @Override
            public void onSuccess(final Void unused) {
                result.success(null);
            }

            @Override
            public void onError(@NonNull final D1Exception exception) {
                result.error(String.format(Locale.US, "%d", exception.getCauseErrorCode()),
                             exception.getLocalizedMessage(),
                             null);
            }
        });
    }

    /**
     * Retrieves the {@code D1Task} instance.
     *
     * @return {@code D1Task} instance.
     */
    private D1Task getD1Task() {
        if (mD1Task == null) {
            throw new IllegalStateException("Need to configure D1 SDK first.");
        }

        return mD1Task;
    }

    /**
     * Converts a HEX String to byte array.
     *
     * @param input Input HEX String.
     * @return Output byte array.
     */
    private byte[] hexStringToByteArray(@NonNull final String input) {
        final int len = input.length();
        final byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(input.charAt(i), 16) << 4) + Character.digit(input.charAt(i + 1), 16));
        }

        return data;
    }

    private static class D1PayTransactionListener extends ContactlessTransactionListener {

        @Override
        public void onTransactionStarted() {
            // TODO
        }

        @Override
        public void onAuthenticationRequired(@NonNull final VerificationMethod verificationMethod) {
            // TODO
        }

        @Override
        public void onReadyToTap() {
            // TODO
        }

        @Override
        public void onTransactionCompleted() {
            // TODO
        }

        @Override
        public void onError(@NonNull final D1Exception e) {
            // TODO
        }
    }
}
```

{% endcode %}
{% endstep %}
{% endstepper %}

### iOS platform <a href="#ios-platform" id="ios-platform"></a>

{% stepper %}
{% step %}

#### Add the D1 SDK binaries to the generated iOS project.

The most simple way to differentiate between the  [Debug and Release version of D1 SDK](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/1.-binary-integration/ios) on the iOS platform, is to wrap the D1 SDK binaries in to [Pods](https://cocoapods.org/).

```
├── d1plugin-libs-debug
│   └── ios
│       ├── D1.xcframework
│       ├── SecureLogAPI.xcframework
│       ├── d1-libs-debug.podspec
│       └── package.json
└── d1plugin-libs-release
    └── ios
        ├── D1.xcframework
        ├── SecureLogAPI.xcframework
        ├── d1-libs-release.podspec
        └── package.json
```

**Debug Podspec**

{% code title="d1plugin-libs-debug/ios/d1-libs-debug.podspec" %}

```
require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))

Pod::Spec.new do |s|
  s.name         = "d1-libs-debug"
  s.version      = package["version"]
  s.summary      = package["description"]
  s.homepage     = package["homepage"]
  s.license      = package["license"]
  s.authors      = package["author"]
  s.platforms    = { :ios => "10.0" }
  s.source       = { :git => "https://www.thalesgroup.com.git", :tag => "#{s.version}" }

  s.ios.vendored_framework = 'D1.xcframework', 'SecureLogAPI.xcframework'
end
```

{% endcode %}

{% code title="d1plugin-libs-debug/ios/package.json" overflow="wrap" expandable="true" %}

```
{
  "name": "d1-libs-debug",
  "version": "3.2.0",
  "homepage": "https://www.thalesgroup.com",
  "description": "D1 framework plugin",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "dynamic-linking"
  ],
  "author": "vladislav.vesely@external.thalesgroup.com",
  "license": "MIT"
}
```

{% endcode %}

**Release Podspec**

{% code title="d1plugin-libs-release/ios/d1-libs-release.podspec" %}

```
require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))

Pod::Spec.new do |s|
  s.name         = "d1-libs-release"
  s.version      = package["version"]
  s.summary      = package["description"]
  s.homepage     = package["homepage"]
  s.license      = package["license"]
  s.authors      = package["author"]
  s.platforms    = { :ios => "10.0" }
  s.source       = { :git => "https://www.thalesgroup.com.git", :tag => "#{s.version}" }

  s.ios.vendored_framework = 'D1.xcframework', 'SecureLogAPI.xcframework'
end
```

{% endcode %}

{% code title="d1plugin-libs-release/ios/package.json" overflow="wrap" expandable="true" %}

```
{
  "name": "d1-libs-release",
  "version": "3.2.0",
  "homepage": "https://www.thalesgroup.com",
  "description": "D1 framework plugin",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [
    "dynamic-linking"
  ],
  "author": "vladislav.vesely@external.thalesgroup.com",
  "license": "MIT"
}
```

{% endcode %}
{% endstep %}

{% step %}

#### Generate initial `Podfile`.

Run the following command to generate the initial `Podfile`.

```
>> flutter build ios
```

{% endstep %}

{% step %}

#### Update the iOS application `Podfile`.

{% code title="validation/ios/Podfile" overflow="wrap" expandable="true" %}

```
target 'Runner' do
  use_frameworks!
  use_modular_headers!

  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
  target 'RunnerTests' do
    inherit! :search_paths
  end
  
  pod 'd1-libs-debug', :path => '../../sdk/d1plugin-libs-debug/ios/', :configurations => ['Debug']
  pod 'd1-libs-release', :path => '../../sdk/d1plugin-libs-release/ios/', :configurations => ['Release']
end
```

{% endcode %}
{% endstep %}

{% step %}

#### Implement the Native iOS entry point of the plugin.

The following code snippets show how to create the method prototypes for the [Login ](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/5.-authentication/sdk-login)and [Configure ](https://app.gitbook.com/o/fwy1mtbRONGA2YDKDBr0/s/62lLFDcmLCeqqwmy4Fee/integrate-d1-sdk/getting-started/configuration/3.-initialization/android-initialization)use cases.

{% code title="validation/ios/Runner/AppDelegate.swift" overflow="wrap" expandable="true" %}

```
import UIKit
import Flutter
import D1

@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
    private var d1Task: D1Task?
    
    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -> Bool {
        
        let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
        let d1PluginChannel = FlutterMethodChannel(name: "d1plugin",
                                                  binaryMessenger: controller.binaryMessenger)
        
        d1PluginChannel.setMethodCallHandler({
            (call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
            switch call.method {
            case "configure":
                self.configure(call, result: result)
                break
            case "login":
                self.login(call, result: result)
                break
            case "logout":
                self.logout(result: result)
                break
            default:
                result(FlutterMethodNotImplemented)
            }
        })
        
        GeneratedPluginRegistrant.register(with: self)
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    
    /// Configures D1 SDK.
    /// - Parameters:
    ///   - call: Call.
    ///   - result: Result.
    private func configure(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let args = call.arguments as! Dictionary<String, Any>
        let consumerId = args["consumerId"] as! String
        let d1ServiceUrl = args["d1ServiceUrl"] as! String
        let digitalCardUrl = args["digitalCardUrl"] as! String
        let issuerId = args["issuerId"] as! String
        let modulus = args["modulus"] as! String
        let exponent = args["exponent"] as! String
        
        var comp = D1Task.Components()
        comp.d1ServiceURLString = d1ServiceUrl
        comp.issuerID = issuerId
        comp.d1ServiceRSAExponent = dataWithHexString(hex: exponent)
        comp.d1ServiceRSAModulus = dataWithHexString(hex: modulus)
        comp.digitalCardURLString = digitalCardUrl
        d1Task = comp.task()
        
        let coreConfig = ConfigParams.coreConfig(consumerID: consumerId)
        // required for Card Processing & OEM Pay
        let cardConfig = ConfigParams.cardConfig()
        
        getD1Task().configure([coreConfig, cardConfig]) { errors in
            if let errors = errors {
                result(FlutterError(code: String(errors[0].code.rawValue),
                                    message: errors[0].localizedDescription,
                                    details: nil))
            } else {
                result(nil)
            }

        }
    }
    
    /// Logs in to D1 services.
    /// - Parameters:
    ///   - call: Call.
    ///   - result: Result.
    private func login(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        let args = call.arguments as! Dictionary<String, Any>
        let authToken = args["authToken"] as! String
        
        if var issueTokenData: Data = authToken.data(using: .utf8) {
            getD1Task().login(&issueTokenData) { error in
                if let error = error {
                    result(FlutterError(code: String(error.code.rawValue),
                                        message: error.localizedDescription,
                                        details: nil))
                } else {
                    result(nil)
                }
            }
        }
    }
    
    /// Logs out from D1 services.
    /// - Parameters:
    ///   - call: Call.
    ///   - result: Result.
    private func logout(result: @escaping FlutterResult) {
        getD1Task().logout() { error in
            if let error = error {
                result(FlutterError(code: String(error.code.rawValue),
                                    message: error.localizedDescription,
                                    details: nil))
            } else {
                result(nil)
            }
        }
    }
    
    /// Converts hexa string to Data.
    /// - Parameter hex: Input hexa string.
    /// - Returns: Hexa string converted to Data.
    private func dataWithHexString(hex: String) -> Data {
        var hex = hex
        var data = Data()
        while(hex.count > 0) {
            let subIndex = hex.index(hex.startIndex, offsetBy: 2)
            let c = String(hex[..<subIndex])
            hex = String(hex[subIndex...])
            var ch: UInt64  = 0
            Scanner(string: c).scanHexInt64(&ch)
            var char = UInt8(ch)
            data.append(&char, count: 1)
        }
        
        return data
    }
    
    /// Retrieves the D1Task. Need to configure the D1 SDK first.
    /// - Returns: D1Task object. fatalError is thrown if called without D1 SDK configuration.
    private func getD1Task() -> D1Task {
        if let d1Task = d1Task {
            return d1Task
        } else {
            fatalError("Need to configure D1 SDK first.")
        }
    }
}
```

{% endcode %}
{% endstep %}
{% endstepper %}

### Calling the D1 Plugin API from the Flutter application <a href="#calling-the-d1-plugin-api-from-the-flutter-application" id="calling-the-d1-plugin-api-from-the-flutter-application"></a>

After the native parts for the Android and iOS platform have been added to the Flutter project, the D1 API can be accessed from the Flutter application.

{% code overflow="wrap" expandable="true" %}

```
final methodChannel = const MethodChannel('d1plugin');

// Configure
try {
    var arguments = <String, String>{
     'consumerId': CONSUMER_ID,
     'd1ServiceUrl': D1_SERVICE_URL,
     'digitalCardUrl': DIGITAL_CARD_URL,
     'issuerId': ISSUER_ID,
     'modulus': D1_SERVICE_RSA_MODULUS,
     'exponent': D1_SERVICE_RSA_EXPONENT,
    };

    await methodChannel.invokeMethod<void>('configure', arguments);

    // Configure OK.
} on PlatformException catch (e) {
    // Handle error.
}

// Login
try {
    var arguments = <String, String>{'authToken': "<auth-token>"};

    await methodChannel.invokeMethod<void>('login', arguments);

 // Login OK.
} on PlatformException catch (e) {
 // Handle error.
}

// Logout
try {
    await methodChannel.invokeMethod<void>('logout');

    // Logout OK.
} on PlatformException catch (e) {
 // Handle error.
}
```

{% endcode %}

### References <a href="#references" id="references"></a>

* [D1 developer portal](https://developer.dbp.thalescloud.io/docs/d1-developer-portal/branches/main/ZG9jOjE1MjEwNTMy-digital-first-d1-ux)
* [D1 Android Sample application](https://github.com/ThalesGroup/dp-d1-sample-android)
* [D1 iOS Sample application](https://github.com/ThalesGroup/dp-d1-sample-ios)
* [Flutter](https://docs.flutter.dev/)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.payments.thalescloud.io/pin-management/integrate-d1-sdk/getting-started/multiplatform-technology/integrate-d1-sdk-using-flutter.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
