FileManager replacement for Local, iCloud and Remote (WebDAV/FTP/Dropbox/OneDrive) files -- Swift

Overview

File Provider

This Swift library provide a swifty way to deal with local and remote files and directories in a unified way.

Swift Version Platform License Build Status Codebeat Badge

Release version CocoaPods version Carthage compatible Cocoapods Downloads Cocoapods Apps

This library provides implementaion of WebDav, FTP, Dropbox, OneDrive and SMB2 (incomplete) and local files.

All functions do async calls and it wont block your main thread.

Features

  • LocalFileProvider a wrapper around FileManager with some additions like builtin coordinating, searching and reading a portion of file.
  • CloudFileProvider A wrapper around app's ubiquitous container API of iCloud Drive.
  • WebDAVFileProvider WebDAV protocol is defacto file transmission standard, supported by some cloud services like ownCloud, Box.com and Yandex.disk.
  • FTPFileProvider While deprecated in 1990s due to serious security concerns, it's still in use on some Web hosts.
  • DropboxFileProvider A wrapper around Dropbox Web API.
    • For now it has limitation in uploading files up to 150MB.
  • OneDriveFileProvider A wrapper around OneDrive REST API, works with onedrive.com and compatible (business) servers.
  • AmazonS3FileProvider Amazon storage backend. Used by many sites.
  • GoogleFileProvider A wrapper around Goodle Drive REST API.
  • SMBFileProvider SMB2/3 introduced in 2006, which is a file and printer sharing protocol originated from Microsoft Windows and now is replacing AFP protocol on macOS.
    • Data types and some basic functions are implemented but main interface is not implemented yet!.
    • For now, you can use amosavian/AMSMB2 framework to connect to SMB2.

Requirements

  • Swift 4.0 or higher
  • iOS 8.0 , OSX 10.10
  • XCode 9.0

Legacy version is available in swift-3 branch.

Installation

Important: this library has been renamed to avoid conflict in iOS 11, macOS 10.13 and Xcode 9.0. Please read issue #53 to find more.

Cocoapods / Carthage / Swift Package Manager

Add this line to your pods file:

pod "FilesProvider"

Or add this to Cartfile:

github "amosavian/FileProvider"

Or to use in Swift Package Manager add this line in Dependencies:

.Package(url: "https://github.com/amosavian/FileProvider.git", majorVersion: 0)

Manually

To have latest updates with ease, use this command on terminal to get a clone:

git clone https://github.com/amosavian/FileProvider

You can update your library using this command in FileProvider folder:

git pull

if you have a git based project, use this command in your projects directory to add this project as a submodule to your project:

git submodule add https://github.com/amosavian/FileProvider

Then you can do either:

  • Copy Source folder to your project and Voila!

  • Drop FilesProvider.xcodeproj to you Xcode workspace and add the framework to your Embeded Binaries in target.

Design

To find design concepts and how to implement a custom provider, read Concepts and Design document.

Usage

Each provider has a specific class which conforms to FileProvider protocol and share same syntax.

Find a sample code for iOS here.

Initialization

For LocalFileProvider if you want to deal with Documents folder:

import FilesProvider

let documentsProvider = LocalFileProvider()

// Equals with:
let documentsProvider = LocalFileProvider(for: .documentDirectory, in: .userDomainMask)

// Equals with:
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let documentsProvider = LocalFileProvider(baseURL: documentsURL)

Also for using group shared container:

import FilesProvider

let documentsProvider = LocalFileProvider(sharedContainerId: "group.yourcompany.appContainer")
// Replace your group identifier

You can't change the base url later. and all paths are related to this base url by default.

To initialize an iCloud Container provider look at here to see how to update project settings then use below code, This will automatically manager creating Documents folder in container:

import FilesProvider

let documentsProvider = CloudFileProvider(containerId: nil)

For remote file providers authentication may be necessary:

import FilesProvider

let credential = URLCredential(user: "user", password: "pass", persistence: .permanent)
let webdavProvider = WebDAVFileProvider(baseURL: URL(string: "http://www.example.com/dav")!, credential: credential)
  • In case you want to connect non-secure servers for WebDAV (http) or FTP in iOS 9+ / macOS 10.11+ you should disable App Transport Security (ATS) according to this guide.

  • For Dropbox & OneDrive, user is clientID and password is Token which both must be retrieved via OAuth2 API o. There are libraries like p2/OAuth2 or OAuthSwift which can facilate the procedure to retrieve token. The latter is easier to use and prefered. Please see OAuth example for Dropbox and OneDrive for detailed instruction.

For interaction with UI, set delegate property of FileProvider object.

You can use url(of:) method if provider to get direct access url (local or remote files) for some file systems which allows to do so (Dropbox doesn't support and returns path simply wrapped in URL).

Delegates

For updating User interface please consider using delegate method instead of completion handlers. Delegate methods are guaranteed to run in main thread to avoid bugs.

There's simply three method which indicated whether the operation failed, succeed and how much of operation has been done (suitable for uploading and downloading operations).

Your class should conforms FileProviderDelegate class:

override func viewDidLoad() {
	documentsProvider.delegate = self as FileProviderDelegate
}
	
func fileproviderSucceed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
	switch operation {
	case .copy(source: let source, destination: let dest):
		print("\(source) copied to \(dest).")
	case .remove(path: let path):
		print("\(path) has been deleted.")
	default:
		print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) succeed")
	}
}

func fileproviderFailed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
    switch operation {
	case .copy(source: let source, destination: let dest):
		print("copy of \(source) failed.")
	case .remove:
		print("file can't be deleted.")
	default:
		print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) failed")
	}
}
	
func fileproviderProgress(_ fileProvider: FileProviderOperations, operation: FileOperationType, progress: Float) {
	switch operation {
	case .copy(source: let source, destination: let dest):
		print("Copy\(source) to \(dest): \(progress * 100) completed.")
	default:
		break
	}
}

Note: fileproviderProgress() delegate method is not called by LocalFileProvider currently.

It's recommended to use completion handlers for error handling or result processing.

Controlling file operations

You can also implement FileOperationDelegate protocol to control behaviour of file operation (copy, move/rename, remove and linking), and decide which files should be removed for example and which won't.

fileProvider(shouldDoOperation:) method is called before doing a operation. You sould return true if you want to do operation or false if you want to stop that operation.

fileProvider(shouldProceedAfterError:, operation:) will be called if an error occured during file operations. Return true if you want to continue operation on next files or false if you want stop operation further. Default value is false if you don't implement delegate.

Note: In LocalFileProvider, these methods will be called for files in a directory and its subfolders recursively.

Directory contents and file attributes

There is a FileObject class which holds file attributes like size and creation date. You can retrieve information of files inside a directory or get information of a file directly.

For a single file:

documentsProvider.attributesOfItem(path: "/file.txt", completionHandler: {
	attributes, error in
	if let attributes = attributes {
		print("File Size: \(attributes.size)")
		print("Creation Date: \(attributes.creationDate)")
		print("Modification Date: \(attributes.modifiedDate)")
		print("Is Read Only: \(attributes.isReadOnly)")
	}
})

To get list of files in a directory:

documentsProvider.contentsOfDirectory(path: "/", completionHandler: {
	contents, error in
	for file in contents {
		print("Name: \(file.name)")
		print("Size: \(file.size)")
		print("Creation Date: \(file.creationDate)")
		print("Modification Date: \(file.modifiedDate)")
	}
})

To get size of strage and used/free space:

func storageProperties(completionHandler: { total, used in
	print("Total Storage Space: \(total)")
	print("Used Space: \(used)")
	print("Free Space: \(total - used)")
})
  • if this function is unavailable on provider or an error has been occurred, total space will be reported -1 and used space 0

Creating File and Folders

Creating new directory:

documentsProvider.create(folder: "new folder", at: "/", completionHandler: { error in
    if let error = error {
        // Error handling here
    } else {
        // The operation succeed
    }
})

To create a file, use writeContents(path:, content:, atomically:, completionHandler:) method.

Copy and Move/Rename Files

Copy file old.txt to new.txt in current path:

documentsProvider.copyItem(path: "new folder/old.txt", to: "new.txt", overwrite: false, completionHandler: nil)

Move file old.txt to new.txt in current path:

documentsProvider.moveItem(path: "new folder/old.txt", to: "new.txt", overwrite: false, completionHandler: nil)

Note: To have a consistent behavior, create intermediate directories first if necessary.

Delete Files

documentsProvider.removeItem(path: "new.txt", completionHandler: nil)

Fetching Contents of File

There is two method for this purpose, one of them loads entire file into Data and another can load a portion of file.

documentsProvider.contents(path: "old.txt", completionHandler: {
	contents, error in
	if let contents = contents {
		print(String(data: contents, encoding: .utf8)) // "hello world!"
	}
})

If you want to retrieve a portion of file you can use contents method with offset and length arguments. Please note first byte of file has offset: 0.

documentsProvider.contents(path: "old.txt", offset: 2, length: 5, completionHandler: {
	contents, error in
	if let contents = contents {
		print(String(data: contents, encoding: .utf8)) // "llo w"
	}
})

Write Data To Files

let data = "What's up Newyork!".data(encoding: .utf8)
documentsProvider.writeContents(path: "old.txt", content: data, atomically: true, completionHandler: nil)

Copying Files to and From Local Storage

There are two methods to download and upload files between provider's and local storage. These methods use URLSessionDownloadTask and URLSessionUploadTask classes and allows to use background session and provide progress via delegate.

To upload a file:

let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("image.jpg")
documentsProvider.copyItem(localFile: fileURL, to: "/upload/image.jpg", overwrite: true, completionHandler: nil)

To download a file:

let fileURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!.appendingPathComponent("image.jpg")
documentsProvider.copyItem(path: "/download/image.jpg", toLocalURL: fileURL, overwrite: true, completionHandler: nil)
  • It's safe only to assume these methods won't handle directories to upload/download recursively. If you need, you can list directories, create directories on target and copy files using these methods.
  • FTP provider allows developer to either use apple implemented URLSessionDownloadTask or custom implemented method based on stream task via useAppleImplementation property. FTP protocol is not supported by background session.

Operation Progress

Creating/Copying/Deleting/Searching functions return a (NS)Progress. It provides operation type, progress and a .cancel() method which allows you to cancel operation in midst. You can check cancellable property to check either you can cancel operation via this object or not.

  • Note: Progress reporting is not supported by native (NS)FileManager so LocalFileProvider.

Undo Operations

Providers conform to FileProviderUndoable can perform undo for some operations like moving/renaming, copying and creating (file or folder). Now, only LocalFileProvider supports this feature. To implement:

// To setup a new UndoManager:
documentsProvider.setupUndoManager()
// or if you have an UndoManager object already:
documentsProvider.undoManager = self.undoManager

// e.g.: To undo last operation manually:
documentsProvider.undoManager?.undo()

You can also bind UndoManager object with view controller to use shake gesture and builtin undo support in iOS/macOS, add these code to your ViewController class like this sample code:

class ViewController: UIViewController
    override var canBecomeFirstResponder: Bool {
        return true
    }
    
    override var undoManager: UndoManager? {
        return (provider as? FileProvideUndoable)?.undoManager
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // Your code here
        UIApplication.shared.applicationSupportsShakeToEdit = true
        self.becomeFirstResponder()
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // Your code here
        UIApplication.shared.applicationSupportsShakeToEdit = false
        self.resignFirstResponder()
    }
    // The rest of your implementation
}

File Coordination

LocalFileProvider and its descendents has a isCoordinating property. By setting this, provider will use NSFileCoordinating class to do all file operations. It's mandatory for iCloud, while recommended when using shared container or anywhere that simultaneous operations on a file/folder is common.

Monitoring File Changes

You can monitor updates in some file system (Local and SMB2), there is three methods in supporting provider you can use to register a handler, to unregister and to check whether it's being monitored or not. It's useful to find out when new files added or removed from directory and update user interface. The handler will be dispatched to main threads to avoid UI bugs with a 0.25 sec delay.

// to register a new notification handler
documentsProvider.registerNotifcation(path: "/") {
	// calling functions to update UI 
}
	
// To discontinue monitoring folders:
documentsProvider.unregisterNotifcation(path: "/")
  • Please note in LocalFileProvider it will also monitor changes in subfolders. This behaviour can varies according to file system specification.

Thumbnail and meta-information

Providers which conform ExtendedFileProvider are able to generate thumbnail or provide file meta-information for images, media and pdf files.

Local, OneDrive and Dropbox providers support this functionality.

Thumbnails

To check either file thumbnail is supported or not and fetch thumbnail, use (and modify) these example code:

let path = "/newImage.jpg"
let thumbSize = CGSize(width: 64, height: 64) // or nil which renders to default dimension of provider
if documentsProvider.thumbnailOfFileSupported(path: path {
    documentsProvider.thumbnailOfFile(path: file.path, dimension: thumbSize, completionHandler: { (image, error) in
        // Interacting with UI must be placed in main thread
        DispatchQueue.main.async {
            self.previewImage.image = image
        }
    }
}
  • Please note it won't cache generated images. if you don't do it yourself, it may hit you app's performance.
Meta-informations

To get meta-information like image/video taken date, location, dimension, etc., use (and modify) these example code:

if documentsProvider..propertiesOfFile(path: file.path, completionHandler: { (propertiesDictionary, keys, error) in
    for key in keys {
        print("\(key): \(propertiesDictionary[key])")
    }
}
  • Bonus: You can modify/extend Local provider generator by setting LocalFileInformationGenerator static variables and methods

Contribute

We would love for you to contribute to FileProvider, check the LICENSE file for more info.

Things you may consider to help us:

  • Implement request/response stack for SMBClient
  • Implement Test-case (XCTest)
  • Add Sample project for iOS
  • Add Sample project for macOS

Projects in use

If you used this library in your project, you can open an issue to inform us.

Meta

Amir-Abbas Mousavian – @amosavian

Thanks to Hootan Moradi for designing logo.

Distributed under the MIT license. See LICENSE for more information.

https://github.com/amosavian/

Comments
  • WebDavFileProvider example

    WebDavFileProvider example

    This is my example code for os x:

    import Cocoa
    import FileProvider
    
    class ViewController: NSViewController {
        
        @IBOutlet weak var writeText: NSTextField!
        @IBOutlet weak var textSavedFromFile: NSTextField!
        @IBOutlet weak var folderList: NSTextField!
        
        var webdavFile: WebDAVFileProvider?
        var operation: OperationHandle?
        
        @IBAction func saveText(_ sender: NSButton) {
            let user = "[email protected]"
            let password = "xxxx"
            
            let credential = URLCredential(user: user, password: password, persistence: .forSession)
            let myUrlWebdav = URL(string: "https://webdav.pcloud.com")
            let webdavFile = WebDAVFileProvider(baseURL: myUrlWebdav!, credential: credential)
            let path = "newFile1.txt"
            let nameFolder = "Text"
            let atFolder = "/"
            let atFile = atFolder + nameFolder + atFolder + path
            
            print(atFile)
    
            if writeText.stringValue != "" {
                let data = writeText.stringValue.data(using: .utf8)
                print("Data is: \(data)")
                
                webdavFile?.create(folder: nameFolder, at: atFolder, completionHandler: { error in
                    if error == nil {
                    print("La cartella è stata creata con successo.")
                    }
                    else
                    {
                    print("La cartella non è stata creata con il seguente errore: \(error)")
                    }
                    webdavFile?.writeContents(path: atFile, contents: data, atomically: false, overwrite: false, completionHandler: { error in
                        if error == nil {
                            print("Il file è stato creato con successo.")
                        }
                        else
                        {
                            print("Il file non è stato creato con il seguente errore: \(error)")
                        }
                    })
                
                })
            }
            
        }
    
        @IBAction func readText(_ sender: NSButton) {
            
        }
        
        @IBAction func folderList(_ sender: NSButton) {
            
        }
        
    
        override func viewDidLoad() {
            super.viewDidLoad()
            
            // Do any additional setup after loading the view.
            webdavFile?.delegate = (self as! FileProviderDelegate)
        }
    
        override var representedObject: Any? {
            didSet {
            // Update the view, if already loaded.
            }
        }
    
        func fileproviderSucceed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
            switch operation {
            case .copy(source: let source, destination: let dest):
                print("\(source) copied to \(dest).")
            case .remove(path: let path):
                print("\(path) has been deleted.")
            default:
                print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) succeed")
            }
        }
        
        func fileproviderFailed(_ fileProvider: FileProviderOperations, operation: FileOperationType) {
            switch operation {
            case .create(path: let pathFile):
                print("create file: \(pathFile) failed.")
            case .modify(path: let pathFile):
                print("modify file: \(pathFile) failed.")
            case .copy(source: let source, destination: let dest):
                print("copy of \(source) failed.")
            case .remove:
                print("file can't be deleted.")
            default:
                print("\(operation.actionDescription) from \(operation.source!) to \(operation.destination) failed")
            }
        }
        
        func fileproviderProgress(_ fileProvider: FileProviderOperations, operation: FileOperationType, progress: Float) {
            switch operation {
            case .copy(source: let source, destination: let dest):
                print("Copy\(source) to \(dest): \(progress * 100) completed.")
            case .create(path: let pathFile):
                print("Create file or folder to \(pathFile): \(progress * 100) completed.")
            default:
                break
            }
        }
    }
    

    My problems are:

    1. If I do not use "create folder" and the folder does not exist the file is not created without any error.
    2. If the directory exists the file is created, but without any information.
    3. It does not work the delegate method.

    Can anyone change the code so that it works? Thank you Cesare Piersigilli

    bug 
    opened by CPiersigilli 46
  • HELP WANTED - Addchild example use

    HELP WANTED - Addchild example use

    I have this method:

    func upLoadMultiPhotoWithAddChild(folder:String, namePhotos:[String], completion: GeoCompletionHandler) -> Progress {
            progress = Progress(totalUnitCount: Int64(namePhotos.count)*2)
            for namePhoto in namePhotos {
                guard progress?.isCancelled != true else {
                    return progress!
                }
                let createProgress = webdav?.create(folder: "test", at: "/", completionHandler: { (error) in
                    if let error = error {
                        if self.handleWebdavError(error: error).errorCode != 405 {
                            completion!(self.handleWebdavError(error: error))
                            return
                        }
                    }
                    let copyProgress = self.webdav?.copyItem(localFile: namePhoto.toLocalURL(), to: namePhoto.toRemotePath(destFolder: "test"), completionHandler: { (error) in
                        if let error = error {
                            completion!(self.handleWebdavError(error: error))
                            return
                        }
                        completion!(GeoErrorStruct())
                    })
                    // Add the copyProgress task's progress as a child to the overall progress.
                    self.progress?.addChild(copyProgress!, withPendingUnitCount: 1)
                })
                // Add the writeProgress task's progress as a child to the overall progress.
                progress?.addChild(createProgress!, withPendingUnitCount: 1)
            }
            return progress!
        }
    

    In my View Controller:

    @IBAction func uploadMultiPhoto(_ sender: UIButton) {
            WebdavHelper.shared.setWebdav()
            progressView.setProgress(0, animated: true)
            let progress = WebdavHelper.shared.upLoadMultiPhotoWithAddChild(folder: "test", namePhotos: namePhotos) { (geoError) in
                if geoError.errorCode == nil {
                    print("Upload foto riuscito.")
                }
            }
            progressView.observedProgress = progress
        }
    

    Unfortunately, even if the upload of the photos has been properly completed, progressView never reaches 1, that is at the end: why? Where am I wrong?

    opened by CPiersigilli 20
  • WedDavFileProvider. No check error:

    WedDavFileProvider. No check error: "A server with the specified hostname could not be found".

    I'd like to check the credentials within the app (URL, user and password), but if the URL is wrong here's what I get: error.errorDescription = "A server with the specified hostname could not be found" Therefore I thought I could replace it with if let error = error as? FileProviderWebDavError { in order to have the exact error number but I get nil and I'm not able to handle the error. Any idea? Best Regards.

    question 
    opened by CPiersigilli 17
  • FTP Upload TLS/SSL Error

    FTP Upload TLS/SSL Error

    I am getting an error when trying to upload using a file using a FTP handler. Here is the function that I am calling:

    func sendDataToServer(_ file: URL){
            let credentials = URLCredential(user: "sample", password: "sample", persistence: .forSession)
            
            let host = URL(string: "ftp://ftp.site.com")!
            let ftpProvider = FTPFileProvider(baseURL: host, passive: false, credential: credentials)!
            
            ftpProvider.copyItem(localFile: file, to: "/directory/test.csv", overwrite: true, completionHandler: { (error) in
                print(error?.localizedDescription ?? "no error")
            })
        }
    

    Once this is executed I get the following error:

    Invalid sequence of commands (AUTH SSL/TLS required prior to authentication).

    Could you advise on what the next steps would be for this?

    Thanks in advance!

    bug enhancement 
    opened by webmasterjunkie 16
  • FTP data connection request times out every time on iOS 11

    FTP data connection request times out every time on iOS 11

    So the problem is that I'm currently working on a project and when I was testing it on iOS 9, everything was fine , but when we updated the devices to iOS 11, every FTP data connection request times out.

    opened by brashkov 14
  • FTPFileProvider protocol exception?

    FTPFileProvider protocol exception?

    Hi amosavian,

    first of all I would like to thank you! This library is awesome.

    However, I think I found an issue which may happen with server responses. Long time ago I developed a small http-server and discovered that not all servers are "literally" following the specification. Sometimes there is whitespaces missing or just a dash inserted so that the parser gets confused. I am not sure if this is the case here. Maybe you could have a look at this:

    In the

    func ftpRetrieve(_ task: filePath: from position: length: onTask: onProgress: completionHandler:)

    the framework calls the closure

    { (response, error) in
                                            
               do {
                            if let error = error {
                                throw error
                            }
                            
                            guard let response = response else {
                                throw self.urlError(filePath, code: .cannotParseResponse)
                            }
                            
                            if !(response.hasPrefix("1") || response.hasPrefix("2")) {
                                throw FileProviderFTPError(message: response)
                            }
      
         
                        } catch {
                            self.dispatch_queue.async {
                                completionHandler(error)
                            }
                     }
    

    I was curious what happened, because "officially" the connection timed out. I did a debug-dump of the variable response. The result was:

    200 Type set to I\r\n350 Restarting at 0. Send STORE or RETRIEVE to initiate transfer\r\n227 Entering Passive Mode (212,227,24,12,218,208).

    So it looks like the server works properly and accepts the calls from your framework. Is this probably a case which could be covered by this framework?

    Or did I misunderstand how it works? Because I assume the callback is correct. But no data is being transmitted, the frameworks stops with a timeout.

    bug 
    opened by JackPearse 11
  • FTPFileProvider.isReachable returns false with errors even though I can read file contents on FTP server.

    FTPFileProvider.isReachable returns false with errors even though I can read file contents on FTP server.

    I'm trying to use FTPFileProvider with latest iOS public beta and XCode public beta. I am able to read contents of files on FTP server but when I call some of the methods like isRechable(), recursiveList(), attributesOfItem() then it doesn't seem to work and also I get some errors.

    Here is the simple piece of code I've written in viewDidLoad()

        let credential = URLCredential(user: "seenu", password: "mypassword", persistence: .permanent)
        let ftpProvider = FTPFileProvider(baseURL: URL(string: "ftp://192.168.0.3:21")!, credential: credential)
        ftpProvider?.delegate = self as FileProviderDelegate
        ftpProvider?.contents(path: "HD/Photos/test.jpg", completionHandler: { (data, error) in
            DispatchQueue.main.async {
                self.image.image = UIImage(data: data!)
                print("Image has been read using ftpProvider")
            }
        })
        
        ftpProvider?.isReachable(completionHandler: {bool in
            print("ftp is rechable: \(bool)");
        })
        
        ftpProvider?.recursiveList(path: "HD/Photos", useMLST: false, completionHandler: {
            contents, error in
            for file in contents {
                print("Name: \(file.name)")
                print("Size: \(file.size)")
                print("Creation Date: \(file.creationDate)")
                print("Modification Date: \(file.modifiedDate)")
            }
        })
        
        ftpProvider?.attributesOfItem(path: "HD/Photos/test.jpg", completionHandler: {
            attributes, error in
            if let attributes = attributes {
                print("File Size: \(attributes.size)")
                print("Creation Date: \(attributes.creationDate)")
                print("Modification Date: \(attributes.modifiedDate)")
                print("Is Read Only: \(attributes.isReadOnly)")
            }
        })
        
        ftpProvider?.contents(path: "HD/test.txt", completionHandler: {
            contents, error in
            if let contents = contents {
                print("File content is: \(String(data: contents, encoding: .utf8))") // "hello world!"
            }
        })
    

    Reading the test.jpg and test.txt file works fine but the other calls doesn't given any output. Below is the console output.

    2017-08-01 00:18:29.450605-0400 ftp[1183:64255] [] nw_connection_fillout_tcp_statistics 1 Connection is not ready 2017-08-01 00:18:29.450846-0400 ftp[1183:64255] [] tcp_connection_get_statistics Failed to get statistics from connection 2017-08-01 00:18:29.456293-0400 ftp[1183:64255] [] nw_connection_fillout_tcp_statistics 2 Connection is not ready 2017-08-01 00:18:29.456840-0400 ftp[1183:64255] [] tcp_connection_get_statistics Failed to get statistics from connection 2017-08-01 00:18:29.460717-0400 ftp[1183:64255] [] nw_connection_fillout_tcp_statistics 3 Connection is not ready 2017-08-01 00:18:29.461325-0400 ftp[1183:64255] [] tcp_connection_get_statistics Failed to get statistics from connection ftp is rechable: false 2017-08-01 00:18:29.490551-0400 ftp[1183:64272] TIC TCP Conn Missing Error [3:0x60400016f600]: Generating 1:54 2017-08-01 00:18:29.490794-0400 ftp[1183:64272] TIC Read Status [3:0x60400016f600]: 1:57 Image has been read using ftpProvider File content is: Optional("Hello world !!") 2017-08-01 00:20:29.543466-0400 ftp[1183:81206] TIC TCP Conn Missing Error [1:0x60000016e1c0]: Generating 1:54 2017-08-01 00:20:29.544054-0400 ftp[1183:81206] TIC TCP Conn Missing Error [2:0x60000016e4c0]: Generating 1:54

    Let me know if I'm doing something wrong or is it some genuine problem ?

    bug 
    opened by gsrinivas37 11
  • WebDav File Path Question

    WebDav File Path Question

    So I've started playing with the WebDav file provider, to see how that fares, and I ran into a bit of an issue or question really.

    Say I make a call to list the contents of a directory with a path: "/data/Hello/Settings/background"

    Everything works, and looks OK, at first glance. Except if I look at the relative path of the FileObjects I got back, its got paths like: "/remote.php/dav/files/skela/remote.php/dav/files/skela/data/Hello/Settings/background/portrait_phones.pdf"

    That to me seems wrong, for instance in Dropbox, all the paths are relative and would be for example: "/data/Hello/Settings/background/portrait_phones.pdf"

    Is this a design choice, or a possible issue ? Just asking because it feels wrong to me.

    Again, really appreciate the work you do on this library!

    bug 
    opened by skela 11
  • Can not login

    Can not login

    I tried to login to my FTP server and get this error:

    "220-You are user number 1 of 50 allowed.\r\n220-Local time is now 09:40. Server port: 21.\r\n220-This is a private system - No anonymous login\r\n220 You will be disconnected after 15 minutes of inactivity.\r\n331 User ****** OK. Password required"

    Please help!

    bug 
    opened by LinhTN-AltPlus 10
  • Occasional error when loggin in

    Occasional error when loggin in

    When executing contentsOfDirectory on my FTP server I get occasional failures with error code -1 and errorDescription 220 Welcome to IC Co. FTP Site. This seems like an instability as it happens totally randomly and quite frequently. Is there anything I can try?

    bug 
    opened by fotiDim 10
  • Progress error when use writecontents or copyitem webdav function

    Progress error when use writecontents or copyitem webdav function

    Using your Sample-iOS.swift, which I modified to perform the tests, I understood that with the functions webdav?.writeContents (path:, webdav?.copyItem (path: and webdav.copyItem (localfile: I get two notifications and the progress of the variable after reaching 1.0 return to 0.75 and then return to 1.0. How can I resolve?

    Moreover, setting wrong values to server, user or password variables the function doesn't end but keep on going.

    I performed the tests on pcloud.com.

    You can see what I reported by downloading the XCODE 9 file here and pressing the "Download File" or "Upload File with copy item" or "Upload File write contents" button from the application.

    I doing something wrong?

    needs investigation 
    opened by CPiersigilli 9
  • Fix onedrive

    Fix onedrive

    • fixed issue with missing auth token in searchFiles request
    • cleaned up a lot of warnings
    • fixed several issues in OneDriveFileProvider ** fixed restore of provider ** fixed issue where searching for an empty string would throw an error ** fixed searching for files at a path ** fixed reachability check
    opened by drallgood 0
  • Linux Support

    Linux Support

    Is this package designed to be compatible with Linux? According to SwiftPackageIndex, it's currently failing to compile due to it not importing FoundationNetworking.

    https://swiftpackageindex.com/amosavian/FileProvider

    It would be great to use this package on server-side Swift to load files over FTP.

    opened by Sherlouk 0
  • FTPS using port 21 not establishing a secure connection

    FTPS using port 21 not establishing a secure connection

    the same credentials "ftps://site.com:21" with username and password, are working successfully in FileZilla, but using FTPFileProvider the connection is never established. (I'm aware that ftps usually uses 990, but my provider forces me onto 21 even for FTPS).

    any suggestions?

    opened by littlewatchman 0
  • FTPFileProvider not working for some mobile networks and wifi

    FTPFileProvider not working for some mobile networks and wifi

    Hello, I am using FTPFileProvider for downloading and uploading files from FTP server , but it is working for only few networks, can you please let me know if I want to make any additional settings in code? Thanks

    opened by Monika-Tapadiya 0
Releases(0.26.0)
  • 0.25.1(May 3, 2018)

    • Fixed Cocoapods error

    Changes in version 0.25.0:

    • General

      • Updated Podspec Swift version to 4.1 and fixed warnings.
      • Introduced FileProviderReadWriteProgressive to allow FTP and HTTP-based providers to fetch file content progressively, suitable for streaming.
      • Fixed encoding error using NSCoding.
      • Fixed FileObject equality and hashing methods
      • Known Issue: Progress for thumbnail and properties does not work yet.
    • Local

      • MadeLocalFileMonitor class public to monitor folder/file changes directly without using provider's registerNotification
      • More items for image metadata in ExtendedLocalFileProvider, including GPS info and White-balance.
    • iCloud

      • Fixed iCloud download/upload progress report, Fixed #93 crash.
    • FTP

      • Fixed race conditions, Possible fix for #79.
      • Returning real error instead of timeout.
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(27.99 MB)
  • 0.25.0(May 3, 2018)

    • General

      • Updated Podspec Swift version to 4.1 and fixed warnings.
      • Introduced FileProviderReadWriteProgressive to allow FTP and HTTP-based providers to fetch file content progressively, suitable for streaming.
      • Fixed encoding error using NSCoding.
      • Fixed FileObject equality and hashing methods
      • Known Issue: Progress for thumbnail and properties does not work yet.
    • Local

      • MadeLocalFileMonitor class public to monitor folder/file changes directly without using provider's registerNotification
      • More items for image metadata in ExtendedLocalFileProvider, including GPS info and White-balance.
    • iCloud

      • Fixed iCloud download/upload progress report, Fixed #93 crash.
    • FTP

      • Fixed race conditions, Possible fix for #79.
      • Returning real error instead of timeout.
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(27.99 MB)
  • 0.24.0(Mar 27, 2018)

    • General

      • Fixed podspec Swift 4.0 setting (#90)
      • Known Issue: Progress for thumbnail and properties does not work yet.
    • FTP

      • Added Extended Passive (EPSV) data connection mode
      • Added support for Windows/DOS style directory list
      • Fixed FTP on TLS data connection failure
    • OneDrive

      • Fixed operation fall on files with non-ASCII names
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(27.74 MB)
  • 0.23.0(Mar 6, 2018)

    • General

      • Source breaking change: isReachable() returns error encountered in addition to success.
      • Optimizations and refactorings
      • Added Concepts and design document.
      • Fixed error description for file provider errors.
      • Known Issue: Progress for thumbnail and properties does not work yet.
    • OneDrive

      • OneDrive provider now works with new Microsoft Graph API perfectly
      • Unlimited uploading
    • iCloud

      • iCloud overwrite parameter ignored when uploading file (#82)
    • WebDAV

      • searchFiles() "including" param was being ignored.
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(20.89 MB)
  • 0.22.0(Dec 30, 2017)

    • General

      • Added test cases for Local, Dropbox, WebDAV and FTP.
      • Remove monitoring notification on deinit.
      • Updated Swift Package Manager to version 4.0.
    • WebDAV

      • Directory are parsed as regular files.
      • Handling space and illegal characters in urls inside response.
    • FTP

      • Problems with iOS 11 and NSURLSessionStreamTask.
      • Crash on downloading and uploading.
      • Removed dependency on Apples FTP implementation for downloading.
      • Faster uploading (Single stream instead of muliple)
    • Dropbox

      • attributesOfItem() returned error instead of result.
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(19.81 MB)
  • 0.21.0(Oct 27, 2017)

    This is the last pod which will work with Swift 3. If you are using Swift 3 in your project, please use swift-3 (will be created soon) branch directly using other installation methods. I will maintain code for Swift 3 as far as possible.

    OneDrive provider is updated to latest version according to Microsoft documentations. You can use OneDriveProvider.Route enum to determine which root should be used to access files, use .me to access your own files or other options to access enterprise and shared files.

    -Important: storageProperties() method signature has been changed and you have to rectify it manually.

    contents(path:, progressHandler:) method added to allow fetch data of remote file progressively. This allows buffering and showing files while downloading.

    Other improvements:

    • storageProperties() method now returns VolumeObject instance in completion handler, which contains volume size and other informations.
    • Added progressive downloading method contents(path:, progressHandler:) for HTTP-based providers
    • Removed currentPath property.
    • Code is Swift 4 compatible now.
    • copy(path:toLocalURL) and copy(localURL:to:) reading and writing to local url are coordinated now.
    • refactored paginated listing. (Dropbox, OneDrive and GoogleDrive in future)
    • Added HEIF thumbnail and properties generators. (iOS 11.0, macOS 10.13)

    Bugs fixed:

    • Cloud provider misbehaves in subdirectories.
    • OneDrive download progress was not available due to Transfer-Encoding: chunked.
    • Overwrite flag didn't work in HTTP-based providers.
    • url(of:) crash when path is empty.
    • Progress returned didn't parented correctly.
    • Improved compilation speed.
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(25.61 MB)
  • 0.20.1(Aug 29, 2017)

    currentPath property is now deprecated and out of use. It will be marked as obsoleted soon. Use local var in case you want to track it. Also fileproviderFailed() delegate method signature has changed to send Error object to user.

    Changes:

    • Making more method implementations overridable for user.
    • Consistency to delegate call in all contents(of:) methods, with .fetch case.
    • moved to v2 api in Dropbox for copy, move and delete files.
    • Using URL.checkResourceIsReachable() to check file exists instead if FileManager.fileExists() for iCloud and promised urls.
    • Added convenience methods for URLRequest headers for Content-Type, Accept-Encoding, Range, etc.

    Bugs fixed:

    • Downloading/Uploading files with colon in name would be failed due to percent encoding
    • Recursive search in FTP, OneDrive, WebDAV
    • FTP crash on rucursive remove due to Progress exception
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(31.61 MB)
  • 0.20.0(Aug 19, 2017)

    Dropbox, WebDAV & OneDrive all are refactored to HTTPFileProvider base class, decreases bugs and adds more consistency.

    Because FileOperationType.source is not optional anymore, I had to increase version.

    Also:

    • Added fileURL to Progress
    • critical bugfix: KVO exception crash on task completion
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(30.17 MB)
  • 0.19.0(Aug 15, 2017)

    Important: Deprecating OperationHandle class in favor of Foundation's Progress class is a source breaking change. You may have to update your current code to use new feature.

    Other improvements:

    • Fixed broken OneDrive API & redundant percent encoding of path (#57 , #59)
    • Fixed Dropbox issue with file path in HTTP header (#58)
    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(31.23 MB)
  • 0.18.1(Jul 17, 2017)

    • Better handling of FTPS (explicit mode)
    • Fixed FTP login problem (#54)
    • Enhanced PDF meta-information:
      • included Producer and Keywords meta-informations.
      • Boolean pdf properties like Allows printing are now really boolean instead of Yes/No string.
      • Dates (Creation date/Modified date) are now correctly handled and parsed for all types of PDF files.

    Note: the library has been renamed to FilesProvider, in case you missed it

    Source code(tar.gz)
    Source code(zip)
    FilesProvider.framework.zip(30.57 MB)
  • 0.18.0(Jul 1, 2017)

    To avoid conflict with new introduced intrinsic framework in iOS 11, macOS 10.13 and tvOS 11, this project has renamed to FilesProvider you may have to update your project settings see #53 for more information.

    Source code(tar.gz)
    Source code(zip)
  • 0.17.0(Jun 27, 2017)

  • 0.16.2(May 5, 2017)

    • Introduced new protocol FileProviderSharing, contains publicLink() method for Dropbox, OneDrive and iCloud providers.
    • Added WebDAV OAuth support by changing WebDAVFileProvider.credentialType property.
    • Now LocalOperationHandle.inProgress property is usable and determines either local file operation is in progress or not.
    • Fixed bug: problem in LocalFileProvider baseURL assignment.
    • Fixed bug: creating percent-encoded folder in WebDAV provider.
    • Fixed bug: Listing FTP directory when server doesn't support RFC3657 (MLST)
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(30.53 MB)
  • 0.16.1(Apr 15, 2017)

  • 0.16.0(Apr 14, 2017)

    This is a patch indeed, but because FileObject.url is now a non-optional, which is source breaking change, I had to increase minor version instead of patch.

    In scenarios which there is no url for FileObject e.g. Dropbox, it will return percent encoded path.

    Bugs fixed in this release:

    • FTP uploading (#36) which caused crash when uploading files and data larger than 64kb (chunked).
    • url initializing were sometimes nil because path/string were not percent encoded.
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(27.21 MB)
  • 0.15.5(Apr 14, 2017)

  • 0.15.4(Apr 11, 2017)

  • 0.15.3(Apr 9, 2017)

  • 0.15.2(Apr 3, 2017)

    session property now can be set by developer. Note that it's delegate must be an instance of SessionDelegate class. You can create a session with background configuration and replace main session like this:

    let sessionDelegate = SessionDelegate(fileProvider: fileProvider, credential: fileProvider.credential)
    let backgroundconfig = URLSessionConfiguration.background(withIdentifier: "com.company.myapp")
    fileProvider.session = URLSession(configuration: backgroundconfig, delegate: sessionDelegate as URLSessionDelegate?, delegateQueue: fileProvider.operation_queue)
    
    • Note: setting session after calling a function may have unpreceded result.

    Also:

    • Fixed issue with colliding handlers between sessions.
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(29.59 MB)
  • 0.15.1(Apr 3, 2017)

    Bug Fixed: Calling completion handler for upload tasks

    Added including (file object properties) argument to WebDAV provider this is the sample code for fetching ETag and size property of file from WebDAV:

    provider.attributesOfItem(path: "/path/to/file", including: [.fileSizeKey, .entryTagKey], completionHandler: { attributes, error in
        print(attributes.size)
        print(attributes.entryTag)
    }
    

    This is also true for contentsOfDirectory() method

    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(28.48 MB)
  • 0.15.0(Apr 1, 2017)

    This release adds FTP protocol support with some minor limitations. (see below)

    Background sessions can be set now for sessions while not recommended due to serious bugs in Apple CFNetwork implementation when you want download a file with a ranged request.

    A new class, FileProviderStreamTask is introduced which is technically a replica of Apple's URLSessionStreamTask with iOS 8 support using low level Core Foundation routines.

    Here is the list of improvements:

    • Credential is open to set/change anytime.
    • Deprecating create(file:) method which was a duplicate of writeContents(path:contents:) method. Now you can pass nil for data argument to create an empty file.

    Here is the list of other bug fixes:

    • WebDAV file listing may omit files contains space in name.
    • Delegate's progress handler didn't call when uploading/downloading was in progress.
    • Swift 3.1 warnings.

    FTP provider limitations:

    • searchFiles() is not implemented and removeItem() won't delete not-empty directories in servers that don't support SITE RMDIR extension command. This limitations will be removed when ftpRecursiveList() is implemented.
    • Active mode is not implemented, technically saying, I didn't find a workaround to set tcp port manually in CFNetwork API
    • FTP over TLS (FTPS) protocol is not tested while implemented.
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(28.54 MB)
  • 0.14.5(Mar 25, 2017)

  • 0.14.4(Mar 18, 2017)

    Optimized PDF thumbnail/meta handling.

    • Fixed relativePath(of:) crashing bug.
    • Fixed ISO speed and GPS Area image meta, better ExposureTime calculation.
    • Fixed Dropbox name NOT BEGINSWITH % search query.
    • Better LocalFileObject initialization with empty path.
    • Refactored DispatchTime.
    • Refactored methods to extensions.
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(24.97 MB)
  • 0.14.3(Feb 24, 2017)

  • 0.14.1(Feb 20, 2017)

  • 0.14.0(Feb 19, 2017)

    searchFiles() method now moved to FileProviderBasic, where it belonged. Now there is two version for searchFiles(), one of them gets String for query to search within files name, also you can set a NSPredicate object to query to filter files based on properties like size and modification date, please read inline help for sample predicates.

    Also:

    • all methods are now open to become overridable
    • Fixed Documentation errors about urlCache
    Source code(tar.gz)
    Source code(zip)
    FileProvider.framework.zip(24.46 MB)
  • 0.12.9(Feb 16, 2017)

  • 0.12.8(Feb 14, 2017)

  • 0.12.7(Feb 13, 2017)

Owner
Amir Abbas Mousavian
A Swift lover based in Tehran
Amir Abbas Mousavian
ZipArchive is a simple utility class for zipping and unzipping files on iOS, macOS and tvOS.

SSZipArchive ZipArchive is a simple utility class for zipping and unzipping files on iOS, macOS and tvOS. Unzip zip files; Unzip password protected zi

ZipArchive 5.2k Jan 2, 2023
FileExplorer is a powerful iOS file browser that allows its users to choose and remove files and/or directories

FileExplorer (iOS 9.0+) ?? Project created and maintained by Rafał Augustyniak. You can find me on twitter (@RaAugustyniak). Introduction FileExplorer

Rafał Augustyniak 717 Dec 19, 2022
Swift framework for zipping and unzipping files.

Zip A Swift framework for zipping and unzipping files. Simple and quick to use. Built on top of minizip. Usage Import Zip at the top of the Swift file

Roy Marmelstein 2.3k Dec 30, 2022
NV_MVVM-C is a template file generator. This can reduce the time taken to write the boilerplate code and create the files.

NV_MVVM-C Template, is an MVVM-C Boilerplate generator which will help you generate all the necessary files for your project architected in MVVM-C.

Nikhil Vinod 9 Sep 6, 2022
SwiftXLSX - A library focused creating Excel spreadsheet (XLSX) files directly on mobile devices

SwiftXLSX Excel spreadsheet (XLSX) format writer on pure SWIFT. SwiftXLSX is a l

null 19 Dec 13, 2022
FileKit is a Swift framework that allows for simple and expressive file management.

FileKit is a Swift framework that allows for simple and expressive file management.

Nikolai Vazquez 2.2k Jan 7, 2023
File management and path analysis for Swift

Pathos offers cross-platform virtual file system APIs for Swift. Pathos is implement from ground-up with on each OS's native API. It has zero dependen

Daniel Duan 104 Nov 19, 2022
zip file I/O library for iOS, macOS and tvOS

ZipZap is a zip file I/O library for iOS, macOS and tvOS. The zip file is an ideal container for compound Objective-C documents. Zip files are widely

Glen Low 1.2k Dec 27, 2022
Zero-setup P2P file transfer between Macs and iOS devices

?? Ares Zero-setup* P2P file transfer between Macs and iOS devices Ares is a service that I built in under 24 hours, winning first place at HackED 201

Indragie Karunaratne 131 Jan 10, 2022
Edit a file, create a new file, and clone from Bitbucket in under 2 minutes

Edit a file, create a new file, and clone from Bitbucket in under 2 minutes When you're done, you can delete the content in this README and update the

Nikunj Munjiyasara 0 Nov 9, 2021
RavynOS File manager built in Cocoa/Appkit and ObjC

Filer A file manager and re-implementation of macOS's Finder. A key component of ravynOS, Filer is the first application you see after you start ravyn

RavynSoft 8 Oct 3, 2022
Effortless path operations in Swift

PathKit Effortless path operations in Swift. Usage let path = Path("/usr/bin/swift") Joining paths let path = Path("/usr/bin") + Path("swift") Determi

Kyle Fuller 1.4k Jan 5, 2023
Effortless ZIP Handling in Swift

ZIP Foundation is a library to create, read and modify ZIP archive files. It is written in Swift and based on Apple's libcompression for high performa

Thomas Zoechling 1.9k Dec 27, 2022
Finder-style iOS file browser written in Swift

FileBrowser iOS Finder-style file browser in Swift 4.0 with search, file previews and 3D touch. Simple and quick to use. Features ✨ Features ?? Browse

Roy Marmelstein 1.5k Dec 16, 2022
Swift framework to connect SMB2/3 shares

AMSMB2 This is small Swift library for iOS, macOS and tvOS which wraps libsmb2 and allows to connect a SMB2/3 share and do file operation. Install Coc

Amir Abbas Mousavian 157 Dec 19, 2022
Simple camera application for iOS that uploads pictures to WebDAV server or Dropbox quickly. Available on the AppStore.

Upupu Simple camera application for iOS that uploads pictures to WebDAV server or Dropbox quickly. Also available on the AppStore. Features Easy and f

Xcoo 65 Nov 15, 2022
StorageManager - FileManager framework that handels Store, fetch, delete and update files in local storage

StorageManager - FileManager framework that handels Store, fetch, delete and update files in local storage. Requirements iOS 8.0+ / macOS 10.10+ / tvOS

Amr Salman 47 Nov 3, 2022
Cloud Drive(GoogleDrive/Dropbox/BaiduPan/OneDrive/pCloud) File Management

CloudServiceKit Easy to integrate cloud service using Oauth2. Supported platforms: AliyunDrive BaiduPan Box Dropbox Google Drive OneDrive pCloud Requi

null 18 Aug 10, 2022
Player for streaming local and remote audio files. Written in Swift.

Jukebox is an iOS audio player written in Swift. Contents Features Installation Supported OS & SDK versions Usage Handling remote events Public interf

Teo 545 Nov 11, 2022
AudioPlayer is syntax and feature sugar over AVPlayer. It plays your audio files (local & remote).

AudioPlayer AudioPlayer is a wrapper around AVPlayer. It also offers cool features such as: Quality control based on number of interruption (buffering

Kevin Delannoy 676 Dec 25, 2022