react-native-fast-image 8.16.0 → 8.16.2

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
@@ -349,6 +349,8 @@ for (const result of results) {
349
349
  }
350
350
  ```
351
351
 
352
+ Each source's `cache` applies, as for a view: with `web` the preload follows the HTTP cache, and with `cacheOnly` it doesn't download. A `cacheOnly` preload resolves `ok` only if the image is cached, and loads it from the disk cache into memory, so a view shows it at once.
353
+
352
354
  ### `FastImage.clearMemoryCache: () => Promise<void>`
353
355
 
354
356
  Clear all images from memory cache.
@@ -2,6 +2,7 @@ package com.dylanvann.fastimage;
2
2
 
3
3
  import android.content.Context;
4
4
  import androidx.annotation.NonNull;
5
+ import androidx.annotation.Nullable;
5
6
 
6
7
  import com.bumptech.glide.Glide;
7
8
  import com.bumptech.glide.Registry;
@@ -42,6 +43,15 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
42
43
 
43
44
  private static final DispatchingProgressListener progressListener = new DispatchingProgressListener();
44
45
  private static final long WEB_CACHE_SIZE = 50 * 1024 * 1024;
46
+ // The HTTP cache of `cache: 'web'` images, once Glide has set up.
47
+ @Nullable
48
+ private static Cache webCache;
49
+
50
+ // Empties the HTTP cache of `cache: 'web'` images (clearDiskCache).
51
+ static void clearWebCache() throws IOException {
52
+ Cache cache = webCache;
53
+ if (cache != null) cache.evictAll();
54
+ }
45
55
 
46
56
  @Override
47
57
  public void registerComponents(
@@ -64,15 +74,14 @@ public class FastImageOkHttpProgressGlideModule extends LibraryGlideModule {
64
74
  OkHttpUrlLoader.Factory factory = new OkHttpUrlLoader.Factory(client);
65
75
  registry.replace(GlideUrl.class, InputStream.class, factory);
66
76
 
67
- // `cache: 'web'` skips Glide's caches and relies on HTTP caching, but
68
- // React Native's shared client has no HTTP cache (unless the app gave
69
- // it one), so those urls get a client with one (#280). Other urls are
70
- // cached by Glide, so they don't use it (that would store them twice).
71
- OkHttpClient webClient = client.cache() != null
72
- ? client
73
- : client.newBuilder()
74
- .cache(new Cache(new File(context.getCacheDir(), "fast-image-http-cache"), WEB_CACHE_SIZE))
75
- .build();
77
+ // `cache: 'web'` skips Glide's caches and relies on HTTP caching, so
78
+ // those urls get a client with an HTTP cache (#280): one of their own,
79
+ // not the app's (if it gave React Native's shared client one), so
80
+ // clearDiskCache can empty it without the app's other responses.
81
+ // Other urls are cached by Glide, so they don't use it (that would
82
+ // store them twice).
83
+ webCache = new Cache(new File(context.getCacheDir(), "fast-image-http-cache"), WEB_CACHE_SIZE);
84
+ OkHttpClient webClient = client.newBuilder().cache(webCache).build();
76
85
  registry.prepend(FastImageWebGlideUrl.class, InputStream.class, new WebUrlLoaderFactory(webClient));
77
86
  }
78
87
 
@@ -24,6 +24,7 @@ import com.facebook.react.bridge.UiThreadUtil;
24
24
  import com.facebook.react.bridge.WritableArray;
25
25
  import com.facebook.react.bridge.WritableMap;
26
26
 
27
+ import java.io.IOException;
27
28
  import java.util.ArrayDeque;
28
29
 
29
30
  class FastImageViewModule extends ReactContextBaseJavaModule {
@@ -190,6 +191,13 @@ class FastImageViewModule extends ReactContextBaseJavaModule {
190
191
  }
191
192
 
192
193
  Glide.get(activity.getApplicationContext()).clearDiskCache();
194
+ // And the HTTP cache of `cache: 'web'` images, which Glide doesn't
195
+ // cache.
196
+ try {
197
+ FastImageOkHttpProgressGlideModule.clearWebCache();
198
+ } catch (IOException e) {
199
+ // Cleared as far as it could.
200
+ }
193
201
  promise.resolve(null);
194
202
  }
195
203
  }
@@ -2,6 +2,8 @@
2
2
  #import <UIKit/UIKit.h>
3
3
  #import <SDWebImage/SDWebImageDownloaderRequestModifier.h>
4
4
  #import <SDWebImage/SDWebImageCacheKeyFilter.h>
5
+ #import <SDWebImage/SDWebImageDefine.h>
6
+ #import <SDWebImage/SDImageLoader.h>
5
7
 
6
8
  typedef NS_ENUM(NSInteger, FFFPriority) {
7
9
  FFFPriorityLow,
@@ -42,4 +44,17 @@ typedef NS_ENUM(NSInteger, FFFCacheControl) {
42
44
  // Caches the image under cacheKey, or nil without one.
43
45
  - (SDWebImageCacheKeyFilter *)cacheKeyFilter;
44
46
 
47
+ // The load options for `cache`: web follows the HTTP cache, cacheOnly never
48
+ // downloads. For views and preload alike.
49
+ - (SDWebImageOptions)cacheOptions;
50
+
51
+ // The loader for `cache: 'web'` images, whose HTTP cache is their own (see
52
+ // webURLCache), or nil for SDWebImage's shared one.
53
+ - (id<SDImageLoader>)imageLoader;
54
+
55
+ // The HTTP cache of `cache: 'web'` images: their own rather than the app's
56
+ // shared NSURLCache, so clearDiskCache can empty it without the app's other
57
+ // responses. 50 MB, as on Android.
58
+ + (NSURLCache *)webURLCache;
59
+
45
60
  @end
@@ -1,4 +1,9 @@
1
1
  #import "FFFastImageSource.h"
2
+ #import <SDWebImage/SDWebImageDownloader.h>
3
+ #import <SDWebImage/SDWebImageDownloaderResponseModifier.h>
4
+ #import <SDWebImage/SDWebImageDownloaderDecryptor.h>
5
+
6
+ static NSUInteger const FFFWebCacheSize = 50 * 1024 * 1024;
2
7
 
3
8
  @implementation FFFastImageSource
4
9
 
@@ -29,6 +34,71 @@
29
34
  }];
30
35
  }
31
36
 
37
+ - (SDWebImageOptions)cacheOptions
38
+ {
39
+ switch (_cacheControl) {
40
+ case FFFCacheControlWeb:
41
+ return SDWebImageRefreshCached;
42
+ case FFFCacheControlCacheOnly:
43
+ return SDWebImageFromCacheOnly;
44
+ case FFFCacheControlImmutable:
45
+ return 0;
46
+ }
47
+ return 0;
48
+ }
49
+
50
+ - (id<SDImageLoader>)imageLoader
51
+ {
52
+ if (_cacheControl != FFFCacheControlWeb) {
53
+ return nil;
54
+ }
55
+ static SDWebImageDownloader *downloader;
56
+ static dispatch_once_t once;
57
+ dispatch_once(&once, ^{
58
+ // As SDWebImage's shared downloader is set up, with the HTTP cache.
59
+ SDWebImageDownloaderConfig *config = [SDWebImageDownloader.sharedDownloader.config copy];
60
+ NSURLSessionConfiguration *session = [(config.sessionConfiguration ?: NSURLSessionConfiguration.defaultSessionConfiguration) copy];
61
+ session.URLCache = [FFFastImageSource webURLCache];
62
+ config.sessionConfiguration = session;
63
+ downloader = [[SDWebImageDownloader alloc] initWithConfig:config];
64
+ // The shared downloader's response modifier and decryptor, when it
65
+ // has them (as they are at each download). Its request modifier
66
+ // wouldn't apply anyway: each load's own (for its headers) replaces
67
+ // it. Headers set with setValue:forHTTPHeaderField: can't be read
68
+ // back, so web images don't get those.
69
+ downloader.responseModifier = [SDWebImageDownloaderResponseModifier responseModifierWithBlock:^NSURLResponse * _Nullable(NSURLResponse * _Nonnull response) {
70
+ id<SDWebImageDownloaderResponseModifier> shared = SDWebImageDownloader.sharedDownloader.responseModifier;
71
+ return shared ? [shared modifiedResponseWithResponse:response] : response;
72
+ }];
73
+ downloader.decryptor = [SDWebImageDownloaderDecryptor decryptorWithBlock:^NSData * _Nullable(NSData * _Nonnull data, NSURLResponse * _Nullable response) {
74
+ id<SDWebImageDownloaderDecryptor> shared = SDWebImageDownloader.sharedDownloader.decryptor;
75
+ return shared ? [shared decryptedDataWithData:data response:response] : data;
76
+ }];
77
+ });
78
+ return downloader;
79
+ }
80
+
81
+ + (NSURLCache *)webURLCache
82
+ {
83
+ static NSURLCache *cache;
84
+ static dispatch_once_t once;
85
+ dispatch_once(&once, ^{
86
+ NSString *name = @"fast-image-http-cache";
87
+ if (@available(iOS 13.0, tvOS 13.0, *)) {
88
+ NSURL *caches = [NSFileManager.defaultManager URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask].firstObject;
89
+ cache = [[NSURLCache alloc] initWithMemoryCapacity:0
90
+ diskCapacity:FFFWebCacheSize
91
+ directoryURL:[caches URLByAppendingPathComponent:name]];
92
+ } else {
93
+ // In the app's caches directory.
94
+ cache = [[NSURLCache alloc] initWithMemoryCapacity:0
95
+ diskCapacity:FFFWebCacheSize
96
+ diskPath:name];
97
+ }
98
+ });
99
+ return cache;
100
+ }
101
+
32
102
  - (SDWebImageDownloaderRequestModifier *)requestModifier
33
103
  {
34
104
  NSDictionary* headers = _headers;
@@ -500,17 +500,7 @@ NSString *FFFErrorMessage(NSError *error)
500
500
  break;
501
501
  }
502
502
 
503
- switch (_source.cacheControl) {
504
- case FFFCacheControlWeb:
505
- options |= SDWebImageRefreshCached;
506
- break;
507
- case FFFCacheControlCacheOnly:
508
- options |= SDWebImageFromCacheOnly;
509
- break;
510
- case FFFCacheControlImmutable:
511
- break;
512
- }
513
- return options;
503
+ return options | [_source cacheOptions];
514
504
  }
515
505
 
516
506
  // Headers, and the size to decode at (see FFFDownsampledImage), which it
@@ -518,6 +508,7 @@ NSString *FFFErrorMessage(NSError *error)
518
508
  - (SDWebImageContext*) loadContext {
519
509
  SDWebImageMutableContext* context = [NSMutableDictionary dictionary];
520
510
  context[SDWebImageContextDownloadRequestModifier] = _source.requestModifier;
511
+ context[SDWebImageContextImageLoader] = _source.imageLoader;
521
512
  context[SDWebImageContextCacheKeyFilter] = _source.cacheKeyFilter;
522
513
  CGSize box = [self decodeBox];
523
514
  self.decodedBox = box;
@@ -42,6 +42,7 @@ static SDWebImageMutableContext *FFFPreloadContext(FFFastImageSource *source)
42
42
  {
43
43
  SDWebImageMutableContext *context = [NSMutableDictionary dictionary];
44
44
  context[SDWebImageContextDownloadRequestModifier] = source.requestModifier;
45
+ context[SDWebImageContextImageLoader] = source.imageLoader;
45
46
  context[SDWebImageContextCacheKeyFilter] = source.cacheKeyFilter;
46
47
  return context;
47
48
  }
@@ -89,8 +90,9 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
89
90
  }
90
91
  };
91
92
  // With the prefetcher's options (low priority), but one source at a
92
- // time (not SDWebImagePrefetcher), to get each source's result and to
93
- // send its headers with its own request only.
93
+ // time (not SDWebImagePrefetcher), to get each source's result, to
94
+ // send its headers with its own request only, and to follow its
95
+ // `cache` (#406).
94
96
  SDWebImageOptions prefetcherOptions = [SDWebImagePrefetcher sharedImagePrefetcher].options;
95
97
 
96
98
  [sources enumerateObjectsUsingBlock:^(FFFastImageSource * _Nonnull source, NSUInteger idx, BOOL * _Nonnull stop) {
@@ -112,6 +114,7 @@ RCT_EXPORT_METHOD(preload:(nonnull NSArray<FFFastImageSource *> *)sources
112
114
  options |= SDWebImageHighPriority;
113
115
  }
114
116
  }
117
+ options |= [source cacheOptions];
115
118
  [FFFPendingPreloads addObject:[^{
116
119
  // Once per slot: SDWebImage calls this once with finished set
117
120
  // (a progressive load calls it more, without).
@@ -151,6 +154,8 @@ RCT_EXPORT_METHOD(clearMemoryCache:(RCTPromiseResolveBlock)resolve reject:(RCTPr
151
154
 
152
155
  RCT_EXPORT_METHOD(clearDiskCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
153
156
  {
157
+ // And the HTTP cache of `cache: 'web'` images.
158
+ [FFFastImageSource.webURLCache removeAllCachedResponses];
154
159
  [SDImageCache.sharedImageCache clearDiskOnCompletion:^(){
155
160
  resolve(NULL);
156
161
  }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-fast-image",
3
- "version": "8.16.0",
3
+ "version": "8.16.2",
4
4
  "description": "🚩 FastImage, performant React Native image component.",
5
5
  "keywords": [
6
6
  "cache",