[SwiftUI] iPad でもUIActivityViewController を使う

2 min read読了の目安(約1900字

コンテンツを共有する機能のためにUIActivityViewController を使いたかったのですが、iPad の時にどうするか困ったのでメモ。

iPhone の場合

SwiftUI でも、window のrootViewControllerpresentedViewController からUIActivityViewController をpresent することで、OS のシェアシートを呼ぶことが出来ました。

https://zenn.dev/ariiyu/articles/333c1cb96feb9b#.fullscreencover-で扱うview-からuiactivityviewcontroller-を提示しようとすると失敗する

iPad の場合

問題

iPad の場合はこのままだとクラッシュしてしまいます。
UIActivityViewController の popoverPresentationController?.sourceViewpopoverPresentationController?.sourceRect を指定する必要があるのですが、SwiftUI のView からそれらをどうやってやるのかで困りました。

解決方法

UIViewControllerRepresentable を利用することで、iPad でもUIActivityViewController を使うことが出来ました。

import UIKit
import SwiftUI

struct ActivityViewController: UIViewControllerRepresentable {
    var activityItems: [Any]
    var applicationActivities: [UIActivity]? = nil

    func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityViewController>) -> UIActivityViewController {
        let controller = UIActivityViewController(activityItems: activityItems, applicationActivities: applicationActivities)
        return controller
    }

    func updateUIViewController(_ uiViewController: UIActivityViewController, context: UIViewControllerRepresentableContext<ActivityViewController>) {}
}
@State private var showingActivityView = Bool(false)

var body: some View {
  YourView()
    .background(EmptyView().sheet(isPresented: $showingActivityView, content: {
      ActivityViewController(activityItems: activityItems)
    }))
}

private func didTapActionButton() {
  if isIPad() {
    showingActivityView = true
  } else {
    //
  }
}

参考

Showing 'UIActivityViewController' in SwiftUI - Stack Overflow