Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI exporting or sharing files

I'm wondering if there is a good way export or share a file through SwiftUI. There doesn't seem to be a way to wrap a UIActivityViewController and present it directly. I've used the UIViewControllerRepresentable to wrap a UIActivityViewController, and it crashes if I, say, present it in a SwiftUI Modal.

I was able to create a generic UIViewController and then from there call a method that presents the UIActivityViewController, but that's a lot of wrapping.

And if we want to share from the Mac using SwiftUI, is there a way to wrap NSSharingServicePicker?

Anyway, if anyone has an example of how they're doing this, it would be much appreciated.

like image 994
MScottWaller Avatar asked Jun 29 '19 17:06

MScottWaller


People also ask

What is UIActivityViewController?

The UIActivityViewController allows the application user to easily share data between the current application and services. A number of services such as social networks, email, and SMS are provided by the OS.


2 Answers

You can define this function anywhere (preferably in the global scope):

@discardableResult
func share(
    items: [Any],
    excludedActivityTypes: [UIActivity.ActivityType]? = nil
) -> Bool {
    guard let source = UIApplication.shared.windows.last?.rootViewController else {
        return false
    }
    let vc = UIActivityViewController(
        activityItems: items,
        applicationActivities: nil
    )
    vc.excludedActivityTypes = excludedActivityTypes
    vc.popoverPresentationController?.sourceView = source.view
    source.present(vc, animated: true)
    return true
}

You can use this function in a button action, or anywhere else needed:

Button(action: {
    share(items: ["This is some text"])
}) {
    Text("Share")
}
like image 50
Ken Mueller Avatar answered Sep 24 '22 02:09

Ken Mueller


Most of the solutions here forget to populate the share sheet on the iPad.

So, if you intend to have an application not crashing on this device, you can use this method where popoverController is used and add your desired activityItems as a parameter.

import SwiftUI

/// Share button to populate on any SwiftUI view.
///
struct ShareButton: View {

  /// Your items you want to share to the world.
  ///
  let itemsToShare = ["https://itunes.apple.com/app/id1234"]

  var body: some View {
    Button(action: { showShareSheet(with: itemsToShare) }) {
      Image(systemName: "square.and.arrow.up")
        .font(.title2)
        .foregroundColor(.blue)
    }
  }
}

extension View {
  /// Show the classic Apple share sheet on iPhone and iPad.
  ///
  func showShareSheet(with activityItems: [Any]) {
    guard let source = UIApplication.shared.windows.last?.rootViewController else {
      return
    }

    let activityVC = UIActivityViewController(
      activityItems: activityItems,
      applicationActivities: nil)

    if let popoverController = activityVC.popoverPresentationController {
      popoverController.sourceView = source.view
      popoverController.sourceRect = CGRect(x: source.view.bounds.midX,
                                            y: source.view.bounds.midY,
                                            width: .zero, height: .zero)
      popoverController.permittedArrowDirections = []
    }
    source.present(activityVC, animated: true)
  }
}
like image 30
Roland Lariotte Avatar answered Sep 24 '22 02:09

Roland Lariotte