luke
luke

Reputation: 2773

Uploading to S3 bucket Swift 3 issue

func startUploadingImage() {

    var localFileName:String?

// Issue #1: This here causes a segmentation fault 11 - Worked completely fine in swift 2.3
    if let imageToUploadUrl = selectedImageUrl {

        let phResult = PHAsset.fetchAssets(withALAssetURLs: [imageToUploadUrl], options: nil)
        localFileName = phResult.firstObject?.fileManager
    }

    if localFileName == nil {
        return
    }

    // Configure AWS Cognito Credentials
    let myIdentityPoolId = ""

    let credentialsProvider:AWSCognitoCredentialsProvider = AWSCognitoCredentialsProvider(regionType:AWSRegionType.euWest1, identityPoolId: myIdentityPoolId)

    let configuration = AWSServiceConfiguration(region:AWSRegionType.euWest1, credentialsProvider:credentialsProvider)

    AWSServiceManager.default().defaultServiceConfiguration = configuration

    // Set up AWS Transfer Manager Request
    let S3BucketName = ""

    let remoteName = localFileName!
    print(remoteName)
    let uploadRequest = AWSS3TransferManagerUploadRequest()
    uploadRequest?.body = generateImageUrl(remoteName)
    uploadRequest?.key = remoteName
    uploadRequest?.bucket = S3BucketName
    uploadRequest?.contentType = "image/jpeg"

    let transferManager = AWSS3TransferManager.default()

    // Perform file upload

// #issue 2: Here I recieve an error of ambiguous reference to member 'continue' 

    transferManager.upload(uploadRequest).continue {
        task -> AnyObject! in

        if let error = task.error {
            print("Upload failed with error: (\(error.localizedDescription))")
        }

        if let exception = task.exception {
            print("Upload failed with exception (\(exception))")
        }

        if task.result != nil {

            let s3URL = URL(string: "https://s3.amazonaws.com/\(S3BucketName)/\(uploadRequest.key!)")!
            print("Uploaded to:\n\(s3URL)")

            // Remove locally stored file
            self.remoteImageWithUrl(uploadRequest.key!)

            DispatchQueue.main.async {
                self.submitImageToDatabase("https://s3-eu-west-1.amazonaws.com/\(S3BucketName)/\(uploadRequest.key!)")
            }

        }
        else {
            print("Unexpected empty result.")
        }
        return nil
    }

}

Had a look at the AWS docs but can't seem to find nothing that's been updated since swift 3 (at least not that I can find). Most of it is written in Obj-c anyway which doesn't help.

I also seem to have the issues No such Module 'AWSS3' and No such Module 'AWSCore' even though they run fine when the project is built and i can cmd click to see the files.

Upvotes: 2

Views: 1829

Answers (3)

Saeed Ir
Saeed Ir

Reputation: 2332

We should use AWSS3TransferUtility now because AWSS3TransferManagerUploadRequest is deprecated, here is the jpeg upload function in Swift 4.2 but it can be easily changed for any data type:

func uploadS3(image: UIImage,
              name: String,
              progressHandler: @escaping (Progress) -> Void,
              completionHandler: @escaping (Error?) -> Void) {

    guard let data = UIImageJPEGRepresentation(image, Constants.uploadImageQuality) else {
        DispatchQueue.main.async {
            completionHandler(NetErrors.imageFormatError) // Replace your error
        }
        return
    }

    let credentialsProvider = AWSStaticCredentialsProvider(accessKey: Constants.accessKeyS3, secretKey: Constants.secretKeyS3)
    let configuration = AWSServiceConfiguration(region: Constants.regionS3, credentialsProvider: credentialsProvider)
    AWSServiceManager.default().defaultServiceConfiguration = configuration
    let expression = AWSS3TransferUtilityUploadExpression()
    expression.progressBlock = { task, progress in
        DispatchQueue.main.async {
            progressHandler(progress)
        }
    }

    AWSS3TransferUtility.default().uploadData(
        data,
        bucket: Constants.bucketS3,
        key: name,
        contentType: "image/jpg",
        expression: expression) { task, error in
            DispatchQueue.main.async {
                completionHandler(error)
            }
            print("Success")

        }.continueWith { task -> AnyObject? in
            if let error = task.error {
                DispatchQueue.main.async {
                    completionHandler(error)
                }
            }
            return nil
    }
}

Do not forget to define or change Constants in the code. If you don't want to give public access, you should also define a user in IAM, and put this code in your bucket policy:

{
  "Version": "2012-10-17",
  "Id": "S3AccessPolicy",
  "Statement": [
    {
      "Sid": "GiveAppPutAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/YOUR_USER"
      },
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Resource": "arn:aws:s3:::YOUR_BUCKET/*"
    }
  ]
}

Upvotes: 0

Karthick Selvaraj
Karthick Selvaraj

Reputation: 2505

func uploadButtonPressed(_ sender: AnyObject) {
    if documentImageView.image == nil {
       // Do something to wake up user :) 
    } else {
        let image = documentImageView.image!
        let fileManager = FileManager.default
        let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("\(imageName!).jpeg")
        let imageData = UIImageJPEGRepresentation(image, 0.99)
        fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)

        let fileUrl = NSURL(fileURLWithPath: path)
        var uploadRequest = AWSS3TransferManagerUploadRequest()
        uploadRequest?.bucket = "BucketName"
        uploadRequest?.key = "key.jpeg"
        uploadRequest?.contentType = "image/jpeg"
        uploadRequest?.body = fileUrl as URL!
        uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
        uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
            DispatchQueue.main.async(execute: {
                self.amountUploaded = totalBytesSent // To show the updating data status in label.
                self.fileSize = totalBytesExpectedToSend
            })
        }

        let transferManager = AWSS3TransferManager.default()
        transferManager?.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), withSuccessBlock: { (taskk: AWSTask) -> Any? in
            if taskk.error != nil {
               // Error.
            } else {
                // Do something with your result.
            }
            return nil
        })
    }
}

This is the complete code to upload an image to Amazon S3 written in swift 3 . TO configure your cognate identity pool add following code in app delegate.

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    customiseAppearance()

    let credentialsProvider =AWSCognitoCredentialsProvider(regionType:"YOUR REGION",identityPoolId:"YOUR POOL ID")
    let configuration = AWSServiceConfiguration(region:"YOUR REGION",    credentialsProvider:credentialsProvider)
    AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
    return true
}

Let me answer to this error No such Module 'AWSS3' and No such Module 'AWSCore' , Check whether you added the AWSS3 framework and AWSCore framework in bridging header file like

#import <AWSCore/AWSCore.h>

Thanks!!

Upvotes: 5

Mohamed Jaleel Nazir
Mohamed Jaleel Nazir

Reputation: 5821

Update cocoapods to 1.0.0 version

gem list | grep cocoa

cocoapods (1.0.0)

Upvotes: 0

Related Questions