【Androidアプリ開発】S3に格納した画像のPre-Signed URLを発行し、kotlinで表示する


## やりたいこと
S3においた画像イメージをLambda経由で取得しkotlinで表示する。

## 問題
元々はS3に格納した画像をLambdaで呼び出し、ByteArray形式に変換してクライアント端末に渡していたのですが、Lambdaにはレスポンス6MBの制限があり、大量の画像データを扱えなくなりました。

## 解決方法
S3のPre-Signed URLを使います。
Pre-Sined URLを使うと、S3オブジェクトへの限定的なアクセスを提供することが可能で、URLを渡すため、ByteArrayを渡すより格段に容量を減らせます。

## 実装例

### S3
TESTバケットにsample.jpgを格納

### Lambda
- 環境：AWS Lambda Python 3.9

- アタッチするポリシー：
```JSON
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject"
            ],
            "Resource": "arn:aws:s3:::sample-s3-presignedurl/*"
        }
    ]
}
```
- Lambda関数
```python
# -- coding: utf-8 --
import json
import json
import boto3
import base64
from boto3.dynamodb.conditions import Key	#Keyオブジェクトを利用できるようにする


S3_BUCKET_NAME = 'TEST'
S3_OBJECT_KEY = 'sample.jpg'

s3 = boto3.client('s3')

def lambda_handler(event, context):
    # TODO implement
    url = s3.generate_presigned_url(
        'get_object',
        Params={
            'Bucket': S3_BUCKET_NAME,
            'Key': S3_OBJECT_KEY
        },
        ExpiresIn=3600
    )
    return {
        'statusCode': 200,
        'body': url
    }
```
### kotlin

- 本題ではないので、API Gatewayやcoroutine使ってhttps通信するとことろは省きます。
- 頑張ってLambdaの戻り値を取得した前提です
- GlideというURL画像を取得するライブラリを使います。

**Glideの初期設定**
「build.gradle」のdependenciesに下記のコードを追加します

    implementation 'com.github.bumptech.glide:glide:4.10.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.10.0'

**レイアウトの作成**
ImageViewを作成
```xml:activity_glide.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".GlideActivity"
    android:gravity="center">
 
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:id="@+id/glideTest"
        android:layout_weight="1" />
 
</LinearLayout>
```


**Glideで画像をロード**

GlideUrl を継承したクラスを用意し、getCacheKeyメソッドをオーバーライドします

```kotlin:GlideActivity.kt
import com.bumptech.glide.load.model.GlideUrl

class GlideNoTokenUrl(private val url: String) : GlideUrl(url) {
  override fun getCacheKey(): String {
    // Domain(バケット名含む) + Path で判定する
    return url.substringBefore("?")
  }
}
```

Activity内でGlideで画像をロードしてImageViewに格納します

```kotlin:GlideActivity.kt
package com.example.hoge
 
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import com.bumptech.glide.Glide
 
class GlideActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_glide)

        val glideTest = findViewById<ImageView>(R.id.glideTest)  //イメージビュー

        // API Gateway+Lambdaで画像のPre-Signed URLを取得
        imageURL = getImageURL() // ここでHTTP通信などして画像URLを取得してください

        //GlideでImageViewに設定
        Glide.with(context)
             .load(GlideNoTokenUrl(url))  // ロードしたいイメージのURLを入力
             .placeholder(R.drawable.dreamhanks) //イメージをロード中に見せるイメージ設定
             .into(glideTest)  // セットしたいImageViewを入力
        }
    }
}
```

Glideの主要メソッド

- 「with」：ContextやActivityについて設定
- 「load」：実際にロードしたいイメージのURLを設定
- 「placeholder」：イメージをロード中に見せるイメージを設定（なくてもいい）
- 「into」：イメージを適用する「ImageView」を設定

以上

## 参考にさせていただいた素晴らしいサイト様
- [21. 【Android/Kotlin】Glide（イメージをロード） ](https://blog.dreamhanks.com/21-%E3%80%90android-kotlin%E3%80%91glide%EF%BC%88%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%82%92%E3%83%AD%E3%83%BC%E3%83%89%EF%BC%89/)
- [S3-Pre-Signed-URLでダウンロードした画像を Android の画像ライブラリ Glide 4 でキャッシュする](https://dev.classmethod.jp/articles/android-glide-s3-pre-signed-url/)
- [Lambdaで6MBを超えるデータをReturnできなかったので、S3のPre-Signed URLを使った話](https://dev.classmethod.jp/articles/lambda-over-6mb-response-use-s3-pre-signed-url/)
- [S3に直接アップロード可能なPre-Signed URLをLambdaで作ってみる](https://dev.classmethod.jp/articles/create-pre-signed-url-with-lambda/)


## 旅行アプリ、Tig Travelをリリースしました
おすすめの旅行プランを多数掲載。旅行プランをカスタマイズし、自分だけのプランを簡単に作成できます！

https://tigtravel.my.canva.site/tigtravel-lp