まず結論:SwiftUIで生成したPDFがAirDrop送信失敗する原因は、URL共有ではPDFとして認識されない場合があるためで、UIActivityItemSourceでDataとUTType.pdfを明示することで解決できます。

さて、本文へどうぞ~

SwiftUIでPDFを生成し、
UIActivityViewController で共有――。

表示までは問題ない。
AirDropも候補に出る。
でも、送信すると失敗する。

しかも、

  • 以前に保存したPDFは送れる
  • 今回生成したPDFだけ失敗する
  • エラー表示も出ない

この記事は、そんな正体不明のAirDrop送信失敗を、
仮説 → 検証 → 失敗 → 深掘り → 完全解決まで辿った実録です。

同じ沼にハマっている開発者を、
一人でも減らせたら本望です。


起きていた現象

  • SwiftUIアプリでPDFを生成
  • UIActivityViewController を表示
  • AirDropが選択肢に出る
  • 送信操作をすると失敗する

一方で、

  • Filesアプリなどに保存されていた既存PDFは正常に送信できる

つまり、

AirDrop自体は壊れていない

ここが最初の重要なヒントでした。


最初に疑った原因(多くの人が通る道)

temporaryDirectory 問題

最初に疑ったのは、
PDFの保存先が temporaryDirectory だったこと。

iOSでは temporaryDirectory

  • OSがいつ削除してもいい
  • 共有中でも消える可能性がある

という特性があります。

対応

  • 保存先を documentDirectory に変更
  • 共有後も削除しない

👉 一部のケースでは改善する

しかし、
それでもAirDrop失敗が発生するケースが残った。


なぜ documentDirectory でも失敗するのか?

ここが本題です。

結論から言うと、

UIActivityViewController に「URLだけ」を渡しているのが原因

でした。


AirDropは「URL」ではなく「ファイルらしさ」を見る

多くの実装例では、こうなっています。

UIActivityViewController(activityItems: [pdfURL], applicationActivities: nil)

一見、正しそうに見えます。

しかし AirDrop は内部で、

  • そのURLが指す実体
  • データの型
  • ファイルとしてのUTType

厳密に判定しています。

問題点

  • URLだけ渡されている
  • PDFのUTTypeが明示されていない
  • iOS側で「PDFとして扱えない」ケースがある

結果として、

  • 表示はできる
  • 共有候補にも出る
  • 送信時に失敗する

という、非常に分かりづらい挙動になります。


決定打となった解決策

UIActivityItemSource を使う

最終的に問題を完全に解決したのは、
UIActivityItemSource を使う方法でした。

ポイントは3つ

  1. URLではなく Data を返す
  2. ファイル名を明示する
  3. UTType.pdf を明示する

これにより、AirDrop側は

「これはPDFファイルである」

と確実に認識します。


実装イメージ(要点)

    final class PDFDataShareItemSource: NSObject, UIActivityItemSource {
    let data: Data
    let filename: String

    init(data: Data, filename: String) {
        self.data = data
        self.filename = filename
    }

    func activityViewControllerPlaceholderItem(
        _ activityViewController: UIActivityViewController
    ) -> Any {
        data
    }

    func activityViewController(
        _ activityViewController: UIActivityViewController,
        itemForActivityType activityType: UIActivity.ActivityType?
    ) -> Any {
        data
    }

    func activityViewController(
        _ activityViewController: UIActivityViewController,
        dataTypeIdentifierForActivityType activityType: UIActivity.ActivityType?
    ) -> String {
        UTType.pdf.identifier
    }

    func activityViewController(
        _ activityViewController: UIActivityViewController,
        subjectForActivityType activityType: UIActivity.ActivityType?
    ) -> String {
        filename
    }
}

そして共有時は:

let item = PDFDataShareItemSource(data: pdfData, filename: filename)
UIActivityViewController(activityItems: [item], applicationActivities: nil)

なぜこれで直るのか

  • AirDropは Data + UTType を最優先で信頼する
  • URLは補助情報に過ぎない
  • 「PDFらしさ」が保証されることで送信が安定する

つまり、

「表示されるPDF」と「送信できるPDF」は別物

ということ。


この問題から得た学び

  • AirDropが表示される ≠ 正しく送信できる
  • temporaryDirectory問題は「入口」にすぎない
  • 本丸は UTTypeとDataの扱い
  • UIActivityViewControllerは想像以上に厳密

同じ問題に遭遇した人へ

もしあなたが、

  • SwiftUIでPDF生成している
  • AirDropがなぜか失敗する
  • 原因が分からず時間を溶かしている

なら、
**まず疑うべきはURLではなく「渡している中身」**です。


まとめ(結論)

  • 保存先を documentDirectory にするのは正しい
  • しかし それだけでは不十分
  • UIActivityItemSource + Data + UTType.pdf
  • これが AirDrop送信失敗の完全解

この問題、
公式ドキュメントを読んでも一発では分かりません。

だからこそ、
この実録が誰かの時間を救えたら嬉しいです。

もしこの記事が役に立ったら、
同じ沼にいそうな開発者にそっと共有してください。