AWS AmplifyでS3のBucket名を取得する [メモ]

## はじめに
基本は自分のための備忘録だが、誰かの参考になれば幸い。
なお、クイックハックです。正式なやり方ではないと思うのでご注意を。

## 動機
AWSのAmplifyを使ってモバイルアプリを作ることになったが、使いやすい半面、小回りがきかなそうで困ってる。

### すごいざっくりのAmplify概要
Amplifyは、CLIから簡単にバックエンドを構築できて、そのバックエンドへのアクセス方法をライブラリが隠蔽するので、開発者はその詳細を知らなくてもアクセス出来るというところがメリット。

また、Dev -> Prodの2Stageで開発するときに、アプリで使うバックエンドを下記のコマンドでDev用、Prod用に切り替えることが出来る。当然、開発者はバックエンドの詳細を知らなくてもよい。

```
$ amplify env checkout <stage>
```

### 困ってること
詳細が隠蔽されているので、バックエンドのリソース名が取れない（ようにみえる）。
例えば、バケット名を表示したいと思っても、のバケット名を取得する方法がない（ようにみえる）。

~~具体的に困っているのは、Amplifyを使ってS3にアップロードしたファイルを、Amplifyで作成したAPI-Gateway -> Lambdaからアクセスしたい。だが、Lambdaが直接Amplifyが作成したS3のBucketの名前を取得する方法がない（こちらも、ようにみえる）。なので、アプリからAPI-Gatewayを叩くときに、バケット名を渡してやる必要がある。必要があるのだが、上記のようにバケット名を取る方法がない。こまるー。~~
→Lambdaで使う場合、バケットにアクセスすることを明示しておけば、環境変数に入れてくれるようでした。。Amplify ディスってごめんよ。一応、以下、何かのときのために残しておく。


## 方式案
### 方式案１：設定ファイルから読み込む。
上述した`amplify env checkout <stage>`でバックエンドを切り替えると、`/res/raw/amplifyconfiguration.json`の内容が書き換わる。これにより、開発者は詳細を知らずにバックエンドを切り替えてアプリを動かすことが出来る。

なので、こいつをパースしてやれば良い。

### 方式案２：android-amplifyをカスタマイズしちゃう。
https://github.com/aws-amplify/amplify-android からcloneして、ソースコード書き換えちゃおうぜ。という方法。

### 方式案１ vs 方式案２
どちらも、正式な方法じゃないと思われる。思われるが、おそらく方式案１のほうがよろしかろうと思われる。

でも、どうせ正しくないのだから、敢えて方式案２でやってみる。(^_^:)/

ちなみに、正しい方法は、featureリクエスト/pullリクエストを出して実装してもらうことだ。

## 手順

### githubからクローン

```
$ git clone https://github.com/aws-amplify/amplify-android.git -b release_v1.3.1
$ git checkout -b release_v1.3.1
```

### arrを作成

#### プロジェクトを開く
プロジェクトをオープンする。モジュールがいろいろ入っているが、トップのプロジェクトをオープンしましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/64b746fc-cd92-089c-5b46-d4c9599366ab.png)

#### 必要なソースコード編集を行う。
今回は、`aws-storage-s3`の`com.amplifyframework.storage.s3.AWSS3StoragePlugin.java`をいじります。（ここでは、すごく適当にやってますが、ご参考頂く方々はもう少しマトモに配慮いただけると信じてます。）

インスタンス変数に下記を追加。

```
    public String regionStr;
    public String bucket;
```

`configure`メソッドのローカル変数をコメントアウト

```
 public void configure(
            JSONObject pluginConfiguration,
            @NonNull Context context
    ) throws StorageException {
//        String regionStr;
//        String bucket;
```

#### ビルド
Android Studioの右にGradleのタスク一覧を出せるウィンドウがあるので[^1]、buildを選んで実行しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/dab18243-f930-7973-4f07-2166bae1f0f9.png)

なんか、エラーがちらほら出ますが、s3のモジュールには出てないようなので、今回は無視します。`build/outputs/arr/aws-storage-s3-release.aar`が作成されていたらOKです。

[^1]: デフォルトでは右端の細長いところにあるのですが、最初これが見つからなくて困りました。AndroidStudioは機能が多すぎて大変です。。。


### arrをインポート
それでは、作成したarrを自分のアプリにインポートします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/0582049a-ce32-3ef4-57b7-bfd37c374344.png)

ファイル名に先ほど作成したarrを指定します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/365991/e37599bc-3f8c-1f59-a948-1457d67cec41.png)

これにより、`Open Modules settings`から依存関係を設定できるようになります。なるはずです、、、なりませんね。おかしい。。。（バグかな？　使っているのはv4.0.1です。）

ということで、自力で`build.gradle`を書き換えます。`dependencies`に下記を追加します。

```
    implementation project(path: ':aws-storage-s3-release')
    implementation 'com.amazonaws:aws-android-sdk-s3:2.18.0' // カスタムのaws-storage-s3-releaseを使うときに必要。理由は不明。
```

以上で、pluginからバケット名にアクセスすることが出来るようになりました。下のような文を追加して、正しく出力されるか確認してみましょう。

```
val plugin = Amplify.Storage.getPlugin("awsS3StoragePlugin") as AWSS3StoragePlugin
Log.e(TAG,"Bucket  ${plugin.bucketName} ${plugin.regionStr}")
```

## 最後に
普通にjsonファイルをパースしたほう(方式案１)が早そうですね。ただ、これまでAmplifyを使った結果、今後もいろいろ小回りがきかなくて困りそうだったので、カスタマイズすることを前提にarrのインポートをするという手段をとってみました。

どなたかのご参考になれば幸いです。（自己責任でお願いします。）