はじめに
SwiftUIでシェア機能を実装する際はUIActivityViewController
を使用します。
ここにかなり深い落とし穴があるので落ちないように気をつけましょう。
私は落っこちて原因に気づかず長い間、クラッシュを生み出していました笑
みなさんはそうならない様に気をつけましょう。
結論
iPadで普通にUIActivityViewController
を使うとクラッシュします
パターン1(おすすめ)
import SwiftUI
struct ContentView: View {
@State var ShowSharePopover: Bool = false
var body: some View {
Button("シェア") {
Share()
}
.popover(isPresented: $ShowSharePopover) {
ShareView()
}
}
// iPhone: ハーフモーダル
// iPad: ポップアップ
func Share() {
if UIDevice.current.userInterfaceIdiom == .pad {
ShowSharePopover = true
} else {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController(activityItems: [link], applicationActivities: nil)
let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
let viewController = scene?.keyWindow?.rootViewController
viewController?.present(activityViewController, animated: true, completion: nil)
}
}
}
struct ShareView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIActivityViewController {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController( activityItems: [link], applicationActivities: nil)
return activityViewController
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
iPhone |
iPad |
|
|
パターン2
import SwiftUI
struct ContentView: View {
@State var ShowShareSheet: Bool = false
var body: some View {
Button("シェア") {
share()
}
.sheet(isPresented: $ShowShareSheet) {
ShareView()
}
}
// iPhone: ハーフモーダル
// iPad: 中央ポップアップ
func share() {
if UIDevice.current.userInterfaceIdiom == .pad {
ShowShareSheet = true
} else {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController(activityItems: [link], applicationActivities: nil)
let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
let viewController = scene?.keyWindow?.rootViewController
viewController?.present(activityViewController, animated: true, completion: nil)
}
}
}
struct ShareView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIActivityViewController {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController( activityItems: [link], applicationActivities: nil)
return activityViewController
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
iPhone |
iPad |
|
|
パターン3(使用してはいけない)
import SwiftUI
struct ContentView: View {
var body: some View {
Button("シェア") {
share()
}
}
// iPhone: ハーフモーダル
// iPad: クラッシュ
func share() {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController(activityItems: [link], applicationActivities: nil)
let scene = UIApplication.shared.connectedScenes.first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene
let viewController = scene?.keyWindow?.rootViewController
viewController?.present(activityViewController, animated: true, completion: nil)
}
}
iPhone |
iPad |
|
クラッシュ |
パターン4
import SwiftUI
struct ContentView: View {
@State var ShowSharePopover: Bool = false
var body: some View {
Button("シェア") {
Share()
}
.popover(isPresented: $ShowSharePopover) {
ShareView()
}
}
// iPhone: モーダル
// iPad: ポップアップ
func Share() {
ShowSharePopover = true
}
}
struct ShareView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIActivityViewController {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController( activityItems: [link], applicationActivities: nil)
return activityViewController
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
iPhone |
iPad |
|
|
パターン5
import SwiftUI
struct ContentView: View {
@State var ShowShareSheet: Bool = false
var body: some View {
Button("シェア") {
Share()
}
.sheet(isPresented: $ShowShareSheet) {
ShareView()
}
}
// iPhone: モーダル
// iPad: 中央ポップアップ
func Share() {
ShowShareSheet = true
}
}
struct ShareView: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> UIActivityViewController {
let link = URL(string: "https://qiita.com/SNQ-2001/items/86646b661ccc4a7a9034")!
let activityViewController = UIActivityViewController( activityItems: [link], applicationActivities: nil)
return activityViewController
}
func updateUIViewController(_ vc: UIActivityViewController, context: Context) {
}
}
iPhone |
iPad |
|
|
おわり
今回作成したプロジェクトを置いとくので参考にしてください。