AWS Mobile Application Development

AWSのサービスをモバイルから使うにあたって調べた情報などまとめて行きます。

AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (2/2) AWSコンソールでの作業

AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (1/2) ローカルPC上の準備 - AWS Mobile Application Developmentに続き、AWS LambdaのS3への画像ファイルアップロード後にリサイズを行うファンクションの作成です。

[目次]

AWS S3 bucketの作成

加工前の画像が入るファイルのバッケットを「android-pic-tank」とし、加工後のファイルを「android-pic-tank-risize」として作成します。

android-pic-tank
f:id:azumami:20161125151311p:plain

android-pic-tank-resize
f:id:azumami:20161125151327p:plain

Lambda関数の作成

Lambda管理画面から新規作成
f:id:azumami:20161125151519p:plain

「Blank Function」をクリック。
f:id:azumami:20161125151558p:plain

トリガーとなる条件を記載。「android-pic-tank」に「put」(アップロード)されたファイルが「jpg」という名前が入っていればファイヤー。
f:id:azumami:20161125151615p:plain

以下みたいな感じで、設定。「Lambda Function Code」の方に前のステップで作成したzipファイルを指定。
f:id:azumami:20161125153420p:plain

f:id:azumami:20161125153638p:plain

今の状態では、S3のデータの読み込み権限しかないので、S3に書き込めるポリシーをアタッチします。
f:id:azumami:20161125153648p:plain

「AmazonS3FullAccess」をアタッチ。
f:id:azumami:20161125153727p:plain
これを設定していない場合、以下の権限エラーが発生します。

2016-11-28T01:01:33.431Z	3296e5ca-b506-11e6-95d7-b790461b4b89	Unable to resize android-pic-tank/604fb235-s.jpg and upload to android-pic-tank-resize/resized-604fb235-s.jpg due to an error: AccessDenied: Access Denied

Lambdaの関数設定画面に戻って、トリガーを「enable」にします。
f:id:azumami:20161125153817p:plain

確認画面で「enable」にした後、以下のように「disable」に設定できる状態であることを確認します。
f:id:azumami:20161125153848p:plain

S3の「android-pic-tank」バケットにファイルをアップロードします。
f:id:azumami:20161125153856p:plain

S3の「android-pic-tank-resize」に自動的に小さいファイルが作成されていることを確認します。
f:id:azumami:20161125153903p:plain

これで終了。うまくいかない場合は以下のようなテストを実行してみてエラーログなどを確認します。

Lambdaでのテスト

テストはまず以下のナビゲーションからテスト用のデータ設定をします。
f:id:azumami:20161125154336p:plain

テストデータ入力画面がでるので赤枠部分に値を設定します。「Save and Test」で実行します。
f:id:azumami:20161125155018p:plain

エラーでが出る場合というか出たのでタイムアウト値を変更します。

{
  "errorMessage": "2016-11-25T06:51:29.366Z 95e036c5-b2db-11e6-a945-f5f796929e8e Task timed out after 3.00 seconds"
}

10に設定。
f:id:azumami:20161125155250p:plain

設定後「test」ボタンで成功
f:id:azumami:20161125155406p:plain

LambdaxS3 を使う場合の注意点

トリガー設定を行うに当たって、S3の1つのバケット内に変換元ファイル、変換後ファイルをフォルダでわけるなどする場合は注意が必要です。トリガー設定の箇所でprefixでバケット配下のフォルダをチャント指定していないと、変換後に作成されたファイルの作成自体を検知して、無限ループが発生します。

ですので、設計として、バケット内のフォルダを複数階層にしない、バケットを複数もってそれぞれを変換元、変換先として用意したほうが安全です。知らないうちにクラウド破産になりかねません。

おしまい。

AWS LambdaでのS3画像アップロードをトリガーとしたリサイズ(サムネイル作成) (1/2) ローカルPC上の準備

Androidからアップロードした画像ファイルのサムネイルを作成する目的でAWS Lambdaを使用してみましたので、簡単な動作確認までをご紹介。

[目次]

AWS Lambdaとは

AWS LambdaはNode.js(javascript)、pythonjavaクラウド上の自動化処理の用途でプログラミングをすることができます。

AWS Lambda は、コードを AWS Lambda にアップロードすると、サービスが AWS インフラストラクチャを使用してコードの実行を代行するコンピューティングサービスです。コードをアップロードして、Lambda 関数と呼ばれる関数を作成することで、AWS Lambda がコードを実行するサーバーのプロビジョニングおよび管理を行います。AWS Lambda は次のように使用できます。

・Amazon S3 バケットまたは Amazon DynamoDB テーブルのデータ変更などのイベントに対応して AWS Lambda がコードを実行するイベント駆動型コンピューティングサービスとして。
・Amazon API Gateway を使用した HTTP リクエストまたは AWS SDK を使用した API 呼び出しに対応してコードを実行するコンピューティングサービスとして。

AWS Lambda とは - AWS Lambda

料金

遊ぶ分には無料で使えますな。

リクエストのうち毎月最初の 1,000,000 件は無料
その後は 0.20 USD/1,000,000 件のリクエスト(0.0000002 USD/リクエスト)

料金 - AWS Lambda | AWS

ローカルでのNode.js環境作成

今回はNode.jsベースで動かしてみたので、まずNode.jsをローカルのPCにインストールします。ちなみにAWSマニュアルにはNode.js v4.3で対応とありますので、Node.jsのサイトからv4.3をダウンロードします。

Note
The code sample is compliant with the Node.js runtime v4.3. For more information, see Programming Model (Node.js)

Step 2.1: Create a Deployment Package - AWS Lambda

Node.jsのダンロード

https://nodejs.org/download/release/v4.3.2/
私の環境はwindows x64のPCなので「node-v4.3.2-x64.msi」をダウンロードました。

Node.jsのインストール

全てデフォルトの設定値で、インストールします。

Lambdaプログラムアップロード用ファイルを作成

どこでもいいので「createThumbnail」フォルダを作成して、配下で「npm install async gm」を実行して、asyncとgmモジュールをダウンロードし展開します。

C:\>mkdir createThumbnail

C:\>cd createThumbnail

C:\createThumbnail>npm install async gm
gm@1.23.0 node_modules\gm
├── array-parallel@0.1.3
├── array-series@0.1.5
├── debug@2.2.0 (ms@0.7.1)
└── cross-spawn@4.0.2 (lru-cache@4.0.1, which@1.2.12)

async@2.1.4 node_modules\async
└── lodash@4.17.2

「createThumbnail」フォルダ内に「index.js」というファイル名で以下のプログラムを貼り付けます。

「createThumbail.js」という風にAWSのマニュアルは書いてありますが、Lambdaファンクションを作成する際のハンドラのデフォルト値が「index.handler」なのでこれとファイル名がマッチする必要があります。マッチしない場合は以下のようにLambdaファンクション実行した際にエラーになります。

{
  "errorMessage": "Cannot find module '/var/task/index'",
  "errorType": "Error",
  "stackTrace": [
    "Function.Module._load (module.js:276:25)",
    "Module.require (module.js:353:17)",
    "require (internal/module.js:12:17)"
  ]
}

コード(index.js)

// dependencies
var async = require('async');
var AWS = require('aws-sdk');
var gm = require('gm')
            .subClass({ imageMagick: true }); // Enable ImageMagick integration.
var util = require('util');

// constants
var MAX_WIDTH  = 100;
var MAX_HEIGHT = 100;

// get reference to S3 client 
var s3 = new AWS.S3();
 
exports.handler = function(event, context, callback) {
    // Read options from the event.
    console.log("Reading options from event:\n", util.inspect(event, {depth: 5}));
    var srcBucket = event.Records[0].s3.bucket.name;
    // Object key may have spaces or unicode non-ASCII characters.
    var srcKey    =
    decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, " "));  
    var dstBucket = srcBucket + "-resize";  
    var dstKey    = "resized-" + srcKey;  //★

    // Sanity check: validate that source and destination are different buckets.
    if (srcBucket == dstBucket) {
        callback("Source and destination buckets are the same.");
        return;
    }

    // Infer the image type.
    var typeMatch = srcKey.match(/\.([^.]*)$/);
    if (!typeMatch) {
        callback("Could not determine the image type.");
        return;
    }
    var imageType = typeMatch[1];
    if (imageType != "jpg" && imageType != "png") {
        callback('Unsupported image type: ${imageType}');
        return;
    }

    // Download the image from S3, transform, and upload to a different S3 bucket.
    async.waterfall([
        function download(next) {
            // Download the image from S3 into a buffer.
            s3.getObject({
                    Bucket: srcBucket,
                    Key: srcKey
                },
                next);
            },
        function transform(response, next) {
            gm(response.Body).size(function(err, size) {
                // Infer the scaling factor to avoid stretching the image unnaturally.
                var scalingFactor = Math.min(
                    MAX_WIDTH / size.width,
                    MAX_HEIGHT / size.height
                );
                var width  = scalingFactor * size.width;
                var height = scalingFactor * size.height;

                // Transform the image buffer in memory.
                this.resize(width, height)
                    .toBuffer(imageType, function(err, buffer) {
                        if (err) {
                            next(err);
                        } else {
                            next(null, response.ContentType, buffer);
                        }
                    });
            });
        },
        function upload(contentType, data, next) {
            // Stream the transformed image to a different S3 bucket.
            s3.putObject({
                    Bucket: dstBucket,
                    Key: dstKey,
                    Body: data,
                    ContentType: contentType
                },
                next);
            }
        ], function (err) {
            if (err) {
                console.error(
                    'Unable to resize ' + srcBucket + '/' + srcKey +
                    ' and upload to ' + dstBucket + '/' + dstKey +
                    ' due to an error: ' + err
                );
            } else {
                console.log(
                    'Successfully resized ' + srcBucket + '/' + srcKey +
                    ' and uploaded to ' + dstBucket + '/' + dstKey
                );
            }

            callback(null, "message");
        }
    );
};

Step 2.1: Create a Deployment Package - AWS Lambdaのコードになりますが一部、バケット名などを個別に指定するために変更しています。★の部分。

AsyncTaskで取得してきたデータをアクティビティに引き渡す方法

stackoverlowで良いサンプルがあったのですメモ。Activity外の外出個別クラスから、Activityクラスへデータを返す方法を探してたら、データを、返すんではなく外出しクラスへActivityを受け渡すやり方。

つまり、件名とはやってることは違いますが最終的やりたいことは同じ。

Asynctask側のコンストラクタにActivity自体を渡してます。それでAsynctask側のメソッドでActivity側のメンバlistをAsynctask側から更新する。

一般的なgetやAWS S3とかDynamodbのデータをAsynctaskでとってきたあと、Activityに結果を、反映する用途で使えますね。

・YourActivity.java

public class YourActivity extends Activity {
    private List<String> list = new ArrayList<String>();

    public void onCreate(Bundle state) {
        //...
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    private void fireYourAsyncTask() {
        new LoadStringsAsync(this).execute();
    }

}    

・LoadStringsAsync.java

public class LoadStringsAsync extends AsyncTask<Void, Void, List<String>> {

    List<String> str;
    private YourAcitivity activity;

    public LoadStringsAsync(YourAcitivity activity) {
        this.activity = activity;
    }

    @Override
    protected List<String> doInBackground(Void... arg0) {
    }

    @Override
    protected void onPostExecute(List<String> str) {
        super.onPostExecute(events);
        activity.setList(str);
    }
}

android - AsyncTask return List to Activity - Stack Overflow

AndroidとDynamoDB実装方法 (4/4) - コーディング -

AWSのNoSQLデータベースDynamoDBをDBとしてデータ操作を行うための基本的な設定のご紹介です。

AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -に続き、プログラミングになります。

MainActivity.javaと、DynamoDBのテーブルクラスを定義したBooks.javaの2ファイルからの構成となるプログラミングを行います。

[目次]

コード

Books.java

package com.example.sample.dynamodb_sample;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.dynamodbv2.*;
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*;

/* Dynammoテーブル名*/
@DynamoDBTable(tableName = "Books")
public class Books {

    private String author;
    private String title;
    private int price;
    private String releasedate;

  /* パーティションキーで指定した属性名 */
    @DynamoDBHashKey(attributeName = "Author")
    public String getAuthor() {return author; }
    public void setAuthor(String author) { this.author = author; }

  /* ソートキーで指定した属性名 */
    @DynamoDBRangeKey(attributeName = "Title")
    public String getTitle() {return title; }
    public void setTitle(String title) { this.title = title; }

  /* 任意の属性名 AWSコンソールで事前定義不要*/
    @DynamoDBAttribute(attributeName = "Price")
    public int getPrice() {return price; }
    public void setPrice(Integer price) { this.price = price; }

  /* 任意の属性名 AWSコンソールで事前定義不要*/
    @DynamoDBAttribute(attributeName = "Releasedate")
    public String getReleasedate() {return releasedate; }
    public void setReleasedate(String releasedate) { this.releasedate = releasedate; }

}

プログラム内で記載している以下はAWSコンソールで事前定義をしたDynamoDBのマッピング定義で必ず定義が必要なアノテーションです。

@DynamoDBTable(tableName = "Books")
@DynamoDBHashKey(attributeName = "Author")
@DynamoDBRangeKey(attributeName = "Title")

以下は、AWSコンソールで事前定義をしたものではなく、本アプリで使用し得る属性名として定義しているアノテーションです。

@DynamoDBAttribute(attributeName = "Price")
@DynamoDBAttribute(attributeName = "Releasedate")

他にも色々とアノテーションを定義するルールが以下に記載されています。
docs.aws.amazon.com

MainActivity.java

package com.example.sample.dynamodb_sample;

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

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.regions.Region;
import com.amazonaws.services.dynamodbv2.*;
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*;

import java.util.Date;

public class MainActivity extends AppCompatActivity {

    private Books book;
    private Runnable runnable;


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


        // (1) Cognitoで出力した認証定義です
        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                getApplicationContext(),
                "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxxxxxx
", // Identity Pool ID
                Regions.AP_NORTHEAST_1 // Region
        );

        // (2) DynamoDBのクライアントセッションを作成します
        AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient(credentialsProvider);

        // (3) デフォルトではUS-EASTがリージョンで指定されてしまうため意図的にAP_NORTHEASTにしています
        Region apNortheast1 = Region.getRegion(Regions.AP_NORTHEAST_1);
        ddbClient.setRegion(apNortheast1);

        // (4) マッパーのインスタンス作成
        final DynamoDBMapper mapper = new DynamoDBMapper(ddbClient);

        // (5) インターネットのアクセスを行うためにスレッドを作成し、その中でインサート処理を定義します
        runnable = new Runnable() {
            public void run() {
                Books book = new Books();
                book.setAuthor("Charles Dickens");
                book.setTitle("Great Expectations");
                book.setPrice(20000);
                Date date = new Date();
                book.setReleasedate(date.toString());
                mapper.save(book);
            };
        };

        Thread mythread = new Thread(runnable);
        mythread.start();

    }

}

コード解説

(1) AWSの認証

AndroidとDynamoDB実装方法 (2) - Cognito初期設定 - - AWS Mobile Application Developmentで取得した「Get AWS Credentials」を定義して認証処理を行います。

(2) DynamoDBのクライアントセッション作成

(1)でDynamoDB用のクライアントセッションを作成します。

(3) リージョンの指定

デフォルトではUS-EASTがリージョンで指定されてしまうため、これを設定しないと以下のエラーが発生します。その為、意図的にAP_NORTHEASTにしています。

E/AndroidRuntime: FATAL EXCEPTION: Thread-9
                  Process: com.example.sample.dynamodb_sample, PID: 2269
                  com.amazonaws.AmazonServiceException: User: arn:aws:sts::xxxxxxxxxxxxx:assumed-role/Cognito_DynamoTestUnauth_Role/CognitoIdentityCredentials is not authorized to perform: dynamodb:UpdateItem on resource: arn:aws:dynamodb:us-east-1:xxxxxxxxxxxxxx:table/Books (Service: AmazonDynamoDB; Status Code: 400; Error Code: AccessDeniedException; Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx)

(4) マッパーのインスタンス作成

DynamoDBクライアントセッション情報を元に、DynamoDBのマッパーインスタンスを作成します。

(5) 別スレッドでDB処理を行う

Androidではインターネット処理をメインスレッド(UIスレッド)で行ってはいけません。ワーカスレッドを作成しそれ上で処理を行う必要があります。これを行わなかった場合以下のエラーが発生します。

E/AndroidRuntime: FATAL EXCEPTION: main
                  Process: com.example.sample.dynamodb_sample, PID: 3056
                  java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.sample.dynamodb_sample/com.example.sample.dynamodb_sample.MainActivity}: android.os.NetworkOnMainThreadException

Mainスレッドとは別でインターネットの処理し結果をメインスレッドへコールバックをすることがAndroidの基本です。実現方法法として、「Runnable」と「AsyncTask」がありますので「Runnable」は上記に書いていますので「AsyncTask」実装例を以下に記載します。

package com.example.sample.dynamodb_sample;

import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.regions.Regions;
import com.amazonaws.regions.Region;
import com.amazonaws.services.dynamodbv2.*;
import com.amazonaws.mobileconnectors.dynamodbv2.dynamodbmapper.*;

import java.util.Date;

public class MainActivity extends AppCompatActivity {

    private CognitoCachingCredentialsProvider credentialsProvider;
    private static final String TAG = MainActivity.class.getSimpleName();

    private Books book;
    private DynamoDBMapper mapper;

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

        // (1) Cognitoで出力した認証定義です
        CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
                getApplicationContext(),
                "ap-northeast-1:xxxxxxxxxxxxxxxxxxxxxxx", // Identity Pool ID
                Regions.AP_NORTHEAST_1 // Region
        );

        // (2) DynamoDBのクライアントセッションを作成します
        AmazonDynamoDBClient ddbClient = new AmazonDynamoDBClient(credentialsProvider);

        // (3) デフォルトではUS-EASTがリージョンで指定されてしまうため意図的にAP_NORTHEASTにしています
        Region apNortheast1 = Region.getRegion(Regions.AP_NORTHEAST_1);
        ddbClient.setRegion(apNortheast1);

        // (4) マッパーのインスタンス作成
        mapper = new DynamoDBMapper(ddbClient);

        new db().execute("");

    }

    //AsyncTask<Params, Progress, Result>
    private class db extends AsyncTask<String, Integer, String> {

        /** doInBackgroundメソッドの実行前にメインスレッドで実行されます。
         非同期処理前に何か処理を行いたい場合に使用。
         */
        @Override
        protected void onPreExecute() {
            Log.i(TAG,"onPreExecuted ....");
        }

        /** メインスレッドとは別のスレッドで実行されます。
        非同期で処理したい内容を記述します。記載必須。
         */
        @Override
        protected String doInBackground(String... params) {
            Log.i(TAG,"doInBackground ....");

            Books book = new Books();

            int i = 0;

            for(i = 0; i < 20; i++){
                try {
                    Thread.sleep(1500);
                    book.setAuthor("村上春樹");
                    book.setTitle("1Q24" + "第" + i + "版");
                    book.setPrice(20000);
                    Date date = new Date();
                    book.setReleasedate(date.toString());
                    mapper.save(book);

                    publishProgress(i);

                }catch(InterruptedException e){
                    Toast.makeText(MainActivity.this, "Error", Toast.LENGTH_SHORT).show();
                }
            }
            /* onPostExecute(String s) の s に "Executed" が入ります */
            return "Executed";
        }

        /**メインスレッドで実行されます。
         非同期処理の進行状況をプログレスバーで 表示したい時などに使うことができます。
         */

        @Override
        protected void onProgressUpdate(Integer... values) {
            Log.i(TAG,"onProgressUpdate .... " + values[0]);
        }

        /**doInBackgroundメソッドの実行後にメインスレッドで実行されます。
         doInBackgroundメソッドの戻り値をこのメソッドの引数として受け取り、
         その結果を画面に反映させることができます。
         */
        @Override
        protected void onPostExecute(String s) {
            Log.i(TAG,"onPostExecute ....return value is " + s);
        }

    }
}

developer.android.com

[参考]

AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -

AWSのNoSQLデータベースDynamoDBをDBとしてデータ操作を行うための基本的な設定のご紹介です。

AndroidとDynamoDB実装方法 (3/4) - DynamoDB初期設定 -に続き、AWS DynamoDBの設定を行います。

[目次]

設定の前にまずDynamoDBについて基本から抑えておき、設定まで進みます。

DynamoDBの基本

まずDynamoDBの基本ですが、DynamoDBはNoSQL型のデータベースで以下で詳細に紹介されていますが、かいつまんで構造に関する部分のみ列挙します。

データの特徴

name/value型でjsonのようなデータの構造になっている

DynamoDBの構成要素

  • テーブル(table)

RDBで言うテーブルと同意

  • アイテム(item)

RDBで言う行(row)と同意

  • 属性(attribute)

RDBで言う列(column)と同意

RDBで言うプライマリキー。パーティションキーに指定した属性にハッシュインデックスが作成される。

  • ソートキー(旧レンジプライマリレンジキー(Range Primary Key / Primary sort key)

RDBで言うプライマリキー以外に、ソートキーとして指定した属性にレンジハッシュインデックスが作成される。

DynamoDB設定手順

DynamoDBのテーブル作成

DynamoDBでサンプルのテーブル「Books」を作ってみます。AWSコンソールにログインしてDynamoDBを選択します。
f:id:azumami:20161107054736p:plain


続いて、「Create Table」をクリックします。
f:id:azumami:20161107054745p:plain


「Table name」、「Primary key」を入力後、「add sort key」をクリックし以下の通り入力します。その後「Create」をクリックしテーブルを作成します。
f:id:azumami:20161107054754p:plain
この「Primary key(ハッシュプライマリキー)」はRDBでいう、そのままですがプライマリキーで、「Sort Key」というのがテーブルに1つだけ設定できるデータをソートするための列です。DynamoDBではこのソートキーでしたソートができません。

参照
www.magtranetwork.com


作成後、詳細が表示されるますが次のステップではこのテーブルへの権限設定をするため、「Amazon Resource Name (ARN)」の文字列にてこのテーブルを指定するためテキストとしてコピーしておきます。
f:id:azumami:20161107054803p:plain

IAMでのポリシー作成

AWSコンソールにログインして「Identity & Access Management」を選択します。左側のメニューのロールを選択します。前ステップで作成したDyanmoDBテーブル名が含まれたエントリが2つありますので、「Unauth」の文字列がある方をクリックします。
f:id:azumami:20161107153845p:plain


表示される画面の中で以下の「Create Role Policy」を選択します。
f:id:azumami:20161107153903p:plain


「Policy Generator」を選択した状態で「Select」を選択します。
f:id:azumami:20161107153910p:plain


以下の設定を行います。前ステップで作成したARN(DyanmoDBの作成したテーブル)へフルアクセスを可能とするポリシーという意味になります。「Add Statement」をクリックし、「Next Step」をクリックします。
f:id:azumami:20161107153917p:plain


生成されるjson形式のポリシーが表示されますので「Apply Policy」をクリックして終了します。
f:id:azumami:20161107153948p:plain


以上で、Cognito経由でDynamoDBへアクセスするための権限設定が完了です。

続いてプログラミングです。

【Android基礎】BitbucketとAndroid Studioの連携設定

Android Studioで作ったプログラムを管理するリポジトリとして、リポジトリをクローズドな形で管理できるBitbucketとの連携手順です。

[目次]

事前作業

Bitbucketのアカウント登録

bitbucket.org
こちらよりアカウント登録を行います。登録だけだと無料です。

Android Studioインストール

developer.android.com
こちらより事前にインストールをしておきます。

連携設定

Android Studioのメニュー > VCS > Enable Version Control Integration... を選択
f:id:azumami:20161107063845p:plain

Gitを選択
f:id:azumami:20161107063859p:plain


Bitbucketからリポジトリを定義します。
f:id:azumami:20161107063747p:plain


Android Studioに戻って「Vesion Control」の箇所で、「Unversioned」を右リックから「Git」> 「Add」を選択。
f:id:azumami:20161107063923p:plain


「Vesion Control」の箇所で、「Unversioned」を右リックから「Git」> 「Commit Files」を選択。
f:id:azumami:20161107063939p:plain


Commit Messageに何か記載して、「Commit」をクリック。
f:id:azumami:20161107064127p:plain


「Commit」をクリック。
f:id:azumami:20161107064137p:plain


Bitbucketから先ほどの作成したレポジトリのURLを取ってきて、貼り付け「OK」をクリック。
f:id:azumami:20161107064146p:plain


「Push」をクリック
f:id:azumami:20161107064908p:plain


Bitbucketのソース部分にアップロードされていることが確認できます。
f:id:azumami:20161107064206p:plain

ご参考

qiita.com

【Android基礎】 外部のクラスファイルが利用できない時の対処法

MainActivity.javaと同じディレクトリのHello.javaというクラスファイルを定義してそれをMainActivity.javaから読もうとすると、「Unknown Class」、「Invalid Method declaration」、「return type required」と表示されたりする。

あくまで一例ですが、原因のその一つにメソッドやコンストラクタ以外のところで、プログラムを書いている可能性があります。


例えば、以下のような独自のクラスがあるとして、

Hello.java

package com.example.azwoo.test;


public class Hello {

    public String love;
    public String death;

    public void setLove(String love){

        this.love = love;
    }

    public void setDeath(String death){

        this.death = death;
    }

}

ちゃんとonCreateメソッド(例)内でインスタンスを作成していればエラーは起きませんが、

MainActivity.java

package com.example.azwoo.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private Hello hello;

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

        hello = new Hello();
        hello.setLove("I love you");
        hello.setDeath("I love you");

        Log.e("test","love = " + hello.love);
        Log.e("test","death = " + hello.death);

    }
}

こんな感じでメソッドでもなくコンストラクタでもないところで書いているとエラーになります。

MainActivity.java

package com.example.azwoo.test;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    private Hello hello;

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

    hello = new Hello();
    hello.setLove("I love you");
    hello.setDeath("I love you");

    Log.e("test","love = " + hello.love);
    Log.e("test","death = " + hello.death);

}