[Android] RxAndroid と AWS SDK for Android を組み合わせて使う

2015.07.08

AWS を Reactive に実装

最近 Android アプリ開発で RxAndroid を良く触っているのですが、RxJava と同様、非常に良く考えられているライブラリだと思います。

RxAndroid は非同期処理やイベントベースの処理などを構成するためのライブラリです。Android アプリ開発界隈では使われるケースが徐々に増えてきている印象です。RxAndroid や RxJava については以下の記事が分かりやすいです。

この記事では、そんな RxAndroid と AWS for Android を絡めて「Lambda Functionを呼び出す」という処理を実装してみました。

ライブラリのインポート

まず、Android Studio にて新規プロジェクトを作成した状態が前提となりますので、今回の内容を試す場合は新規プロジェクトを作成した状態で読み進めてください。

まずはアプリモジュールの build.gradle にライブラリを追加します。今回は aws-android-sdk-coreaws-android-sdk-cognitoaws-android-sdk-lambda を使います。

dependencies {
    compile 'io.reactivex:rxandroid:0.25.0'
    compile 'com.amazonaws:aws-android-sdk-core:2.2.2'
    compile 'com.amazonaws:aws-android-sdk-cognito:2.2.2'
    compile 'com.amazonaws:aws-android-sdk-lambda:2.2.2'
}

保存したら、Sync Project を実行しておきましょう。

早速実装する

ということで、早速実装します。モバイルアプリから AWS の API をコールするには Amazon Cognito を利用しましょう。Amazon Cognito の基本的な使いかたは、以前ブログで紹介した内容を参考にしていただければと思います。

Amazon Cognito の Identity Pool の作成を済ませたら、次のように実装していきましょう。今回はシンプルにしたいので Activity のみで実装しています。

package com.example.sampleapp;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.Toast;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.lambdainvoker.LambdaFunction;
import com.amazonaws.mobileconnectors.lambdainvoker.LambdaInvokerFactory;
import com.amazonaws.regions.Regions;

import rx.Observable;
import rx.Observer;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;


public class MainActivity extends AppCompatActivity {

    final AppCompatActivity self = this;
    static final String IDENTITY_POOL_ID = "us-east-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Lambda FunctionのInvokeを非同期で実行
        invokeLambdaFunction("Class", "Method")
                .subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onCompleted() {
                    }

                    @Override
                    public void onError(Throwable e) {
                    }

                    @Override
                    public void onNext(String s) {
                        // レスポンスをToastで表示
                        Toast.makeText(self, s, Toast.LENGTH_LONG).show();
                    }
                });
    }

    // Lambda FunctionのInvokerの非同期処理
    Observable<String> invokeLambdaFunction(final String firstName, final String lastName) {
        return Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                // Cognito
                CognitoCachingCredentialsProvider provider
                        = new CognitoCachingCredentialsProvider(self, IDENTITY_POOL_ID, Regions.US_EAST_1);
                LambdaInvokerFactory factory = new LambdaInvokerFactory(self, Regions.US_EAST_1, provider);

                // Lambda
                SampleInvoker invoker = factory.build(SampleInvoker.class);
                String message = invoker.hello(new NameInfo(firstName, lastName));

                // Subscriberに通知
                subscriber.onNext(message);
                subscriber.onCompleted();
            }
        });
    }

    // LambdaのInvoker
    public interface SampleInvoker {
        @LambdaFunction
        String hello(NameInfo nameInfo);
    }

    // Lambda Functionに渡すパラメータ
    public class NameInfo {
        String firstName;
        String lastName;
        public NameInfo(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

}

上記は Lambda Function を呼び出す処理を実装しています。Lambda Function 自体は以下のブログで作成したものと同じものを使っています。firstNamelastName を受けて、あいさつ的なメッセージを返却するだけのシンプルなものです。予め作成しておいてください。

こんなかんじの Lambda Function です。

exports.handler = function(payload, context) {
    console.log("Received event");
    context.succeed("Hello "+ payload.firstName + payload.lastName + ". Your user ID is " + context.identity.cognitoIdentityId  + " and your platform is " + context.clientContext.client.platform);
};

SampleInvoker インターフェースでは hello メソッドを定義していますが、これが Lambda Function の名前そのものです。他の名前で作成した場合は適宜修正してください。

実行してみよう

ここまでできたら完成です。デバッグしてみると、下図のような結果になるはずです。

rxandroid-lambda

あ、そういえば AndroidManifest.xml に以下の記述を忘れずに。

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

まとめ

Android アプリから AWS のサービスを RxAndroid 経由で利用する方法のご紹介でした。AWS サービスの呼び出しは基本的に非同期処理になるので、今回の例のような実装は絶対に必要になってきます。ぜひ参考にしてみてください。

参考