Hi, everyone. This issue has been bugging for a while because I make heavy use of iCloud Drive and find it to be incredibly useful. So, I'd like it to cooperate better with Alfred. I've discovered that interacting with files that are offloaded to iCloud (also called "ubiquitous items") is possible with the (NS)FileManager API.
What is probably initially most useful is the "isUbiquitousItem" method, which can be used to conditionalize the code path that handles files offloaded to iCloud by checking whether a file can potentially be evicted from the filesystem. From there, you can kick off a file download with the "startDownloadingUbiquitousItem" method. To check whether the download is complete, you can observe the "NSMetadataQueryDidUpdate" notification via NotificationCenter in conjunction with the usage of an NSMetadataQuery in order to track the availability of the file.
The "resourceValues" method on the URL class lets you pass "ubiquitousItemDownloadingStatusKey" as a desired key, which lets you check the downloading status of a file ("current" (present on disk, up to date), "downloaded" (present on disk, but stale), and "notDownloaded"). There are other keys such as "ubiquitousItemDownloadingErrorKey", which grants you access to the error object if the download fails. Alfred could potentially check this key (and others) to present helpful (error) messages to the user when trying to open a file that needs to be downloaded, such as a lack of internet connection or disk space.
Here is a code sample, in Swift, demonstrating the above (tested in Xcode Version 15.0 beta 2 (15A5161b) with macOS 13.4.1 (c) (22F770820d)):
let manager = FileManager.default
let path = "/Users/slice/Library/Mobile Documents/com~apple~CloudDocs/Downloads/music 2/.just for me alac.m4a.icloud"
let url = URL(filePath: path)
// In this case, `true`.
manager.isUbiquitousItem(at: url)
let query = NSMetadataQuery()
// In a real application, this should probably be a more resilient query. Unfortunately, we are unable
// to use fully-qualified paths (NSMetadataItemPathKey) with this API for some reason. ¯\_(ツ)_/¯
query.predicate = NSPredicate(format: "%K == %@", NSMetadataItemFSNameKey, "just for me alac.m4a")
NotificationCenter.default.addObserver(forName: .NSMetadataQueryDidUpdate, object: query, queue: nil) { notification in
guard let result = query.results.first as? NSMetadataItem else {
return
}
let path = result.value(forAttribute: NSMetadataItemPathKey) as! String
print("Ubiquitous file downloaded: \(path)")
let resourceValues = try! URL(filePath: path).resourceValues(forKeys: [.ubiquitousItemDownloadingStatusKey])
let status = resourceValues.ubiquitousItemDownloadingStatus!
print("Status: \(status)")
guard status == .current else {
return
}
print("Attempting to open.")
NSWorkspace.shared.open(URL(filePath: path))
// Opening the file triggers another metadata query update (likely increasing the amount of times
// opened). Stop the query to prevent an infinite loop.
query.stop()
}
query.start()
try! manager.startDownloadingUbiquitousItem(at: url)
In my case, I am hardcoding the path to the ubiquitous file (with extension ".icloud"). The "isUbiquitousItem" method returns "true" for these paths. Before kicking off the download (which takes place in the background, asynchronously), I register an observer and NSMetadataQuery to track the download status of the file. This is a bit tricky because Spotlight's APIs do not let you form a query over a specific path for some reason, so I have just hardcoded the name of the file. I hope that Alfred has its own ways of coping with this limitation that can hopefully be put to use here.
I would love to see this integrated into Alfred. It's much, much faster than Apple's vanilla Spotlight UI for me when it comes to searching files, and I use iCloud Drive a ton!
P.S. You can interact with ubiquitous items from the command line via the "brctl" tool. See "man 1 brctl".
You can run "brctl download <path>" and "brctl evict <path>" to download a local copy and remove local copies, respectively. There are also other commands related to monitoring, versioning, and logging. But, if you just want to download or evict a file with Finder, you can do that with the "Download Now" and "Remove Download" menu items that are available on ubiquitous files.
cc @Andrew