Core Transferable

RSS for tag

Declare a transfer representation for your model types to participate in system sharing and data transfer operations.

Posts under Core Transferable tag

12 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Share arbitrary struct from HostApp to Extension and get arbitrary result back
I want to share a Transferable (JSON-encoded) data struct from some HostApp with an Extension of my ContainingApp, and get a different Transferable (also JSON-encoded) data struct back on success. Since I want to present my ContainingApp's AppIcon in the sharing sheet to make it easy for the user to find it, I started building a Sharing Extension and not an Action Extension. AFAIK the difference is only in the presentation (Sharing Extension: Icon+name of the ContainingApp vs Action Extension: simple b/w system icon plus a string describing the action (e.g. "Copy", "Save to Files")), and the data flow is identical. Please correct me if I'm wrong. I added the Sharing Extension to my ContainingApp (which are both in the same app group so they can use a shared container to exchange data). The (real) HostApp is from a different company we are collaborating with, and thus is not in our app group. Once everything runs I will add a tailored NSExtensionActivationRule to make sure our Sharing Extension is only shown to our partner's HostApp. Currently I am still using TRUEPREDICATE. The goal is that after the user tapped the "Continue with ContainingApp" (Share-)button in the HostApp, iOS will only show my ContainingApp icon and nothing else, since that's the only useful choice for the user. Side Question 1: The best user experience would be if the HostApp could directly present our extension when the user tapped the "Continue with ContainingApp"-button, without the user needing to choose it manually in the Share-sheet, but I guess this is not possible for privacy/security reasons, right? In the debugger of the HostApp I see this error: Type "com.myapp.shareInput" was expected to be exported in the Info.plist of Host.app, but it was imported instead. Library: UniformTypeIdentifiers | Subsystem: com.apple.runtime-issues | Category: Type Declaration Issues but I definitely want to define and export both ShareInput and ShareResult as UTExportedTypeDeclarations in my extension, and all 3rd-party apps (like this demo HostApp) using my extension need to import them. Side Question 2: Can I just ignore this error? And tell the 3rd-party app developers they also can ignore it? After the user tapped on the ContainingApp icon in the sharing dialog, my Sharing Extension will show its dialog, presenting the shared item it got from the HostApp, and let the user edit the text. When the user taps the "Save"-button in my extension, it creates a ShareResult struct to send back to the HostApp, and dismisses the sheet. This (kinda) works when I share plain text with the 􀈂Text button in my HostApp. My ContainingApp icon is shown together with Mail, Messages, and other apps that can process plain text; with shortcuts to persons and devices (AirDrop targets) in the line above, and with actions (Copy, New Quick Note, Save to Files, Save to Citator, Certificat, Airdrop) below. When I choose my ContainingApp, the extension runs and shows the text it got. ("Kinda" because I am still struggling to send data back. See below...) So the principal operation works... Side Question 3: In the HostApp, can I use ShareLink() to present the Share-sheet and receive the result struct or do I always need to activityViewController!.completionWithItemsHandler = completionHandler windowScene.keyWindow?.rootViewController?.present(activityViewController!, animated: true, completion: nil) and process the result in the completionHandler? If returning (any) data from the extension is possible with ShareLink() also, then how? I didn't find any sample showing this... I implemented the ShareLink() anyway (and ignore the result part for the moment). When I try to share a ShareInput struct with the 􀈂ShareLink button, the same persons are sorted differently, there are less app icons (9 instead of 13), and less actions (only 3: New Quick Note, Save to Files, AirDrop): Note that while the preview correctly shows the preview text provided ("shareInput"), the preview image left of it is blank (instead of arrowshape.right.fill): let preview = SharePreview("shareInput", image: Image(systemName: "arrowshape.right.fill")) When I choose my ContainingApp, the extension runs ... On iOS17, I see that indeed my ShareInput data arrived in my extension: ❗️itemProvider=<NSItemProvider: 0x301b1c460> {types = ( "com.myapp.shareInput" )} Library: ShareExtension | Subsystem: com.myapp.containingdemo.ShareExtensionDemo | Category: ShareSheet However, on iOS 16 it doesn't work: Host[8615:634470] [Type Declaration Issues] Type "com.myapp.shareInput" was expected to be exported in the Info.plist of Host.app, but it was imported instead. Host[8615:634462] [ShareSheet] Couldn't load file URL for Collaboration Item Provider:<NSItemProvider: 0x280f49180> {types = ( "com.myapp.shareInput" )} : (null) That error is shown before I choose the ContainingApp to share with. When I do that, I get: ShareExtension[8774:636786] [ShareSheet] ❗️itemProvider=<NSItemProvider: 0x28243a300> {types = ( "dyn.age8u", "public.file-url" )} which clearly shows the ShareInput struct was not transferred to the extension. But since I don't know how to transfer the ShareResult back to the HostApp when using a ShareLink, I cannot continue this approach anyway. When I try to share a ShareInput struct with the 􀈂JSON button (using present(activityViewController)), I see (both on iOS 16 and iOS 17): My extension (rather, the ContainingApp's icon) is not shown as Sharing target (even though it still has TRUEPREDICATE), which means that my code didn't manage to pack the ShareInput struct for the activityViewController - and thus it doesn't know what to share. I did the same as with the plainText item before: let shareInput = ShareInput(inputStr: "ShareInput as JSON") let preview = SharePreview("shareInput", image: Image(systemName: "arrowshape.right.fill")) VStack(spacing: 25.0) { Text("HostApp!") ShareButton(title: "Text", shareItems: [ItemSource(dataToShare: "sharing some text")]) ShareButton(title: "JSON", shareItems: [ItemSource(dataToShare: shareInput)]) ShareLink("ShareLink", item: shareInput, preview: preview) } (I will continue in the next posting)
15
0
448
2w
TransferRepresentation slow transfer for large video files.
Hi, I notice a very slow transfer rate when I try to transfer a file picked via .photosPicker. This happens especially when I try to import a 4k/60fps video. SwiftUI: VStack { Button("Pick a video") { model.isPhotoPickerView = true } .photosPicker(isPresented: $model.isPhotoPickerView, selection: $model.selectedImageList, maxSelectionCount: 1, matching: .videos) .onChange(of: model.selectedImageList, { old, new in model.handlePhotoPicker() }) } View Model to handle Photo Picker action: private class PageModel: ObservableObject { //other methods @MainActor public func handlePhotoPicker() { if selectedImageList.isEmpty { return } guard let item = selectedImageList.first else { return } Task { do { if let video = try await item.loadTransferable(type: VideoTransferable.self) { let file = video.url //video url arrived } } catch { //handle error } } } } Now the VideoTransferable : struct VideoTransferable: Transferable { let url: URL static var transferRepresentation: some TransferRepresentation { FileRepresentation(contentType: .movie) { video in SentTransferredFile(video.url) } importing: { received in //takes too much time to import large 4K video recorded from iPhone's main camera let copy = FileManager.documentsDirectory.appendingPathComponent(FolderType.temp.rawValue).appendingPathComponent("video_\(Int64(Date().timeIntervalSince1970 * 1000)).MOV") if FileManager.default.fileExists(atPath: copy.path) { try FileManager.default.removeItem(at: copy) } try FileManager.default.copyItem(at: received.file, to: copy) return Self.init(url: copy) } } } To my surprise this issue doesn't happen when I use a custom UIViewControllerRepresentable to wrap UIImagePickerController() and setting videoExportPreset property of the picker to AVAssetExportPresetPassthrough Can someone point me out where I am wrong?
1
0
180
4w
Share multiple Transferables with ShareLink
I am trying to use a ShareLink to share multiple transferrable, and I cannot work out which of the initialisers to use - none seem to work. Assuming I have a transferable that takes some data and processes it asynchronously: struct MyTransferable: some Transferable { let renderer: Renderer static var transferRepresentation: some TransferRepresentation { DataRepresentation(exportedContentType: .png) { transferable in let image = try await transferable.render.render() return image } } } In SwiftUI, I want to share N of these transferables. For example: struct MyView: View { private var transferables: [any Transferable] { [MyTransferable(), MyTransferable()] } var body: some View { ShareLink("Renders", items: transferables) } } But the compiler doesn't like this - it complains with "No exact matches in call to initializer". Is this possible? I feel like it should be?
3
0
867
Jul ’24
Drag and Drop using SwiftUI
Overview I am bit confused regarding drag and drop on SwiftUI I think there are 2 approaches but I am stuck with both approaches WWDC22 When using the new draggable, dropDestination, Transferable API, only single items are draggable. Multiple items in a list are not draggable. I have filed a feedback FB10128110 WWDC21 I have faced a couple of issues for drag and drop introduced in WWDC21 (onDrag, onDrop, itemIdentifier), the Feedback ids are FB9854301, FB9854569, FB9855245, FB9855532, FB9855567, FB9855575. It contains sample projects, would really appreciate if someone could have a look it. Note: All feedbacks include a sample project with detail steps and some even have screenshots and videos Questions: If my approach is wrong or if I am missing something? Unfortunately I didn't manage to get a SwiftUI lab session (got cancelled), so please help me with these issues.
4
1
2.8k
Jul ’24
ShareLink with custom UT type not opening in my app
Hey all, my first time posting on these forums as I've finally become completely stumped. I'm working to implement a ShareLink to share data between users on my app, and have gotten pretty far (file saves, sends correctly), but am having significant issues getting the link to open in my app when sharing by email and not getting any action at all when tapping a shared link in iMessage. I'll go through my setup below: I have declared my new UTType, and created my new model which conforms to transferable here: struct transferTemplate: Codable { var id: UUID = UUID() var name: String = "TempName" var words: [String] = ["word1","word2"] } extension transferTemplate: Transferable { static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .oltemplate) } } extension UTType { static var oltemplate: UTType { UTType(exportedAs: "com.overloadapp.oltemplate") } } I have declared the document type in my info.plist: <key>CFBundleDocumentTypes</key> <array> <dict> <key>CFBundleTypeName</key> <string>Template Session</string> <key>LSHandlerRank</key> <string>Owner</string> <key>LSItemContentTypes</key> <array> <string>com.overloadapp.oltemplate</string> </array> </dict> </array> I have declared the Exported Type Identifier: <key>UTExportedTypeDeclarations</key> <array> <dict> <key>UTTypeConformsTo</key> <array> <string>public.json</string> </array> <key>UTTypeDescription</key> <string>Template Session</string> <key>UTTypeIconFiles</key> <array/> <key>UTTypeIdentifier</key> <string>com.overloadapp.oltemplate</string> <key>UTTypeTagSpecification</key> <dict> <key>public.filename-extension</key> <array> <string>oltemplate</string> </array> <key>public.mime-type</key> <array> <string>application/json</string> </array> </dict> </dict> </array> I've also included the "LSSupportsOpeningDocumentsInPlace" boolean to True in the PLIST. My physical ShareLink setup is: @State private var transferred: transferTemplate = transferTemplate(name: "NameTemplate", words: ["One","Two"]) ... ShareLink(item: transferred, preview: SharePreview("Share your template", image: Image("tanLogo"))) Heres where the above code gets you: ShareLink brings up the share sheet and allows you to send the file (with the .oltemplate file extension). Sharing via iMessage will send a file, but within iMessage, the file cannot be opened at all. By email, the file can be opened but does not show any information. If you open the ShareSheet within the email attachment, you can manually choose to open the file in my app. If the file is saved to "Files", it will open my app when it is tapped (work as intended). Heres what I have tried to fix this: Modifying the Exported File Type "Conforms to" value. Ive used public.data, public.text, public.json. Including and not including the mime type I've scoured forums trying to solve this issue, and it doesn't seem like there is a clear cut solution for this issue. I appreciate any help you can provide! Please let me know if I can include any more helpful information.
0
0
349
Jun ’24
ShareLink does not offer "save to files" when sharing "Transferable" items
In my app I try to use SwiftUI's ShareLink to offer sharing of the app's documents. I followed this video for defining the exported type and the document type. Unfortunately if I use any ShareLink initializer for sharing Transferable items, the option "save to files" is not offered on the displayed share sheet. (Only "copy" is offered, which works if pasted into the destination directory using the Files app, but that is not an acceptable workaround). PS: com.example.transferabletestis defined as conforming to com.apple.package import SwiftUI import UniformTypeIdentifiers extension UTType{     static let transferableTest = UTType(exportedAs: "com.example.transferabletest") } struct Document:Transferable{     static let filePackageURL = URL.documentsDirectory.appending(components: "0815.transferabletest")    public static var transferRepresentation: some TransferRepresentation {         FileRepresentation(exportedContentType: .transferableTest) { document in             _ = try? FileManager.default.createDirectory(at: Self.filePackageURL, withIntermediateDirectories: false)             FileManager.default.createFile(atPath: Self.filePackageURL.appending(components: "data").path(), contents: "Transferable Test\n".data(using: .utf8))             return SentTransferredFile(Document.filePackageURL)         }     } } struct ContentView: View {     var body: some View {         ShareLink("Share as tranferable item", item: Document(), preview: SharePreview("Test"))     } } Is this a bug? What am I doing wrong? Sharing the document using the ShareLink for URLs does offer "save to files" but I can't use that in my app for various reasons.
3
1
1.6k
Jun ’24
How to copy List items within Navigation
I am currently working on a SwiftUI project and encountering an issue with the .copyable(_:) modifier. I want to copy the currently selected items in a List, and while using .copyable(_:) works outside of navigation components, it doesn't seem to have any effect when used within NavigationSplitView or NavigationStack. Has anyone successfully implemented copying functionality within a navigation structure using .copyable(_:)? import SwiftUI struct ContentView: View { var body: some View { NavigationSplitView { List(0..<10) { Text("row \($0)") } } detail: { CopyableList() } } } struct CopyableList: View { let strings = ["Alpha", "Beta", "Gamma"] @State private var selection: Set<String> = [] var body: some View { List(strings, id: \.self, selection: $selection) { Text($0) } .copyable(Array(selection)) } }
1
0
412
Dec ’23
SwiftUI ShareLink Exporting Issues with Custom CSV UTType
Hello! I'm working on an app that generates CSV files in memory and allows users to export them through a ShareLink. I am using a custom UTType for my CSV files as .commaSeparatedText exports a .txt file, and a custom UTType was proposed as a workaround here: https://www.hackingwithswift.com/forums/swiftui/sharelink-problem-with-csv-file/21194. The app works on a development build, albeit with a lot of entitlement and sandboxing errors, but fails in production (sideloaded archive). Development errors are as follow: Error acquiring assertion: <Error Domain=RBSServiceErrorDomain Code=1 "(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)" UserInfo={NSLocalizedFailureReason=(originator doesn't have entitlement com.apple.runningboard.primitiveattribute AND originator doesn't have entitlement com.apple.runningboard.assertions.frontboard AND target is not running or doesn't have entitlement com.apple.runningboard.trustedtarget AND Target not hosted by originator)}> (501) personaAttributesForPersonaType for type:0 failed with error Error Domain=NSCocoaErrorDomain Code=4099 "The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction." UserInfo={NSDebugDescription=The connection to service named com.apple.mobile.usermanagerd.xpc was invalidated: failed at lookup with error 159 - Sandbox restriction.} Received port for identifier response: <> with error:Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false} The additional production error I'm encountering is the following: Type "com.sunkensplashstudios.VRCRoboScout.csv" was expected to be declared and exported in the Info.plist of App.app, but it was not found. I have, to the best of my knowledge, declared these data types properly: Relevant code is below: extension UTType { static var CSVData: UTType { UTType(exportedAs: "com.sunkensplashstudios.VRCRoboScout.csv") } } struct CSVData: Transferable { var csv_string: String static var transferRepresentation: some TransferRepresentation { DataRepresentation(exportedContentType: .CSVData) { csv in csv.csv_string.data(using: .utf8)! } } } ShareLink(item: CSVData(csv_string: csv_string), preview: SharePreview("VRC RoboScout Scouting Data.csv", image: Image(systemName: "tablecells"))) { Text("Download").padding(10) .background(settings.accentColor()) .foregroundColor(.white) .cornerRadius(20) } Any ideas?
3
1
1.3k
Oct ’23
SwiftData model doesn't work with Transferable and Codable
Hi everyone. I trying to implement some drag and drop functionality together with SwiftData. That requires my model to conform Transferable. And Transferable requires to conform Codable. My code doesn't compile with this error: Type 'Item' does not conform to protocol 'Decodable/Encodable'. The error appears right after I add @Model macro. Is there a solution or a workaround? Here's my code: @Model final class Item: Transferable, Codable { let createdAt: Date static var transferRepresentation: some TransferRepresentation { CodableRepresentation(contentType: .myCustomType) } init() { self.createdAt = .now } } extension UTType { static let myCustomType = UTType(exportedAs: "com.olexgreen.mytype") } Thank you very much
3
2
2.2k
Oct ’23
How to drag an item using NSItemProviderWriting using async
Scenario: The following Swift code uses NSItemProviderWriting to load a file from some data source async (The code actually just uses a for loop to simulate the time it needs to load the file). It returns the file url then. This code is used for drag & drop behavior in a macOS app from an app to another app. As the other app does only support file URLs as drop types, I can't send over the data itself. class AnyFile: NSObject, NSItemProviderWriting { let url: URL init(url: URL) { self.url = url } static var writableTypeIdentifiersForItemProvider: [String] { return [UTType.fileURL.identifier] } func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { let count = 100000 let progress = Progress(totalUnitCount: Int64(count)) print("a") Task { print("b") for i in 0...100000 { progress.completedUnitCount = Int64(i) print(i) } print("c") completionHandler(url.dataRepresentation, nil) print("d") } print("e") return progress } } Problem: Drag & drop works, but when I start to drag the view (SwiftUI view using .onDrag), the view gets stuck as long as the loop is running. It is not clear to me why this happens as the loop us running inside a task. The console output also shows that progress is returned before the loop as finished. But still, it is stuck until the end of the loop. So the user experience is like not using async and the task. Log output (shortened) a e b 0 ... 100000 c d Actual Question: Why is this Swift code for dragging files not behaving asynchronously even though it uses Task, completionHandler, and async/await constructs? Alternatives tried: I'm not bound to NSItemProviderWriting in particular. I have tried other ways, like Transferable, .draggable(), and NSItemProvider.registerFileRepresentation. But either they won't return a URL, or do not allow async at all. I also tried AppKit instead of SwiftUI with similar issues.
2
0
773
Sep ’23
Drag URL from my app to another using a promise (in Swift)
Hi All, I have successfully implemented drag & drop of files from and to other apps on macOS successfully using different methods. Including NSFilePromiseProvider for example. There is one app however, that I use on a regular basis, that only support file urls as drop types. So I have to use public.file-url to drag & drop files there. The problem is that the file does not exist when dragging starts. That's why I would like to send a URL promise to the app, instead of a file promise. I can't create the file beforehand because then I would need to create hundreds of large files which will just take up space. So whenever I drag an item from my app to the other app, then the file shall be created and the url shall be sent to that app to be opened. But as the other app only checks the pasteboard for urls without handling promises, this is not working. I do have their code available, but can't change the code. Question: Is there a way in Swift on macOS to drag and drop a an item to another app so that upon mouse up on the other app some async tasks is executed and at the end the other app receives the URL as a result of the async task?
0
1
563
Sep ’23
dropDestination does not work inside List
I've discovered an issue with using iOS 16's Transferable drag-and-drop APIs for SwiftUI. The dropDestination modifier does not work when applied to a subview of a List. This code below will not work, unless you replace the List with a VStack or any other container (which, of course, removes all list-specific rendering). The draggable modifier will still work and the item will drag, but the dropDestination view won't react to it and neither closure will be called. struct MyView: View { var body: some View { List { Section { Text("drag this title") .font(.largeTitle) .draggable("a title") } Section { Color.pink .frame(width: 400, height: 400) .dropDestination(for: String.self) { receivedTitles, location in true } isTargeted: { print($0) } } } } } Has anyone encountered this bug and perhaps found a workaround?
7
0
2.4k
Sep ’23