Swift 3: Image Picker & Upload to S3

Being able to select multiple photos and upload to your own S3 bucket is a very important part for my wedding app. This can be easily achieved.

First of all, you need to install BSImagePicker.

Optionally, there is a cool spinner you can install to display the loading screen.

Then you will need to create a S3 bucket and Federated Identities with Cognito. The latter allows anyone who uses your app, not necessary authenticated (login with a password), to be able to execute Put to your S3 bucket.

You need to import the following libraries:

import UIKit
import Photos
import BSImagePicker
import SwiftSpinner
import AWSS3

To initialize AWS S3 Manager:

let BUCKET_NAME = ""
let POOL_ID = ""
let REGION = AWSRegionType.usEast1</code>

override func viewDidLoad() {

    let credentialsProvider = AWSCognitoCredentialsProvider(regionType:self.REGION, identityPoolId:self.POOL_ID)
    let configuration = AWSServiceConfiguration(region:self.REGION, credentialsProvider:credentialsProvider)
    AWSServiceManager.default().defaultServiceConfiguration = configuration

Then the IBOutlet for the upload button:

@IBAction func onClickUploadPhoto(_ sender: Any) {
    let imagePicker = BSImagePickerViewController()
    imagePicker.takePhotos = true
    bs_presentImagePickerController(imagePicker, animated: true,
        select: { (asset: PHAsset) -> Void in
        }, deselect: { (asset: PHAsset) -> Void in
        }, cancel: { (assets: [PHAsset]) -> Void in
        }, finish: { (assets: [PHAsset]) -> Void in
            print("selected \(assets.count) photos.")

            if (assets.count == 0) {

            DispatchQueue.main.async {
                SwiftSpinner.show("Uploading \(assets.count) photos to the cloud...")
            print("Get ready to upload photos...")

            DispatchQueue.global().async {
                var counter = 0
                for asset in assets {
                    let options: PHContentEditingInputRequestOptions = PHContentEditingInputRequestOptions()
                    asset.requestContentEditingInput(with: options, completionHandler: {
                        (input, info) in

                        let uploadRequest = AWSS3TransferManagerUploadRequest()!
                        uploadRequest.bucket = self.BUCKET_NAME
                        uploadRequest.key =  self.generateS3FileKey(fileName: (input?.fullSizeImageURL?.absoluteString)!)
                        uploadRequest.body = input?.fullSizeImageURL
                        uploadRequest.contentType = "image/jpg"

                        let transferManager = AWSS3TransferManager.default()
                        transferManager?.upload(uploadRequest).continue({ (task) -> AnyObject! in
                            counter += 1

                            if let error = task.error {
                                print("Upload photo \(input?.fullSizeImageURL) failed: \(error)")

                            if let exception = task.exception {
                                print("Upload photo \(input?.fullSizeImageURL) failed: \(exception)")

                            if task.result != nil {
                                print("Upload photo #\(counter) successfully! S3 Key: \(uploadRequest.key)")
                                DispatchQueue.main.async {
                                    SwiftSpinner.show("Uploaded \(counter)/\(assets.count) photos to the cloud.")

                            if (counter == assets.count) {
                                DispatchQueue.main.async {

                            return nil

        }, completion: nil)

That’s it! Enjoy!