Swift 4/5下FTP实现疑问:是否仍支持及操作方案选择
Hey there! Let’s dive straight into your questions since you’ve already confirmed you need to use FTP despite its security concerns.
1. Does Swift 5 still support FTP?
Absolutely! While Apple has shifted focus to more modern, secure protocols like HTTP/HTTPS and iCloud, the underlying Foundation framework (which Swift relies on) still fully supports FTP operations. You can use URLSession—the same API you’d use for HTTP requests—to handle FTP tasks, since ftp:// is a valid URL scheme that URLSession recognizes.
2. How to implement your required FTP operations in Swift 5?
Here’s a breakdown of how to handle each of your needs with native URLSession (no extra frameworks required):
First: Handle FTP Authentication
Most FTP servers require username/password auth. Instead of embedding credentials directly in the URL (which is insecure), use URLSession’s authentication challenge handler:
class FTPManager: NSObject, URLSessionDelegate { func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodFTP { let credential = URLCredential(user: "yourUsername", password: "yourPassword", persistence: .forSession) completionHandler(.useCredential, credential) } else { completionHandler(.performDefaultHandling, nil) } } } // Initialize your session with the delegate let ftpDelegate = FTPManager() let session = URLSession(configuration: .default, delegate: ftpDelegate, delegateQueue: .main)
List/Search Files (Directory Listing)
To get a list of files on the FTP server, send a data request to the directory URL. The response is plain text that you can parse for your search needs:
func listFiles(at ftpDirectoryURL: URL) { let task = session.dataTask(with: ftpDirectoryURL) { data, response, error in guard let data = data, error == nil else { print("Error listing files: \(error?.localizedDescription ?? "Unknown error")") return } // Parse the FTP directory listing (format varies by server, adjust as needed) let fileList = String(data: data, encoding: .utf8)?.components(separatedBy: .newlines) print("Files in directory: \(fileList ?? [])") // Add your custom search logic here to filter files by name/type } task.resume() }
Download a File
Use downloadTask to fetch a file from the FTP server to your local device:
func downloadFile(from ftpFileURL: URL, to localURL: URL) { let task = session.downloadTask(with: ftpFileURL) { tempURL, response, error in guard let tempURL = tempURL, error == nil else { print("Error downloading file: \(error?.localizedDescription ?? "Unknown error")") return } do { // Move the temporary download file to your desired local location try FileManager.default.moveItem(at: tempURL, to: localURL) print("File downloaded successfully to \(localURL)") } catch { print("Error moving downloaded file: \(error.localizedDescription)") } } task.resume() }
Delete a File on the Server
Send a DELETE request to the target file’s FTP URL:
func deleteFile(at ftpFileURL: URL) { var request = URLRequest(url: ftpFileURL) request.httpMethod = "DELETE" let task = session.dataTask(with: request) { _, response, error in if let error = error { print("Error deleting file: \(error.localizedDescription)") } else if let httpResponse = response as? HTTPURLResponse { // FTP uses 2xx codes for success; 250 is the common code for successful deletion if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 { print("File deleted successfully") } else { print("Deletion failed with status code: \(httpResponse.statusCode)") } } } task.resume() }
Upload an Edited File
Use uploadTask to send your edited local file back to the FTP server with a PUT request:
func uploadFile(from localFileURL: URL, to ftpDestinationURL: URL) { var request = URLRequest(url: ftpDestinationURL) request.httpMethod = "PUT" let task = session.uploadTask(with: request, fromFile: localFileURL) { _, response, error in if let error = error { print("Error uploading file: \(error.localizedDescription)") } else if let httpResponse = response as? HTTPURLResponse { if httpResponse.statusCode >= 200 && httpResponse.statusCode < 300 { print("File uploaded successfully") } else { print("Upload failed with status code: \(httpResponse.statusCode)") } } } task.resume() }
3. Should you use FileProvider instead?
Short answer: No, not for your specific use case.
FileProvider is designed to integrate your app with the system’s Files app, letting users browse and manage files stored in your app (or connected services) directly from the system interface. It doesn’t handle FTP operations natively—you’d still need to write the FTP logic yourself, and adding FileProvider would only add unnecessary complexity if you don’t need system-level file integration.
Stick to native URLSession for your core FTP tasks; it’s lightweight, fully supported in Swift 5, and covers all the operations you need.
内容的提问来源于stack exchange,提问作者Neph

