まず結論: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つ
- URLではなく Data を返す
- ファイル名を明示する
- 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送信失敗の完全解
この問題、
公式ドキュメントを読んでも一発では分かりません。
だからこそ、
この実録が誰かの時間を救えたら嬉しいです。
もしこの記事が役に立ったら、
同じ沼にいそうな開発者にそっと共有してください。