how to save pdf file from Firebase to document directory - swift

Hello I'm try to save a file test.pdf from firebase storage to the document directory of my app
but unfortunately not working.
here my content view with a button to run the task:
import SwiftUI
import Firebase
import WebKit
struct ContentView: View {
var body: some View {
VStack {
Button(action: {
let storage = Storage.storage()
let storageRef = storage.reference()
let islandRef = storageRef.child("test.pdf")
// Create local filesystem URL
let localURL = URL(string: self.cartellaDocuments())!
let downloadTask = islandRef.write(toFile: localURL) { (url, err) in
if err != nil {
debugPrint(" // Uh-oh, an error occurred!")
} else {
debugPrint("\(String(describing: url))")
}
}
}) {
Text("esegui")
}
}
}
func cartellaDocuments() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
debugPrint(paths[0])
return paths[0]
}
}
my storage in firebase:
I have try to follow the google firebase instruction but Im getting a following warning:
failed because it was passed an URL which has no scheme
how can I solve this issue.
thanks for the help

You can try this :
let pdfView = PDFView()
pdfView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(pdfView)
pdfView.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor).isActive = true
pdfView.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor).isActive = true
pdfView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor).isActive = true
pdfView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor).isActive = true
if let document = PDFDocument(url: URL.init(string: "https://your storage download url")!) {
pdfView.document = document
}

Related

Add an environment object to UIDocumentPickerViewController

I'm trying to import mp3 files into my app from outside the app's sandbox using the file browser. I have a "store" environment object where i have the folder URL to which I'd like to move the selected file. I want to add that store as an environment object to the file picker.
Here's how I call the document picker from a view (here's just the relevant code):
struct libraryView: View {
#State var filePicker : DocumentPicker
#EnvironmentObject var store : MusicStore
#State var showPicker = false
func presentDocumentPicker() {
let viewController = UIApplication.shared.windows[0].rootViewController!
let controller = filePicker.viewController
viewController.present(controller, animated: true)
}
var body: some View {
Button(action: {showPicker = true
presentDocumentPicker()
}, label: {
Image(systemName: "plus").imageScale(.large)
})
}}
And here's the document picker code:
final class DocumentPicker: NSObject, ObservableObject {
#EnvironmentObject var store : MusicStore
lazy var viewController: UIDocumentPickerViewController = {
let vc = UIDocumentPickerViewController(documentTypes: types, in: .import)
vc.delegate = self
vc.allowsMultipleSelection = self.allowsMultipleSelection
return vc
}()
}
extension DocumentPicker: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
callback(urls)
do {
let filePath = try FileManager.default.contentsOfDirectory(at: url.deletingLastPathComponent(), includingPropertiesForKeys: nil, options: [])[0]
let audioFile = try Data(contentsOf: filePath)
// let destinationURL = store.folderURL!.appendingPathComponent(filePath.lastPathComponent)
// try FileManager.default.moveItem(at: filePath, to: destinationURL)
// print("File moved to documents folder")
}
catch {
print(error)
}
}
}
Here's the store code:
class MusicStore : ObservableObject {
var folderURL : URL?
init(){
do{
self.folderURL = try FileManager.default.url(
for: .documentDirectory,
in: .userDomainMask,
appropriateFor: nil,
create: false
)} catch(let error) {
print(error.localizedDescription)
}
}
So I want to import the file to my app's sandbox within the documentPicker function, like in the commented code. But I can't add an environment object to the view controller. I don't know whether it's possible at all to do it because I'm using the root view controller to show the document picker.

View pdf documents

I have a table with the names of pdf documents. Previously, there were 3 documents and each one has its own ViewController. How can I make it so that with hundreds of documents, I would select one from the table and show it on the View, if I select another document, then on the same View show another document.
while I have such a function, where I substituted the name of the documents in each class and showed it in different representations. But now I need to display everything on one ViewController when selecting any document
import UIKit
import PDFKit
class pdfViewClass {
class func filePDfFunc(nameFile: String, formatFile:String,
nameView:PDFView)
{
if let path = Bundle.main.path(forResource: nameFile,
ofType:formatFile) {
if let pdfDocument = PDFDocument(url: URL(fileURLWithPath:
path)) {
nameView.autoScales = true
nameView.displayDirection = .vertical
nameView.document = pdfDocument
}
}
}
}
You can use Native Apple UIDocumentInteractionController for viewing PDF file.
Create a function like below for View PDF
func viewPdf(urlPath: String, screenTitle: String) {
// open pdf for booking id
guard let url = urlPath.toUrl else {
print("Please pass valid url")
return
}
self.downloadPdf(fileURL: url, screenTitle: screenTitle) { localPdf in
if let url = localPdf {
DispatchQueue.main.sync {
self.openDocument(atURL: url, screenTitle: screenTitle)
}
}
}
}
Function for download PDF
// method for download pdf file
func downloadPdf(fileURL: URL, screenTitle: String, complition: #escaping ((URL?) -> Void)) {
// Create destination URL
if let documentsUrl: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let destinationFileUrl = documentsUrl.appendingPathComponent("\(screenTitle).pdf")
if FileManager.default.fileExists(atPath: destinationFileUrl.path) {
try? FileManager.default.removeItem(at: destinationFileUrl)
}
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url: fileURL)
let task = session.downloadTask(with: request) { tempLocalUrl, response, error in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
complition(destinationFileUrl)
} catch let writeError {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
} else {
print("Error took place while downloading a file. Error description: \(error?.localizedDescription ?? "N/A")")
}
}
task.resume()
} else {
complition(nil)
}
}
Function for open documents
func openDocument(atURL url: URL, screenTitle: String) {
self.documentInteractionController.url = url
self.documentInteractionController.name = screenTitle
self.documentInteractionController.delegate = self
self.documentInteractionController.presentPreview(animated: true)
}
On tap of tableView pass the specific index URL
viewPdf(urlPath: "http://www.africau.edu/images/default/sample.pdf", screenTitle: "Tesing Document")
You can do it using WKWebView easily. Use WKWebView to load your pdf doc.

Could not open obj file

so I'm working on a project that pulls zip files which include .obj files, unzips them and displays them using ARkit. At the moment I've been able to unzip and save the file in my documents directory as a .obj file and it says the file exists, but when I try to convert it into a scn it says "Could not open OBJ file". Here is my code and I'm trying to figure out where I went wrong. The file size is 314 KB so I know that's not the issue and the obj file isn't corrupted because I can download it to my computer and open it up.
class ViewController: UIViewController {
var testData: Store?
var logoImage: UIImage?
var urlForObject: String?
var tempDirectoryString: String?
var tempDirectoryURL: URL?
var testModelData: Data?
var testData2: Data?
var testData3: Models?
var tempDocumentsURL: URL?
#IBOutlet weak var logoImageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
self.clearCowZipFolder()
self.clearCowFolder()
self.requestZipFile(){ response in
self.testData2 = response
do{
let json = try? JSONSerialization.jsonObject(with: response, options: [])
if let array = json as? [String] {
if let firstObject = array.first {
//print(firstObject)
}
for object in array {
// access all objects in array
}
for case let string as String in array {
// access only string values in array
}
}
}catch{
print("errorrrr")
}
}
self.tempDocumentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
let destinationFileUrl = self.tempDocumentsURL!.appendingPathComponent("Man.zip")
var destPath = self.tempDocumentsURL!.appendingPathComponent("Man")
//Create URL to the source file you want to download
let fileURL = URL(string: "http://markitapi.com/stores/TestStore/models/Man")
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url:fileURL!)
let task = session.downloadTask(with: request) { (tempLocalUrl, response3, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Success
if let statusCode = (response3 as? HTTPURLResponse)?.statusCode {
print("Successfully downloaded. Status code: \(statusCode)")
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
} catch (let writeError) {
print("Error creating a file \(destinationFileUrl) : \(writeError)")
}
do{
let unzipDirectory = try Zip.quickUnzipFile(destinationFileUrl) //Unzip
print("HHERHERHEHRE")
destPath = unzipDirectory
}catch{
print("error while unzipping")
}
print("UNZIPPED PATH")
//print(destPath)
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String
let url = NSURL(fileURLWithPath: path)
if let pathComponent = url.appendingPathComponent("Man/Man.obj") {
let filePath = pathComponent.path
//print(filePath)
let fileManager = FileManager.default
if fileManager.fileExists(atPath: filePath) {
print("FILE AVAILABLE")
} else {
print("FILE NOT AVAILABLE")
}
} else {
print("FILE PATH NOT AVAILABLE")
}
let url2 = (String(describing: destPath) + "Man.obj")
let url3 = URL(fileURLWithPath: url2)
print(url3.pathExtension)
let asset = MDLAsset(url: url3)
//print(asset)
let object = asset.object(at: 0)
let node = SCNNode(mdlObject: object)
//print(node)
}
} else {
//print("Error took place while downloading a file. Error description: %#", error?.localizedDescription);
}
}
task.resume()
}
func clearCowZipFolder() {
let fileNameToDelete = "Man.zip"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0 {
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
//print("Local path = \(filePath)")
} else {
print("Could not find local directory to store file")
return
}
do {
let fileManager = FileManager.default
// Check if file exists
if fileManager.fileExists(atPath: filePath) {
// Delete file
try fileManager.removeItem(atPath: filePath)
} else {
print("File does not exist")
}
}
catch let error as NSError {
print("An error took place: \(error)")
}
}
func clearCowFolder() {
let fileNameToDelete = "Man"
var filePath = ""
// Fine documents directory on device
let dirs : [String] = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.allDomainsMask, true)
if dirs.count > 0 {
let dir = dirs[0] //documents directory
filePath = dir.appendingFormat("/" + fileNameToDelete)
//print("Local path = \(filePath)")
} else {
print("Could not find local directory to store file")
return
}
do {
let fileManager = FileManager.default
// Check if file exists
if fileManager.fileExists(atPath: filePath) {
// Delete file
try fileManager.removeItem(atPath: filePath)
} else {
print("File does not exist")
}
}
catch let error as NSError {
print("An error took place: \(error)")
}
}
func requestZipFile(success successBlock: #escaping (Data) -> Void){
Alamofire.request("http://markitapi.com/stores/TestStore/models").responseJSON { (response) in
do{
if(response.result.isSuccess){
successBlock(response.data!)
}
}catch{
print("error")
}
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
The first part of the code checks to see if the file is available and it does print that statement, so I know the file is there.

Read and write permission for user selected folder in Mac OS app?

I am developing MAC OS app which have functionality to create file on the behalf of your. First user select folder for storing file (One time at start of app) and then user can select type and name of the file user want to create on selected folder (Folder selected on start of the app) using apple script. I am able to create file when i add below temporary-exception in entitlement file but its not able to app apple review team but works in sandboxing.
Guideline 2.4.5(i) - Performance
We've determined that one or more temporary entitlement exceptions requested for this app are not appropriate and will not be granted:
com.apple.security.temporary-exception.files.home-relative-path.read-write
/FolderName/
I found :
Enabling App Sandbox - Allows apps to write executable files.
And
Enabling User-Selected File Access - Xcode provides a pop-up menu, in the Summary tab of the target editor, with choices to enable read-only or read/write access to files and folders that the user explicitly selects. When you enable user-selected file access, you gain programmatic access to files and folders that the user opens using an NSOpenPanel object, and files the user saves using an NSSavePanel object.
Using below code for creating file :
let str = "Super long string here"
let filename = getDocumentsDirectory().appendingPathComponent("/xyz/output.txt")
do {
try str.write(to: filename, atomically: true, encoding: String.Encoding.utf8)
} catch {
// failed to write file – bad permissions, bad filename, missing permissions, or more likely it can't be converted to the encoding
}
Also tried adding com.apple.security.files.user-selected.read-write in entitlement file for an NSOpenPanel object :
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
Is there any way to get pass apple review team to approve Mac App with read and write permission to user selected folder ?
Here is my Answer
How to do implement and persist Read and write permission of user selected folder in Mac OS app?
GitHub Example Project link
First :
Add user-selected and bookmarks.app permissions in entitlement file :
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
Then i created class for all bookmark related function required for storeing, loading ... etc bookmarks app.
import Foundation
import Cocoa
var bookmarks = [URL: Data]()
func openFolderSelection() -> URL?
{
let openPanel = NSOpenPanel()
openPanel.allowsMultipleSelection = false
openPanel.canChooseDirectories = true
openPanel.canCreateDirectories = true
openPanel.canChooseFiles = false
openPanel.begin
{ (result) -> Void in
if result.rawValue == NSApplication.ModalResponse.OK.rawValue
{
let url = openPanel.url
storeFolderInBookmark(url: url!)
}
}
return openPanel.url
}
func saveBookmarksData()
{
let path = getBookmarkPath()
NSKeyedArchiver.archiveRootObject(bookmarks, toFile: path)
}
func storeFolderInBookmark(url: URL)
{
do
{
let data = try url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
bookmarks[url] = data
}
catch
{
Swift.print ("Error storing bookmarks")
}
}
func getBookmarkPath() -> String
{
var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
url = url.appendingPathComponent("Bookmarks.dict")
return url.path
}
func loadBookmarks()
{
let path = getBookmarkPath()
bookmarks = NSKeyedUnarchiver.unarchiveObject(withFile: path) as! [URL: Data]
for bookmark in bookmarks
{
restoreBookmark(bookmark)
}
}
func restoreBookmark(_ bookmark: (key: URL, value: Data))
{
let restoredUrl: URL?
var isStale = false
Swift.print ("Restoring \(bookmark.key)")
do
{
restoredUrl = try URL.init(resolvingBookmarkData: bookmark.value, options: NSURL.BookmarkResolutionOptions.withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
}
catch
{
Swift.print ("Error restoring bookmarks")
restoredUrl = nil
}
if let url = restoredUrl
{
if isStale
{
Swift.print ("URL is stale")
}
else
{
if !url.startAccessingSecurityScopedResource()
{
Swift.print ("Couldn't access: \(url.path)")
}
}
}
}
Then open folder selection using NSOpenPanel so the user can select which folders to give you access to. The NSOpenPanel must be stored as a bookmark and saved to disk. Then your app will have the same level of access as it did when the user selected the folder.
To open NSOpenPanel :
let selectedURL = openFolderSelection()
saveBookmarksData()
and to load existing bookmark after app close :
loadBookmarks()
Thats it.
I Hope it will help someone.
Add user-selected and bookmarks.app permissions in entitlement file :
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
Then open folder selection using NSOpenPanel so the user can select which folders to give you access to. The NSOpenPanel must be stored as a bookmark and saved to disk. Then your app will have the same level of access as it did when the user selected the folder.
Since 'unarchiveObject(withFile:)' was deprecated in macOS 10.14, created a new answer in case someone has a similar question.
So after setting this in plist,
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
<key>com.apple.security.files.bookmarks.app-scope</key>
<true/>
Create a BookMark class like below:
import Foundation
#objcMembers final class BookMarks: NSObject, NSSecureCoding {
struct Keys {
static let data = "data"
}
var data: [URL:Data] = [URL: Data]()
static var supportsSecureCoding: Bool = true
required init?(coder: NSCoder) {
self.data = coder.decodeObject(of: [NSDictionary.self, NSData.self, NSURL.self], forKey: Keys.data) as? [URL: Data] ?? [:]
}
required init(data: [URL: Data]) {
self.data = data
}
func encode(with coder: NSCoder) {
coder.encode(data, forKey: Keys.data)
}
func store(url: URL) {
do {
let bookmark = try url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
data[url] = bookmark
} catch {
print("Error storing bookmarks")
}
}
func dump() {
let path = Self.path()
do {
try NSKeyedArchiver.archivedData(withRootObject: self, requiringSecureCoding: true).write(to: path)
} catch {
print("Error dumping bookmarks")
}
}
static func path() -> URL {
var url = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
url = url.appendingPathComponent("Bookmarks.dict")
return url
}
static func restore() -> BookMarks? {
let path = Self.path()
let nsdata = NSData(contentsOf: path)
guard nsdata != nil else { return nil }
do {
let bookmarks = try NSKeyedUnarchiver.unarchivedObject(ofClass: Self.self, from: nsdata! as Data)
for bookmark in bookmarks?.data ?? [:] {
Self.restore(bookmark)
}
return bookmarks
} catch {
// print(error.localizedDescription)
print("Error loading bookmarks")
return nil
}
}
static func restore(_ bookmark: (key: URL, value: Data)) {
let restoredUrl: URL?
var isStale = false
print("Restoring \(bookmark.key)")
do {
restoredUrl = try URL.init(resolvingBookmarkData: bookmark.value, options: NSURL.BookmarkResolutionOptions.withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &isStale)
} catch {
print("Error restoring bookmarks")
restoredUrl = nil
}
if let url = restoredUrl {
if isStale {
print("URL is stale")
} else {
if !url.startAccessingSecurityScopedResource() {
print("Couldn't access: \(url.path)")
}
}
}
}
}
Then using it:
loading
let bookmarks = BookMarks.restore() ?? BookMarks(data: [:])
adding
bookmarks.store(url: someUrl)
saving
bookmarks.dump()
Swift 5 with Xcode 14.2 - Jan-2023 :- below code works fine in my macOS app:
Keep below code in a class and follow instructions given after the code:
private static let BOOKMARK_KEY = "bookmark"
// Check permission is granted or not
public static func isPermissionGranted() -> Bool {
if let data = UserDefaults.standard.data(forKey: BOOKMARK_KEY) {
var bookmarkDataIsStale: ObjCBool = false
do {
let url = try (NSURL(resolvingBookmarkData: data, options: [.withoutUI, .withSecurityScope], relativeTo: nil, bookmarkDataIsStale: &bookmarkDataIsStale) as URL)
if bookmarkDataIsStale.boolValue {
NSLog("WARNING stale security bookmark")
return false
}
return url.startAccessingSecurityScopedResource()
} catch {
print(error.localizedDescription)
return false
}
}
return false
} // isPermissionGranted
static func selectFolder(folderPicked: () -> Void) {
let folderChooserPoint = CGPoint(x: 0, y: 0)
let folderChooserSize = CGSize(width: 450, height: 400)
let folderChooserRectangle = CGRect(origin: folderChooserPoint, size: folderChooserSize)
let folderPicker = NSOpenPanel(contentRect: folderChooserRectangle, styleMask: .utilityWindow, backing: .buffered, defer: true)
let homePath = "/Users/\(NSUserName())"
folderPicker.directoryURL = NSURL.fileURL(withPath: homePath, isDirectory: true)
folderPicker.canChooseDirectories = true
folderPicker.canChooseFiles = false
folderPicker.allowsMultipleSelection = false
folderPicker.canDownloadUbiquitousContents = false
folderPicker.canResolveUbiquitousConflicts = false
folderPicker.begin { response in
if response == .OK {
let url = folderPicker.urls
NSLog("\(url)")
// Save Url Bookmark
if let mUrl = folderPicker.url {
storeFolderInBookmark(url: mUrl)
}
}
}
}
private static func storeFolderInBookmark(url: URL) { // mark 1
do {
let data = try url.bookmarkData(options: NSURL.BookmarkCreationOptions.withSecurityScope, includingResourceValuesForKeys: nil, relativeTo: nil)
UserDefaults.standard.set(data, forKey: BOOKMARK_KEY)
} catch {
NSLog("Error storing bookmarks")
}
}
How to Use:
isPermissionGranted() - this function is to check user has granted directory permission or not. If it returns true then use directory/file operation read/write. If it returns false then use call selectFolder() function
selectFolder() - if isPermissionGranted() returns false then call this function to take permission from user. user will just need to click on as home directory will choose automatically.
storeFolderInBookmark() - Just keep it in the code you don't need to modify it, it will save url as bookmark for future use
Hope this will help & save lots of time. Thanks.
I found the best and working answer here - reusing security scoped bookmark
Super simple, easy to understand and does the job pretty well.
The solution was :-
var userDefault = NSUserDefaults.standardUserDefaults()
var folderPath: NSURL? {
didSet {
do {
let bookmark = try folderPath?.bookmarkDataWithOptions(.SecurityScopeAllowOnlyReadAccess, includingResourceValuesForKeys: nil, relativeToURL: nil)
userDefault.setObject(bookmark, forKey: "bookmark")
} catch let error as NSError {
print("Set Bookmark Fails: \(error.description)")
}
}
}
func applicationDidFinishLaunching(aNotification: NSNotification) {
if let bookmarkData = userDefault.objectForKey("bookmark") as? NSData {
do {
let url = try NSURL.init(byResolvingBookmarkData: bookmarkData, options: .WithoutUI, relativeToURL: nil, bookmarkDataIsStale: nil)
url.startAccessingSecurityScopedResource()
} catch let error as NSError {
print("Bookmark Access Fails: \(error.description)")
}
}
}
Updated to Swift 5 (Thanks Jay!)
var folderPath: URL? {
didSet {
do {
let bookmark = try folderPath?.bookmarkData(options: .securityScopeAllowOnlyReadAccess, includingResourceValuesForKeys: nil, relativeTo: nil)
UserDefaults.standard.set(bookmark, forKey: "bookmark")
} catch let error as NSError {
print("Set Bookmark Fails: \(error.description)")
}
}
}
func applicationDidFinishLaunching(_ aNotification: Notification) {
if let bookmarkData = UserDefaults.standard.object(forKey: "bookmark") as? Data {
do {
var bookmarkIsStale = false
let url = try URL.init(resolvingBookmarkData: bookmarkData as Data, options: .withSecurityScope, relativeTo: nil, bookmarkDataIsStale: &bookmarkIsStale)
url.startAccessingSecurityScopedResource()
} catch let error as NSError {
print("Bookmark Access Fails: \(error.description)")
}
}
}

Show Upload Progress for Image Upload to Amazon S3 using Swift 3 and Amazon SDK

I am able to successfully upload an image to Amazon S3, but I can't seem to figure out how to show the progress of it doing so.
I'm currently uploading like so.
import UIKit
import MapKit
import CoreData
import AWSCore
import AWSCognito
import AWSS3
import MobileCoreServices
import AWSMobileAnalytics
in my upload button I have the following code...
let myIdentityPoolId = "us-west-2:dca2beb4-9a67-etc....etc..."
let credentialsProvider:AWSCognitoCredentialsProvider = AWSCognitoCredentialsProvider(regionType: AWSRegionType.usWest2, identityPoolId: myIdentityPoolId)
let configuration = AWSServiceConfiguration(region: AWSRegionType.usWest2, credentialsProvider: credentialsProvider)
AWSServiceManager.default().defaultServiceConfiguration = configuration
self.uploadImage(filename)
This is the uploadImage function...
func uploadImage(filename:String){
print("AWS Upload Image Attempt...")
//defining bucket and upload file name
let S3BucketName: String = "distribution-tech-mobile-live"
let filepath = "\(AppDelegate.appDelegate.applicationDocumentsDirectory())/\(filename)"
let imageURL = URL(fileURLWithPath: filepath)
let S3UploadKeyName = filename //TODO: Change this later
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = S3BucketName
uploadRequest?.key = filename
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = imageURL
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
print("\(totalBytesSent)/\(totalBytesExpectedToSend)")
})
}
self.uploadCompletionHandler = { (task, error) -> Void in
DispatchQueue.main.async(execute: {
if ((error) != nil){
print("Failed with error")
print("Error: \(error!)");
}
else{
print("Sucess")
}
})
}
let transferUtility = AWSS3TransferUtility.default()
let expression = AWSS3TransferUtilityUploadExpression()
transferUtility.uploadFile(imageURL, bucket: S3BucketName, key: S3UploadKeyName, contentType: "image/jpeg", expression: expression, completionHander: uploadCompletionHandler).continue({ (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;
})
}
I got the code for image uploading progress from another thread but there solution doesn't seem to work or I'm misunderstanding it.
Upload image AWS S3 bucket in swift, and this thread (Swift - AWS S3 Upload Image from Photo Library and download it). They both have 2 different ways to do it, the last link I couldn't get its way to work either.
I'm not sure what I'm doing wrong.
Okay I found the solution to my problem, apparently I just didn't follow through enough.
Here is my new revised uploadImage function
func uploadImage(filename:String){
print("AWS Upload Image Attempt...")
//defining bucket and upload file name
let S3BucketName: String = "distribution-tech-mobile-live"
let filepath = "\(AppDelegate.appDelegate.applicationDocumentsDirectory())/\(filename)"
let imageURL = URL(fileURLWithPath: filepath)
let S3UploadKeyName = filename //TODO: Change this later
let uploadRequest = AWSS3TransferManagerUploadRequest()
uploadRequest?.bucket = S3BucketName
uploadRequest?.key = S3UploadKeyName
uploadRequest?.contentType = "image/jpeg"
uploadRequest?.body = imageURL
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
print("\(totalBytesSent)/\(totalBytesExpectedToSend)")
})
}
let transferManager = AWSS3TransferManager.default()
transferManager?.upload(uploadRequest).continue(with: AWSExecutor.mainThread(), withSuccessBlock: { (taskk: AWSTask) -> Any? in
if taskk.error != nil {
// Error.
print("error")
} else {
// Do something with your result.
print("something with result when its done")
}
return nil
})
}
This has spot for when result is done and during the upload progress and makes a lot more sense.