> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knotapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Android Version 2.0+

## Overview

To simplify your application logic and integration with the Knot Android SDK, Version 2.0 includes a number of breaking changes that may affect the way your integration works or behaves.

The new version includes a number of significant improvements:

1. Enhanced speed and stability in loading merchant flows.
2. More streamlined initialization of the SDK.
3. Simplified event handling, more informative event messaging, and uniform naming conventions for easier debugging.
4. Improved maintainability and foundations for new feature compatibility.

## Breaking Changes

Configuring and opening the Knot SDK has changed significantly in Android Version 2.0 and requires some refactoring in order to initialize the SDK with a session. Errors are now encapsulated in a `KnotError` object which provides an enumerated value to debug with.

### Session Initialization

**Changes**

* `CardOnFileSwitcher.getInstance(); `and `Configuration(environment, clientId, sessionId);` are replaced with a more flexible `KnotConfiguration`.
* The new interface allows configuration of additional properties such as `useCategories`, `useSearch`, and `merchantIds`.
* The `open` action now requires a `KnotConfiguration` and an optional `KnotEventDelegate` which is now `Knot.open(context, knotConfiguration, knotEventDelegate)`.

**Before**

<CodeGroup>
  ```java java theme={"system"}
  CardOnFileSwitcher cardOnFileSwitcher = CardOnFileSwitcher.getInstance();
  Configuration switcherConfig = new Configuration(environment, clientId, sessionId);

  cardOnFileSwitcher.setMerchantIds(new int[]{44});
  cardOnFileSwitcher.setUseCategories(true);
  cardOnFileSwitcher.setUseSearch(true);

  Options options = new Options();
  String[] domainUrls = {"https://domain1.com", "https://domain2.com", ....};
  options.setDomainUrls(domainUrls);

  cardOnFileSwitcher.init(context, switcherConfig, options, onSessionEventListener);

  cardOnFileSwitcher.openCardOnFileSwitcher("Onboarding"); 
  ```

  ```
  console.log("Hello World");
  ```

  ```kotlin kotlin theme={"system"}
  val cardOnFileSwitcher = CardOnFileSwitcher.getInstance()
  val switcherConfig = Configuration(environment, clientId, sessionId)

  cardOnFileSwitcher.setMerchantIds(intArrayOf(44))
  cardOnFileSwitcher.setUseCategories(true)
  cardOnFileSwitcher.setUseSearch(true)

  val options = Options()
  val domainUrls = arrayOf("https://domain1.com", "https://domain2.com")
  options.setDomainUrls(domainUrls)

  cardOnFileSwitcher.init(context, switcherConfig, options, onSessionEventListener)

  cardOnFileSwitcher.openCardOnFileSwitcher("Onboarding")
  ```
</CodeGroup>

**After**

<CodeGroup>
  ```java java theme={"system"}
  KnotConfiguration config = new KnotConfiguration(
      "session_12345",                      // sessionId
      "client_67890",                       // clientId
      Environment.production,               // environment
      Knot.Product.card_switcher,           // product
      new int[]{101, 102, 103},             // merchantIds
      true,                                 // useCategories
      true,                                 // useSearch
      new String[]{"https://example.com"},  // domainUrls
      "onboarding"                          // entryPoint
  );

  KnotEventDelegate knotEventDelegate = new KnotEventDelegate() {
      @Override
      public void onSuccess(String merchant) {
          // Handle successful operation
      }

      @Override
      public void onError(KnotError knotError) {
          // Handle error operation using knotError
      }

      @Override
      public void onExit() {
          // Handle SDK exit event
      }

      @Override
      public void onEvent(KnotEvent knotEvent) {
          // Extract and process event details from KnotEvent
      }
  };

  Knot.open(context, config, knotEventDelegate);
  ```

  ```kotlin kotlin theme={"system"}
  val config = KnotConfiguration(
      "session_12345",                      // sessionId
      "client_67890",                       // clientId
      Environment.PRODUCTION,               // environment
      Knot.Product.card_switcher,           // product
      intArrayOf(101, 102, 103),            // merchantIds
      true,                                 // useCategories
      true,                                 // useSearch
      arrayOf("https://example.com"),       // domainUrls
      "onboarding"                          // entryPoint
  )

  KnotEventDelegate knotEventDelegate = new KnotEventDelegate() {
      @Override
      public void onSuccess(String merchant) {
          // Handle successful operation
      }

      @Override
      public void onError(KnotError knotError) {
          // Handle error operation using knotError
      }

      @Override
      public void onExit() {
          // Handle SDK exit event
      }

      @Override
      public void onEvent(KnotEvent knotEvent) {
          // Extract and process event details from KnotEvent
      }
  };

  Knot.open(context, config, knotEventDelegate)
  ```
</CodeGroup>

### Event Handling

**Changes**

* Event handling is now managed through `KnotEventDelegate` instead of closures.
* Events like `onSuccess`, `onError`, and `onExit` are now **explicit methods** inside a delegate.
* The `onEvent` method introduces the `KnotEvent` object to better handle Knot emitted events.
* The `KnotError` type provides improved error descriptions.
* The `sendCard` parameter is deprecated and its functionality incorporated into the `metaData` dictionary within `KnotEvent` when `KnotEvent.event` equals `AUTHENTICATED`.

**Before**

<CodeGroup>
  ```java java theme={"system"}
  cardOnFileSwitcher.setOnSessionEventListener(new OnSessionEventListener() {
      @Override
      public void onSuccess(String merchant) {
          Log.d("onSuccess", merchant);
      }

      @Override
      public void onError(String errorCode, String errorMessage) {
          Log.d("onError", errorCode + " " + errorMessage);
      }

      @Override
      public void onExit() {
          Log.d("onExit", "exit");
      }

      @Override
      public void onEvent(String eventName, String merchantName, String taskId) {
          Log.d("onEvent", eventName + " " + merchantName + " " + taskId);
      }
  });
  ```

  ```
  cardOnFileSwitcher.setOnSessionEventListener(object : OnSessionEventListener {
      override fun onSuccess(merchant: String) {
          Log.d("onSuccess", merchant)
      }

      override fun onError(errorCode: String, errorMessage: String) {
          Log.d("onError", "$errorCode $errorMessage")
      }

      override fun onExit() {
          Log.d("onExit", "exit")
      }

      override fun onEvent(eventName: String, merchantName: String, taskId: String) {
          Log.d("onEvent", "$eventName $merchantName $taskId")
      }
  })
  ```
</CodeGroup>

**After**

<CodeGroup>
  ```java java theme={"system"}
  KnotEventDelegate knotEventDelegate = new KnotEventDelegate() {
      @Override
      public void onSuccess(String merchant) {
          // Handle successful operation
      }

      @Override
      public void onError(KnotError knotError) {
          // Handle error operation using knotError
      }

      @Override
      public void onExit() {
          // Handle SDK exit event
      }

      @Override
      public void onEvent(KnotEvent knotEvent) {
          // Extract and process event details from KnotEvent
      }
  };
  ```

  ```kotlin kotlin theme={"system"}
  val eventDelegate = object : KnotEventDelegate {
      override fun onSuccess(merchant: String) {
          // Handle successful operation
      }

      override fun onError(knotError: KnotError) {
          // Handle error operation using knotError
      }

      override fun onExit() {
          // Handle SDK exit event
      }

      override fun onEvent(knotEvent: KnotEvent) {
          // Extract and process event details from KnotEvent
      }
  }
  ```
</CodeGroup>

**SendCard**

<Warning>
  Most apps do not use the explicit `sendCard` method, as it is rarely applicable to the integration with the Knot SDK.
</Warning>

The `sendCard` parameter has been deprecated and its functionality is incorporated into the `metaData` object within `KnotEvent` when the `KnotEvent.event` equals `AUTHENTICATED`. This change enhances flexibility by allowing additional contextual data to be included in events without requiring separate parameters. Previously, `sendCard` was accessed as a standalone value, but now developers can retrieve it from the `metaData` object in the event callback. This approach ensures better extensibility and consistency across different event types. To access the `sendCard` value, simply extract it from the event’s `metaData` object.

<CodeGroup>
  ```java java theme={"system"}
  @Override
  public void onEvent(KnotEvent knotEvent) {
      // Extract the metadata map from the KnotEvent
      Map<String, Object> metaData = knotEvent.getMetaData();
      
      // Check if the metadata contains a sendCard flag 
      if (knotEvent.getEvent().equalsIgnoreCase("AUTHENTICATED") && metaData != null && metaData.containsKey("sendCard")) {
          Boolean sendCard = (Boolean) metaData.get("sendCard");
          Log.d("KnotEvent", "sendCard: " + sendCard);
      } 
  }
  ```

  ```kotlin kotlin theme={"system"}
  override fun onEvent(knotEvent: KnotEvent) {
      val metaData = knotEvent.metaData
      if (knotEvent.event.equals("AUTHENTICATED", ignoreCase = true) && metaData != null && metaData.containsKey("sendCard")) {
          val sendCard = metaData["sendCard"] as? Boolean
          Log.d("KnotEvent", "sendCard: $sendCard")
      }
  }
  ```
</CodeGroup>

**Event Names**

The SDK now maps raw event names to standardized event names for easier handling.

| Event Name Prior to 2.0     | 2.0 Event Name                |
| :-------------------------- | :---------------------------- |
| refresh session request     | REFRESH\_SESSION\_REQUEST     |
| merchant clicked            | MERCHANT\_CLICKED             |
| login started               | LOGIN\_STARTED                |
| authenticated               | AUTHENTICATED                 |
| otp required                | OTP\_REQUIRED                 |
| security questions required | SECURITY\_QUESTIONS\_REQUIRED |
| approval required           | APPROVAL\_REQUIRED            |

### Error Handling

Error handling has been improved with more structured and meaningful error messages.

**Changes**

* Errors are now encapsulated in the `KnotError` enum.
* Each error has a **human-readable description** (`errorDescription`) and a **unique error code** (`errorCode`).
* Improved clarity and consistency across error messages.

**Before**

<CodeGroup>
  ```java java theme={"system"}
  @Override
  public void onError(String errorCode, String errorMessage) {
    Log.d("onError", errorCode + " " + errorMessage);
  }
  ```

  ```kotlin kotlin theme={"system"}
  override fun onError(error: String?, errorMessage: String?) {
    Log.d("onError", "$error $errorMessage")
  }
  ```
</CodeGroup>

**After**

<CodeGroup>
  ```swift java theme={"system"}
  public void onError(KnotError error) {
      switch (error) {
          case INVALID_SESSION:
              Log.e("KnotError", "Error: INVALID_SESSION - " + error.getErrorDescription());
              break;
          case EXPIRED_SESSION:
              Log.e("KnotError", "Error: EXPIRED_SESSION - " + error.getErrorDescription());
              break;
          case INVALID_CLIENT_ID:
              Log.e("KnotError", "Error: INVALID_CLIENT_ID - " + error.getErrorDescription());
              break;
          case INTERNAL_ERROR:
              Log.e("KnotError", "Error: INTERNAL_ERROR - " + error.getErrorDescription());
              break;
      }
  }
  ```

  ```kotlin kotlin theme={"system"}
  fun onError(error: KnotError) {
      when (error) {
          KnotError.INVALID_SESSION -> Log.e("KnotError", "Error: INVALID_SESSION - ${error.errorDescription}")
          KnotError.EXPIRED_SESSION -> Log.e("KnotError", "Error: EXPIRED_SESSION - ${error.errorDescription}")
          KnotError.INVALID_CLIENT_ID -> Log.e("KnotError", "Error: INVALID_CLIENT_ID - ${error.errorDescription}")
          KnotError.INTERNAL_ERROR -> Log.e("KnotError", "Error: INTERNAL_ERROR - ${error.errorDescription}")
      }
  }
  ```
</CodeGroup>

**Error Types**

The Knot SDK provides predefined error cases for you to handle based on your own needs.

| Error Case            | Description                 |
| :-------------------- | :-------------------------- |
| *INVALID\_SESSION*    | The session is invalid.     |
| *EXPIRED\_SESSION*    | The session has expired.    |
| *INVALID\_CLIENT\_ID* | The client ID is invalid.   |
| *INTERNAL\_ERROR*     | An internal error occurred. |

### Closing the SDK

<Warning>
  Most apps do not use the explicit `close` method, as it is infrequently applicable to the integration with the Knot SDK.
</Warning>

**Changes**

* Closing the SDK is now statically accessed via `Knot.close()` as opposed to being bound to the session object.

**Before**

<CodeGroup>
  ```java java theme={"system"}
  cardOnFileSwitcher.closeCardOnFileSwitcher();
  ```

  ```kotlin kotlin theme={"system"}
  cardOnFileSwitcher.closeCardOnFileSwitcher()
  ```
</CodeGroup>

**After**

<CodeGroup>
  ```java java theme={"system"}
  Knot.close();
  ```

  ```kotlin kotlin theme={"system"}
  Knot.close()
  ```
</CodeGroup>
