Upload Image, video, audio, and any type of files to AWS S3 Bucket Swift

Nowadays AWS S3 Bucket is a very popular library to upload files like image, video, audio, etc. We are going to use AWS iOS SDK and we will create an AWSS3Manager class, using this manager class, we will upload any files by writing just one line code. AWSS3Manager class will make it super easy to upload any type of files. Let’s not wait anymore and start coding…
We suppose you already have AWS S3 Bucket setup, Pool-Id and bucket name, we will need these informations.
– Create a new project or you can use your existing project as well.
– Open a terminal and navigate to your project.
– Run a command: pod init

-Open the Podfile and write: pod ‘AWSS3’
-Now open the terminal again and run the command: pod install
Now your project file will look like below.

Now open S3BucketUpload.xcworkspace file from onward.

Setup AWS Credentials

Open AppDelegate.swift file and make below changes.
import UIKit
import AWSS3 // 1

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?


    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        
        self.initializeS3() //2
        return true
    }
    //3
    func initializeS3() {
        let poolId = "***** your poolId *****" // 3-1
        let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USWest1, identityPoolId: poolId)//3-2
        let configuration = AWSServiceConfiguration(region: .USWest1, credentialsProvider: credentialsProvider)
        AWSServiceManager.default().defaultServiceConfiguration = configuration
        
        
    }

1 import AWSS3 framework
2 Call this function to set AWS up credential
3-1 Enter your pool Id
3-2 Change your region based on your AWS account region.

Creating AWSS3Manager class

Create a new swift file and name it AWSS3Manager

Add below code in this file.
import Foundation
import UIKit
import AWSS3 //1

typealias progressBlock = (_ progress: Double) -> Void //2
typealias completionBlock = (_ response: Any?, _ error: Error?) -> Void //3

class AWSS3Manager {
    
    static let shared = AWSS3Manager() // 4
    private init () { }
    let bucketName = "***** your bucket name *****" //5
    
    // Upload image using UIImage object
    func uploadImage(image: UIImage, progress: progressBlock?, completion: completionBlock?) {
        
        guard let imageData = image.jpegData(compressionQuality: 1.0) else {
            let error = NSError(domain:"", code:402, userInfo:[NSLocalizedDescriptionKey: "invalid image"])
            completion?(nil, error)
            return
        }
        
        let tmpPath = NSTemporaryDirectory() as String
        let fileName: String = ProcessInfo.processInfo.globallyUniqueString + (".jpeg")
        let filePath = tmpPath + "/" + fileName
        let fileUrl = URL(fileURLWithPath: filePath)
        
        do {
            try imageData.write(to: fileUrl)
            self.uploadfile(fileUrl: fileUrl, fileName: fileName, contenType: "image", progress: progress, completion: completion)
        } catch {
            let error = NSError(domain:"", code:402, userInfo:[NSLocalizedDescriptionKey: "invalid image"])
            completion?(nil, error)
        }
    }
    
    // Upload video from local path url
    func uploadVideo(videoUrl: URL, progress: progressBlock?, completion: completionBlock?) {
        let fileName = self.getUniqueFileName(fileUrl: videoUrl)
        self.uploadfile(fileUrl: videoUrl, fileName: fileName, contenType: "video", progress: progress, completion: completion)
    }
    
    // Upload auido from local path url
    func uploadAudio(audioUrl: URL, progress: progressBlock?, completion: completionBlock?) {
        let fileName = self.getUniqueFileName(fileUrl: audioUrl)
        self.uploadfile(fileUrl: audioUrl, fileName: fileName, contenType: "audio", progress: progress, completion: completion)
    }
    
    // Upload files like Text, Zip, etc from local path url
    func uploadOtherFile(fileUrl: URL, conentType: String, progress: progressBlock?, completion: completionBlock?) {
        let fileName = self.getUniqueFileName(fileUrl: fileUrl)
        self.uploadfile(fileUrl: fileUrl, fileName: fileName, contenType: conentType, progress: progress, completion: completion)
    }
    
    // Get unique file name
    func getUniqueFileName(fileUrl: URL) -> String {
        let strExt: String = "." + (URL(fileURLWithPath: fileUrl.absoluteString).pathExtension)
        return (ProcessInfo.processInfo.globallyUniqueString + (strExt))
    }
    
    //MARK:- AWS file upload
    // fileUrl :  file local path url
    // fileName : name of file, like "myimage.jpeg" "video.mov"
    // contenType: file MIME type
    // progress: file upload progress, value from 0 to 1, 1 for 100% complete
    // completion: completion block when uplaoding is finish, you will get S3 url of upload file here
    private func uploadfile(fileUrl: URL, fileName: String, contenType: String, progress: progressBlock?, completion: completionBlock?) {
        // Upload progress block
        let expression = AWSS3TransferUtilityUploadExpression()
        expression.progressBlock = {(task, awsProgress) in
            guard let uploadProgress = progress else { return }
            DispatchQueue.main.async {
                uploadProgress(awsProgress.fractionCompleted)
            }
        }
        // Completion block
        var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
        completionHandler = { (task, error) -> Void in
            DispatchQueue.main.async(execute: {
                if error == nil {
                    let url = AWSS3.default().configuration.endpoint.url
                    let publicURL = url?.appendingPathComponent(self.bucketName).appendingPathComponent(fileName)
                    print("Uploaded to:\(String(describing: publicURL))")
                    if let completionBlock = completion {
                        completionBlock(publicURL?.absoluteString, nil)
                    }
                } else {
                    if let completionBlock = completion {
                        completionBlock(nil, error)
                    }
                }
            })
        }
        // Start uploading using AWSS3TransferUtility
        let awsTransferUtility = AWSS3TransferUtility.default()
        awsTransferUtility.uploadFile(fileUrl, bucket: bucketName, key: fileName, contentType: contenType, expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in
            if let error = task.error {
                print("error is: \(error.localizedDescription)")
            }
            if let _ = task.result {
                // your uploadTask
            }
            return nil
        }
    }
}

1 import AWSS3 framework
2 This is progress block which tells us how much data has been uploaded
3 This is the completion block which executes when uploading finish
4 Create a shared instance of this class
5 Enter your bucket name here

Move to ViewController class

Open the nib file and add controls as shown in the below image

– Create an IBOutlet of UIProgressView and uploaded file URL UILabel.
– Add IBActions on all four buttons.
The code will look like below
import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var s3UrlLabel: UILabel!
    @IBOutlet weak var progressView: UIProgressView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        self.progressView.progress = Float(0.0)
    }
    
    @IBAction func tapUploadImage(_ sender: Any) {
    }
    
    @IBAction func tapUploadVideo(_ sender: Any) {
    }
    
    @IBAction func tapUploadAudio(_ sender: Any) {
    }
    
    @IBAction func tapUploadFile(_ sender: Any) {
    }
}

Upload Image

We are going to use below function of AWSS3Manager class.
func uploadImage(image: UIImage, progress: progressBlock?, completion: completionBlock?)
Add below code in your tapUploadImage function which is inside your UIViewController class
@IBAction func tapUploadImage(_ sender: Any) {
    
    guard let image = UIImage(named: "your-image") else { return } //1
    AWSS3Manager.shared.uploadImage(image: image, progress: {[weak self] ( uploadProgress) in
        
        guard let strongSelf = self else { return }
        strongSelf.progressView.progress = Float(uploadProgress)//2
        
    }) {[weak self] (uploadedFileUrl, error) in
        
        guard let strongSelf = self else { return }
        if let finalPath = uploadedFileUrl as? String { // 3
            strongSelf.s3UrlLabel.text = "Uploaded file url: " + finalPath
        } else {
            print("\(String(describing: error?.localizedDescription))") // 4
        }
    }
    
}
1 Get your image
2 Update the progress bar
3 In the completion block, you will get the uploaded image URL string

Upload Video

Below function is define under AWSS3Manager class to upload video, we are going to use this
// Upload video from local path url
func uploadVideo(videoUrl: URL, progress: progressBlock?, completion: completionBlock?)
Add below code in your tapUploadVideo function
@IBAction func tapUploadVideo(_ sender: Any) {
    
    //guard let path = Bundle.main.path(forResource: "Video", ofType: "mov") else { return }
    let videoUrl = URL(fileURLWithPath: "your video file path")
    AWSS3Manager.shared.uploadVideo(videoUrl: videoUrl, progress: { [weak self] (progress) in
        
        guard let strongSelf = self else { return }
        strongSelf.progressView.progress = Float(progress)
        
    }) { [weak self] (uploadedFileUrl, error) in
        
        guard let strongSelf = self else { return }
        if let finalPath = uploadedFileUrl as? String {
            strongSelf.s3UrlLabel.text = "Uploaded file url: " + finalPath
        } else {
            print("\(String(describing: error?.localizedDescription))")
        }
    }
}
Now run the code and upload a video.

Upload Audio

To upload audio we will use the below function of AWSS3Manager
// Upload auido from local path url
func uploadAudio(audioUrl: URL, progress: progressBlock?, completion: completionBlock?)
Add below code in your tapUploadAudio function
@IBAction func tapUploadAudio(_ sender: Any) {
    
    let audioUrl = URL(fileURLWithPath: "your audio local file path")
    AWSS3Manager.shared.uploadAudio(audioUrl: audioUrl, progress: { [weak self] (progress) in
        
        guard let strongSelf = self else { return }
        strongSelf.progressView.progress = Float(progress)
        
    }) { [weak self] (uploadedFileUrl, error) in
        
        guard let strongSelf = self else { return }
        if let finalPath = uploadedFileUrl as? String {
            strongSelf.s3UrlLabel.text = "Uploaded file url: " + finalPath
        } else {
            print("\(String(describing: error?.localizedDescription))")
        }
    }
}

Upload other files like plain text, zip, etc

To upload other files, we will use the below function of AWSS3Manager class
// Upload files like Text, Zip, etc from local path url
func uploadOtherFile(fileUrl: URL, conentType: String, progress: progressBlock?, completion: completionBlock?)
Add below code in your tapUploadAudio function
@IBAction func tapUploadAudio(_ sender: Any) {
    
    let audioUrl = URL(fileURLWithPath: "your audio local file path")
    AWSS3Manager.shared.uploadAudio(audioUrl: audioUrl, progress: { [weak self] (progress) in
        
        guard let strongSelf = self else { return }
        strongSelf.progressView.progress = Float(progress)
        
    }) { [weak self] (uploadedFileUrl, error) in
        
        guard let strongSelf = self else { return }
        if let finalPath = uploadedFileUrl as? String {
            strongSelf.s3UrlLabel.text = "Uploaded file url: " + finalPath
        } else {
            print("\(String(describing: error?.localizedDescription))")
        }
    }
}

Read our next article: UIDatePicker as inputView to UITextField in just one line

4 comments on “Upload Image, video, audio, and any type of files to AWS S3 Bucket Swift

  1. robert

    Do you have a tutorial that I can follow that will help with setting up the S3 portion of so that the proper permissions and setup will allow this to work?

    Reply
  2. Daniel

    Hi
    Great tutorial, if you want make public your upload files, you can add this line
    {code}
    expression.setValue(“public-read”, forRequestHeader: “x-amz-acl”)
    {code}
    after create expression constant

    Reply
  3. it should not be this hard

    Value of type ‘AWSS3TransferUtilityUploadExpression’ has no member ‘progressBlock’

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *