In my iOS app, I try to download a file from an AWS S3 bucket. Here is what I tried:
I initialize AWSMobileClient:
import AWSMobileClient
import AWSS3
let configuration = AWSServiceConfiguration(
region: AWSRegionType.EUCentral1,
credentialsProvider: AWSMobileClient.default())
AWSServiceManager.default().defaultServiceConfiguration = configuration
AWSMobileClient.default().initialize { (userState: UserState?, error: Error?) in
if (userState != nil)
{
print("Initialize OK : \(userState.debugDescription)")
}
if (error != nil)
{
print("Initialize error: \(String(describing: error))")
}
}
I got:
"initialize OK : Optional(AWSMobileClient.UserState.guest)"
Now I try to download a file:
let expression = AWSS3TransferUtilityDownloadExpression()
expression.progressBlock = {(task, progress) in DispatchQueue.main.async(execute: {
print("Progress : \(progress)")
})
}
let completionHandler: AWSS3TransferUtilityDownloadCompletionHandlerBlock = {
(task: AWSS3TransferUtilityDownloadTask, url: URL?, data: Data?, error: Error?) -> Void in
DispatchQueue.main.async(execute: {
print("End download 1")
})
}
let fileManager = FileManager.default
let fileURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("100.ogg")
let transferUtility: AWSS3TransferUtility = AWSS3TransferUtility.default()
transferUtility.download(
to: fileURL,
bucket: "my-s3-bucket",
key: "100.ogg",
expression: expression,
completionHandler: completionHandler).continueWith { (task) -> AnyObject? in
if let error = task.error {
print("Error download : \(error)")
}
if let result = task.result {
print("Result : \(result.debugDescription)")
}
print("End download 2 : \(fileManager.fileExists(atPath: fileURL.absoluteString))")
return nil
}
I got:
"Result : <AWSS3TransferUtilityDownloadTask: 0x6000020bd4d0>
"End download 2 : false"
I don't get any progress, and I also don't get the "End download 1"
So basically, I dont get any error, but it does look like nothing has been downloaded. Also, on a side note, it works well with the Android version of my app, so it's very likely that there is an error in my code.
So what should I change to make it work?
Thanks.
My bad, the example above is actually working, But I had to:
change fileManager.fileExists(atPath: fileURL.absoluteString)) by fileManager.fileExists(atPath: fileURL.path))
check if file exists in the first completionHandler (where I wrote print("End download 1"))
Related
I have implemented the basic AWS transfer utility upload video (file) code in my app and this had been working for me flawlessly until recently the uploads got extremely slow and even stuck.
I tried changing many things in the AWS code like shifting from TransferUtilityUpload to TrasferUtility UploadUsing MultiPart, changing the AWSServiceConfiguration from AWSCognitoCredentialsProvider(using poolId & region) to AWSStaticCredentialsProvider (using Accesskey, secret key and region), enabling acceleration etc but nothing has helped to increase the upload speed. Apart from this, the uploads are very inconsistent. For example sometimes a 30sec video (size 180MB) gets uploaded in under 2 mins and then again same video takes more than 5 minutes/gets stuck in the same network (speed 150MBps or more)
Can someone please help me understand the issue and fix it?
Code snippets below.
Service Configuration
let credentialsProvider = AWSStaticCredentialsProvider(accessKey: "******", secretKey: "*****")
let configuration = AWSServiceConfiguration.init(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
AWS Upload function
private func uploadfile(fileSize: Int, fileUrl: URL, fileName: String, contenType: String, progress: progressBlock?, completion: completionBlock?) {
// Upload progress block
var previousUploadedBytes: Double = 0.0
let expression = AWSS3TransferUtilityMultiPartUploadExpression()
expression.progressBlock = {(task, awsProgress) in
if task.status == AWSS3TransferUtilityTransferStatusType.waiting {
task.cancel()
}
guard let uploadProgress = progress else { return }
DispatchQueue.main.async {
uploadProgress(awsProgress.fractionCompleted)
//CODE FOR UI UPDATES
//DO SOMETHING WITH THE PROGRESS
}
}
// Completion block
var completionHandler: AWSS3TransferUtilityMultiPartUploadCompletionHandlerBlock?
completionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
if error == nil {
let url = AWSS3.default().configuration.endpoint.url
let publicURL : URL = (url?.appendingPathComponent(self.bucketName).appendingPathComponent(fileName))!
if let completionBlock = completion {
completionBlock(publicURL.absoluteString, nil)
}
} else {
if let completionBlock = completion {
completionBlock(nil, error)
}
}
})
}
//acceleration mode enabled
let serviceConfiguration = AWSServiceConfiguration(
region: .USEast1,
credentialsProvider: AWSServiceManager.default().defaultServiceConfiguration.credentialsProvider
)
let transferUtilityConfiguration = AWSS3TransferUtilityConfiguration()
transferUtilityConfiguration.isAccelerateModeEnabled = true
AWSS3TransferUtility.register(
with: serviceConfiguration!,
transferUtilityConfiguration: transferUtilityConfiguration,
forKey: "transfer-acceleration"
)
// Start uploading using AWSS3TransferUtility
let awsTransferUtility = AWSS3TransferUtility.default()
awsTransferUtility.uploadUsingMultiPart(fileURL: fileUrl, bucket: bucketName, key: fileName, contentType: contenType, expression: expression, completionHandler: completionHandler).continueWith { (task) -> Any? in
if let error = task.error {
UploadHelper.sharedInstance.showSSLError = false
if (error as NSError).code == -1001 {
DispatchQueue.main.async {
UploadHelper.sharedInstance.noOfRetries = 0
UploadHelper.sharedInstance.changeToRetryUpload() // internal code to call for retry
}
} else if (error as NSError).code == -1009 {
DispatchQueue.main.async {
UploadHelper.sharedInstance.noOfRetries = 0
UploadHelper.sharedInstance.changeToRetryUpload() // internal code to call for retry
}
} else if (error as NSError).code == -1003 {
DispatchQueue.main.async {
UploadHelper.sharedInstance.noOfRetries = 0
UploadHelper.sharedInstance.changeToRetryUpload() // internal code to call for retry
}
} else if (error as NSError).code == -1200 {
DispatchQueue.main.async {
UploadHelper.sharedInstance.noOfRetries = 0
UploadHelper.sharedInstance.changeToRetryUpload() // internal code to call for retry
UploadHelper.sharedInstance.showSSLError = true
}
}
}
if let _ = task.result {
// your uploadTask
}
return nil
}
}
I have a video creating process where a user selects a video using UIImagePickerController. After selecting a video, the url of the video is passed to the video details page. Once the user completes the details and clicks upload, I run this code:
if canProceed(){
let fileName = "\(UUID().uuidString).mov"
storage.reference(withPath: "videos/\(Auth.auth().currentUser?.email ?? "")/\(fileName)").putFile(from: vidURL, metadata: nil) { metadata, err in
if err != nil{
print(err)
return
}
metadata?.storageReference?.downloadURL(completion: { url, err in
if err != nil{
print(err)
return
}
db.collection("reelPool").document(fileName).setData(["url": url])
})
}
}
Nothing is uploaded to cloud storage and the return is:
Error Domain=FIRStorageErrorDomain Code=-13000 "An unknown error occurred, please check the server response."
HI I think Here is your answer Just try with it ,
// Url is Video Url Which you will get when Pick a video from Image Picker
func upload(file: URL, completion: #escaping ((_ url : URL?) -> ())) {
let name = "\(yourFile Name)).mp4"
do {
let data = try Data(contentsOf: file)
let storageRef =
Storage.storage().reference().child("Videos").child(name)
if let uploadData = data as Data? {
let metaData = StorageMetadata()
metaData.contentType = "video/mp4"
storageRef.putData(uploadData, metadata: metaData
, completion: { (metadata, error) in
if let error = error {
completion(nil)
}
else{
storageRef.downloadURL { (url, error) in
guard let downloadURL = url else {
completion(nil)
return
}
completion(downloadURL)
}
print("success")
}
})
}
}catch let error {
print(error.localizedDescription)
}
And then You will get Url of the Video, now run code of firestore and Pass Url in dictionary .
Did you remember to edit your Firestore rules to allow for read/write access? Your database may not allow writing or only allow writing for authenticated users. Typically Code -13000 is related to permissioning issues on the database.
I want t upload a csv file from my iOS App (written in Swift) to my amazon S3 bucket. To do this I'm using following code:
//Create
let fileName = "Export.csv"
let path = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(fileName)
csvText = CreateCSVAccount()
do {
try csvText.write(to: path!, atomically: true, encoding: String.Encoding.utf32BigEndian)
//Prepare Upload
let uploadingFileURL = path
let uploadRequest = AWSS3TransferManagerUploadRequest()
let Bucketname = "mybucket/CSV"
uploadRequest?.bucket = Bucketname
uploadRequest?.key = "mycsvfile.csv"
uploadRequest?.body = uploadingFileURL!
//Upload File
transferManager.upload(uploadRequest!).continueWith(executor: AWSExecutor.mainThread(), block: { (task:AWSTask<AnyObject>) -> 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:
print("Error Contact uploading: \(String(describing: uploadRequest?.key)) Error: \(error)")
}
} else {
print("Error Contact uploading: \(String(describing: uploadRequest?.key)) Error: \(error)")
}
return nil
}
let uploadOutput = task.result
print("Upload complete for: \(String(describing: uploadRequest?.key))")
print("uploadOutput: \(String(describing: uploadOutput))")
return nil
})
} catch {
print("Failed to create file")
print("\(error)")
}
The problem is sometimes it works and sometimes I'm receiving the following error:
Message=You did not provide the number of bytes specified by the Content-Length HTTP header, NumberBytesExpected=412, Code=IncompleteBody, RequestId=075D1F5B0A377E89
Can somebody please help me?
Thank you very much in advance!
Add the contentLength header to your request.
That is:
uploadRequest?.contentLength = 1234
where 1234 is an NSNumber representing the number of bytes in body
Im trying to upload image to Aws S3 bucket. I tried to follow a tutorial and I'm getting a error saying "Returning ENOTCONN because protocol has not yet been set up." I'm new to swift and I'm not able to understand why the error is occurring also.My code for S3 upload is as follows:
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.body = url!
uploadRequest?.key = remoteFileName
uploadRequest?.bucket = S3BucketName
uploadRequest?.contentType = "image/" + ext
let transferManager = AWSS3TransferManager.default()
// Perform Upload
transferManager.upload(uploadRequest!).continueWith(block: { (task:AWSTask<AnyObject>) -> AnyObject! 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((uploadRequest?.bucket!)!).appendingPathComponent((uploadRequest?.key!)!)
print("Uploaded to:\(publicURL)")
}
return nil
})
My S3 is in ap-south-1 and cognito pool id in us-west-2. I guess thats creating the problem.Is there a way to fix the issue without creating another bucket in us-west-2.
I get the following error:
You want the bucket policy to be somewhat like this if the cognito pool is not set up for authentication: Notice Principal and Action values
Also, is there any particular reason you're using AWSS3TransferManagerUploadRequest? If the policy doesn't resolve your issue, you can use the following code for AWSS3TransferUtilityUploadExpression which sends your data in chunks asynchronously.
let expression = AWSS3TransferUtilityUploadExpression()
expression.progressBlock = progressBlock
transferUtility.uploadData(UIImagePNGRepresentation(imageNew!)!,
bucket: "bucket-name",
key: (imgName.removeWhitespace()),
contentType: "image/png",
expression: expression,
completionHandler: completionHandler).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;
}
I'm trying to upload an image to a bucket. The connection is made, the upload apparently starts but does not progress. The permissions on the server I consider to be correct, because an android app is able to upload.
In my appdelegate I have this:
let credentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.USEast1, identityPoolId: "us-east-1:XXXXXX-XXXX-XXXX-XXXX-XXXX”, unauthRoleArn: "arn:aws:iam::XXXXX:role/Cognito_mybucketUnauth_Role", authRoleArn: "arn:aws:iam::XXXXX:role/Cognito_mybucketAuth_Role", identityProviderManager: nil)
let configuration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
AWSServiceManager.defaultServiceManager().defaultServiceConfiguration = configuration
And this to get the image and upload
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)
CampoImagem.image = image
picker.dismissViewControllerAnimated(true, completion: nil)
uploadImage()
}
func uploadImage(){
//defining bucket and upload file name
let S3BucketName: String = “mybucket"
let S3UploadKeyName: String = "profile/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;
}
}
Print: Upload Starting!
I suspect it's something when ID and permission to complete the upload with aws, but I think if it was the upload would not start, correct?
How can I solve this?
Please check this code you can also check by adding credentials in this demo project
https://github.com/awslabs/aws-sdk-ios-samples/blob/master/S3TransferUtility-Sample/Swift/S3BackgroundTransferSampleSwift/FirstViewController.swift