Zaid Pathan
Zaid Pathan

Reputation: 16820

Swift - AWS S3 Upload Image from Photo Library and download it

I've looked many amazon docs but didn't find enough information to upload and download images to S3 using Swift.
How can I do that?

Upvotes: 12

Views: 11310

Answers (4)

Sarth Shah
Sarth Shah

Reputation: 93

The above answers were really helpful to me, but they're quite outdated due to a lot of the nomenclature being changed. So I'm providing an updated version of the answer based on the latest Swift frameworks.

Image Picker Controller:

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
   //getting details of image
   let uploadFileURL = info[UIImagePickerController.InfoKey.referenceURL] as! NSURL
           
   let imageName = uploadFileURL.lastPathComponent
   let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! as String
           
   // getting local path
   let localPath = (documentDirectory as NSString).appendingPathComponent(imageName!)
               
   //getting actual image
   let image = info[UIImagePickerController.InfoKey.originalImage] as! UIImage
   let data = image.pngData()
   let imageData = image.pngData()! as NSData
   
   let photoURL = NSURL(fileURLWithPath: localPath)
    
   self.uploadFileURL = photoURL
   self.uploadImage(inputData: imageData)
      do {
           let result = try data?.write(to: photoURL as URL, options: .atomic)
       } catch let error {
           print(error)
       }
   picker.dismiss(animated: true, completion: nil)
}
    

Upload Image:

A quick note on upload image. I hashed my filenames. This is not a necessary step, but I highly recommend to do so in the production stage just to ensure no filenames conflict in your S3 bucket.

func uploadImage(inputData: NSData) {
        
    //defining bucket and upload file name
    let S3BucketName: String = "your_bucket_name"
    
    let hashed = SHA256.hash(data: inputData)
    let S3UploadKeyName: String = hashed.compactMap { String(format: "%02x", $0) }.joined()
    
    let expression = AWSS3TransferUtilityUploadExpression()
            
    expression.progressBlock = {(task: AWSS3TransferUtilityTask, progress: Progress) in
        print(progress.fractionCompleted)
    }
              
    self.uploadCompletionHandler = { (task, error) -> Void in
        DispatchQueue.main.async(execute: {
            if ((error) != nil){
                print("Failed with error")
                print("Error: \(error!)")
            }
            else{
                print("Success")
            }
        })
    }
              
    let transferUtility = AWSS3TransferUtility.default()
               
    transferUtility.uploadFile(self.uploadFileURL! as URL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHandler: uploadCompletionHandler).continueWith { (task) -> AnyObject? in
        if let error = task.error {
            print("Error: \(error.localizedDescription)")
        }

        if let _ = task.result {
            print("Upload Starting!")
            // Do something with uploadTask.
        }
        
        return nil
    }
}

Upvotes: 0

Sheetal Shinde
Sheetal Shinde

Reputation: 529

func uploadFile(with resource: String, type: String) {
        let key = "\(resource).\(type)"
        let localImagePath = Bundle.main.path(forResource: resource, ofType: type)
        let localImageUrl = URL(fileURLWithPath: localImagePath!)
        let transferManager1 = AWSS3TransferUtility.default()
        let expression = AWSS3TransferUtilityUploadExpression()
        self.uploadCompletionHandler = { (task, error) -> Void in
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2, execute: {
                if ((error) != nil){
                    print("Failed with error")
                    print("Error: \(error!)");
                }
                else{
                    print("Sucess")
                }
            })
        }
        let transferUtility = AWSS3TransferUtility.default()
        transferUtility.uploadFile(localImageUrl, bucket: "", key: key, contentType: "video/mov", expression: expression, completionHandler: uploadCompletionHandler).continueWith { (task) -> AnyObject? in
            if let error = task.error {
                print("Error: \(error.localizedDescription)")
            }
            if let _ = task.result {
                print("Upload Starting!")
            }
            return nil;
        }
    }
@IBAction func uplaodVideo(){
    uploadFile(with: "random", type: "mov")
}

Upvotes: 0

zorro2b
zorro2b

Reputation: 2257

If all you want is to download the image, this is a much more concise and correct way to do it:

func downloadImage(bucketName: String, fileName: String, completion: (image: UIImage?, error: NSError?) -> Void) {
    let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()

    transferUtility.downloadDataFromBucket(bucketName, key: fileName, expression: nil) { (task, url, data, error) in
        var resultImage: UIImage?

        if let data = data {
            resultImage = UIImage(data: data)
        }

        completion(image: resultImage, error: error)
    }
}

Upvotes: 2

Zaid Pathan
Zaid Pathan

Reputation: 16820

After doing many research I've got this working,

import AWSS3
import AWSCore

Upload:

I assume you have implemented UIImagePickerControllerDelegate already.

Step 1:

  • Create variable for holding url:

    var imageURL = NSURL()
    
  • Create upload completion handler obj:

    var uploadCompletionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
    

Step 2: Get Image URL from imagePickerController(_:didFinishPickingMediaWithInfo:):

  • Set value of imageURL in this delegate method:

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]){
    
        //getting details of image
        let uploadFileURL = info[UIImagePickerControllerReferenceURL] as! NSURL
    
        let imageName = uploadFileURL.lastPathComponent
        let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first! as String
    
        // getting local path
        let localPath = (documentDirectory as NSString).stringByAppendingPathComponent(imageName!)
    
    
        //getting actual image
        let image = info[UIImagePickerControllerOriginalImage] as! UIImage
        let data = UIImagePNGRepresentation(image)
        data!.writeToFile(localPath, atomically: true)
    
        let imageData = NSData(contentsOfFile: localPath)!
        imageURL = NSURL(fileURLWithPath: localPath)
    
        picker.dismissViewControllerAnimated(true, completion: nil)
    }
    

Step 3: Call this uploadImage method after imageURL set to Upload Image to your bucket:

func uploadImage(){

    //defining bucket and upload file name
    let S3BucketName: String = "bucketName"
    let S3UploadKeyName: String = "public/testImage.jpg"


    let expression = AWSS3TransferUtilityUploadExpression()
    expression.uploadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
        dispatch_async(dispatch_get_main_queue(), {
            let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
            print("Progress is: \(progress)")
        })
    }

    self.uploadCompletionHandler = { (task, error) -> Void in
        dispatch_async(dispatch_get_main_queue(), {
            if ((error) != nil){
                print("Failed with error")
                print("Error: \(error!)");
            }
            else{
                print("Sucess")
            }
        })
    }

    let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()

    transferUtility.uploadFile(imageURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continueWithBlock { (task) -> AnyObject! in
        if let error = task.error {
            print("Error: \(error.localizedDescription)")
        }
        if let exception = task.exception {
            print("Exception: \(exception.description)")
        }
        if let _ = task.result {
            print("Upload Starting!")
        }

        return nil;
    }
}

Download:

func downloadImage(){

    var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?

    let S3BucketName: String = "bucketName"
    let S3DownloadKeyName: String = "public/testImage.jpg"

    let expression = AWSS3TransferUtilityDownloadExpression()
    expression.downloadProgress = {(task: AWSS3TransferUtilityTask, bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) in
        dispatch_async(dispatch_get_main_queue(), {
            let progress = Float(totalBytesSent) / Float(totalBytesExpectedToSend)
            print("Progress is: \(progress)")
        })
    }

    completionHandler = { (task, location, data, error) -> Void in
        dispatch_async(dispatch_get_main_queue(), {
            if ((error) != nil){
                print("Failed with error")
                print("Error: \(error!)")
            }
            else{
                //Set your image
                var downloadedImage = UIImage(data: data!)
            }
        })
    }

    let transferUtility = AWSS3TransferUtility.defaultS3TransferUtility()

    transferUtility.downloadToURL(nil, bucket: S3BucketName, key: S3DownloadKeyName, expression: expression, completionHander: completionHandler).continueWithBlock { (task) -> AnyObject! in
        if let error = task.error {
            print("Error: \(error.localizedDescription)")
        }
        if let exception = task.exception {
            print("Exception: \(exception.description)")
        }
        if let _ = task.result {
            print("Download Starting!")
        }
        return nil;
    }

}

Ref. for upload image

Ref. for download image

Many thanks to jzorz

Upvotes: 15

Related Questions