WebDAV communication library for Swift
Note: This has only been tested on Nextcloud servers. Submit an issue if you have compatibility issues with other WebDAV servers. Help in adding support for additional services would be greatly appreciated! See Contribution.
- [#43] Apache WebDAV has been reported to not work
Install using Swift Package Manager.
https://github.com/Isvvc/WebDAV-Swift.git
In Xcode: File -> Swift Packages -> Add Package Dependency...
or add in Project settings.
import WebDAV
Create and instance of the WebDAV class.
This currently has two functions: listFiles
and upload
.
WebDAV functions require a path, account, and password.
WebDAVAccount
is a protocol that contains a username and base URL for the WebDAV server.
These properties are optional for easier conformance,
but they must not be optional when making a request, or the request will fail.
Create a class or struct that conforms to WebDAVAccount
that can be used in WebDAV calls,
or use the provided SimpleAccount
struct.
Because the properties are optional, conformance can be added to CoreData entities.
When instantiating a WebDAVAccount
, the baseURL
property should be the URL to access the WebDAV server.
For Nextcloud, this should include remote.php/dav/files/[username]/
(can be found under Settings in the bottom-left of any Files page).
Example:
SimpleAccount(username: "test", baseURL: "https://nextcloud.example.com/remote.php/dav/files/test/")
Every request requires a path, WebDAVAccount
, and password. There is no "logging in".
This is so apps can easily support having multiple accounts without having to log in or out of each.
It is highly recommended you use an app-specific password (for Nextcloud, see Login flow v2). Do not store the user's password in plain text. Use URLCredentialStorage or Keychain (or something like KeychainSwift for easier use).
The path passed into functions should be the path to the file or directory relative to the baseURL
in your account.
For functions that read from or write to a file, this path should include the file name and extension.
The basic WebDAV functions currently available include
listFiles
upload
download
createFolder
deleteFile
moveFile
copyFile
These functions will each return a URLSessionTask which can be cancelled later.
let baseURL = "https://nextcloud.example.com/remote.php/dav/files/Username/"
let account = SimpleAccount(username: username, baseURL: baseURL)
let path = "file.txt"
let data = "File contents".data(using: .utf8)
webDAV.upload(data: data, toPath: path, account: account, password: password) { error in
// Check the error
}
The listFiles
function, if successful, will complete with a WebDAVFile
array, which will be cached to memory and disk for quick retrieval later.
By default, subsequent calls of listFiles
on the same path with the same account will give the cached results instead of making a network request.
See Caching behavior for how to change this behavior.
A useful option for listing files in particular is .requestEvenIfCached
:
webDAV.listFiles(atPath: path, account: account, password: password, caching: .requestEvenIfCached) { files, error in
// Show the cached files immediately.
// Update to show the newly fetched files list after the request is complete.
}
In this case, if there are cached files, the completion closure will run immediately with those cached files. Then a network request will be made to get an updated files list. If the files list from the server is unchanged from the cache, the function ends here and nothing else is called. If the files list from the server is different from the cache, the completion closure will run a second time with the new files list.
The files cache can be cleared using clearFilesCache
, clearFilesDiskCache
, or clearFilesMemoryCache
.
Included is functionality for downloading and caching data, images, and thumbnails (on Nextcloud servers).
Data downloaded using the download
function, or the various image and thumbnail fetching functions, will cache to both memory and disk.
The memory function is based off of NSCache,
meaning it uses Apple's own auto-eviction policies to clear up system memory.
The disk cache data is stored in the app.lyons.webdav-swift
folder in the caches directory.
Data cache functions include
getCachedData
deleteCachedData
deleteAllCachedData
getCacheByteCount
getCacheSize
cachedDataURL
cachedDataURLIfExists
deleteAllDiskCachedData
Default caching behavior is to return a cached result instead of making a request if there is one. Otherwise, make a request and cache the result.
Use the caching options
parameter in functions to change the caching behavior based on WebDAVCachingOptions
.
Setting the caching options to an empty set will use default behavior.
Caching options include
doNotCacheResult
doNotReturnCachedResult
removeExistingCache
- Removes the cached result after returning it, if it exists.
- Use with
doNotReturnCachedResult
if you do not want the cached result returned.
requestEvenIfCached
- The completion closure for the request will run once with the cached data, then again with the newly fetched data, assuming it is different.
Convenience options include
ignoreCache
will ignore the cached result if there is one, and won't cache the new result.- Same as
[.doNotCacheResult, .doNotReturnCachedResult]
.
- Same as
disableCache
disables all caching for the request and deletes any existing cache for it.- Same as
[.doNotCacheResult, .removeExistingCache, .doNotReturnCachedResult]
.
- Same as
Images can be downloaded and cached using downloadImage
. This will complete with a UIImage
if available and caches the same way as the data cache.
Image functions include:
downloadImage
getCachedImage
Why is there no deleteCachedImage
or cachedImageURL
function when there is getCachedThumbnail
and cachedThumbnailURL
?
Images are stored in the disk cache the same way as data. The image-specific functions exist as a convenience for converting the data to UIImages and caching them in memory that way. Since the cached data URL does not change whether the data is an image or not, deleteCachedData
and cachedDataURL
can be used for images.
If there are already cached thumbnails for the image you are trying to fetch, you can use the preview
parameter to specify that you would like to get that thumbnail first while the full-size image is downloading. When you do this, the completion closure will run with a .placeholder
error on the call with the thumbnail.
webDAV.downloadImage(path: imagePath, account: account, password: password, preview: .memoryOnly) { image, error in
switch error {
case .none, .placeholder:
// .none is the full-size image.
// .placeholder is the thumbnail.
// The completion closure will not be run with the thumbnail after
// it is run with the full-size image, so assuming you don't have
// a use for the thumbnail after the full-size image loads, you
// shouldn't need to check which it is before displaying.
break
case .some(let unexpectedError):
// Log the error
}
// Display the image
}
See Thumbnails for more details on thumbnails.
Along with downloading full-sized images, you can download thumbnails from Nextcloud servers. This currently only works with Nextcloud servers as thumbnail generation is not part of the WebDAV standard.
Thumbnail generation requires you to specify the properties for how the server should render the thumbnail.
These properties exist as ThumbnailProperties
objects and include dimensions and content mode.
If no dimensions are specified, the server's default will be used (default is 64x64 on Nextcloud).
When getting the URL of or deleting a cached URL, you must also specify these properties in order to access the correct specific thumbnail.
If you wish to access all thumbnails for a specific image at once, you can use getAllCachedThumbnails
and deleteAllCachedThumbnails
.
Example:
webDAV.downloadThumbnail(path: imagePath, account: account, password: password, with: .init((width: 512, height: 512), contentMode: .fill)) { image, error in
// Check the error
// Display the image
}
Note that ThumbnailProperties
objects can also be initialized using a CGSize
, but doing so will truncate the size to integer pixel counts.
Thumbnail functions include
downloadThumbnail
getCachedThumbnail
getAllCachedThumbnails
deleteCachedThumbnail
deleteAllCachedThumbnails
cachedThumbnailURL
cachedThumbnailURLIfExists
WebDAV servers that support OCS (such as Nextcloud and ownCloud) can give you theming information including accent color, name, slogan, background image, etc. Two functions exist for this:
getNextcloudColorHex
getNextcloudTheme
getNextcloudColorHex
will give the server's accent color as a hex code starting with '#' (eg #0082c9
).
getNextcloudTheme
will give the server's full theming information in the form of an OCSTheme
object.
Version 2.x used 3lvis/Networking for its image caching,
but this was replaced with a custom in-house caching solution in 3.0.
If upgrading from v2 to v3, run the function clearV2Cache()
in order to remove previously cached data.
For example, you could run something like this on startup
if !UserDefaults.standard.bool(forKey: "webDAV-v3-upgrade") {
try? webDAV.clearV2Cache()
UserDefaults.standard.setValue(true, forKey: "webDAV-v3-upgrade")
}
This package depends on drmohundro/SWXMLHash which should automatically be fetched by Swift Package Manager in Xcode.
To test any contributions you make, make test functions in WebDAVTests
.
In order to run tests, you need to add a WebDAV account to the environment variables as described below.
You'll need to add a WebDAV account to your scheme to be able to test.
Edit your scheme in Xcode. Ensure the "Shared" checkbox is unchecked to keep the scheme private.
Under Arguments in Test, add the following environment variables:
webdav_user
: The username for your WebDAV account to test withwebdav_password
: The password for your WebDAV accountwebdav_url
: The URL of the WebDAV server your account is onimage_path
: The path to an image file of type jpg/jpeg, png, or gif in the WebDAV storage
Note that running the tests will create files on your WebDAV server, though they should also be deleted, assuming all the tests pass.