4

I have been pulling my hair out from Morning on trying to download the images (webp image) from Amazon S3 bucket and cache it. Whatever the approach I took, I have hit some or the other road block. Different ways I tried to achieve this,

  1. Subclassing NSURLProtocol & Using the SDWebImage to retrieve the image as shown in the blog post here. The problem with this approach is that, the canInitWithRequest method of the subclassed protocol will never get called even tough I have registered my subclassed NSURLProtocol class.
  2. Planned to use the SDWebImage and other libraries directly, but we can't do that since there is no provision to set the Authorization headers in SDWebImage, even tough if we try setting it, SDWebImage will ignore it while creating an NSMutableURLRequest for downloading.

So right now I am left with an option either to use the Amazon SDK to download the image and then cache it using the SDWebImage's SDImageCache independently, or I need to add the SDWebImage source code to my project and then I need to modify it's source to take the authorization header.

Please let me know if there's any better way to achieve this, it'd be great if I could some pointers on what'd be the best way to achieve what I am trying to do.

Thanks in advance.

iamyogish
  • 2,372
  • 2
  • 23
  • 40
  • You could use the AWS SDK for iOS or try using AWS Mobile Hub https://aws.amazon.com/mobile/ – Rohan Dubal Jun 15 '16 at 18:32
  • @RohanDubal Yeah I can use the AWS SDK, but the problem is that it doesn't support caching out of the box which is my main concern. – iamyogish Jun 15 '16 at 19:03
  • You could use Mobile Hub and enable User Files / Content delivery feature which downloads and stores files in cache so that you can open them natively in the app whenever you want. What is the specific use case? Does the before mentioned feature satisfy your use case? – Rohan Dubal Jun 15 '16 at 19:05
  • My use case is, I have to make my app work offline. I have to fetch images for list of items and have to cache them within the app. So that when user is not connected to the internet he/she would be able to see the images. I don't know about the Mobile Hub will take a look at it. – iamyogish Jun 15 '16 at 19:11
  • The mobile hub app should fit your use case. Do give it a try! – Rohan Dubal Jun 15 '16 at 23:24

2 Answers2

2

You can choose what key Kingfisher uses for the cache. So, create a presigned s3 url, then when loading the image use your s3 key as the cache rather then the full presigned url.

            let getPreSignedURLRequest = AWSS3GetPreSignedURLRequest()
            getPreSignedURLRequest.bucket = media.bucket
            getPreSignedURLRequest.key = media.key
            getPreSignedURLRequest.httpMethod = .GET
            getPreSignedURLRequest.expires = Date(timeIntervalSinceNow: 3600)  // Change the value of the expires time interval as required
            AWSS3PreSignedURLBuilder.default().getPreSignedURL(getPreSignedURLRequest).continueWith { (task:AWSTask<NSURL>) -> Any? in
                if let error = task.error as NSError? {
                    print("Error: \(error)")
                    return nil
                }
                if let presignedURL = task.result {
                    DispatchQueue.main.async {
                        self.imageView.kf.indicatorType = .activity
                        let resource = ImageResource(downloadURL: URL(string: presignedURL.absoluteString!)!, cacheKey: media.key)
                        self.imageView.kf.setImage(with: resource)
                    }
                }
                return nil
            }
Niklas
  • 1,322
  • 14
  • 11
  • Answer seems good, but it does not feel good when you are downloading images for a list, i.e, Table or collectionView. – AsifHabib Dec 26 '21 at 08:53
0

To be honest, I looked into this myself for a long time and was unsatisfied with the built in caching system offered by AWS. Instead, I chose to use Kingfisher https://github.com/onevcat/Kingfisher since it is built in swift and well used. I highly recommend it because it is highly customizable but also works perfectly "out of the box"

Garrett Cox
  • 703
  • 6
  • 10
  • Hi Garrett, I have used kingfisher for my other projects. But the problem is I can't use KF for this task out of the box. I have to tweak the way I download the images using KF. For example if I am using REST authentication for S3, I need to be able to send authorization headers which KF doesn't support. If I am using Amazon SDK to download the images then, I won't be downloading images using KF, I would be using it only for caching images downloaded using Amazon SDK. – iamyogish Jun 21 '16 at 05:01
  • Also please let me know how you downloaded images from S3 using KF. Did you just use the KF's cache for downloaded images or were you able to send authentication headers using KF or is there any method which you followed :). This would help me a great deal. Thanks – iamyogish Jun 21 '16 at 05:03
  • @iamyogish Great question, in my case I was able to user KF to download the images as well. This was because I made my images public. I understand that that is not a possibility for all cases. According to the KF documentation it looks like you can use build into the download request the auth header you need using an NSMutableURLRequest and just make sur to keep the / on the end to avoid [link]http://stackoverflow.com/questions/18885587/nsurlconnection-authorization-header-not-working – Garrett Cox Jun 21 '16 at 14:27