5
4

More than 3 years have passed since last update.

web3j を使って Android アプリから Ethereum につないでみるテスト

Last updated at Posted at 2020-03-03

Android アプリからイーサリアムにつないでテストするまでの簡単な手順をまとめてみました。
イーサリアムクライアントとして、web3j を利用しています。

「ややこしい話は抜きだ!」という方は、GitHub に手順後のプロジェクトが置いてあるのでお使いくださいませ。

では、サクサクいきましょう。

プロジェクトの作成

Android Studio を起動して新規プロジェクトを作成します。
ss000.png

アプリ名は StudyWeb3j、プロジェクトフォルダは適宜、あとはデフォルトで。
ss001.png

APIレベルはあまり古くなければ動くと思います。とりあえず 23(Android 6.0) に。
ss002.png

このアプリは画面タップでテストを実行させるだけなので、シンプルな Empty Activity を選択。
ss003.png

レイアウトファイルをオフにして Finish
ss004.png

空のプロジェクトのできあがりです。
ss005.png

web3j の導入

Gradle Scriptsbuild.gradle(Project: StudyWeb3j) を開き、参照リポジトリに mavenCentral() を追加します。

buildscript {  

     repositories {  
         //- 追加 --------  
         mavenCentral()  
         //---------------  
         google()  
        ...  

ss006.png

Gradle Scriptsbuild.gradle(Module: app) を選択し、アプリの依存関係に web3j を追加します(※バージョンは現在のAndroid向けの最新)。

dependencies {
    ...
    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
    //- 追加 -------------------------------------------
    implementation 'org.web3j:core:4.2.1-android'
    //--------------------------------------------------
}

ss007.png

さて、このままだとビルド時に "Static interface methods are only supported starting with Android N" というエラーが発生するので、build.gradle(Module: app)android.buildTypes ブロック内にて、Javaのバージョンを指定します。

android {
    ...
    buildTypes {
        release{
            ...
        }
        //- 追加 -------------------------------------------
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        //---------------------------------------------------
    }
}

ss008.png

最後に、app -> manifests -> AndroidManifests.xml を開き、アプリがブロックチェーンとやりとりできるように、通信のパーミッションを追加します。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample.studyweb3j">

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

    <application
        ...

ss009.png

設定はこれにて完了。一旦ビルドしてみましょう。
ss010.png

ビルドが通れば web3j の準備は万端です。

テストコードの組み込み

下記の3ファイルをソースフォルダ StudyWeb3j/app/src/main/java/com/sample/studyweb3j/ に追加します。

HelloWorld.java
TestWeb3.java
Web3Helper.java

ss012.png

追加後、各クラスがプロジェクトに認識されてるかを確認してください。
ss013.png

追加されたクラスの役割は下記となります。
 ・HelloWorld … イーサリアムにデプロイされたコントラクトをラップするクラス
 ・TestWeb3 … テスト処理を担当するクラス
 ・Web3Helper … イーサリアムアカウントを管理するヘルパークラス

では早速、MainActivity のメンバーに Web3Test のインスタンスを追加しましょう。

public class MainActivity extends AppCompatActivity {
    //- 追加 テストクラスのインスタンス ----
    private TestWeb3 testWeb3;
    //--------------------------------------

ss014.png

つづいて、MainActivity の作成に合わせて Web3Test インスタンスを作成するコードを追加します。

    protected void onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState);

        //- 追加 テストインスタンスの作成 -----------------
        testWeb3 = new TestWeb3( this );
        //-------------------------------------------------

ss015.png

おっと、初期化に先立って、web3j ライブラリが利用する暗号アルゴリズムを有効にするための処理も呼んでおきます(※これがないと「ECDSAアルゴリズムが無いよ」例外がでます)。

        //- 追加 ECDSAアルゴリズムを利用するための設定 ----
        Web3Helper.SetupBouncyCastle();
        //-------------------------------------------------

ss016.png

最後に、タッチイベントを組み込んで、画面がタップされたらテストが実行されるようにします。

    //- 追加 タッチイベント:押下されたらテスト処理を呼び出す -------
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if( event.getAction() == MotionEvent.ACTION_DOWN ){
            // テストの呼び出し
            testWeb3.test();
        }

        return super.onTouchEvent(event);
    }
    //---------------------------------------------------------------

ss017.png

これでコーディングは終了、お疲れさまでした!
早速ビルド&実行しましょう。
ss018.png

動作確認

アプリが起動したら LogCat を表示し、Android端末の画面をタップしてテストを開始しましょう。


一回目のログ(タップで開閉します)


@ TestWeb3: START...
@ [setTarget]
@ target=4(Rinkeby)
@ [setAccount]
@ loadAccount EXCEPTION e=/data/user/0/com.sample.studyweb3j/files/key.json (No such file or directory)
@ CREATE NEW ACCOUNT
@ Write down below json code to import generated account into your wallet apps(e.g. MetaMask)
{"address":"143cffb00a1100b5df461686c13accf46cda0e00","id":"dcf655d2-e38b-4300-ae37-830488bfeea1","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"5d53f2ed9122b43de787685a1fabe179"},"ciphertext":"1e4c4a61bb3a03de3e4313f6c9023985f7b16977351a886b8163002f5697969e","kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"d762c0e0e1ae60d091d4a34f6f18d154c536d9fc7befdc478d1c96832637f5a9"},"mac":"fe66a4cc41f119ea30fcb13f503b17a7a512ec7806bef5821b7ff105f3a85335"}}
@ privateKey=f49ebafaa01f39e7895efa75e4ddacffd55b003fb9136dfa931ad760664cf001
@ CURRENT ACCOUNT
@ ethereumAddress=0x143cffb00a1100b5df461686c13accf46cda0e00
@ [checkBalance]
@ balance=0wei
@ [checkSend]
@ EXCEPTION e=java.lang.RuntimeException: Error processing transaction request: insufficient funds for gas * price + value
@ [execCheckHelloWorld]
@ EXCEPTION e=Unable to execute Ethereum request
@ [execDeployHelloWorld]
@ EXCEPTION e=java.lang.RuntimeException: Error processing transaction request: insufficient funds for gas * price + value
@ TestWeb3: FAILED TO INTERACT [HellowWorld] CONTRACT
@ TestWeb3: FINISHED


テストが開始されると、アプリは Rinkeby テストネットへ接続します。

その後、アプリのプライベート領域にアカウント情報(jsonファイル)があるかをチェックし、有効なファイルが無い場合(初回起動時)、アカウントを新規作成します。この時、作成されたアカウント情報は、key.json の名前でアプリのプライベート領域に保存され、次回以降のテストに利用されます。

ログを見ると、新規アカウント 0x143cffb00a1100b5df461686c13accf46cda0e00 が作成されていることがわかります。

また、作成直後のアカウントには残高がないので、送金やコントラクトのデプロイテストが残高不足の例外 "Error processing transaction request: insufficient funds for gas * price + value" により、失敗している様子がうかがえます。

ss020.png

お次は、上記のアカウントへイーサを送金した状況で再テストしてみましょう(※イーサの送金はMetaMask 等で行ってください)。


二回目のログ(タップで開閉します)


@ TestWeb3: START...
@ [setTarget]
@ target=4(Rinkeby)
@ [setAccount]
@ FOUND KEY FILE: json={"address":"143cffb00a1100b5df461686c13accf46cda0e00","id":"dcf655d2-e38b-4300-ae37-830488bfeea1","version":3,"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"5d53f2ed9122b43de787685a1fabe179"},"ciphertext":"1e4c4a61bb3a03de3e4313f6c9023985f7b16977351a886b8163002f5697969e","kdf":"scrypt","kdfparams":{"dklen":32,"n":4096,"p":6,"r":8,"salt":"d762c0e0e1ae60d091d4a34f6f18d154c536d9fc7befdc478d1c96832637f5a9"},"mac":"fe66a4cc41f119ea30fcb13f503b17a7a512ec7806bef5821b7ff105f3a85335"}}
@ CURRENT ACCOUNT
@ ethereumAddress=0x143cffb00a1100b5df461686c13accf46cda0e00
@ [checkBalance]
@ balance=200000000000000000wei
@ [checkSend]
@ transaction hash=0x9ad7d8e5b54b7d5de1d0070e126274d3ddfced383611866897b92dcbb432cb08
@ [execCheckHelloWorld]
@ EXCEPTION e=Unable to execute Ethereum request
@ [execDeployHelloWorld]
@ DEPLOYED: contractAddress=0xe82a3e49c9d2408c388897c1a3c623fce083fc07
@ [execInteractHelloWorld]
@ BEFORE: HelloWorld.getWord()=Hello web3j world
@ HelloWorld.setWord( Greeting from web3j at Wed Mar 04 01:22:00 GMT+09:00 2020 )
@ AFTER: HelloWorld.getWorld()=Greeting from web3j at Wed Mar 04 01:22:00 GMT+09:00 2020
@ TestWeb3: FINISHED


今回は残高が十分(0.2 eth)あるので、イーサの送金コントラクトのデプロイ等が成功しているのがわかります。

ss021.png

補足

コントラクトのラップクラスの作り方

上でも書きましたが HelloWorld.java はコントラクトをラップするクラスとなります。もととなるソースファイル HelloWorld.sol から出力された .abi.bin を、web3j コマンドで変換して作成しています。

web3j コマンドによるラップクラスの生成手順等に関しては、GitHubReadMe.md をご覧ください。

開発環境

 ・Windows10
 ・AndroidStudio 3.1.2
 ・java 1.8.0_152

検証端末

 ・Nexus6 android 7.1.1

以上です。
この記事が少しでも、誰かのお役に立ってくれたら嬉しいです。

5
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
4