Hi there, I am trying to add a simple intent (just a URL parameter) to my application, and it shows up in the shortcuts app. However, when I try to donate the intent from the app, there is a weird error that shows up and I have been struggling with it for a long time.
What even is a shortcut type, isn't a system type considered valid or no?
2022-07-18 17:29:08.342668-0400 Asobi[25910:394998] [Intents] -[INInteraction donateInteractionWithCompletion:]_block_invoke Cannot donate interaction with LoadUrlIntent that has no valid shortcut types
Interaction donation failed: %@ Error Domain=IntentsErrorDomain Code=1901 "Cannot donate interaction with intent that has no valid shortcut types: <INInteraction: 0x600000fe1680> {
intent = <INIntent: 0x6000019ec870> {
};
dateInterval = <_NSConcreteDateInterval: 0x600002b4f260> (Start Date) 2022-07-18 21:29:08 +0000 + (Duration) 0.000000 seconds = (End Date) 2022-07-18 21:29:08 +0000;
intentResponse = <null>;
groupIdentifier = <null>;
intentHandlingStatus = Unspecified;
identifier = B3A8CA1F-6CCD-4AC3-8A9F-1D8A1B23834F;
direction = Unspecified;
} for intent <LoadUrlIntent: 0x6000019e81b0> {
url = https://google.com;
}" UserInfo={NSLocalizedDescription=Cannot donate interaction with intent that has no valid shortcut types: <INInteraction: 0x600000fe1680> {
intent = <INIntent: 0x6000019ec870> {
};
dateInterval = <_NSConcreteDateInterval: 0x600002b4f260> (Start Date) 2022-07-18 21:29:08 +0000 + (Duration) 0.000000 seconds = (End Date) 2022-07-18 21:29:08 +0000;
intentResponse = <null>;
groupIdentifier = <null>;
intentHandlingStatus = Unspecified;
identifier = B3A8CA1F-6CCD-4AC3-8A9F-1D8A1B23834F;
direction = Unspecified;
} for intent <LoadUrlIntent: 0x6000019e81b0> {
url = https://google.com;
}}
The intent definitions file is provided in this link (since I cannot attach it)
https://gist.github.com/bdashore3/c370bf3459ea78180273c9bf00e0c74f
Here is the button code for calling the donation function (which provides the error shown)
Button("Donate intent") {
let intent = LoadUrlIntent()
intent.suggestedInvocationPhrase = "Open google"
intent.url = URL(string: "https://google.com")
let interaction = INInteraction(intent: intent, response: nil)
interaction.donate { (error) in
if error != nil {
if let error = error as NSError? {
print("Interaction donation failed: %@", error)
} else {
print("Successfully donated interaction")
}
}
}
}
Post
Replies
Boosts
Views
Activity
Hi there, I am currently making an app and trying to download content to a user-selected download directory (like how safari does it).
However, whenever I set the download directory outside the App's documents, I get the following error when running my code on a real iOS device.
downloadedFileMoveFailed(error: Error Domain=NSCocoaErrorDomain Code=513 "“CFNetworkDownload_dlIcno.tmp” couldn’t be moved because you don’t have permission to access “Downloads”." UserInfo={NSSourceFilePathErrorKey=/private/var/mobile/Containers/Data/Application/A24D885A-1306-4CE4-9B15-952AF92B7E6C/tmp/CFNetworkDownload_dlIcno.tmp, NSUserStringVariant=(Move), NSDestinationFilePath=/private/var/mobile/Containers/Shared/AppGroup/E6303CBC-62A3-4206-9C84-E37041894DEC/File Provider Storage/Downloads/100MB.bin, NSFilePath=/private/var/mobile/Containers/Data/Application/A24D885A-1306-4CE4-9B15-952AF92B7E6C/tmp/CFNetworkDownload_dlIcno.tmp, NSUnderlyingError=0x281d045d0 {Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted"}}, source: file:///private/var/mobile/Containers/Data/Application/A24D885A-1306-4CE4-9B15-952AF92B7E6C/tmp/CFNetworkDownload_dlIcno.tmp, destination: file:///private/var/mobile/Containers/Shared/AppGroup/E6303CBC-62A3-4206-9C84-E37041894DEC/File%20Provider%20Storage/Downloads/100MB.bin)
The summary of that error is that I don't have permission to access the folder I just granted access to.
Here's my attached code (I'm using AlamoFire since it's easier to understand, but I'm having a problem saving files in iOS):
import SwiftUI
import UniformTypeIdentifiers
import Alamofire
struct ContentView: View {
@AppStorage("downloadsDirectory") var downloadsDirectory = ""
@State private var showFileImporter = false
var body: some View {
VStack {
Button("Set downloads directory") {
showFileImporter.toggle()
}
Button("Save to downloads directory") {
Task {
do {
let destination: DownloadRequest.Destination = { _, response in
let documentsURL = URL(string: downloadsDirectory)!
let suggestedName = response.suggestedFilename ?? "unknown"
let fileURL = documentsURL.appendingPathComponent(suggestedName)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
let _ = try await AF.download(URL(string: "https://i.imgur.com/zaVQDFJ.png")!, to: destination).serializingDownloadedFileURL().value
} catch {
print("Downloading error!: \(error)")
}
}
}
}
.fileImporter(isPresented: $showFileImporter, allowedContentTypes: [UTType.folder]) { result in
switch result {
case .success(let url):
downloadsDirectory = url.absoluteString
case .failure(let error):
print("Download picker error: \(error)")
}
}
}
}
To reproduce (Run on a REAL iOS device!):
Click the Set downloads directory button to On my iPhone
Click the Save to downloads directory button
Error occurs
Upon further investigation, I found that safari uses the Files and Folders privacy permission (Located in Settings > Privacy > Files and folders on an iPhone) to access folders outside the app sandbox (see the attached image for a visual representation of what I'm talking about). I scoured the web as much as I can and I couldn't find any documentation for this exact permission.
I have seen non-apple apps (such as VLC) use this permission, but I cannot figure out how it's granted.
I tried enabling the following plist properties, but none of them work (because I later realized these are for macOS only)
<key>NSDocumentsFolderUsageDescription</key>
<string>App wants to access your documents folder</string>
<key>NSDownloadsFolderUsageDescription</key>
<string>App wants to access your downloads folder</string>
Can someone please help me figure out how to grant the files and folder permission and explain what it does? I would really appreciate the help.
Image of the permission in question: