Skip to content

Commit 96ce12f

Browse files
committed
Added iCloud Drive provider CloudFileProvider
- Refactored initializers - Replaced `NSSearchPathForDirectoriesInDomains` with `FileManager.urls(for:In:)`
1 parent 091fd14 commit 96ce12f

7 files changed

Lines changed: 101 additions & 51 deletions

File tree

FileProvider.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Pod::Spec.new do |s|
1616
#
1717

1818
s.name = "FileProvider"
19-
s.version = "0.10.2"
19+
s.version = "0.10.3"
2020
s.summary = "FileManager replacement for Local and Remote (WebDAV/Dropbox/OneDrive/SMB2) files on iOS and macOS."
2121

2222
# This description is used to generate tags and improve search results.

FileProvider.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,7 +595,7 @@
595595
799396601D48B7BF00086753 /* Debug */ = {
596596
isa = XCBuildConfiguration;
597597
buildSettings = {
598-
BUNDLE_VERSION_STRING = 0.10.2;
598+
BUNDLE_VERSION_STRING = 0.10.3;
599599
CLANG_WARN_BOOL_CONVERSION = YES;
600600
CLANG_WARN_CONSTANT_CONVERSION = YES;
601601
CLANG_WARN_EMPTY_BODY = YES;
@@ -625,7 +625,7 @@
625625
799396611D48B7BF00086753 /* Release */ = {
626626
isa = XCBuildConfiguration;
627627
buildSettings = {
628-
BUNDLE_VERSION_STRING = 0.10.2;
628+
BUNDLE_VERSION_STRING = 0.10.3;
629629
CLANG_WARN_BOOL_CONVERSION = YES;
630630
CLANG_WARN_CONSTANT_CONVERSION = YES;
631631
CLANG_WARN_EMPTY_BODY = YES;

README.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Local and WebDAV providers are fully tested and can be used in production enviro
3030
* For now it has limitation in uploading files up to 150MB.
3131
- [x] **OneDriveFileProvider** A wrapper around OneDrive Web API, works with `onedrive.com` and compatible (business) servers.
3232
* For now it has limitation in uploading files up to 100MB.
33-
- [ ] **CloudFilePRovider** A wrapper around app's ubiquitous container to iCloud Drive in iOS 8+ API.
33+
- [x] **CloudFileProvider** A wrapper around app's ubiquitous container to iCloud Drive in iOS 8+ API.
3434
- [ ] **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.
3535
* Data types and some basic functions are implemented but *main interface is not implemented yet!*
3636
* SMB1/CIFS is depericated and very tricky to be implemented
@@ -103,18 +103,23 @@ For LocalFileProvider if you want to deal with `Documents` folder
103103

104104
``` swift
105105
let documentsProvider = LocalFileProvider()
106-
```
107106

108-
is equal to:
107+
// Equals with:
108+
let documentsProvider = LocalFileProvider(directory: .documentDirectory, domainMask: = .userDomainMask)
109109

110-
``` swift
111-
let documentPath = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true);
112-
let documentsURL = URL(fileURLWithPath: documentPath);
110+
// Equals with:
111+
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
113112
let documentsProvider = LocalFileProvider(baseURL: documentsURL)
114113
```
115114

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

117+
To initialize an iCloud Container provider use below code, This will automatically manager creating Documents folder in container:
118+
119+
```swift
120+
let documentsProvider = CloudFileProvider(containerId: nil)
121+
```
122+
118123
For remote file providers authentication may be necessary:
119124

120125
``` swift

Sources/DropboxFileProvider.swift

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,14 @@ import CoreGraphics
1313
// Because this class uses NSURLSession, it's necessary to disable App Transport Security
1414
// in case of using this class with unencrypted HTTP connection.
1515

16-
open class DropboxFileProvider: NSObject, FileProviderBasicRemote {
16+
open class DropboxFileProvider: FileProviderBasicRemote {
1717
open static let type: String = "DropBox"
18-
open let isPathRelative: Bool = true
18+
open let isPathRelative: Bool
1919
open let baseURL: URL?
20-
open var currentPath: String = ""
20+
open var currentPath: String
2121

22-
open let apiURL = URL(string: "https://api.dropboxapi.com/2/")!
23-
open let contentURL = URL(string: "https://content.dropboxapi.com/2")!
22+
open let apiURL: URL
23+
open let contentURL: URL
2424

2525
open var dispatch_queue: DispatchQueue {
2626
willSet {
@@ -30,8 +30,8 @@ open class DropboxFileProvider: NSObject, FileProviderBasicRemote {
3030
open weak var delegate: FileProviderDelegate?
3131
open let credential: URLCredential?
3232
open private(set) var cache: URLCache?
33-
public var useCache: Bool = false
34-
public var validatingCache: Bool = true
33+
public var useCache: Bool
34+
public var validatingCache: Bool
3535

3636
fileprivate var _session: URLSession?
3737
fileprivate var sessionDelegate: SessionDelegate?
@@ -50,10 +50,17 @@ open class DropboxFileProvider: NSObject, FileProviderBasicRemote {
5050

5151
public init? (credential: URLCredential?, cache: URLCache? = nil) {
5252
self.baseURL = nil
53-
dispatch_queue = DispatchQueue(label: "FileProvider.\(DropboxFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
54-
//let url = baseURL.uw_absoluteString
55-
self.credential = credential
53+
self.isPathRelative = true
54+
self.currentPath = ""
55+
self.useCache = false
56+
self.validatingCache = true
5657
self.cache = cache
58+
self.credential = credential
59+
60+
self.apiURL = URL(string: "https://api.dropboxapi.com/2/")!
61+
self.contentURL = URL(string: "https://content.dropboxapi.com/2")!
62+
63+
dispatch_queue = DispatchQueue(label: "FileProvider.\(DropboxFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
5764
}
5865

5966
deinit {

Sources/LocalFileProvider.swift

Lines changed: 44 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,37 +9,38 @@
99
import Foundation
1010

1111
open class LocalFileProvider: FileProvider, FileProviderMonitor {
12-
open static let type = "Local"
13-
open var isPathRelative: Bool = true
14-
open private(set) var baseURL: URL? = LocalFileProvider.defaultBaseURL()
15-
open var currentPath: String = ""
12+
open static let type: String = "Local"
13+
open var isPathRelative: Bool
14+
open fileprivate(set) var baseURL: URL?
15+
open var currentPath: String
1616
open var dispatch_queue: DispatchQueue
1717
open var operation_queue: DispatchQueue
1818
open weak var delegate: FileProviderDelegate?
19-
open let credential: URLCredential? = nil
19+
open fileprivate(set) var credential: URLCredential?
2020

2121
open private(set) var fileManager = FileManager()
2222
open private(set) var opFileManager = FileManager()
2323
fileprivate var fileProviderManagerDelegate: LocalFileProviderManagerDelegate? = nil
2424

25-
public init () {
26-
dispatch_queue = DispatchQueue(label: "FileProvider.\(LocalFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
27-
operation_queue = DispatchQueue(label: "FileProvider.\(LocalFileProvider.type).Operation", attributes: [])
28-
fileProviderManagerDelegate = LocalFileProviderManagerDelegate(provider: self)
29-
opFileManager.delegate = fileProviderManagerDelegate
25+
/// default values are `directory: .documentDirectory, domainMask: .userDomainMask`
26+
public convenience init (directory: FileManager.SearchPathDirectory = .documentDirectory, domainMask: FileManager.SearchPathDomainMask = .userDomainMask) {
27+
self.init(baseURL: FileManager.default.urls(for: directory, in: domainMask).first!)
3028
}
3129

3230
public init (baseURL: URL) {
3331
self.baseURL = baseURL
32+
self.isPathRelative = true
33+
self.currentPath = ""
34+
self.credential = nil
35+
3436
dispatch_queue = DispatchQueue(label: "FileProvider.\(LocalFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
3537
operation_queue = DispatchQueue(label: "FileProvider.\(LocalFileProvider.type).Operation", attributes: [])
3638
fileProviderManagerDelegate = LocalFileProviderManagerDelegate(provider: self)
3739
opFileManager.delegate = fileProviderManagerDelegate
3840
}
3941

40-
open static func defaultBaseURL() -> URL {
41-
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true);
42-
return URL(fileURLWithPath: paths[0])
42+
open class func defaultBaseURL() -> URL {
43+
return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
4344
}
4445

4546
open func contentsOfDirectory(path: String, completionHandler: @escaping ((_ contents: [FileObject], _ error: Error?) -> Void)) {
@@ -356,3 +357,33 @@ public extension LocalFileProvider {
356357
}
357358
}
358359
}
360+
361+
class CloudFileProvider: LocalFileProvider {
362+
// FIXME: convert static var type to class var in next Swift version
363+
364+
open var type: String { return "iCloudDrive" }
365+
366+
public init? (containerId: String?) {
367+
assert(!Thread.isMainThread, "LocalFileProvider.init(containerId:) is not recommended to be executed on Main Thread.")
368+
guard FileManager.default.ubiquityIdentityToken == nil else {
369+
return nil
370+
}
371+
guard let ubiquityURL = FileManager.default.url(forUbiquityContainerIdentifier: containerId) else {
372+
return nil
373+
}
374+
super.init(baseURL: ubiquityURL.appendingPathComponent("Documents"))
375+
376+
dispatch_queue = DispatchQueue(label: "FileProvider.\(self.type)", attributes: DispatchQueue.Attributes.concurrent)
377+
operation_queue = DispatchQueue(label: "FileProvider.\(self.type).Operation", attributes: [])
378+
379+
fileManager.url(forUbiquityContainerIdentifier: containerId)
380+
opFileManager.url(forUbiquityContainerIdentifier: containerId)
381+
fileProviderManagerDelegate = LocalFileProviderManagerDelegate(provider: self)
382+
opFileManager.delegate = fileProviderManagerDelegate
383+
}
384+
385+
open override static func defaultBaseURL() -> URL {
386+
return FileManager.default.url(forUbiquityContainerIdentifier: nil) ?? super.defaultBaseURL()
387+
}
388+
389+
}

Sources/OneDriveFileProvide.swift

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,16 @@ import CoreGraphics
1313
// Because this class uses NSURLSession, it's necessary to disable App Transport Security
1414
// in case of using this class with unencrypted HTTP connection.
1515

16-
open class OneDriveFileProvider: NSObject, FileProviderBasicRemote {
16+
open class OneDriveFileProvider: FileProviderBasicRemote {
1717
open static let type: String = "OneDrive"
18-
open let isPathRelative: Bool = true
18+
open let isPathRelative: Bool
1919
open let baseURL: URL?
20+
open var serverURL: URL { return baseURL! }
2021
open var drive: String
2122
open var driveURL: URL {
2223
return URL(string: "/drive/\(drive):/", relativeTo: baseURL)!
2324
}
24-
open var currentPath: String = ""
25+
open var currentPath: String
2526

2627
open var dispatch_queue: DispatchQueue {
2728
willSet {
@@ -31,8 +32,8 @@ open class OneDriveFileProvider: NSObject, FileProviderBasicRemote {
3132
open weak var delegate: FileProviderDelegate?
3233
open let credential: URLCredential?
3334
open private(set) var cache: URLCache?
34-
public var useCache: Bool = false
35-
public var validatingCache: Bool = true
35+
public var useCache: Bool
36+
public var validatingCache: Bool
3637

3738
fileprivate var _session: URLSession?
3839
fileprivate var sessionDelegate: SessionDelegate?
@@ -49,13 +50,16 @@ open class OneDriveFileProvider: NSObject, FileProviderBasicRemote {
4950
return _session!
5051
}
5152

52-
public init? (baseURL: URL?, drive: String = "root", credential: URLCredential?, cache: URLCache? = nil) {
53-
self.baseURL = baseURL ?? URL(string: "https://api.onedrive.com")
53+
public init? (credential: URLCredential?, serverURL: URL? = nil, drive: String = "root", cache: URLCache? = nil) {
54+
self.baseURL = serverURL ?? URL(string: "https://api.onedrive.com")
5455
self.drive = drive
55-
dispatch_queue = DispatchQueue(label: "FileProvider.\(OneDriveFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
56-
//let url = baseURL.uw_absoluteString
57-
self.credential = credential
56+
self.isPathRelative = true
57+
self.currentPath = ""
58+
self.useCache = false
59+
self.validatingCache = true
5860
self.cache = cache
61+
self.credential = credential
62+
dispatch_queue = DispatchQueue(label: "FileProvider.\(OneDriveFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
5963
}
6064

6165
deinit {
@@ -341,7 +345,7 @@ extension OneDriveFileProvider: ExtendedFileProvider {
341345

342346
extension OneDriveFileProvider: FileProvider {
343347
open func copy(with zone: NSZone? = nil) -> Any {
344-
let copy = OneDriveFileProvider(baseURL: self.baseURL, drive: self.drive, credential: self.credential, cache: self.cache)!
348+
let copy = OneDriveFileProvider(credential: self.credential, serverURL: self.baseURL, drive: self.drive, cache: self.cache)!
345349
copy.currentPath = self.currentPath
346350
copy.delegate = self.delegate
347351
copy.fileOperationDelegate = self.fileOperationDelegate

Sources/WebDAVFileProvider.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ public final class WebDavFileObject: FileObject {
3535
/// Because this class uses NSURLSession, it's necessary to disable App Transport Security
3636
/// in case of using this class with unencrypted HTTP connection.
3737

38-
open class WebDAVFileProvider: NSObject, FileProviderBasicRemote {
38+
open class WebDAVFileProvider: FileProviderBasicRemote {
3939
open static let type: String = "WebDAV"
40-
open let isPathRelative: Bool = true
40+
open let isPathRelative: Bool
4141
open let baseURL: URL?
42-
open var currentPath: String = ""
42+
open var currentPath: String
4343
public var dispatch_queue: DispatchQueue {
4444
willSet {
4545
assert(_session == nil, "It's not effective to change dispatch_queue property after session is initialized.")
@@ -48,8 +48,8 @@ open class WebDAVFileProvider: NSObject, FileProviderBasicRemote {
4848
public weak var delegate: FileProviderDelegate?
4949
open let credential: URLCredential?
5050
open private(set) var cache: URLCache?
51-
public var useCache: Bool = false
52-
public var validatingCache: Bool = true
51+
public var useCache: Bool
52+
public var validatingCache: Bool
5353

5454
fileprivate var _session: URLSession?
5555
fileprivate var sessionDelegate: SessionDelegate?
@@ -71,10 +71,13 @@ open class WebDAVFileProvider: NSObject, FileProviderBasicRemote {
7171
return nil
7272
}
7373
self.baseURL = baseURL
74-
dispatch_queue = DispatchQueue(label: "FileProvider.\(WebDAVFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
75-
//let url = baseURL.uw_absoluteString
76-
self.credential = credential
74+
self.isPathRelative = true
75+
self.currentPath = ""
76+
self.useCache = false
77+
self.validatingCache = true
7778
self.cache = cache
79+
self.credential = credential
80+
dispatch_queue = DispatchQueue(label: "FileProvider.\(WebDAVFileProvider.type)", attributes: DispatchQueue.Attributes.concurrent)
7881
}
7982

8083
deinit {

0 commit comments

Comments
 (0)