最近一个项目RN版本是0.61,因里面有个图片浏览功能,要做一个清理缓存的功能。一番捣鼓后功能解决,记录如下
找到的清理缓存组建是react-native-http-cache,因为该组建长期没人维护android编译不过,本人又不善长android,遂找了个进化版react-native-http-cache3。这个在安卓上面需要更改两个地方才可正常工作,不做讨论,本文主要是讲ios上面。
iOS在解决了2个bug之后这个组建也能使用,但是发现ios导给rn的方法getImageCacheSize以及clearImageCache都只是空实现,没有具体内容。原因下面解释。
三年前我写的分析RN端图片缓存的策略(https://www.jianshu.com/p/c7376db9b7ec),当时图片是没有磁盘缓存的,内存缓存也无效。现在再看下新的RN版本图片缓存相关代码,经过测试发现,对解压后2M以内的图片,内存缓存生效。磁盘缓存依旧没有。正因为没有磁盘缓存,所谓的清理图片缓存也就不存在,于是方法为空实现也就能理解了。
本人项目中有图片浏览功能,当预览图片时图片是高清的原图,比较大,按照rn默认的行为图片不做缓存,那么每次预览时都会去下载,很缓慢,影响体验。而且因为图片远大于2M内存缓存也无法生效,效果很差劲。这里需要自定义图片的缓存
网上搜索了一圈发现都是解决方案都是使用react-native-img-cache,但是要求使用特定的
翻看RN图片加载相关的代码,发现了关键地方。在RCTImageLoaderProtocol.h这个图片加载相关的协议里面发现
/**
* Allows developers to set their own caching implementation for
* decoded images as long as it conforms to the RCTImageCache
* protocol. This method should be called in bridgeDidInitializeModule.
*/
- (void)setImageCache:(id)cache;
很明显,这里可以让开发者自定义图片的缓存类,只需实现RCTImageCache协议即可。
很简单,我使用SDWebImage实现了这个协议
#import "PSImageCache.h"
#import
@implementation PSImageCache
- (UIImage *)imageForUrl:(NSString *)url
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode{
if (!url) return nil;
return [[SDImageCache sharedImageCache] imageFromCacheForKey:url];
}
- (void)addImageToCache:(UIImage *)image
URL:(NSString *)url
size:(CGSize)size
scale:(CGFloat)scale
resizeMode:(RCTResizeMode)resizeMode
response:(NSURLResponse *)response{
if (!image || !url) return;
[[SDImageCache sharedImageCache] storeImage:image forKey:url completion:nil];
}
@end
现在只需要在一个合适的时机,将自定义的PSImageCache类赋值给RCTImageLoader即可。
多方实验,如下最佳实践。在didFinishLaunchingWithOptions中
// 监听RCTImageLoader模块加载完毕,自定义imageCache为sdwebimage缓存图片
[[NSNotificationCenter defaultCenter] addObserverForName:RCTDidInitializeModuleNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
RCTImageLoader *imageLoader = note.userInfo[@"module"];
if ([imageLoader isKindOfClass:[RCTImageLoader class]]) {
[imageLoader setImageCache:[PSImageCache new]];
}
}];
现在图片缓存已经走Sdwebcache通道了,一切正常。最上面说的清理缓存的两个空方法需要更改下。将Podfile中倒入的react-native-http-cache3删除,RNHttpCache文件挪到本地文件,修改getImageCacheSize和clearImageCache方法
RCT_EXPORT_METHOD(getImageCacheSize:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
resolve(@([[SDImageCache sharedImageCache] totalDiskSize]));
}
RCT_EXPORT_METHOD(clearImageCache:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject)
{
[[SDImageCache sharedImageCache] clearDiskOnCompletion:^{
resolve(nil);
}];
}
大功告成!