I have implemented the AWSS3 to upload the video to the AWS server and also I want to get the value of task which has been completed using AWSS3TransferUtilityUploadExpression() to show the value on progress bar. But I am not getting the value please see the below code atached.
///1
typealias progressBlock = (_ progress: Double) -> Void //2
typealias completionBlock = (_ response: Any?, _ error: Error?) -> Void //3
//2
// Upload video from local path url
func uploadVideo(videoUrl: URL, progress: progressBlock?, completion: completionBlock?) {
print("video url is \(videoUrl)")
let fileName = self.getUniqueFileName(fileUrl: videoUrl)
print("keyname \(fileName)")
self.uploadfile(fileUrl: videoUrl, fileName: fileName, contenType: "video", progress: progress, completion: completion)
}
//method to upload the video
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 {
debugPrint("completed portion of the task is \(awsProgress.fractionCompleted)")
uploadProgress(awsProgress.fractionCompleted)
//progress!(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)
if let completionBlock = completion {
completionBlock(publicURL?.absoluteString, nil)
}
} else {
if let completionBlock = completion {
print("error is at completionBlock \(error?.localizedDescription)")
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 url = task.result {
// your uploadTask
print("url is \(url)")
}
return nil
}
}
Install cocoapods pod 'AWSS3'.
Here filePath is the path of the file to be uploaded.
func saveModelInAmazonS3() {
let remoteName = fileName + ".mov" //extension of your file name
let S3BucketName = "bucketName"
let uploadRequest = AWSS3TransferManagerUploadRequest()!
uploadRequest.body = filePath!
uploadRequest.key = remoteName
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "application/zip"
uploadRequest.acl = .publicRead
uploadRequest.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: { // here you can track your progress
let amountUploaded = totalBytesSent
let fileSize = totalBytesExpectedToSend
print("\(amountUploaded)/\(fileSize)")
let progress = (CGFloat(amountUploaded) / CGFloat(fileSize)))
})
}
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest).continueWith(block: { (task: AWSTask) -> Any? in
if let error = task.error {
self.delegate.errorInUpload(uploadState: self.uploadState)
print("Upload failed with error: (\(error.localizedDescription))")
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
print("Uploaded to:\(String(describing: url))")
}
return nil
})
}
Related
I'm trying to make a simple Instagram Clone App to learn more about Firebase. So far I can share Images, Comments, Likes, but when it comes to videos, the app fails to do that. I mange to upload the Videofile to the Storage, but I don't get the videoUrl to the Database. I'm grateful for suggestions.
class ShareService {
static var REF_STORAGE_POST = Storage.storage().reference().child("posts")
static func uploadDataToStorage(imageData: Data, videoUrl: URL? = nil, postText: String, imageRatio: CGFloat, onSuccess: #escaping () -> Void ) {
// 1. upload Video
if let _videoUrl = videoUrl {
self.uploadVideoToFireBaseStorage(videoUrl: _videoUrl, onSucces: { (videoUrlString) in
self.uploadImageToFireBaseStorage(data: imageData, onSucces: { (thumbnailUrlString) in
self.uploadDataToDatabase(imageUrl: thumbnailUrlString, videoUrl: videoUrlString, postText: postText, imageRatio: imageRatio, onSuccess: onSuccess)
})
})
} else {
// 2. upload image
self.uploadImageToFireBaseStorage(data: imageData, onSucces: { (imageUrlString) in
self.uploadDataToDatabase(imageUrl: imageUrlString, postText: postText, imageRatio: imageRatio, onSuccess: onSuccess)
})
}
}
fileprivate static func uploadVideoToFireBaseStorage(videoUrl: URL, onSucces: #escaping (_ videoUrl: String) -> Void) {
let videoIdString = NSUUID().uuidString
let storageRef = REF_STORAGE_POST.child(videoIdString)
print(videoUrl)
let metadata = StorageMetadata()
//specify MIME type
metadata.contentType = "video/quicktime"
if let videoUrl = NSData(contentsOf: videoUrl) as Data? {
storageRef.putData(videoUrl, metadata: metadata) { (metaData, error) in
if error != nil {
print("upload video error")
}
}
storageRef.downloadURL(completion: { (url, error) in
if error != nil {
print(error!.localizedDescription)
return
}
let videoUrlString = url?.absoluteString
onSucces(videoUrlString ?? "no video")
})
}
}
// upload image
fileprivate static func uploadImageToFireBaseStorage(data: Data, onSucces: #escaping (_ imageUrl: String) -> Void) {
let photoIdString = NSUUID().uuidString
let storageRef = REF_STORAGE_POST.child(photoIdString)
storageRef.putData(data, metadata: nil) { (metaData, error) in
if error != nil {
print("upload image error")
}
storageRef.downloadURL(completion: { (url, error) in
if error != nil {
print(error!.localizedDescription)
return
}
let imageUrlString = url?.absoluteString
onSucces(imageUrlString ?? "no image")
})
}
}
fileprivate static func uploadDataToDatabase(imageUrl: String, videoUrl: String? = nil, postText: String, imageRatio: CGFloat, onSuccess: #escaping () -> Void) {
let newPostId = PostApi.shared.REF_POSTS.childByAutoId().key
let newPostRef = PostApi.shared.REF_POSTS.child(newPostId!)
let postTime = Date().timeIntervalSince1970
print(postTime)
guard let currentUserUid = UserApi.shared.CURRENT_USER_UID else { return }
var dic = ["uid" : currentUserUid, "imageUrl" : imageUrl, "imageRatio" : imageRatio, "postText" : postText] as [String : Any]
if let _videoUrl = videoUrl {
dic["videoUrl"] = _videoUrl
}
newPostRef.setValue(dic) { (error, _) in
if error != nil {
print(error?.localizedDescription as Any)
}
// Show posts in newsfeed
FeedApi.shared.REF_NEWSFEED.child(currentUserUid).child(newPostId!).setValue(true)
// Eigene Posts markieren
PostApi.shared.REF_MY_POSTS.child(currentUserUid).child(newPostId!).setValue(true)
print("Post created")
onSuccess()
}
}
}
UIDocumentPickerViewController to pick some document and upload into AWS S3 with help of TransferUtility. Here, While uploading I need to show upload file name, status(progressive loader %),size into tableview cell. If i upload multiple files tableview cell need to show multiple cell with loading status.
Issues:
I have done UIDocumentPickerViewController to pick some documents and get those document URL,name,size,etc. but I don't know how to use (or) pass those values into upload part.
// MARK - File Storage Access
public func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentAt url: URL) {
let fileurl: URL = url as URL
let filename = url.lastPathComponent
let fileextension = url.pathExtension
let filedata = url.dataRepresentation
print("DATA: \(filedata)","URL: \(fileurl)", "NAME: \(filename)", "EXTENSION: \(fileextension)")}
//Need to store above values and use it to below functions
Below upload part how to interact with tableview cell.
transferUtility.uploadData(data,bucket: S3BucketName,key: name,contentType: "text/plain",expression: expression,completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error: \(error.localizedDescription)")
DispatchQueue.main.async {
cells.statusLabel_util.text = "Failed"
print("Failed")
}
}
if let _ = task.result {
DispatchQueue.main.async {
print("Upload Starting!")
}
// Do something with uploadTask.
}
return nil;
}
You can upload file and track progress with this code
if let uploadRequest = AWSS3TransferManagerUploadRequest(){
uploadRequest.bucket = "your bucket"
uploadRequest.key = fileName
//uploadRequest.acl = AWSS3ObjectCannedACL.publicRead
uploadRequest.body = fileUrl
uploadRequest.uploadProgress = {(bytesSent: Int64, totalBytesSent: Int64, totalBytesExpectedToSend: Int64) -> Void in
DispatchQueue.main.async(execute: {() -> Void in
//Update progress
})
}
if let transferManager = AWSS3TransferManager.default(){
transferManager.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), with: { (task) -> Any? in
if let error = task.error as NSError? {
if error.domain == AWSS3TransferManagerErrorDomain, let code = AWSS3TransferManagerErrorType(rawValue: error.code) {
switch code {
case .cancelled, .paused:
break
default:
break
//print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
} else {
//print("Error uploading: \(uploadRequest?.key) Error: \(error)")
}
return nil
}
return nil
})
}
}
I'm trying to upload an image to a bucket S3 AWS, I am using the following code. but do I use it to upload to an image stored in a variable or imageView.image?
let ext = "jpg"
let imageURL = NSBundle.mainBundle().URLForResource("imagename", withExtension: ext)
print("imageURL:\(imageURL)")
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = imageURL
uploadRequest.key = NSProcessInfo.processInfo().globallyUniqueString + "." + ext
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/" + ext
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed ❌ (\(error))")
}
if let exception = task.exception {
print("Upload failed ❌ (\(exception))")
}
if task.result != nil {
let s3URL = NSURL(string: "http://s3.amazonaws.com/\(self.S3BucketName)/\(uploadRequest.key!)")!
print("Uploaded to:\n\(s3URL)")
}
else {
print("Unexpected empty result.")
}
return nil
}
AWSS3TransferManager is deprecated. Use AWSS3TransferUtility instead.
The transfer utility provides methods for both single-part and
multipart uploads. When a transfer uses multipart upload, the data is
chunked into a number of 5 MB parts which are transferred in parallel
for increased speed.
func uploadFile(withImage image: UIImage) {
let access = "YOUR ACCESS KEY"
let secret = "YOUR SECRET KEY"
let credentials = AWSStaticCredentialsProvider(accessKey: access, secretKey: secret)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentials)
AWSServiceManager.default().defaultServiceConfiguration = configuration
let s3BucketName = "YOUR BUCKET NAME"
let compressedImage = image.resizedImage(newSize: CGSize(width: 80, height: 80))
let data: Data = compressedImage.pngData()!
let remoteName = generateRandomStringWithLength(length: 12)+"."+data.format
print("REMOTE NAME : ",remoteName)
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = { (task, progress) in
DispatchQueue.main.async(execute: {
// Update a progress bar
})
}
var completionHandler: AWSS3TransferUtilityUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
// Do something e.g. Alert a user for transfer completion.
// On failed uploads, `error` contains the error object.
})
}
let transferUtility = AWSS3TransferUtility.default()
transferUtility.uploadData(data, bucket: s3BucketName, key: remoteName, contentType: "image/"+data.format, expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in
if let error = task.error {
print("Error : \(error.localizedDescription)")
}
if task.result != nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL = url?.appendingPathComponent(S3BucketName).appendingPathComponent(remoteName)
if let absoluteString = publicURL?.absoluteString {
// Set image with URL
print("Image URL : ",absoluteString)
}
}
return nil
}
}
For generating random strings for remote name.
func generateRandomStringWithLength(length: Int) -> String {
let randomString: NSMutableString = NSMutableString(capacity: length)
let letters: NSMutableString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
var i: Int = 0
while i < length {
let randomIndex: Int = Int(arc4random_uniform(UInt32(letters.length)))
randomString.append("\(Character( UnicodeScalar( letters.character(at: randomIndex))!))")
i += 1
}
return String(randomString)
}
For resizing the image and data formatting. Use below Image and Data extensions.
extension UIImage {
func resizedImage(newSize: CGSize) -> UIImage {
guard self.size != newSize else { return self }
UIGraphicsBeginImageContextWithOptions(newSize, false, 0.0);
self.draw(in: CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height))
let newImage: UIImage = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return newImage
}
}
extension Data {
var format: String {
let array = [UInt8](self)
let ext: String
switch (array[0]) {
case 0xFF:
ext = "jpg"
case 0x89:
ext = "png"
case 0x47:
ext = "gif"
case 0x49, 0x4D :
ext = "tiff"
default:
ext = "unknown"
}
return ext
}
}
I Have modified your code, try this
let ext = "jpg"
let imageURL = NSBundle.mainBundle().URLForResource("imagename", withExtension: ext)
print("imageURL:\(imageURL)")
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = imageURL
uploadRequest.key = "\(NSProcessInfo.processInfo().globallyUniqueString).\(ext)"
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/\(ext)"
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed ❌ (\(error))")
}
if let exception = task.exception {
print("Upload failed ❌ (\(exception))")
}
if task.result != nil {
let s3URL = NSURL(string: "http://s3.amazonaws.com/\(self.S3BucketName)/\(uploadRequest.key!)")!
print("Uploaded to:\n\(s3URL)")
}
else {
print("Unexpected empty result.")
}
return nil
}
or you can use my code below to upload to AWS s3, its worked fine for me. This code is written in swift 3.
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
})
}
}
Thanks :)
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": "GiveAppAccess",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::123456789012:user/YOUR_USER"
},
"Action": [
"s3:GetObject",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::YOUR_BUCKET/*"
}
]
}
This is the latest code based on SWIFT 4 syntax
I am using the code of #Karthick Selvaraj.
I think now its help to other developers to understand new syntax
func uploadButtonPressed() {
if myimageView.image == nil {
// Do something to wake up user :)
} else {
let image = myimageView.image!
let fileManager = FileManager.default
let path = (NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString).appendingPathComponent("test3.jpeg")
let imageData = UIImageJPEGRepresentation(image, 0)
fileManager.createFile(atPath: path as String, contents: imageData, attributes: nil)
let fileUrl = NSURL(fileURLWithPath: path)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = "<Your Bucket Name>"
uploadRequest?.key = "<Image Name>"
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = fileUrl as URL!
uploadRequest?.serverSideEncryption = AWSS3ServerSideEncryption.awsKms
uploadRequest?.uploadProgress = { (bytesSent, totalBytesSent, totalBytesExpectedToSend) -> Void in
DispatchQueue.main.async(execute: {
// print("totalBytesSent",totalBytesSent)
// print("totalBytesExpectedToSend",totalBytesExpectedToSend)
// self.amountUploaded = totalBytesSent // To show the updating data status in label.
// self.fileSize = totalBytesExpectedToSend
})
}
let transferManager = AWSS3TransferManager.default()
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> Any? in
if task.error != nil {
// Error.
print("error")
} else {
// Do something with your result.
print("No error Upload Done")
}
return nil
})
}
}
Enjoy !!!
This is image uploading using AWS S3 bucket this below code i implemented image uploading from gallery to uploading
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject])
{
if(picker.sourceType == UIImagePickerControllerSourceType.PhotoLibrary)
{
selectedImageUrl = info[UIImagePickerControllerReferenceURL] as! NSURL
myImageViewC.image = info[UIImagePickerControllerOriginalImage] as? UIImage
myImageViewC.backgroundColor = UIColor.clearColor()
myImageViewC.contentMode = UIViewContentMode.ScaleAspectFit
self.dismissViewControllerAnimated(true, completion: nil)
startUploadingImage()
}
else if(picker.sourceType == UIImagePickerControllerSourceType.Camera)
{
myImageViewC.image = info[UIImagePickerControllerOriginalImage] as? UIImage
myImageViewC.backgroundColor = UIColor.clearColor()
myImageViewC.contentMode = UIViewContentMode.ScaleAspectFit
self.dismissViewControllerAnimated(true, completion: nil)
myActivityIndicator.startAnimating()
let S3BucketName = "streetsmartb2/sai"
let date3 = NSDate()
let timeInMi = "\(CLongLong((floor(date3.timeIntervalSince1970 * 1000))))"
let S3UploadKeyName = "File.jpg\(timeInMi)"
//print("value1:\(S3UploadKeyName)")
//settings temp location for image
let imageName = NSURL.fileURLWithPath(NSTemporaryDirectory() + S3UploadKeyName).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 = UIImageJPEGRepresentation(image, 0.5)
let data = CreateTeamViewController().resizeImage(image)
data.writeToFile(localPath, atomically: true)
//let imageData = NSData(contentsOfFile: localPath)!
let photoURL = NSURL(fileURLWithPath: localPath)
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest.body = photoURL
uploadRequest.key = S3UploadKeyName
uploadRequest.bucket = S3BucketName
uploadRequest.contentType = "image/jpeg"
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
// Perform file upload
transferManager.upload(uploadRequest).continueWithBlock { (task) -> AnyObject! in
if let error = task.error {
print("Upload failed with error: (\(error.localizedDescription))")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
CreateTeamViewController().displayAlertMessage("Error uploading Image")
}
}
if let exception = task.exception {
print("Upload failed with exception (\(exception))")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
CreateTeamViewController().displayAlertMessage("Error uploading Image")
}
}
if task.result != nil {
// Remove locally stored file
self.remoteImageWithUrl(uploadRequest.key!)
let s3URL = NSURL(string: "https://s3.amazonaws.com/\(S3BucketName)/\(uploadRequest.key!)")!
// print("Uploaded to:\n\(s3URL)")
dispatch_async(dispatch_get_main_queue()) {
// self.returnToAddView()
self.myActivityIndicator.stopAnimating()
self.createTeamImageButton?.setImage(self.loadImage, forState: .Normal)
self.uploadedImageURL = (s3URL.URLString)
// self.teamImageNameCreate = self.uploadedImageURL
// self.createTeamImageButton.sd_setImageWithURL(NSURL(string: self.uploadedImageURL)!, forState: .Normal, placeholderImage: UIImage(named: "no_image_one.jpg"))
let url = NSURL.init(string: self.uploadedImageURL)
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// do some task
let imagedata = NSData(contentsOfURL: url!)
if let imageObj = UIImage.init(data: imagedata!) {
self.createTeamPic = imageObj
}
dispatch_async(dispatch_get_main_queue()) {
self.createTeamImageButton?.setImage(self.createTeamPic, forState: .Normal)
}
}
}
}
else {
// print("Unexpected empty result.")
}
return nil
}
}
}
I've recently been working on a project that uploads and downloads files through the Amazon S3 service, specifically a user uploaded profile picture. I am also using Amazon Cognito (Username, full name, etc), and one of the things I like about Cognito is that it saves the downloaded data locally on the phone and displays it even when the app is offline. Then, when the app goes online, it updates any data changes. Unfortunately, the same doesn't happen with S3. Every time the app starts, it has to download the profile picture from my S3 bucket before displaying them. What I want to do is have the app save the user's profile picture from the S3 bucket on the iOS device so the user can see their picture even when the app goes offline. Here is what I currently have:
func downloadImage(){
var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?
//downloading image
let S3BucketName: String = "*******"
let S3DownloadKeyName: String = self.credentialsProvider.identityId + "/profileImage.png"
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)
// self.statusLabel.text = "Downloading..."
NSLog("Progress is: %f",progress)
})
}
completionHandler = { (task, location, data, error) -> Void in
dispatch_async(dispatch_get_main_queue(), {
if ((error) != nil){
NSLog("Failed with error")
NSLog("Error: %#",error!);
//self.statusLabel.text = "Failed"
} else {
//self.statusLabel.text = "Success"
self.userProfile.image = UIImage(data: data!)
self.profileBackground.image = 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 {
NSLog("Error: %#",error.localizedDescription);
// self.statusLabel.text = "Failed"
}
if let exception = task.exception {
NSLog("Exception: %#",exception.description);
// self.statusLabel.text = "Failed"
}
if let _ = task.result {
// self.statusLabel.text = "Starting Download"
NSLog("Download Starting!")
// Do something with uploadTask.
}
return nil;
}
}
Thanks in advance!
This is a helper to download an image from S3 Bucket and save it on local phone
next time if you seek to this image. the helper will check if a local copy exists if not it will download from S3
import UIKit
import AWSCore
import AWSS3
class S3Helper: NSObject {
#objc var completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock?
#objc lazy var transferUtility = {
AWSS3TransferUtility.default()
}()
let DocDirPath = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
func downloadImage(imageView: UIImageView!, S3Folder: String, S3FileName: String) {
let S3DownloadKeyName: String = S3Folder + "/" + S3FileName
imageView.image = UIImage(named: "ic_place_holder.pdf")
let filePath = DocDirPath.appendingPathComponent(S3FileName).path
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath) {
let imageURL = self.DocDirPath.appendingPathComponent(S3FileName)
imageView.image = UIImage(contentsOfFile: imageURL.path)!
} else {
let expression = AWSS3TransferUtilityDownloadExpression()
expression.progressBlock = {(task, progress) in
DispatchQueue.main.async(execute: {
})
}
self.completionHandler = { (task, location, data, error) -> Void in
DispatchQueue.main.async(execute: {
if let error = error {
NSLog("Failed with error: \(error)")
//self.statusLabel.text = "Failed"
}
else{
//self.statusLabel.text = "Success"
imageView.image = UIImage(data: data!)
do{
let imgPath = URL(fileURLWithPath: self.DocDirPath.appendingPathComponent(S3FileName).path)
try (imageView.image ?? UIImage(named: "ic_place_holder.pdf")!).jpegData(compressionQuality: 1.0)?.write(to: imgPath, options: .atomic)
} catch let error1{
print(error1.localizedDescription)
}
}
})
}
transferUtility.downloadData(
forKey: S3DownloadKeyName,
expression: expression,
completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
NSLog("Error: %#",error.localizedDescription);
DispatchQueue.main.async(execute: {
//self.statusLabel.text = "Failed"
})
}
if let _ = task.result {
DispatchQueue.main.async(execute: {
//self.statusLabel.text = "Downloading..."
})
NSLog("Download Starting!")
// Do something with uploadTask.
}
return nil;
}
}
}
}
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?
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
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)
}
}
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")
}
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
}
}