Xcode: macOSでドラッグ&ドロップ起動するようにする

macOSアプリです。
ファイルをアプリのアイコンにドラッグ&ドロップして起動させるタイプのアプリを作ろうと思ったんです。
Xcodeに使うドキュメントタイプを設定する(というかInfo.plistを作る)、というのは分かったのですが、ここが結構XcodeのバージョンなのかmacOSのバージョンなのか、ともかく参考にするページごとに違っていて、混乱するんですね。
現行のXcode 15.4でちょっと書いていきます。
TARGETS→Info→Document Typesに、開くドキュメントの型を登録していきます。
Xcode 15.4時点では、以下のような項目があります。
- Name:適当に入力
- Identifier:ここがキモです。UTI(Uniform Type Identifier)を入れる必要があります。独自のファイル形式の場合は、逆DNS記法で他のアプリとかぶらないようなものを指定します。
- Class:空でOK。使う場合は自分のドキュメントクラスを指定します。
- Role:読み込みしかしなければViewer、保存もする場合はEditorを指定します。
- Legacy Icon:空でOK。macOS 10.15以前のOSでは古き.icnsとかを使ったアイコンを表示するらしいんですが、それ用ですね。
- Handler Rank: このIdentiferを定義したのが自分か(Owner)、そうでないか(Alternative)、ということですね。意味合いとしては、ドキュメントアイコンをダブルクリックしたときにデフォルトで起動するアプリかどうか、ということになると思います。
publicでないIdentiferを利用する場合は、Exported Type Identifiers(自分のアプリで定義する場合)、Imported Type Identifiers(3rdパーティ製ファイル定義を利用する場合)も定義する必要があります。
詳しくは以下を見るといいですね。
独自アイコン作成方法は以下を見るといいですね。

UTType
に定義されている型ならPlaygroundで以下のようにしてIdentiferを確認できます。
import UniformTypeIdentifiers
let t = UTType.midi // 例えばMIDIファイルの場合
print("\(t.identifier)")

ちなみに。
Xcode 14以降、Document Types、Exported Type Identifers、Imported Type Identifiersは、削除する機能がなくなっているようです。バグなのか仕様なのか。バグじゃないかと言われていますが。
なので間違って追加したら、Info.plistを開いて直接編集して削除する必要があります。
TARGETS→InfoはInfo.plistのエディタではあるんですが、ファイルを直接編集したことを検知しません。
Info.plistを直接編集すると、その後にTARGETS→Infoで編集した際に不整合が生じます。
Info.plistを直接編集したら、いったんプロジェクトファイルを閉じて開き直すのがいいと思います。
これもバグに近い仕様というか。これ直してくれると世界中の開発者の生産性があがると思うんですけどね。

アプリ側の対応ですが、SwiftUIの場合は以下のようになります。
まず、アプリ側にAppDelegateを設定してやる必要があります。
@main
struct MyGreatApp: App {
@NSApplicationDelegateAdaptor(MyAppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class MyAppDelegate: NSObject, NSApplicationDelegate {
func application(sender: NSApplication, openFile filename: String) -> Bool {
print("\(filename)")
return false
}
func application(_ application: NSApplication, open urls: [URL]) {
print("\(urls)")
}
}
最初はopenFile
のほうだけを実装して試したんですが、来なかったんです。
もう一つのopen
のほうを実装したら来ましたね。
さらに、以下の説明では、open
を実装するとopenFile
やopenFiles
は来なくなる、と書いてあります。
もうopen
だけで良さそうです。