S3-Pre-Signed-URLでダウンロードした画像を Android の画像ライブラリ Glide 4 でキャッシュする

今回はAndroidでS3の画像を表示するときにPre-Signed URL つかうと、発行される度にURLが違うためGlideをつかってる場合キャッシュのキーにURLをつかうため、表示するたびにキャッシュされてしまう現象がおきてしまい、その対策を調べました
2019.12.19

西田@大阪@Android 修行中 です

今回はAndroidでS3の画像を表示するときにPre-Signed URL つかうと、発行される度にURLが違うためGlideをつかってる場合キャッシュのキーにURLをつかうため、表示するたびにキャッシュされてしまう現象がおきてしまい、その対策を調べました

ためした Glide のバージョンは 4.9 です

GlideのCache

GlideのCacheは2種類あります。

  • メモリ上のキャッシュ
  • ディスク上のキャッシュ

画像を取得するタイミングでメモリ上にキャッシュがあればメモリ上のキャッシュを返し、次にディスク上のキャッシュがあれば、ディスク上のキャッシュを返し、それすらもなければ Origin のリソースを取得しにいきます

GlideがCacheする単位

2つの要素をキーとして比較します

  1. Model(File, Uri, Url)
  2. 追加で Signature を指定することで同じ Model でも違うものとして扱える

S3-Presingd-URL は発行のたびに毎回異なる一時的なクエリーパラメーターがURLに付与されます

https://example.s3.amazonaws.com/images/1.JPG?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXX&X-Amz-Date=20191018T011014Z&X-Amz-Expires=17760&X-Amz-SignedHeaders=host&X-Amz-Security-Token=XXXX&X-Amz-Signature=XXX

今回はクエリーパラメーターの抜いた https://example.s3.amazonaws.com/images/1.JPGのみをキーとするようカスタムします

実装

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

import com.bumptech.glide.load.model.GlideUrl

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

Glideの load メソッドに渡すパラメーターにカスタムした GlideNoTokenUrl のインスタンスを渡します

val url = "https://example.s3.amazonaws.com/...."

Glide.with(context)
    .load(GlideNoTokenUrl(url))

最後に

わかってしまえば簡単なことなのですがなれてないせいかはまってしまいました。誰かのお役に立てれば幸いです

参考

Best strategy to load images using Glide — Image loading library for Android

Stack Overflow