Updated on 2026-08-14

This commit is contained in:
Tangem 2020-04-27 05:01:40 +00:00
commit 73c298e21a
5 changed files with 402 additions and 148 deletions

View file

@ -21,7 +21,7 @@ interface CardSessionRunnable<T : CommandResponse> {
/**
* The starting point for custom business logic.
* Implement this interface and use [TangemSdk.startSession] to run.
* Implement this interface and use [TangemSdk.startSessionWithRunnable] to run.
* @param session run commands in this [CardSession].
* @param callback trigger the callback to complete the task.
*/

View file

@ -49,7 +49,7 @@ class TangemSdk(
* in the form of [Card] if the task was performed successfully or [SessionError] in case of an error.
*/
fun scanCard(initialMessage: Message? = null, callback: (result: CompletionResult<Card>) -> Unit) {
startSession(ScanTask(), null, initialMessage, callback)
startSessionWithRunnable(ScanTask(), null, initialMessage, callback)
}
/**
@ -72,7 +72,7 @@ class TangemSdk(
*/
fun sign(hashes: Array<ByteArray>, cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<SignResponse>) -> Unit) {
startSession(SignCommand(hashes), cardId, initialMessage, callback)
startSessionWithRunnable(SignCommand(hashes), cardId, initialMessage, callback)
}
/**
@ -90,7 +90,7 @@ class TangemSdk(
*/
fun readIssuerData(cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<ReadIssuerDataResponse>) -> Unit) {
startSession(ReadIssuerDataCommand(config.issuerPublicKey), cardId, initialMessage, callback)
startSessionWithRunnable(ReadIssuerDataCommand(config.issuerPublicKey), cardId, initialMessage, callback)
}
/**
@ -109,7 +109,7 @@ class TangemSdk(
*/
fun readIssuerExtraData(cardId: String,
callback: (result: CompletionResult<ReadIssuerExtraDataResponse>) -> Unit) {
startSession(ReadIssuerExtraDataCommand(config.issuerPublicKey), cardId, null, callback)
startSessionWithRunnable(ReadIssuerExtraDataCommand(config.issuerPublicKey), cardId, null, callback)
}
/**
@ -140,7 +140,7 @@ class TangemSdk(
issuerDataCounter,
config.issuerPublicKey
)
startSession(command, cardId, initialMessage, callback)
startSessionWithRunnable(command, cardId, initialMessage, callback)
}
/**
@ -179,7 +179,7 @@ class TangemSdk(
issuerDataCounter,
config.issuerPublicKey
)
startSession(command, cardId, initialMessage, callback)
startSessionWithRunnable(command, cardId, initialMessage, callback)
}
/**
@ -206,7 +206,7 @@ class TangemSdk(
callback: (result: CompletionResult<WriteUserDataResponse>) -> Unit
) {
val command = WriteUserDataCommand(userData, userProtectedData, userCounter, userProtectedCounter)
startSession(command, cardId, initialMessage, callback)
startSessionWithRunnable(command, cardId, initialMessage, callback)
}
/**
@ -228,7 +228,7 @@ class TangemSdk(
*/
fun readUserData(cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<ReadUserDataResponse>) -> Unit) {
startSession(ReadUserDataCommand(), cardId, initialMessage, callback)
startSessionWithRunnable(ReadUserDataCommand(), cardId, initialMessage, callback)
}
/**
@ -250,7 +250,7 @@ class TangemSdk(
*/
fun createWallet(cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<CreateWalletResponse>) -> Unit) {
startSession(CreateWalletTask(), cardId, initialMessage, callback)
startSessionWithRunnable(CreateWalletTask(), cardId, initialMessage, callback)
}
/**
@ -269,7 +269,7 @@ class TangemSdk(
*/
fun purgeWallet(cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<PurgeWalletResponse>) -> Unit) {
startSession(PurgeWalletCommand(), cardId, initialMessage, callback)
startSessionWithRunnable(PurgeWalletCommand(), cardId, initialMessage, callback)
}
/**
@ -287,7 +287,7 @@ class TangemSdk(
* */
fun depersonalize(cardId: String, initialMessage: Message? = null,
callback: (result: CompletionResult<DepersonalizeResponse>) -> Unit) {
startSession(DepersonalizeCommand(), cardId, initialMessage, callback)
startSessionWithRunnable(DepersonalizeCommand(), cardId, initialMessage, callback)
}
/**
@ -313,7 +313,7 @@ class TangemSdk(
initialMessage: Message? = null,
callback: (result: CompletionResult<Card>) -> Unit) {
val command = PersonalizeCommand(config, issuer, manufacturer, acquirer)
startSession(command, null, initialMessage, callback)
startSessionWithRunnable(command, null, initialMessage, callback)
}
/**
@ -330,7 +330,7 @@ class TangemSdk(
* If null, default message will be used.
* @callback: Standard [TangemSdk] callback.
*/
fun <T : CommandResponse> startSession(
fun <T : CommandResponse> startSessionWithRunnable(
runnable: CardSessionRunnable<T>, cardId: String? = null, initialMessage: Message? = null,
callback: (result: CompletionResult<T>) -> Unit) {
val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
@ -349,8 +349,7 @@ class TangemSdk(
* @callback: At first, you should check that the [SessionError] is not null,
* then you can use the [CardSession] to interact with a card.
*/
fun <T : CommandResponse> startSession(
cardId: String? = null, initialMessage: Message? = null,
fun startSession(cardId: String? = null, initialMessage: Message? = null,
callback: (session: CardSession, error: SessionError?) -> Unit) {
val cardSession = CardSession(buildEnvironment(), reader, viewDelegate, cardId, initialMessage)
Thread().run { cardSession.start(callback) }

View file

@ -0,0 +1,23 @@
version: 2.1
orbs:
android: circleci/android@0.2.0
jobs:
build:
executor: android/android
environment:
JVM_OPTS: -Xmx2048m
GRADLE_OPTS: -Xmx1536m -XX:+HeapDumpOnOutOfMemoryError -Dorg.gradle.caching=true -Dorg.gradle.configureondemand=true -Dkotlin.compiler.execution.strategy=in-process -Dkotlin.incremental=false
steps:
- checkout
- run:
name: Build
command: ./gradlew build
- run:
name: Run Tests
command: ./gradlew test
- store_test_results: # for display in Test Summary: https://circleci.com/docs/2.0/collect-test-data/
path: tangem-core/build/test-results/

View file

@ -1,5 +1,6 @@
![Release](https://jitpack.io/v/Tangem/tangem-sdk-android.svg)
[![Release](https://jitpack.io/v/Tangem/tangem-sdk-android.svg)](https://jitpack.io/#tangem/tangem-sdk-android)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![CircleCI](https://circleci.com/gh/Tangem/tangem-sdk-android.svg?style=shield)](https://circleci.com/gh/Tangem/tangem-sdk-android)
# Welcome to Tangem
The Tangem card is a self-custodial hardware wallet for blockchain assets. The main functions of Tangem cards are to securely create and store a private key from a blockchain wallet and sign blockchain transactions. The Tangem card does not allow users to import/export, backup/restore private keys, thereby guaranteeing that the wallet is unique and unclonable.
@ -12,10 +13,24 @@ The Tangem card is a self-custodial hardware wallet for blockchain assets. The m
- [Card interaction](#card-interaction)
- [Scan card](#scan-card)
- [Sign](#sign)
- [Wallet](#wallet)
- [Create Wallet](#create-wallet)
- [Purge Wallet](#purge-wallet)
- [Issuer Data](#issuer-data)
- [Read Issuer Data](#read-issuer-data)
- [Read Issuer Extra Data](#read-issuer-extra-data)
- [Write Issuer Data](#write-issuer-data)
- [Write Issuer Extra Data](#write-issuer-extra-data)
- [User Data](#user-data)
- [Write User Data](#write-user-data)
- [Read User Data](#read-user-data)
- [Personalization](#personalization)
- [Depersonalize](#depersonalize)
- [Personalize](#personalize)
- [Customization](#customization)
- [UI](#ui)
- [Tasks](#tasks)
- [Localization](#localization)
- [Reader](#reader)
- [Custom Tasks](#custom-tasks)
## Getting Started
@ -25,9 +40,9 @@ Android with minimal SDK version of 21 and a device with NFC support
### Installation
1) Add Tangem library to the project:
1. Add Tangem library to the project:
Add to a project build.gradle file:
Add to a project `build.gradle` file:
```gradle
allprojects {
@ -37,18 +52,18 @@ allprojects {
}
```
And add Tangem library to the dependencies (in an app or module build.gradle file):
And add Tangem library to the dependencies (in an app or module `build.gradle` file):
```gradle
dependencies {
implementation "com.github.tangem.tangem-sdk-android:tangem-core:$latestVersionOfCore"
implementation "com.github.tangem.tangem-sdk-android:tangem-sdk:$latestVersionOfSdk"
implementation "com.github.tangem.tangem-sdk-android:tangem-core:$latestVersion"
implementation "com.github.tangem.tangem-sdk-android:tangem-sdk:$latestVersion"
}
```
Tangem Core is a JVM library (without Android dependencies) that provides core functionality of interacting with Tangem cards.
Tangem Sdk is an Android library that implements NFC interaction between Android devices and Tangem cards and graphical interface for this interaction.
`tangem-core` is a JVM library (without Android dependencies) that provides core functionality of interacting with Tangem cards.
`tangem-sdk` is an Android library that implements NFC interaction between Android devices and Tangem cards and graphical interface for this interaction.
2) Add res file tech_filter with the following:
2. Save the file (you can name it anything you wish) with the following tech-list filters in the `<project-root>/res/xml`
```xml
<resources>
@ -60,170 +75,361 @@ Tangem Sdk is an Android library that implements NFC interaction between Android
</resources>
```
3) Add to Manifest:
3. Add to `AndroidManifest.xml`:
```xml
<intent-filter>
<action android:name=“android.nfc.action.TECH_DISCOVERED” />
<action android:name=“android.nfc.action.TECH_DISCOVERED” />
</intent-filter>
<meta-data
android:name=“android.nfc.action.TECH_DISCOVERED”
android:resource=“@xml/tech_filter” />
android:name=“android.nfc.action.TECH_DISCOVERED”
android:resource=“@xml/tech_filter” />
```
## Usage
Tangem SDK is a self-sufficient solution that implements a card abstraction model, methods of interaction with the card and interactions with the user via UI.
### Initialization
To get started, you need to create an instance of the `CardManager` class. It provides the simple way of interacting with the card.
Our default implementation of `CardManager` requires `NfcReader` and `DefaultCardManagerDelegate`.
To get started, you need to create an instance of the `TangemSdk` class. It provides the simple way of interacting with the card.
```kotlin
private val nfcManager = NfcManager()
private val cardManagerDelegate: DefaultCardManagerDelegate = DefaultCardManagerDelegate(nfcManager.reader)
private val cardManager = CardManager(nfcManager.reader, cardManagerDelegate)
val tangemSdk: TangemSdk = TangemSdk.init(activity)
```
NfcManager requires a reference to activity in order to use Android API for interacting with NFC. DefaultCardManagerDelegate requires a reference to activity in order to render views.
```kotlin
nfcManager.setCurrentActivity(this)
cardManagerDelegate.activity = this
```
```kotlin
lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
```
Default implementation of `NfcManager`, `CardReader` and `CardManagerDelegate` allows you to start using CardManager in your application without any additional setup.
You can also provide your implementations of `CardReader` and `CardManagerDelegate`.
You can read more about this in [Customization](#сustomization).
### Tasks
TangemSdk requires a reference to activity in order to use Android API for interacting with NFC and to render views.
Default implementation of `TangemSdk` allows you to start using SDK in your application without any additional setup.
(You can read about additional options in [Customization](#customization)).
### Card interaction
#### Scan card
To start using any card, you first need to read it using the `scanCard()` method. This method launches an NFC session, and once its connected with the card, it obtains the card data. Optionally, if the card contains a wallet (private and public key pair), it proves that the wallet owns a private key that corresponds to a public one.
To obtain data from the card use `scanCard()` method. This method launches an NFC session, and once its connected with the card, it obtains the card data. If the card contains a wallet (private and public key pair), it proves that the wallet owns a private key that corresponds to a public one.
Example:
```kotlin
cardManager.scanCard { taskEvent ->
when (taskEvent) {
is TaskEvent.Event<ScanEvent> -> {
when (taskEvent.data) {
is ScanEvent.OnReadEvent -> {
// Handle returned card data
cardId = (taskEvent.data as ScanEvent.OnReadEvent).card.cardId
// Switch to UI thread to show results in UI
runOnUiThread {}
}
is ScanEvent.OnVerifyEvent -> {
//Handle card verification
val isGenuine = (taskEvent.data as ScanEvent.OnVerifyEvent).isGenuine
}
tangemSdk.scanCard { result ->
when (result) {
is CompletionResult.Success -> {
// Handle returned card data
val card = result.data
cardId = card.cardId
// Switch to UI thread to show results in UI
runOnUiThread {
tv_card_cid?.text = cardId
}
}
is TaskEvent.Completion<ScanEvent> -> {
if (taskEvent.error != null) {
if (taskEvent.error is TaskError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle completion
// Handle other errors
}
}
}
```
Communication with the card is an asynchronous operation. In order to get a result for the method, you need to subscribe to the task callback. In order to render the callback results on UI, you need to switch to the main thread.
Communication with the card is an asynchronous operation. In order to get a result for the method, you need to implement the callback function. In order to render the callback results on UI, you need to switch to the main thread.
Every task can invoke callback several times with different events:
`CompletionResult<T>` this is the sealed class for the results of `CardSessionRunnable`.
`Completion<T>(val error: TaskError? = null)` this event is triggered only once when task is completely finished. It means that it's the final callback. If error is not nil, then something went wrong during the operation.
`Event<T>(val data: T)` this event is triggered when one of operations inside the task is completed.
**Possible events of the Scan card task:**
`OnReadEvent(val result: Card)` this event is triggered after the card has been successfully read. In addition, the obtained card object is contained inside the enum. At this stage, the authenticity of the card is ***NOT*** verified.
`OnVerifyEvent(val isGenuine: Boolean)` this event is triggered when the cards authenticity has been verified. If the card is authentic, isGenuine will be set to true, otherwise, it will be set to false.
`Success<T>(val data: T)` is triggered after successful operation and contains a `CommandResponse`.
`Failure<T>(val error: SessionError)` is triggered on error.
#### Sign
This method allows you to sign one or multiple hashes. Simultaneous signing of array of hashes in a single SIGN command is required to support Bitcoin-type multi-input blockchains (UTXO). The SIGN command will return a corresponding array of signatures.
```kotlin
cardManager.sign(
tangemSdk.sign(
hashes = arrayOf(hash1, hash2),
cardId = card.cardId) { taskEvent ->
when (taskEvent) {
is TaskEvent.Event -> {
// Handle sign response data
val signResponse = taskEvent.data
cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is TaskEvent.Completion<ScanEvent> -> {
if (taskEvent.error != null) {
if (taskEvent.error is TaskError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
// Handle completion
is CompletionResult.Success -> {
val signResponse = result.data
}
}
}
```
#### Issuer Data
##### Read Issuer Data
An example of usage (description is available at documentation for `TangemSdk.readIssuerData` method and corresponding command class):
```kotlin
tangemSdk.readIssuerData(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> {
val issuerData = result.data.issuerData
val issuerDataSignature = result.data.issuerDataSignature
}
}
}
```
##### Read Issuer Extra Data
An example of usage (description is available at documentation for `TangemSdk.readIssuerExtraData` method and corresponding command class):
```kotlin
tangemSdk.readIssuerExtraData(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> {
val issuerData = result.data.issuerData
val issuerDataSignature = result.data.issuerDataSignature
}
}
}
```
##### Write Issuer Data
An example of usage (description is available at documentation for `TangemSdk.writeIssuerData` method and corresponding command class):
```kotlin
tangemSdk.writeIssuerData(cardId, issuerData, issuerDataSignature, issuerDataCounter) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> {
val writeIssuerDataResult = result.data
}
}
}
```
##### Write Issuer Extra Data
An example of usage (description is available at documentation for `TangemSdk.writeIssuerExtraData` method and corresponding command class):
```kotlin
tangemSdk.writeIssuerExtraData(cardId,
issuerData, startingSignature, finalizingSignature, issuerDataCounter
) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val writeIssuerDataResult = result.data
}
}
}
```
#### User Data
##### Write User Data
An example of usage (description is available at documentation for `TangemSdk.writeUserData` method and corresponding command class):
```kotlin
tangemSdk.writeUserData(
cardId, userData, userProtectedData, userCounter, userProtectedCounter
) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val writeUserDataResult = result.data
}
}
}
```
##### Read User Data
An example of usage (description is available at documentation for `TangemSdk.readUserData` method and corresponding command class):
```kotlin
tangemSdk.readUserData(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val readUserDataResult = result.data
}
}
}
```
#### Wallet
##### Create Wallet
An example of usage (description is available at documentation for `TangemSdk.createWallet` method and corresponding command class):
```kotlin
tangemSdk.createWallet(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val createWalletResult = result.data
}
}
}
```
##### Purge Wallet
An example of usage (description is available at documentation for `TangemSdk.purgeWallet` method and corresponding command class):
```kotlin
tangemSdk.purgeWallet(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val purgeWalletResult = result.data
}
}
}
```
#### Personalization
##### Depersonalize
An example of usage (description is available at documentation for `TangemSdk.depersonalize` method and corresponding command class):
```kotlin
tangemSdk.depersonalize(cardId) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val depersonalizeResult = result.data
}
}
}
```
##### Personalize
An example of usage (description is available at documentation for `TangemSdk.personalize` method and corresponding command class):
```kotlin
tangemSdk.personalize(config, issuer, manufacturer, acquirer) { result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> runOnUiThread {
val card = result.data
}
}
}
```
## Customization
### UI
If the interaction with user is required, the SDK performs the entire cycle of this interaction. In order to change the appearance or behavior of the user UI, you can provide you own implementation of the `CardManagerDelegate` inteface. After this, initialize the `CardManager` class with your delegate class.
If the interaction with user is required, the SDK performs the entire cycle of this interaction. In order to change the appearance or behavior of the user UI, you can provide you own implementation of the `SessionViewDelegate` interface. After this, initialize the `TangemSdk` class with your delegate class.
```kolin
val myCardManagerDelegate = MyCardManagerDelegate()
val cardManager = CardManager(cardManagerDelegate = myCardManagerDelegate)
val tangemSdk = TangemSdk.customInit(this, MySessionViewDelegate())
```
> If you pass null instead of `cardManagerDelegate`, the SDK wont be able to process errors that require user intervention and return them to `.failure(let error)`.
### Reader
### Tasks
`CardManager` only covers general tasks. If you want to trigger card commands in a certain order, you need to create your own task.
TangemSdk uses Android NFC capabilities to communicate with TangemCards. If there is a need to use other means of communication or other platforms, it is possible to implement this functionality by implementing `CardReader` interface and using it instead of the default `NfcReader`.
To do this, you need to create a subclass of the `Task` class, and override the `onRun(..)` method.
### Custom Tasks
`TangemSdk` specific methods run particular commands and tasks. If you want to trigger card commands in a different order, or implement additional
business logic, you have several options.
One option is to start a session, get an instance of `CardSession`, and use it to perform commands.
To do this, you need to call `tangemSdk.startSession()` method and get a `CardSession` instance in a callback.
Then call the `runTask(..)` method of the `CardManager` class with you task.
> For example, if you want to read the card and immediately sign a transaction with it, you can achieve it this way.
```kotlin
val task = YourTask()
cardManager.runTask(task) { taskEvent ->
// Handle your events
}
```
> For example, you want to read the card and immediately sign a transaction on it. In such a case, you need to inherit from the `Task` class and override the `onRun(..)` method, in which you implement the required behavior.
Its possible to run just one command without the need to create a separate task by using the `runCommand(..)` method.
> For example, if you need to read the card details, but dont need to check the authenticity.
```kotlin
// Create command
val readCommand = ReadCardCommand()
// Run command with the callback
cardManager.runCommand(readCommand) { taskEvent ->
when (taskEvent) {
is TaskEvent.Event -> {
// Handle returned card data
val card: Card = taskEvent.data
}
is TaskEvent.Completion -> {
if (taskEvent.error != null) {
if (taskEvent.error is TaskError.UserCancelledError) {
// Handle case when user cancelled manually
tangemSdk.startSession { session, error ->
if (error == null) {
session.startWithRunnable(
SignCommand(createSampleHashes())) {result ->
when (result) {
is CompletionResult.Failure -> {
if (result.error is SessionError.UserCancelledError) {
// Handle case when user cancelled manually
}
// Handle other errors
}
is CompletionResult.Success -> {
val signResponse = result.data
}
}
}
}
}
```
Another option is to put all logic in a in `CardSessionRunnable` class and launch it using `tangemSdk.startSessionWithRunnable()` method.
In Tangem SDK we use this approach for our `ScanTask`.
> For example, if you want to read the card and immediately sign a transaction with it, with subclassing `CardSessionRunnable` you can achieve it this way.
```kotlin
class OneTapSignTask(private val hashesToSign: Array<ByteArray>) : CardSessionRunnable<Card> {
override fun run(session: CardSession, callback: (result: CompletionResult<Card>) -> Unit) {
val card = session.environment.card
if (card == null) {
callback(CompletionResult.Failure(SessionError.MissingPreflightRead()))
} else if (card.cardData?.productMask?.contains(Product.Tag) != false) {
callback(CompletionResult.Success(card))
} else if (card.status != CardStatus.Loaded) {
callback(CompletionResult.Success(card))
} else if (card.curve == null || card.walletPublicKey == null) {
callback(CompletionResult.Failure(SessionError.CardError()))
} else {
val signCommand = SignCommand(hashesToSign)
signCommand.run(session) { result ->
when (result) {
is CompletionResult.Success -> callback(CompletionResult.Success(result.data))
is CompletionResult.Failure -> callback(CompletionResult.Failure(result.error))
}
// Handle other errors
}
// Handle completion
}
}
}

View file

@ -1,21 +1,47 @@
package com.tangem.tangem_sdk_new.extensions
import androidx.fragment.app.FragmentActivity
import com.tangem.Config
import com.tangem.SessionViewDelegate
import com.tangem.TangemSdk
import com.tangem.tangem_sdk_new.DefaultSessionViewDelegate
import com.tangem.tangem_sdk_new.NfcLifecycleObserver
import com.tangem.tangem_sdk_new.TerminalKeysStorage
import com.tangem.tangem_sdk_new.nfc.NfcManager
fun TangemSdk.Companion.init(activity: FragmentActivity): TangemSdk {
val nfcManager = NfcManager().apply {
this.setCurrentActivity(activity)
activity.lifecycle.addObserver(NfcLifecycleObserver(this))
}
val viewDelegate = DefaultSessionViewDelegate(nfcManager.reader).apply {
this.activity = activity
}
return TangemSdk(nfcManager.reader, viewDelegate).apply {
this.setTerminalKeysService(TerminalKeysStorage(activity.application))
}
fun TangemSdk.Companion.init(activity: FragmentActivity, config: Config = Config()): TangemSdk {
val nfcManager = TangemSdk.initNfcManager(activity)
val viewDelegate = DefaultSessionViewDelegate(nfcManager.reader)
viewDelegate.activity = activity
val tangemSdk = TangemSdk(nfcManager.reader, viewDelegate, config)
tangemSdk.setTerminalKeysService(TerminalKeysStorage(activity.application))
return tangemSdk
}
fun TangemSdk.Companion.customInit(
activity: FragmentActivity,
viewDelegate: SessionViewDelegate? = null,
config: Config = Config()
): TangemSdk {
val nfcManager = TangemSdk.initNfcManager(activity)
val tangemSdk = TangemSdk(
nfcManager.reader,
viewDelegate ?: DefaultSessionViewDelegate(nfcManager.reader)
.apply { this.activity = activity },
config
)
tangemSdk.setTerminalKeysService(TerminalKeysStorage(activity.application))
return tangemSdk
}
fun TangemSdk.Companion.initNfcManager(activity: FragmentActivity): NfcManager {
val nfcManager = NfcManager()
nfcManager.setCurrentActivity(activity)
activity.lifecycle.addObserver(NfcLifecycleObserver(nfcManager))
return nfcManager
}