반응형

이번 포스팅에서는 키스토어의 계정을 연동해서 keystore를 이용해서 이더를 송금하는 실습을 진행해보겠습니다.

keystore를 최신으로 업데이트하여야합니다. 우선 전체 코드입니다. 

package com.example.samsungblockchainsdk;
import androidx.appcompat.app.AppCompatActivity;
import com.samsung.android.sdk.blockchain.account.Account;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.Toast;
import com.samsung.android.sdk.blockchain.CoinType;
import com.samsung.android.sdk.blockchain.ListenableFutureTask;
import com.samsung.android.sdk.blockchain.SBlockchain;
import com.samsung.android.sdk.blockchain.account.ethereum.EthereumAccount;
import com.samsung.android.sdk.blockchain.coinservice.CoinNetworkInfo;
import com.samsung.android.sdk.blockchain.coinservice.CoinServiceFactory;
import com.samsung.android.sdk.blockchain.coinservice.ethereum.EthereumService;
import com.samsung.android.sdk.blockchain.exception.HardwareWalletException;
import com.samsung.android.sdk.blockchain.exception.RootSeedChangedException;
import com.samsung.android.sdk.blockchain.network.EthereumNetworkType;
import com.samsung.android.sdk.blockchain.ui.CucumberWebView;
import com.samsung.android.sdk.blockchain.ui.OnSendTransactionListener;
import com.samsung.android.sdk.blockchain.wallet.HardwareWallet;
import com.samsung.android.sdk.blockchain.wallet.HardwareWalletType;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;

public class Main2Activity extends AppCompatActivity implements OnSendTransactionListener {
    Button connect;
    Button generateAccount;
    Button getAccounts;
    Button paymentsheet;
  //  Button sendSmartContract;
    // 웹뷰버튼
    Button webViewInitBtn;


    private SBlockchain sBlockchain ;
    private HardwareWallet wallet;
    private CucumberWebView webView; // 웹뷰 변수 선언
    Account generateAccount1;
    private List<Account> accounts;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main2);
        // Blockchain SDK Init
        sBlockchain = new SBlockchain(); // Blockchain SDK Init
        try {
            sBlockchain.initialize(this);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 끝


        //이벤트 리스너 호출 //
        connect = findViewById(R.id.connect);
        generateAccount =  findViewById(R.id.generateAccount);
        getAccounts = findViewById(R.id.getAccounts);
        paymentsheet = findViewById(R.id.paymentsheet);
        //cucumber 이벤트 리스너 호출
        webViewInitBtn = findViewById(R.id.webviewinit); // 웹뷰버튼 객체생성
        webView = findViewById(R.id.cucumber); //큐컴버 웹뷰 객체생성

        connect.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"connect버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                connected();
            }
        });

        generateAccount.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"generateAccount버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                generate();
            }
        });

        getAccounts.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(getApplicationContext(),"getAccounts버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
                setgetAccounts();

            }
        });

      paymentsheet.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {
              Toast.makeText(getApplicationContext(),"paymentsheet버튼이 눌러졌습니다.",Toast.LENGTH_SHORT).show();
              setPaymentsheet();
          }
      });

      webViewInitBtn.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View v) {

              webViewInit();
          }
      });

        //이벤트 리스너 호출  끝//
    }




    //1. connect
    public void connected(){
       sBlockchain.getHardwareWalletManager()
               .connect(HardwareWalletType.SAMSUNG,true) //하드웨어 wallet을 반환하는 형태입니다.
               .setCallback(new ListenableFutureTask.Callback<HardwareWallet>() { //비동기화  자기혼자 쓰레드로 돌아가기 위해서
                   @Override
                   public void onSuccess(HardwareWallet hardwareWallet) {
                        wallet = hardwareWallet;
                   }

                   @Override
                   public void onFailure(ExecutionException e) {
                       Throwable cause = e.getCause();

                       if (cause instanceof HardwareWalletException) {
                           // handling hardware wallet error
                       } else if (cause instanceof RootSeedChangedException) {
                           // handling root seed changed exception
                       }
                   }

                   @Override
                   public void onCancelled(InterruptedException e) {

                   }
               });
    }




    //2. generateAccount
    private  void generate() { //계정생성
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager()
                .generateNewAccount(wallet, coinNetworkInfo)
                .setCallback(new ListenableFutureTask.Callback< Account >() {
                    @Override
                    public void onSuccess(Account account) {
                        generateAccount1 = account;
                        Log.e("MyApp", account.toString());
                    }

                    @Override
                    public void onFailure(@NotNull ExecutionException e) {
                        Log.e("MyApp fail",e.toString());

                    }

                    @Override
                    public void onCancelled(@NotNull InterruptedException e) {
                        Log.e("MyApp cancel",e.toString());
                    }
                });

    }



    //3. getAccounts
    private  void setgetAccounts() { //
        accounts = sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(),CoinType.ETH, EthereumNetworkType.ROPSTEN);
        Log.d("MyApp", Arrays.toString(new List[]{accounts})); // 리스트형태로 로그메시지 출력
    }



    //4. paymentsheet
    private  void setPaymentsheet(){ //계정으로 0.01이더만큼 전송합니다.
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager() //우리 어카운트가 잇겟죠
                .getAccounts(wallet.getWalletId(),
                        CoinType.ETH,
                        EthereumNetworkType.ROPSTEN
                        );
        // 메타마스크와 삼성키스토어의 계좌번호는 서로 다르다. 규칙이 다르기 때문이다.

        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this,coinNetworkInfo);
        Intent intent = service
                .createEthereumPaymentSheetActivityIntent(
                        this,
                        wallet,
                        (EthereumAccount) accounts.get(0),
                        "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019",
                        new BigInteger("10000000000000000"),
                        null,
                        null
                );
        startActivityForResult(intent,0);


    }
    //5. 웹을 가져오는 실습
    private void webViewInit() {
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"
        );
        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this, coinNetworkInfo);

        accounts =  sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(), CoinType.ETH, EthereumNetworkType.ROPSTEN);

        webView.init(service, accounts.get(0), this);
        webView.loadUrl("https://faucet.metamask.io/");
    }

    @Override
    public void onSendTransaction(
            @NotNull String requestId,
            @NotNull EthereumAccount fromAccount,
            @NotNull String toAddress,
            @org.jetbrains.annotations.Nullable BigInteger value,
            @org.jetbrains.annotations.Nullable String data,
            @org.jetbrains.annotations.Nullable BigInteger nonce
    ) {
        HardwareWallet wallet =
                sBlockchain.getHardwareWalletManager().getConnectedHardwareWallet();

        Intent intent =
                webView.createEthereumPaymentSheetActivityIntent(
                        this,
                        requestId,
                        wallet,
                        toAddress,
                        value,
                        data,
                        nonce
                );

        startActivityForResult(intent, 0);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != 0) {
            return;
        }
        webView.onActivityResult(requestCode, resultCode, data);
    }



}

 

버튼객체선언입니다.

 Button connect;
    Button generateAccount;
    Button getAccounts;
    Button paymentsheet;
    // 웹뷰버튼
    Button webViewInitBtn;

SBlockchain은 1) samsung Blockchain SDK Init을 하고,  2) 하드웨어 wallet을 반환받고, 3) coinNetworkInfo에서 받은 네트워크 정보로 계정을 생성하는데 사용됩니다. 이후 계정에 대한 정보를 해당객체를 통해 얻어옵니다.

wallet은 메소드를 통해 하드웨어 wallet에 대한 정보를 받아와 저장하는 역할입니다. generateAccount1은 계정에 대한 정보를 받아오는 default형 객체이고 List형태로 계정들의 정보를 가져오는 accounts도 선언했습니다. (웹뷰에 관한 내용은 이더송금과는 별개이기에 생략하겠습니다.)

 private SBlockchain sBlockchain ;
    private HardwareWallet wallet;
    private CucumberWebView webView; // 웹뷰 변수 선언
    Account generateAccount1;
    private List<Account> accounts;

SBlockchain의 객체를 초기화합니다.

 // Blockchain SDK Init
        sBlockchain = new SBlockchain(); // Blockchain SDK Init
        try {
            sBlockchain.initialize(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

이벤트 리스너 호출을 위해 객체들을 생성합니다.

 //이벤트 리스너 호출 //
        connect = findViewById(R.id.connect);
        generateAccount =  findViewById(R.id.generateAccount);
        getAccounts = findViewById(R.id.getAccounts);
        paymentsheet = findViewById(R.id.paymentsheet);
        //cucumber 이벤트 리스너 호출
        webViewInitBtn = findViewById(R.id.webviewinit); // 웹뷰버튼 객체생성
        webView = findViewById(R.id.cucumber); //큐컴버 웹뷰 객체생성

이후 각각의 리스너객체에서는 toast메시지를 출력하고 각각에 해당하는 메소드들을 호출하는 구조입니다.

1. connect입니다. 하드웨어 wallet정보를 가져와서 계정과 연결하는 함수입니다. 

//1. connect
    public void connected(){
       sBlockchain.getHardwareWalletManager()
               .connect(HardwareWalletType.SAMSUNG,true) //하드웨어 wallet을 반환하는 형태입니다.
               .setCallback(new ListenableFutureTask.Callback<HardwareWallet>() { //비동기화  자기혼자 쓰레드로 돌아가기 위해서
                   @Override
                   public void onSuccess(HardwareWallet hardwareWallet) {
                        wallet = hardwareWallet;
                   }

                   @Override
                   public void onFailure(ExecutionException e) {
                       Throwable cause = e.getCause();

                       if (cause instanceof HardwareWalletException) {
                           // handling hardware wallet error
                       } else if (cause instanceof RootSeedChangedException) {
                           // handling root seed changed exception
                       }
                   }

                   @Override
                   public void onCancelled(InterruptedException e) {

                   }
               });
    }

2. 네트워크정보를 받습니다. 이때 퍼블릭노드가 필요한데, "https://ropsten.infura.io/" 에 들어가셔서 로그인 하시면 퍼블릭노드를 얻을 수 있습니다. CoinType.ETH, EthereumNetworkType.ROPSTEN로 설정합니다.

해당 네트워크정보와 wallet정보로 계정을 생성합니다. 디버그를 통해 계정의 주소를 알 수 있고 메타마스크에 추가도 할 수 있습니다. 

 

    //2. generateAccount
    private  void generate() { //계정생성
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager()
                .generateNewAccount(wallet, coinNetworkInfo)
                .setCallback(new ListenableFutureTask.Callback< Account >() {
                    @Override
                    public void onSuccess(Account account) {
                        generateAccount1 = account;
                        Log.e("MyApp", account.toString());
                    }

                    @Override
                    public void onFailure(@NotNull ExecutionException e) {
                        Log.e("MyApp fail",e.toString());

                    }

                    @Override
                    public void onCancelled(@NotNull InterruptedException e) {
                        Log.e("MyApp cancel",e.toString());
                    }
                });

    }

3. 계정들의 정보를 리스트형태로 저장하고 log에 출력하는 구문입니다. 

    //3. getAccounts
    private  void setgetAccounts() { //
        accounts = sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(),CoinType.ETH, EthereumNetworkType.ROPSTEN);
        Log.d("MyApp", Arrays.toString(new List[]{accounts})); // 리스트형태로 로그메시지 출력
    }

 

4. 결제창을 띄우는 코드입니다. 네트워크정보와 어카운트매니저를 불러오고, EthereumService의 객체를 생성해서 인텐트를 구현합니다. 라이브러리에 의해 인텐트되는 것이고 아래 "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019"는

보낼 주소 new BigInteger("10000000000000000")는 1wei단위의 이더리움을 의미합니다. 이렇게 하면 0.1이더를 보내는 형태가 될것입니다. 

 

 private  void setPaymentsheet(){ //계정으로 0.01이더만큼 전송합니다.
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"// 퍼블릭 노드인 공짜인 주소를 가져온거야  + ropsten.infura.io로 들어가서 퍼블릭 노드 불러오기
        );

        sBlockchain.getAccountManager() //우리 어카운트가 잇겟죠
                .getAccounts(wallet.getWalletId(),
                        CoinType.ETH,
                        EthereumNetworkType.ROPSTEN
                        );
        // 메타마스크와 삼성키스토어의 계좌번호는 서로 다르다. 규칙이 다르기 때문이다.

        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this,coinNetworkInfo);
        Intent intent = service
                .createEthereumPaymentSheetActivityIntent(
                        this,
                        wallet,
                        (EthereumAccount) accounts.get(0),
                        "0x94e44C14e7A5863fed31a68AAD9bbc7d30d6A019",
                        new BigInteger("10000000000000000"),
                        null,
                        null
                );
        startActivityForResult(intent,0);


    }

 

5. 웹뷰를 통해서 웹의 화면은 앱으로 보여주는 역할을 합니다. 어렵기도 하지만 하나의 규칙처럼 사용되기도 하고, 복잡하여서 설명을 생략하겠습니다.

 

  //5. 웹을 가져오는 실습
    private void webViewInit() {
        CoinNetworkInfo coinNetworkInfo = new CoinNetworkInfo(
                CoinType.ETH,
                EthereumNetworkType.ROPSTEN,
                "https://ropsten.infura.io/v3/70ddb1f89ca9421885b6268e847a459d"
        );
        EthereumService service = (EthereumService) CoinServiceFactory.getCoinService(this, coinNetworkInfo);

        accounts =  sBlockchain.getAccountManager()
                .getAccounts(wallet.getWalletId(), CoinType.ETH, EthereumNetworkType.ROPSTEN);

        webView.init(service, accounts.get(0), this);
        webView.loadUrl("https://faucet.metamask.io/");
    }

    @Override
    public void onSendTransaction(
            @NotNull String requestId,
            @NotNull EthereumAccount fromAccount,
            @NotNull String toAddress,
            @org.jetbrains.annotations.Nullable BigInteger value,
            @org.jetbrains.annotations.Nullable String data,
            @org.jetbrains.annotations.Nullable BigInteger nonce
    ) {
        HardwareWallet wallet =
                sBlockchain.getHardwareWalletManager().getConnectedHardwareWallet();

        Intent intent =
                webView.createEthereumPaymentSheetActivityIntent(
                        this,
                        requestId,
                        wallet,
                        toAddress,
                        value,
                        data,
                        nonce
                );

        startActivityForResult(intent, 0);

    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if (requestCode != 0) {
            return;
        }
        webView.onActivityResult(requestCode, resultCode, data);
    }

 

다음시간에는 블록체인 sdk 심화과정이 있겠습니다. 

모르시는 부분은 아래 댓글에 남겨주세요. 

반응형

'Blockchain 개발 > SAMSUNG Blockchain SDK' 카테고리의 다른 글

SAMSUNG Blockchain SDK 따라하기(1)  (0) 2020.02.10
반응형

The Samsung Blockchain Platform SDK brings developers and consumers to the blockchain world by providing a full set of functions that the Decentralized App (DApp) or Blockchain App needs. It helps developers to manage blockchain accounts easily and to make a transaction easier by abstracted transfer APIs for each type of ledger system. The Samsung Blockchain Platform SDK offers a cryptocurrency payment solution with its UI.

 

 삼성 블록 체인 플랫폼 SDK는 분산 앱 (DApp) 또는 블록 체인 앱에 필요한 모든 기능을 제공하여 개발자와 소비자를 블록 체인 세계에 제공합니다. 개발자는 각 유형의 원장 시스템에 대한 추상 전송 API를 통해 블록 체인 계정을 쉽게 관리하고 거래를 쉽게 할 수 있습니다. Samsung Blockchain Platform SDK는 UI와 함께 cryptocurrency 지불 솔루션을 제공합니다.

 

즉, Dapp을 개발하는 툴입니다. SAMSUNG Blockchain은  platform SDK와 keystore로 나누어집니다. SDK는 실제 dapp을개발하는데 필요한 다양한 라이브러리와 keystore과의 연결을 지원합니다. keystore는 개인키를 스마트폰에서 쉽고  안전하게 관리할 수 있도록 도와줍니다. 

자세한 내용은 아래 링크에서 확인해보세요.

https://developer.samsung.com/blockchain/platform/overview.html

불러오는 중입니다...

 

준비물:  안드로이드 스튜디오, 갤럭시 s10이상의 keystore를 지원하는 삼성 스마트폰

 

우선 기본설정들은 알아보겠습니다. 

 

1. 위 링크에서 BlockchainPlatformSDK_1.0.00.aar, KeystoreSDK_v1.2.0.aar 를 다운받아서 안드로이드 스튜디오 프로젝트안에 app >> lib 안에 추가합니다. 

 

그다음에 build.gradle에서 dependencies부분을 이렇게 수정합니다. 

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'


    // sdk 를 위해 추가한 부분
    repositories {
        flatDir {
            dirs 'libs'
        }
    }

    implementation name: 'BlockchainPlatformSDK_1.0.00', ext: 'aar'

// network
    implementation 'com.squareup.retrofit2:retrofit:2.6.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.6.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0'
    implementation 'com.google.code.gson:gson:2.8.5'

// KeyStore SDK
    implementation name: 'KeystoreSDK_v1.2.0', ext: 'aar'

// web3j
    implementation 'org.web3j:core:4.2.0-android'

// for check developer mode
    implementation 'org.ini4j:ini4j:0.5.4'

// ledger
    implementation 'com.ledger.lib:ledger-android-library:1.0.0'

// dagger
    implementation 'com.google.dagger:dagger:2.21'
    annotationProcessor 'com.google.dagger:dagger-compiler:2.21'
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.50"

}

AndroidManifest.xml 파일 하단에 아래 코드를 추가합니다.

<uses-permission android:name="android.permission.INTERNET" />

 

기본셋팅은 이정도로 하고 다음 포스팅에서는 계정과 연결하는 실습을 진행해보겠습니다. 

반응형

'Blockchain 개발 > SAMSUNG Blockchain SDK' 카테고리의 다른 글

SAMSUNG Blockchain SDK 따라하기(2)  (0) 2020.02.11

+ Recent posts