Skip to content

Commit

Permalink
feat: ignoreQueryParamsForCacheKey image option (iOS & Android)
Browse files Browse the repository at this point in the history
Ignores URL query parameters for cache keys when the new option is set to true, defaults to false.

This is needed for example when downloading images using S3 presigned URL's that include a signature that changes between requests preventing the images from being found in the cache.

Also fixes the merge error in FasterImageViewManager.kt which came from commit 86a23fd
  • Loading branch information
numsu committed Oct 9, 2024
1 parent 9d9cf7a commit f55d6ce
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.graphics.RectF
import android.graphics.Path
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.net.Uri
import android.os.Build
import android.util.Base64
import android.view.View
Expand All @@ -18,6 +19,7 @@ import android.widget.ImageView.ScaleType
import androidx.appcompat.widget.AppCompatImageView
import coil.annotation.ExperimentalCoilApi
import coil.imageLoader
import coil.memory.MemoryCache
import coil.request.CachePolicy
import coil.request.ImageRequest
import coil.size.Scale
Expand Down Expand Up @@ -93,9 +95,10 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
val failureImage = options.getString("failureImage")
val grayscale = if (options.hasKey("grayscale")) options.getDouble("grayscale") else 0.0
val allowHardware = if (options.hasKey("allowHardware")) options.getBoolean("allowHardware") else true
val headers = options.getMap("headers")
val headers = options.getMap("headers")
val ignoreQueryParamsForCacheKey = if (options.hasKey("ignoreQueryParamsForCacheKey")) options.getBoolean("ignoreQueryParamsForCacheKey") else false

val borderRadii = BorderRadii(
val borderRadii = BorderRadii(
uniform = if (options.hasKey("borderRadius")) options.getDouble("borderRadius") else 0.0,
topLeft = if (options.hasKey("borderTopLeftRadius")) options.getDouble("borderTopLeftRadius") else 0.0,
topRight = if (options.hasKey("borderTopRightRadius")) options.getDouble("borderTopRightRadius") else 0.0,
Expand Down Expand Up @@ -127,6 +130,20 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
)
} else {
requestBuilder = requestBuilder.data(it)
if (ignoreQueryParamsForCacheKey) {
val uri = Uri.parse(it)
val keyUri = uri.buildUpon().clearQuery().build()
val cacheKey = keyUri.toString()
val memoryCacheKey = MemoryCache.Key(cacheKey)
if (cachePolicy.equals("memory")) {
requestBuilder = requestBuilder
.memoryCacheKey(memoryCacheKey)
} else {
requestBuilder = requestBuilder
.memoryCacheKey(memoryCacheKey)
.diskCacheKey(cacheKey)
}
}
headers?.let {
for (entry in it.entryIterator) {
requestBuilder.setHeader(entry.key, entry.value as String)
Expand Down Expand Up @@ -232,20 +249,6 @@ import com.facebook.react.uimanager.events.RCTEventEmitter

private fun makeThumbHash(view: AppCompatImageView, hash: String): Drawable {
val thumbHash = ThumbHash.thumbHashToRGBA(Base64.decode(hash, Base64.DEFAULT))
val bitmap = Bitmap.createBitmap(thumbHash.width, thumbHash.height, Bitmap.Config.ARGB_8888)
bitmap.setPixels(toIntArray(thumbHash.rgba), 0, thumbHash.width, 0, 0, thumbHash.width, thumbHash.height)
return BitmapDrawable(view.context.resources, bitmap)
}

private fun makeBlurHash(view: AppCompatImageView, hash: String): Drawable {
val bitmap = BlurHashDecoder.decode(hash, 8, 8)
return BitmapDrawable(view.context.resources, bitmap)
}

private fun toIntArray(byteArray: ByteArray): IntArray {
val intArray = IntArray(byteArray.size)
for (i in byteArray.indices) {
intArray[i] = byteArray[i].toInt() and 0xFF
val intArray = IntArray(thumbHash.width * thumbHash.height)
for (i in intArray.indices) {
val r = thumbHash.rgba[i * 4].toInt() and 0xFF
Expand All @@ -259,6 +262,11 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
return BitmapDrawable(view.context.resources, bitmap)
}

private fun makeBlurHash(view: AppCompatImageView, hash: String): Drawable {
val bitmap = BlurHashDecoder.decode(hash, 8, 8)
return BitmapDrawable(view.context.resources, bitmap)
}

companion object {
private val RESIZE_MODE = mapOf(
"contain" to ScaleType.FIT_CENTER,
Expand All @@ -276,6 +284,7 @@ import com.facebook.react.uimanager.events.RCTEventEmitter
}
}


object ThumbHash {
/**
* Encodes an RGBA image to a ThumbHash. RGB should not be premultiplied by A.
Expand Down
12 changes: 11 additions & 1 deletion ios/FasterImageViewManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ struct ImageOptions: Decodable {
let url: String
let headers: [String: String]?
let grayscale: Double?
let ignoreQueryParamsForCacheKey: Bool?
}

struct BorderRadii {
Expand Down Expand Up @@ -134,12 +135,19 @@ final class FasterImageView: UIView {
}
progressiveLoadingEnabled = options.progressiveLoadingEnabled ?? false
grayscale = options.grayscale ?? 0.0
ignoreQueryParamsForCacheKey = options.ignoreQueryParamsForCacheKey ?? false

if let url = URL(string: options.url) {
var urlRequestFromOptions = URLRequest(url: url)
urlRequestFromOptions.allHTTPHeaderFields = options.headers

urlRequest = urlRequestFromOptions

if ignoreQueryParamsForCacheKey {
var components = URLComponents(url: url, resolvingAgainstBaseURL: false)
components?.query = nil
var url = components?.url?.absoluteString ?? url.absoluteString
lazyImageView.request?.userInfo[.imageIdKey] = url
}
} else {
onError?([
"error": "Expected a valid url but got: \(options.url)",
Expand Down Expand Up @@ -270,6 +278,8 @@ final class FasterImageView: UIView {
}
}

var ignoreQueryParamsForCacheKey = false

// MARK: - Optional Properties

var base64Placeholder: String? {
Expand Down
2 changes: 2 additions & 0 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export type AndroidImageResizeMode =
* @property {number} [borderBottomRightRadius] - Bottom right border radius of the image
* @property {number} [grayscale] - Grayscale value of the image, 0-1
* @property {boolean} [allowHardware] - Allow hardware rendering, defaults to true (Android only)
* @property {boolean} [ignoreQueryParamsForCacheKey] - Ignore query params for cache key, defaults to false
*/
export type ImageOptions = {
blurhash?: string;
Expand All @@ -70,6 +71,7 @@ export type ImageOptions = {
headers?: Record<string, string>;
grayscale?: number;
allowHardware?: boolean;
ignoreQueryParamsForCacheKey?: boolean;
};

/**
Expand Down

0 comments on commit f55d6ce

Please sign in to comment.