admin管理员组

文章数量:1125295

I have a String and an URL containing audio and want to share both via a Sharelink.

I have written a Transferable:

struct TransferableTextAndAudio: Codable, Transferable {
  let text: String
  let audio: URL
  
  static var transferRepresentation: some TransferRepresentation {
    ProxyRepresentation(exporting: \.text)
    FileRepresentation(exportedContentType: .audio) { item in
      return SentTransferredFile(item.audio, allowAccessingOriginalFile: true)
    }
  }
}

and I share with:

ShareLink(item: TransferableTextAndAudio(text: "String to share", audio: audioUrl),
          preview: SharePreview("Preview")) {
  Label("Share text and audio", systemImage: "square.and.arrow.up")
}

However, only the text is shared. When I comment out the ProxyRepresentation line, then the audio is shared. Why is that ? Do I miss some understanding how Transferable works ?

I have a String and an URL containing audio and want to share both via a Sharelink.

I have written a Transferable:

struct TransferableTextAndAudio: Codable, Transferable {
  let text: String
  let audio: URL
  
  static var transferRepresentation: some TransferRepresentation {
    ProxyRepresentation(exporting: \.text)
    FileRepresentation(exportedContentType: .audio) { item in
      return SentTransferredFile(item.audio, allowAccessingOriginalFile: true)
    }
  }
}

and I share with:

ShareLink(item: TransferableTextAndAudio(text: "String to share", audio: audioUrl),
          preview: SharePreview("Preview")) {
  Label("Share text and audio", systemImage: "square.and.arrow.up")
}

However, only the text is shared. When I comment out the ProxyRepresentation line, then the audio is shared. Why is that ? Do I miss some understanding how Transferable works ?

Share Improve this question asked 2 days ago ChrisChris 1,4032 gold badges11 silver badges23 bronze badges 5
  • What do you mean by "share both"? That doesn't make sense to me. Can you give an example of a well known app that allows you to share two different things at the same time? – Sweeper Commented 2 days ago
  • Perhaps you want the share link to share a folder containing the audio file and a text file containing the string? – Sweeper Commented 2 days ago
  • @Sweeper: What I want to do is sharing to e.g. an email app and embedding the text into the body and putting the audio as attachment IN ONE STEP. I know that I can do so using MFMailComposeViewController(), but I want to address other mail clients like gmail as well and therefore want to use the generic "share" methods. – Chris Commented 2 days ago
  • You will be depending on the implementation details of the email apps then. Sharing two items, one with a proxy representation and one with a file representation, works for Mail.app. I don't know if it will work for Gmail though. – Sweeper Commented 2 days ago
  • No, even Mail.app is not accepting that. I only takes one of both. In earlier times using the UI Share dialog it was possible to specify an array of items (which worked) and I was thinking that this functionality is provided by ShareLink, but it seems not to be the case. – Chris Commented 2 days ago
Add a comment  | 

1 Answer 1

Reset to default 1

Sharing one transferable item having multiple representations is still just sharing one item. Only one representation will be picked. Since you put the text representation first, that is the one that will be prioritised.

You need to use one of the ShareLink initialisers that take multiple items, like this one. Share the text and audio file as two separate items. The two items annoyingly needs to be of the same type. You can write an enum with two cases like this:

enum TextOrAudio: Codable, Transferable {
    case text(String)
    case audio(URL)
    
    var text: String? {
        if case let .text(s) = self {
            s
        } else {
            nil
        }
    }
    
    var audio: URL? {
        if case let .audio(url) = self {
            url
        } else {
            nil
        }
    }
    
    static var transferRepresentation: some TransferRepresentation {
        FileRepresentation(exportedContentType: .audio) { item in
            return SentTransferredFile(item.audio!, allowAccessingOriginalFile: false)
        }
        .exportingCondition { $0.audio != nil }
        ProxyRepresentation(exporting: \.text!)
            .exportingCondition { $0.text != nil }
    }
}

The exportingConditions make sure that the correct representation is used for each enum case.

Then you can write:

ShareLink(
    items: [
        TextOrAudio.audio(someURL),
        TextOrAudio.text("Some Text")
    ]
) { _ in
    SharePreview("Preview")
} label: {
    Label("Share text and audio", systemImage: "square.and.arrow.up")
}

Mail.app will put the text in the email body and attach the audio file, but ultimately it is up to the receiving app what to do with these two items.

本文标签: swiftuiShareLink with multiple items only shares one at a timeStack Overflow