react-native-fast-image 8.17.2 → 8.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -371,6 +371,34 @@ Clear all images from memory cache.
371
371
 
372
372
  Clear all images from disk cache.
373
373
 
374
+ ### `FastImage.getCachePath: (source: Source) => Promise<CachePathResult>`
375
+
376
+ The path of the source's downloaded file in the disk cache, e.g. to share, save or upload an image without downloading it again. If the file isn't there, it's downloaded first, without decoding the image or keeping it in memory. Resolves with `{ ok: true, path }`, or `{ ok: false, error }` if it can't be downloaded. Never rejects.
377
+
378
+ ```js
379
+ const result = await FastImage.getCachePath({ uri: photo.url })
380
+ if (result.ok) {
381
+ await shareFile(`file://${result.path}`) // e.g. with react-native-share
382
+ }
383
+ ```
384
+
385
+ With `cache: 'cacheOnly'` it doesn't download: use it to check whether an image is cached.
386
+
387
+ ```js
388
+ const { ok } = await FastImage.getCachePath({
389
+ uri: photo.url,
390
+ cache: FastImage.cacheControl.cacheOnly,
391
+ })
392
+ ```
393
+
394
+ - The source's `headers`, `cacheKey` and `priority` apply, as for a view. Downloads wait in the same queue as `preload`'s, so they don't hold up the images on screen.
395
+ - The file belongs to the cache, which can remove it at any time: copy it to keep it.
396
+ - Its name may not have an image extension (on Android it ends in `.0` or `.1`): copy it with one for APIs that need it.
397
+ - A `file://` source is its own path. Other local images (`require()` in a release build, `content://`) have no file to give.
398
+ - With `cache: 'web'`, Android only keeps the file if the server allows caching it (in an HTTP cache), and returns `ok: false` otherwise. If the server compressed the image with `Content-Encoding` (rare for images), that file is compressed.
399
+
400
+ There's no way to remove a single image from the cache. To load an image again after it changed on the server, change its [`cacheKey`](#sourcecachekey-string).
401
+
374
402
  ## Troubleshooting
375
403
 
376
404
  If you have any problems using this library try the steps in [troubleshooting](docs/troubleshooting.md) and see if they fix it.
@@ -29,6 +29,7 @@ import java.util.Map;
29
29
  import java.util.WeakHashMap;
30
30
 
31
31
  import okhttp3.Cache;
32
+ import okhttp3.HttpUrl;
32
33
  import okhttp3.Interceptor;
33
34
  import okhttp3.JavaNetCookieJar;
34
35
  import okhttp3.MediaType;
@@ -50,6 +51,9 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
50
51
  // The HTTP cache of `cache: 'web'` images, once Glide has set up.
51
52
  @Nullable
52
53
  private static Cache webCache;
54
+ // The client that loads them, with that cache.
55
+ @Nullable
56
+ private static OkHttpClient webClient;
53
57
 
54
58
  // Empties the HTTP cache of `cache: 'web'` images (clearDiskCache).
55
59
  static void clearWebCache() throws IOException {
@@ -57,6 +61,43 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
57
61
  if (cache != null) cache.evictAll();
58
62
  }
59
63
 
64
+ // Downloads a `web` image (with its headers) through the client with the
65
+ // HTTP cache, which stores it if the server allows it (getCachePath).
66
+ // Blocking. Glide must be set up.
67
+ static void downloadToWebCache(GlideUrl url) throws IOException {
68
+ OkHttpClient client = webClient;
69
+ if (client == null) throw new IOException("Glide isn't set up");
70
+ Request.Builder request = new Request.Builder().url(url.toStringUrl());
71
+ for (Map.Entry<String, String> header : url.getHeaders().entrySet()) {
72
+ request.addHeader(header.getKey(), header.getValue());
73
+ }
74
+ try (Response response = client.newCall(request.build()).execute()) {
75
+ if (!response.isSuccessful()) {
76
+ // As Glide's HttpException reports it.
77
+ throw new IOException(response.message() + ", status code: " + response.code());
78
+ }
79
+ ResponseBody body = response.body();
80
+ if (body == null) return;
81
+ // Read to the end, so the cache stores it.
82
+ BufferedSource source = body.source();
83
+ Buffer buffer = new Buffer();
84
+ while (source.read(buffer, 8192) != -1) buffer.clear();
85
+ }
86
+ }
87
+
88
+ // The file with the body of url's response in the HTTP cache of
89
+ // `cache: 'web'` images (getCachePath), or null. OkHttp has no API for it:
90
+ // its cache stores each response as `<Cache.key(url)>.0` (headers) and
91
+ // `.1` (body, as the server sent it) once it's complete.
92
+ @Nullable
93
+ static File webCacheFile(String url) {
94
+ Cache cache = webCache;
95
+ HttpUrl httpUrl = HttpUrl.parse(url);
96
+ if (cache == null || httpUrl == null) return null;
97
+ File file = new File(cache.directory(), Cache.key(httpUrl) + ".1");
98
+ return file.isFile() ? file : null;
99
+ }
100
+
60
101
  @Override
61
102
  public void registerComponents(
62
103
  @NonNull Context context,
@@ -87,7 +128,7 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
87
128
  // Other urls are cached by Glide, so they don't use it (that would
88
129
  // store them twice).
89
130
  webCache = new Cache(new File(context.getCacheDir(), "fast-image-http-cache"), WEB_CACHE_SIZE);
90
- OkHttpClient webClient = client.newBuilder().cache(webCache).build();
131
+ webClient = client.newBuilder().cache(webCache).build();
91
132
  registry.prepend(FastImageWebGlideUrl.class, InputStream.class, new WebUrlLoaderFactory(webClient));
92
133
  }
93
134
 
@@ -138,7 +138,7 @@ class FastImageViewConverter {
138
138
  return options;
139
139
  }
140
140
 
141
- private static FastImageCacheControl getCacheControl(ReadableMap source) {
141
+ static FastImageCacheControl getCacheControl(ReadableMap source) {
142
142
  return getValueFromSource("cache", "immutable", FAST_IMAGE_CACHE_CONTROL_MAP, source);
143
143
  }
144
144
 
@@ -256,6 +256,165 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
256
256
  return result;
257
257
  }
258
258
 
259
+ // Where getCachePath looks in the caches and downloads `web` images
260
+ // (blocking calls, off the UI and modules threads).
261
+ private static final Executor cachePathExecutor = Executors.newSingleThreadExecutor();
262
+
263
+ private static WritableMap pathResult(File file) {
264
+ WritableMap result = Arguments.createMap();
265
+ result.putBoolean("ok", true);
266
+ result.putString("path", file.getAbsolutePath());
267
+ return result;
268
+ }
269
+
270
+ // The source's downloaded file in the disk cache, downloading it first if
271
+ // it isn't there (without decoding it or keeping it in memory, and in the
272
+ // preloads' queue): { ok, path } or { ok: false, error }. Never rejects.
273
+ // With `cacheOnly` it doesn't download. A local file is its own path.
274
+ @ReactMethod
275
+ public void getCachePath(final ReadableMap source, final Promise promise) {
276
+ final ReactApplicationContext context = getReactApplicationContext();
277
+ if (!FastImageViewConverter.hasUri(source)) {
278
+ promise.resolve(failure("Invalid source: no uri"));
279
+ return;
280
+ }
281
+ final FastImageSource imageSource = FastImageViewConverter.getImageSource(context, source);
282
+ if (imageSource.getUri().toString().isEmpty()) {
283
+ promise.resolve(failure("Invalid source: can't resolve " + source.getString("uri")));
284
+ return;
285
+ }
286
+ if ("file".equalsIgnoreCase(imageSource.getUri().getScheme())) {
287
+ File file = new File(imageSource.getUri().getPath());
288
+ promise.resolve(file.isFile() ? pathResult(file) : failure("No file at this uri"));
289
+ return;
290
+ }
291
+ if (!imageSource.isRemote()) {
292
+ // content://, a resource or a data uri: there's no file to give.
293
+ promise.resolve(failure("Not a remote image"));
294
+ return;
295
+ }
296
+ final boolean cacheOnly = FastImageViewConverter.getCacheControl(source) == FastImageCacheControl.CACHE_ONLY;
297
+ final RequestOptions options = FastImageViewConverter.getOptions(context, imageSource, source);
298
+ final RequestOptions preloadOptions = source.hasKey("priority") && !source.isNull("priority")
299
+ ? options
300
+ : options.priority(Priority.LOW);
301
+ final String url = imageSource.getUri().toString();
302
+ cachePathExecutor.execute(new Runnable() {
303
+ @Override
304
+ public void run() {
305
+ // On disk already: in Glide's cache (not for `web` images,
306
+ // which it doesn't cache), or in the HTTP cache of `web`
307
+ // images (set up by Glide, which is started first).
308
+ File file = null;
309
+ Glide.get(context);
310
+ if (!imageSource.isWebCache()) {
311
+ try {
312
+ file = Glide.with(context)
313
+ .asFile()
314
+ .load(imageSource.getSourceForLoad())
315
+ .apply(options)
316
+ .onlyRetrieveFromCache(true)
317
+ .submit()
318
+ .get();
319
+ } catch (Exception e) {
320
+ // Not in Glide's cache.
321
+ }
322
+ }
323
+ if (file == null) file = FastImageOkHttpProgressGlideModule.webCacheFile(url);
324
+ if (file != null) {
325
+ promise.resolve(pathResult(file));
326
+ return;
327
+ }
328
+ if (cacheOnly) {
329
+ promise.resolve(failure("Not in the disk cache"));
330
+ return;
331
+ }
332
+ UiThreadUtil.runOnUiThread(new Runnable() {
333
+ @Override
334
+ public void run() {
335
+ pendingPreloads.add(imageSource.isWebCache()
336
+ ? downloadToWebCache(imageSource, url, promise)
337
+ : downloadToDiskCache(context, imageSource, preloadOptions, promise));
338
+ startPendingPreloads();
339
+ }
340
+ });
341
+ }
342
+ });
343
+ }
344
+
345
+ // Frees a preload slot (on the UI thread) and resolves.
346
+ private static void finishDownload(final Promise promise, final WritableMap result) {
347
+ UiThreadUtil.runOnUiThread(new Runnable() {
348
+ @Override
349
+ public void run() {
350
+ preloadsInFlight--;
351
+ startPendingPreloads();
352
+ promise.resolve(result);
353
+ }
354
+ });
355
+ }
356
+
357
+ // Downloads the image into Glide's disk cache (as a disk-only preload).
358
+ private static Runnable downloadToDiskCache(
359
+ final Context context,
360
+ final FastImageSource imageSource,
361
+ final RequestOptions options,
362
+ final Promise promise) {
363
+ return new Runnable() {
364
+ @Override
365
+ public void run() {
366
+ Glide
367
+ .with(context)
368
+ .asFile()
369
+ .load(imageSource.getSourceForLoad())
370
+ .apply(options)
371
+ .listener(new RequestListener<File>() {
372
+ @Override
373
+ public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<File> target, boolean isFirstResource) {
374
+ finishDownload(promise, failure(FastImageRequestListener.errorMessage(e)));
375
+ return false;
376
+ }
377
+
378
+ @Override
379
+ public boolean onResourceReady(File file, Object model, Target<File> target, DataSource dataSource, boolean isFirstResource) {
380
+ finishDownload(promise, pathResult(file));
381
+ return false;
382
+ }
383
+ })
384
+ .preload();
385
+ }
386
+ };
387
+ }
388
+
389
+ // Downloads a `web` image into its HTTP cache, which keeps it only if the
390
+ // server allows caching it.
391
+ private static Runnable downloadToWebCache(
392
+ final FastImageSource imageSource,
393
+ final String url,
394
+ final Promise promise) {
395
+ return new Runnable() {
396
+ @Override
397
+ public void run() {
398
+ cachePathExecutor.execute(new Runnable() {
399
+ @Override
400
+ public void run() {
401
+ WritableMap result;
402
+ try {
403
+ FastImageOkHttpProgressGlideModule.downloadToWebCache(imageSource.getGlideUrl());
404
+ File file = FastImageOkHttpProgressGlideModule.webCacheFile(url);
405
+ result = file != null
406
+ ? pathResult(file)
407
+ : failure("Not stored in the disk cache (the server doesn't allow caching it)");
408
+ } catch (IOException e) {
409
+ result = failure(e.getMessage() != null ? e.getMessage() : e.toString());
410
+ }
411
+ finishDownload(promise, result);
412
+ }
413
+ });
414
+ }
415
+ };
416
+ }
417
+
259
418
  @ReactMethod
260
419
  public void clearMemoryCache(final Promise promise) {
261
420
  final Activity activity = getCurrentActivity();
package/dist/index.cjs.js CHANGED
@@ -195,6 +195,7 @@ FastImage.preload = (sources) => Promise.resolve(react_native.NativeModules.Fast
195
195
  }));
196
196
  FastImage.clearMemoryCache = () => react_native.NativeModules.FastImageView.clearMemoryCache();
197
197
  FastImage.clearDiskCache = () => react_native.NativeModules.FastImageView.clearDiskCache();
198
+ FastImage.getCachePath = (source) => Promise.resolve(react_native.NativeModules.FastImageView.getCachePath(source || {}));
198
199
  const styles = react_native.StyleSheet.create({
199
200
  fallbackImage: {
200
201
  position: "absolute",
@@ -53,6 +53,10 @@ export type LoadResult =
53
53
  | {| ok: true, width: number, height: number |}
54
54
  | {| ok: false, error: string |}
55
55
 
56
+ export type CachePathResult =
57
+ | {| ok: true, path: string |}
58
+ | {| ok: false, error: string |}
59
+
56
60
  export type PreloadSuccess = {|
57
61
  uri: string,
58
62
  ok: true,
@@ -118,4 +122,5 @@ declare export default class FastImage extends React$Component<FastImageProps> {
118
122
  static preload: PreloadFn;
119
123
  static clearMemoryCache: () => Promise<void>;
120
124
  static clearDiskCache: () => Promise<void>;
125
+ static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
121
126
  }
package/dist/index.d.ts CHANGED
@@ -62,6 +62,13 @@ export type LoadResult = {
62
62
  ok: false;
63
63
  error: string;
64
64
  };
65
+ export type CachePathResult = {
66
+ ok: true;
67
+ path: string;
68
+ } | {
69
+ ok: false;
70
+ error: string;
71
+ };
65
72
  export interface OnProgressEvent {
66
73
  nativeEvent: {
67
74
  loaded: number;
@@ -179,6 +186,12 @@ export interface FastImageStaticProperties {
179
186
  preload: (sources: Source[]) => Promise<PreloadResult[]>;
180
187
  clearMemoryCache: () => Promise<void>;
181
188
  clearDiskCache: () => Promise<void>;
189
+ /**
190
+ * The path of the source's downloaded file in the disk cache, downloading
191
+ * it first if it isn't there (without decoding it). With
192
+ * `cache: 'cacheOnly'` it doesn't download. Never rejects.
193
+ */
194
+ getCachePath: (source: Source) => Promise<CachePathResult>;
182
195
  }
183
196
  declare const FastImage: React.ComponentType<FastImageProps> & FastImageStaticProperties;
184
197
  export interface FastImageBackgroundProps extends Omit<FastImageProps, 'style' | 'children'> {
package/dist/index.js CHANGED
@@ -168,6 +168,7 @@ FastImage.preload = (sources) => Promise.resolve(NativeModules.FastImageView.pre
168
168
  }));
169
169
  FastImage.clearMemoryCache = () => NativeModules.FastImageView.clearMemoryCache();
170
170
  FastImage.clearDiskCache = () => NativeModules.FastImageView.clearDiskCache();
171
+ FastImage.getCachePath = (source) => Promise.resolve(NativeModules.FastImageView.getCachePath(source || {}));
171
172
  const styles = StyleSheet.create({
172
173
  fallbackImage: {
173
174
  position: "absolute",
@@ -53,6 +53,10 @@ export type LoadResult =
53
53
  | {| ok: true, width: number, height: number |}
54
54
  | {| ok: false, error: string |}
55
55
 
56
+ export type CachePathResult =
57
+ | {| ok: true, path: string |}
58
+ | {| ok: false, error: string |}
59
+
56
60
  export type PreloadSuccess = {|
57
61
  uri: string,
58
62
  ok: true,
@@ -118,4 +122,5 @@ declare export default class FastImage extends React$Component<FastImageProps> {
118
122
  static preload: PreloadFn;
119
123
  static clearMemoryCache: () => Promise<void>;
120
124
  static clearDiskCache: () => Promise<void>;
125
+ static getCachePath: (source: FastImageSource) => Promise<CachePathResult>;
121
126
  }
@@ -47,6 +47,27 @@ static SDWebImageMutableContext *FFFPreloadContext(FFFastImageSource *source)
47
47
  return context;
48
48
  }
49
49
 
50
+ // A preload's options: the prefetcher's (low priority), with the source's own
51
+ // priority instead if it has one (as on Android), and its `cache` (#406). One
52
+ // source at a time, not SDWebImagePrefetcher, to get each source's result and
53
+ // to send its headers with its own request only. Failed urls are tried again,
54
+ // as views do (SDWebImage otherwise fails a url that failed before, e.g. with
55
+ // data that isn't an image, without a request until the app is relaunched,
56
+ // #394).
57
+ static SDWebImageOptions FFFPreloadOptions(FFFastImageSource *source)
58
+ {
59
+ SDWebImageOptions options = [SDWebImagePrefetcher sharedImagePrefetcher].options | SDWebImageRetryFailed;
60
+ if (source.hasPriority) {
61
+ options &= ~(SDWebImageLowPriority | SDWebImageHighPriority);
62
+ if (source.priority == FFFPriorityLow) {
63
+ options |= SDWebImageLowPriority;
64
+ } else if (source.priority == FFFPriorityHigh) {
65
+ options |= SDWebImageHighPriority;
66
+ }
67
+ }
68
+ return options | [source cacheOptions];
69
+ }
70
+
50
71
  static NSUInteger FFFPreloadLimit(void)
51
72
  {
52
73
  NSUInteger limit = [SDWebImagePrefetcher sharedImagePrefetcher].maxConcurrentPrefetchCount;
@@ -91,11 +112,6 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
91
112
  resolve(results);
92
113
  }
93
114
  };
94
- // With the prefetcher's options (low priority), but one source at a
95
- // time (not SDWebImagePrefetcher), to get each source's result, to
96
- // send its headers with its own request only, and to follow its
97
- // `cache` (#406).
98
- SDWebImageOptions prefetcherOptions = [SDWebImagePrefetcher sharedImagePrefetcher].options;
99
115
 
100
116
  [sources enumerateObjectsUsingBlock:^(FFFastImageSource * _Nonnull source, NSUInteger idx, BOOL * _Nonnull stop) {
101
117
  if (!source.url) {
@@ -106,20 +122,7 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
106
122
  return;
107
123
  }
108
124
  [results addObject:[NSNull null]];
109
- // A source's own priority replaces the prefetcher's, as on Android.
110
- // Failed urls are tried again, as views do (SDWebImage otherwise
111
- // fails a url that failed before, e.g. with data that isn't an
112
- // image, without a request until the app is relaunched, #394).
113
- SDWebImageOptions options = prefetcherOptions | SDWebImageRetryFailed;
114
- if (source.hasPriority) {
115
- options &= ~(SDWebImageLowPriority | SDWebImageHighPriority);
116
- if (source.priority == FFFPriorityLow) {
117
- options |= SDWebImageLowPriority;
118
- } else if (source.priority == FFFPriorityHigh) {
119
- options |= SDWebImageHighPriority;
120
- }
121
- }
122
- options |= [source cacheOptions];
125
+ SDWebImageOptions options = FFFPreloadOptions(source);
123
126
  SDWebImageMutableContext *context = FFFPreloadContext(source);
124
127
  if (!source.memoryCache) {
125
128
  // Not decoded (only its header is read, for the size), and not
@@ -161,6 +164,82 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
161
164
  });
162
165
  }
163
166
 
167
+ // The source's downloaded file in the disk cache, downloading it first if it
168
+ // isn't there (without decoding it or keeping it in memory, and in the
169
+ // preloads' queue): { ok, path } or { ok: false, error }. Never rejects. With
170
+ // `cacheOnly` it doesn't download. A local file is its own path.
171
+ RCT_EXPORT_METHOD(getCachePath:(FFFastImageSource *)source
172
+ resolve:(RCTPromiseResolveBlock)resolve
173
+ reject:(__unused RCTPromiseRejectBlock)reject)
174
+ {
175
+ if (!source.url) {
176
+ resolve(@{@"ok": @NO, @"error": @"Invalid source: no uri"});
177
+ return;
178
+ }
179
+ if (source.url.isFileURL) {
180
+ BOOL exists = [NSFileManager.defaultManager fileExistsAtPath:source.url.path];
181
+ resolve(exists
182
+ ? @{@"ok": @YES, @"path": source.url.path}
183
+ : @{@"ok": @NO, @"error": @"No file at this uri"});
184
+ return;
185
+ }
186
+ SDWebImageMutableContext *context = FFFPreloadContext(source);
187
+ // The key SDWebImage stores it under (the cacheKey, or the converted url).
188
+ NSString *key = [SDWebImageManager.sharedManager cacheKeyForURL:source.url context:context];
189
+ SDImageCache *cache = SDImageCache.sharedImageCache;
190
+ void (^resolveFromDisk)(NSString *) = ^(NSString *error) {
191
+ [cache diskImageExistsWithKey:key completion:^(BOOL exists) {
192
+ resolve(exists
193
+ ? @{@"ok": @YES, @"path": [cache cachePathForKey:key]}
194
+ : @{@"ok": @NO, @"error": error});
195
+ }];
196
+ };
197
+ [cache diskImageExistsWithKey:key completion:^(BOOL exists) {
198
+ // On the main queue, where the preloads' queue is used.
199
+ if (exists) {
200
+ resolve(@{@"ok": @YES, @"path": [cache cachePathForKey:key]});
201
+ return;
202
+ }
203
+ if (source.cacheControl == FFFCacheControlCacheOnly) {
204
+ resolve(@{@"ok": @NO, @"error": @"Not in the disk cache"});
205
+ return;
206
+ }
207
+ if (!FFFPendingPreloads) {
208
+ FFFPendingPreloads = [NSMutableArray array];
209
+ }
210
+ // As a disk-only preload: not decoded, and not looked up in or kept in
211
+ // memory (an image in memory may not be on disk). It resolves once the
212
+ // file is written.
213
+ SDWebImageOptions options = FFFPreloadOptions(source) | SDWebImageAvoidDecodeImage | SDWebImageWaitStoreCache;
214
+ context[SDWebImageContextQueryCacheType] = @(SDImageCacheTypeDisk);
215
+ context[SDWebImageContextStoreCacheType] = @(SDImageCacheTypeDisk);
216
+ [FFFPendingPreloads addObject:[^{
217
+ __block BOOL done = NO;
218
+ [[SDWebImageManager sharedManager] loadImageWithURL:source.url
219
+ options:options
220
+ context:[context copy]
221
+ progress:nil
222
+ completed:^(UIImage *image, NSData *data, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) {
223
+ if (!finished || done) {
224
+ return;
225
+ }
226
+ done = YES;
227
+ FFFPreloadsInFlight--;
228
+ FFFStartPendingPreloads();
229
+ if (error) {
230
+ [source forgetResponseAfterError:error];
231
+ }
232
+ if (!image) {
233
+ resolve(@{@"ok": @NO, @"error": FFFErrorMessage(error)});
234
+ return;
235
+ }
236
+ resolveFromDisk(@"Not stored in the disk cache");
237
+ }];
238
+ } copy]];
239
+ FFFStartPendingPreloads();
240
+ }];
241
+ }
242
+
164
243
  RCT_EXPORT_METHOD(clearMemoryCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
165
244
  {
166
245
  [SDImageCache.sharedImageCache clearMemory];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "8.17.2",
3
+ "version": "8.18.0",
4
4
  "description": "🚩 FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",