共有機能(UIActivityViewController)を実装してみて分かったこと

共有機能(UIActivityViewController)を実装してみて分かったこと トラブルシューティング

MapKitでの地図表示ができるようになったので、記録した内容をユーザーが他のアプリへ共有できるよう、標準の共有シート(UIActivityViewController)を実装してみました。

1. SwiftUIから直接呼び出せると思い込んでいた

SwiftUIのボタンから、共有シートも他のビューと同じような感覚で表示できるものだと思い込んでいました。

UIApplication.shared.connectedScenes
    .compactMap { $0 as? UIWindowScene }
    .first?.windows.first?.rootViewController?
    .present(activityVC, animated: true)

UIActivityViewControllerはUIKitのコンポーネントのため、SwiftUIだけで完結する書き方はなく、UIViewControllerRepresentableでラップするか、上記のように現在表示中のUIViewControllerを取得してpresentする必要がありました。SwiftUIとUIKitの橋渡しが必要な場面の一つだと実感しました。

2. iPadで原因不明のクラッシュが発生した

iPhoneでは問題なく動作していたのに、iPadの実機で試したところ共有シートを開こうとした瞬間にクラッシュしてしまいました。

if let popover = activityVC.popoverPresentationController {
    popover.sourceView = sourceView
}

iPadでは共有シートがポップオーバー形式で表示されるため、popoverPresentationControllerに表示元となるsourceView(あるいはsourceRect)を明示的に指定する必要がありました。iPhoneではこの設定がなくてもエラーにならなかったため、iPad特有の落とし穴として見落としがちなポイントでした。

3. 共有する内容にテキストと画像を両方渡そうとして表示が崩れた

記録内容のテキストと、記録画面のスクリーンショット画像を両方共有できるようにしたところ、共有先アプリによっては意図しない見た目になることがありました。

let items: [Any] = [text, image]

共有先のアプリごとにテキストと画像の扱い方(両方表示する、片方しか使わない等)が異なるため、渡す組み合わせによって見え方が変わることを理解しておく必要がありました。今回はテキストのみ・画像のみをそれぞれ別ボタンで選べるようにし、混乱を避けることにしました。

4. 共有した画像がぼやけていた

スクリーンショットを共有用に生成する処理で、想定より画質の粗い画像が共有されてしまう不具合がありました。

画面のレンダリング処理でスケール(UIScreen.main.scale相当の倍率)を指定しておらず、低解像度で書き出されていたのが原因でした。生成時にデバイスの表示倍率を明示的に指定するよう修正したところ、通常の見た目に近い画質で共有できるようになりました。

まとめ

  • UIActivityViewControllerはUIKitのコンポーネント。SwiftUIから使うには橋渡しの実装が必要
  • iPadでは共有シートがポップオーバー表示になるため、sourceViewの指定を忘れるとクラッシュする
  • テキストと画像を同時に渡すと共有先アプリによって見え方が変わる。用途に応じて渡す組み合わせを整理する
  • 共有用の画像を生成する際は、表示倍率を明示的に指定しないとぼやけた画質になる

「共有ボタンを付けるだけ」の単純な機能に見えて、iPad対応や画質など細部にこだわりが必要な実装でした。


本記事は生成AI(Claude)を活用して執筆・編集しています。内容は実体験に基づき、執筆者本人が確認・監修しています。

コメント

タイトルとURLをコピーしました