diff --git a/MVMCore/MVMCore/Constants/MVMCoreConstants.h b/MVMCore/MVMCore/Constants/MVMCoreConstants.h index 9774912..cf74414 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreConstants.h +++ b/MVMCore/MVMCore/Constants/MVMCoreConstants.h @@ -43,3 +43,6 @@ extern NSString * const URLComponentKeepAlive; extern NSString * const NotificationResponseLoaded; extern NSString * const MVMCoreNotificationGoingToServer; + +#pragma mark - Image Cache +extern NSTimeInterval const ImageTimeOut; diff --git a/MVMCore/MVMCore/Constants/MVMCoreConstants.m b/MVMCore/MVMCore/Constants/MVMCoreConstants.m index b0b9d17..c579b3b 100644 --- a/MVMCore/MVMCore/Constants/MVMCoreConstants.m +++ b/MVMCore/MVMCore/Constants/MVMCoreConstants.m @@ -29,3 +29,6 @@ NSString * const URLComponentKeepAlive = @"isAlive.jsp"; NSString * const NotificationResponseLoaded = @"responseLoaded"; NSString * const MVMCoreNotificationGoingToServer = @"MVMCoreGoServer"; + +#pragma mark - Image Cache +NSTimeInterval const ImageTimeOut = 60; diff --git a/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.h b/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.h index dc0daee..a737d45 100644 --- a/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.h +++ b/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.h @@ -44,7 +44,9 @@ typedef void(^FreebeeLoadFinishedHandler)(MVMCoreOperation* _Nullable freebeeOpe - (BOOL)isFreeBeeAuthorizedValidUrl:(nullable NSURL*)url; - (nullable NSString*)urlForidFromConfigDict:(nonnull NSString*)urlId; +// Tries to get the data using freebee. If freebee is not enabled, gets the data without freebee. - (nullable NSData*)freebee_dataWithContentsOfURL:(NSURL *_Nullable)url; +- (nullable NSCachedURLResponse*)freebee_dataWithImageURL:(NSURL *_Nullable)imageURL; - (void)configureFreeBeeWithDict:(nullable NSDictionary*)configDict withSessionReset:(BOOL)isReset; @end diff --git a/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.m b/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.m index 2a8d2cb..ef3a0fa 100644 --- a/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.m +++ b/MVMCore/MVMCore/LoadHandling/FreeBee/MFFreebeeHandler.m @@ -230,30 +230,45 @@ typedef NS_ENUM(NSUInteger, FreeBeeCampaignState) { } #pragma mark FreeBee Helper for NSData -- (nullable NSData*)freebee_dataWithContentsOfURL:(NSURL *)url { - - NSData* data = nil; - NSDictionary* proxyDict = [self proxyDictionaryforUrl:url]; + +- (nullable NSData *)freebeeDataWithURL:(NSURL *)url response:(NSURLResponse **)response { + NSData *data = nil; + NSDictionary *proxyDict = [self proxyDictionaryforUrl:url]; if ([self isFreeBeeEnabled] && [self isValidCampaign] && proxyDict && ![self isExpired] && [self isFreeBeeEnabledForCurrentModule]) { + + MVMCoreLog(@"Free Data Url, %@", url); + NSError *error = nil; + data = [self sendSynchronousRequest:url returningResponse:response error:&error]; + if (error) { + data = nil; + } + MVMCoreLog(@"freebee_dataWithContentsOfURL:Free Data, %lu", (unsigned long)data.length); + } + return data; +} - MVMCoreLog(@"Free Data Url, %@", url); - NSURLResponse* response = nil; - NSError* error = nil; - data = [self sendSynchronousRequest:url returningResponse:&response error:&error]; - - if (error) - data = nil; - - MVMCoreLog(@"freebee_dataWithContentsOfURL:Free Data, %lu", (unsigned long)data.length); - } else { +- (nullable NSData*)freebee_dataWithContentsOfURL:(NSURL *)url { + NSData *data = [self freebeeDataWithURL:url response:nil]; + if (!data) { data = [NSData dataWithContentsOfURL:url]; } return data; } +- (nullable NSCachedURLResponse*)freebee_dataWithImageURL:(NSURL *)imageURL { + + NSURLResponse *response = nil; + NSData *data = [self freebeeDataWithURL:imageURL response:&response]; + if (data) { + NSCachedURLResponse *cachedResponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; + return cachedResponse; + } + return nil; +} + #pragma mark - FreeBee Registration - (void)responseJSONUpdated:(nonnull NSNotification *)notification { diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m index e0c5884..bb97f89 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m @@ -13,6 +13,7 @@ #import "MFFreebeeHandler.h" #import "MVMCoreGetterUtility.h" #import "MVMCoreObject.h" +#import "MVMCoreConstants.h" @interface MVMCoreCache () @@ -456,31 +457,18 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; - (void)getGif:(nonnull NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 format:(nullable NSString *)format localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - BOOL isFallBackImage = NO; NSData *imageData = nil; if (pathOrName.length > 0) { - - if([pathOrName containsString:@"http"]) { - + if (pathOrName.length >=4 && [[pathOrName substringToIndex:4] isEqualToString:@"http"]) { // Gets the full path NSURL *s7URL = [self handleS7Path:pathOrName useWidth:useWidth widthForS7:widthForS7 useHeight:useHeight heightForS7:heightForS7 format:format finalRect:CGRectNull flipImage:NO]; if (s7URL) { - - // Check in memory cache - imageData = [self getCachedDataWithName:s7URL.absoluteString]; - - if (!imageData) { - imageData = [[MFFreebeeHandler sharedHandler] freebee_dataWithContentsOfURL:s7URL]; - if (imageData) { - [self addDataToCache:imageData withName:s7URL.absoluteString]; - } - } + [self downloadImage:s7URL isGif:YES fallbackImageName:fallbackImageName completionHandler:completionHandler]; + return; } } else { - // Try Local. Check in memory cache imageData = [self getCachedDataWithName:pathOrName]; - if (!imageData) { imageData = [NSData dataWithContentsOfFile:[[self bundleToUseForImages] pathForResource:pathOrName ofType:@"gif"]]; if (imageData) { @@ -489,25 +477,7 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; } } } - - // Set to the fallback image. - UIImage *fallbackImage = nil; - if (!imageData && fallbackImageName) { - isFallBackImage = YES; - // Grab fallback from cache - fallbackImage = [self getCachedImageWithName:fallbackImageName]; - if (!fallbackImage) { - - fallbackImage = [UIImage imageNamed:fallbackImageName inBundle:[self bundleToUseForImages] compatibleWithTraitCollection:nil]; - if (fallbackImage) { - - // Cache the fallback image if not already cached. - [self addImageToCache:fallbackImage withName:fallbackImageName]; - } - } - } - - completionHandler(fallbackImage, imageData, isFallBackImage); + [self checkImage:nil imageData:imageData fallbackImage:fallbackImageName completionHandler:completionHandler]; }); } @@ -518,60 +488,87 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; - (void)getImage:(nonnull NSString *)pathOrName useWidth:(BOOL)useWidth widthForS7:(NSInteger)widthForS7 useHeight:(BOOL)useHeight heightForS7:(NSInteger)heightForS7 format:(nullable NSString *)format finalRect:(CGRect)finalRect flipImage:(BOOL)flip localFallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - BOOL isFallBackImage = NO; - UIImage *img = nil; + UIImage *image = nil; if (pathOrName.length > 0) { - // try the url if it's a url. if (pathOrName.length >=4 && [[pathOrName substringToIndex:4] isEqualToString:@"http"]) { - // Gets the full path NSURL *s7URL = [self handleS7Path:pathOrName useWidth:useWidth widthForS7:widthForS7 useHeight:useHeight heightForS7:heightForS7 format:format finalRect:finalRect flipImage:flip]; if (s7URL) { - - // Check in memory cache - img = [self getCachedImageWithName:s7URL.absoluteString]; - - if (!img) { - NSData *imageData = [[MFFreebeeHandler sharedHandler] freebee_dataWithContentsOfURL:s7URL]; - img = [[UIImage alloc] initWithData:imageData scale:[UIScreen mainScreen].scale]; - if (img) { - [self addImageToCache:img withName:s7URL.absoluteString]; - } - } + [self downloadImage:s7URL isGif:NO fallbackImageName:fallbackImageName completionHandler:completionHandler]; + return; } } else { - // Try native image. Check in memory cache - img = [self getCachedImageWithName:pathOrName]; - - if (!img) { - img = [UIImage imageNamed:pathOrName inBundle:[self bundleToUseForImages] compatibleWithTraitCollection:nil]; - - if (img) { - [self addImageToCache:img withName:pathOrName]; + image = [self getCachedImageWithName:pathOrName]; + if (!image) { + image = [UIImage imageNamed:pathOrName inBundle:[self bundleToUseForImages] compatibleWithTraitCollection:nil]; + if (image) { + [self addImageToCache:image withName:pathOrName]; } } } } - - // Set to the fallback image. - if (!img && fallbackImageName) { - isFallBackImage = YES; - // Grab fallback from cache - img = [self getCachedImageWithName:fallbackImageName]; - if (!img) { + [self checkImage:image imageData:nil fallbackImage:fallbackImageName completionHandler:completionHandler]; + }); +} + +//download image +- (void)downloadImage:(NSURL *)s7URL isGif:(BOOL)isGif fallbackImageName:(nullable NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler { + + NSURLSession *session = [MVMCoreSessionObject sharedGlobal].session; + NSURLCache *sharedCache = session.configuration.URLCache; + NSURLRequest *request = [NSURLRequest requestWithURL:s7URL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:ImageTimeOut]; + + //use Freebee to download image first if it is not already in the cache, then store image to cache + NSCachedURLResponse *cachedResponse = [sharedCache cachedResponseForRequest:request]; + if (!cachedResponse.data) { + cachedResponse = [[MFFreebeeHandler sharedHandler] freebee_dataWithImageURL:s7URL]; + if (cachedResponse) { + //system stores cache based datatask and check cache based on response, + //need to manually store cache for response + [sharedCache storeCachedResponse:cachedResponse forRequest:request]; + } + } + //call nsurlsession again, if image is cached by Freebee, the second session will grab image data from cache instead of making another server call + NSURLSessionDownloadTask *downloadImageTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) { + NSData *data = [NSData dataWithContentsOfURL:location]; + //check data and response first, since they are nullable + if (data && response) { + NSCachedURLResponse *cachedReponse = [[NSCachedURLResponse alloc] initWithResponse:response data:data]; + //system stores cache based datatask and check cache based on response, + //need to manually store cache for response + [sharedCache storeCachedResponse:cachedReponse forRequest:request]; + } + if (isGif) { + [self checkImage:nil imageData:data fallbackImage:fallbackImageName completionHandler:completionHandler]; + } else { + UIImage *image = [UIImage imageWithData:data scale:[UIScreen mainScreen].scale]; + [self checkImage:image imageData:nil fallbackImage:fallbackImageName completionHandler:completionHandler]; + } + }]; + [downloadImageTask resume]; +} + +//check whether get image or imageData, if not, return fallbackImage +- (void)checkImage:(UIImage *)image imageData:(NSData *)imageData fallbackImage:(NSString *)fallbackImageName completionHandler:(nonnull MVMCoreGetImageBlock)completionHandler { + // Set to the fallback image. + BOOL isFallBackImage = NO; + if (!image && !imageData && fallbackImageName) { + isFallBackImage = YES; + // Grab fallback from cache + image = [self getCachedImageWithName:fallbackImageName]; + if (!image) { + + image = [UIImage imageNamed:fallbackImageName inBundle:[self bundleToUseForImages] compatibleWithTraitCollection:nil]; + if (image) { - img = [UIImage imageNamed:fallbackImageName inBundle:[self bundleToUseForImages] compatibleWithTraitCollection:nil]; - if (img) { - - // Cache the fallback image if not already cached. - [self addImageToCache:img withName:fallbackImageName]; - } + // Cache the fallback image if not already cached. + [self addImageToCache:image withName:fallbackImageName]; } } - completionHandler(img, nil, isFallBackImage); - }); + } + completionHandler(image, imageData, isFallBackImage); } - (nullable UIImage *)getCachedImageWithName:(nonnull NSString *)imageName {