Mac OS X 10.4〜10.6(Tiger〜Snow Leopard)時代のFinderの雰囲気を再現した、個人開発の
ファイラーアプリです。Apple社および実際のFinderとは無関係の非公式・非商用プロジェクトです。
⚠️ 起動しようとすると「"AquaFinder"は開いていません」と出る場合
Apple Developer Programでの正式な署名(Notarization)をしていないアプリのため、
ダウンロードしたばかりの状態ではこの警告が出ます。
再起動しても直りません。
次のいずれかの方法で開けます。
- 「システム設定」→「プライバシーとセキュリティ」を開き、下の方にある
「このまま開く」をクリックしてから、もう一度AquaFinderを起動する
- または、
AquaFinder.appを右クリック(Control+クリック)→
「開く」を選び、表示されるダイアログで「開く」を選ぶ
(macOSのバージョンによってはこの方法が出てこないことがあります。その場合は方法1へ)
- それでも解決しない場合は、ターミナルで次のコマンドを実行してから起動する:
xattr -cr /Applications/AquaFinder.app
一度許可すれば、以降は通常どおりダブルクリックで起動できます。
※「フルディスクアクセス」の設定は、この問題とは無関係です。
更新履歴
- 2026-09-09 — サイドバーの「共有」項目に接続先ホスト名を表示(例:「書類 (192.168.11.12)」)。Apple IDのファイル共有で他のMacの「書類」「ダウンロード」をSMBマウントすると、ローカルの同名フォルダと見分けがつかなかったため。「場所」「デバイス」の項目は変更なし
- 2026-08-29 — Dropbox等の同期ツールや低速なネットワーク共有で、短時間に大量のファイル変更イベントが発生すると、リスト表示の行が一時的に重複・消失して見える不具合を修正。変更イベントが300ms静かになるまでまとめてから再読み込みするように変更
主な機能
- アイコン表示・リスト表示・カラム表示
- 複数ウィンドウ対応、ファイルのコピー&ペースト(⌘C / ⌘V)
- リスト表示でフォルダのサイズを自動計算して表示
- テーマ切り替え:10.6風グラファイト/10.4風ブラッシュドメタル
- 文字サイズ・行の高さの調整(環境設定)
- 日本語・英語ローカライズ対応
- ラベルカラー、Get Info、Quick Look など classic Finder の主要機能
対応バージョン
| バージョン | 0.1 |
| 動作環境 | macOS 10.15 (Catalina) 以降 |
| 対応アーキテクチャ | Apple Silicon(M1以降)・Intel Mac 両対応(Universal Binary) |
インストール手順
- 上のボタンから
AquaFinder.dmg をダウンロードします。
- DMGを開き、
AquaFinder.app を Applications フォルダにドラッグします。
-
初回起動時、Appleに登録された開発者による署名ではないため「開発元が未確認のため開けません」という警告が必ず出ます(これは不具合ではありません)。
その場合は次のいずれかの方法で開いてください。
AquaFinder.app を右クリック(またはControl+クリック)→「開く」を選択し、表示されるダイアログで「開く」を選ぶ
- もしくは、システム設定 →「プライバシーとセキュリティ」を開き、AquaFinderに関するメッセージの横にある「このまま開く」をクリックする
一度許可すれば、以降は通常どおり起動できます。
ライセンス
MIT License で公開しています。
AquaFinderは一枚の巨大なアプリじゃなくて、FSCore・FSUIKit・FSWindow・FSIconView・FSColumnView・
FSListView・FSGetInfo・FSSidebar・FSQuickLookと、それをまとめる AquaFinderApp 本体、10個くらいの
小さなSwiftパッケージに分かれてます。Storyboardもnibも一切使ってなくて、ウィンドウもツールバーの
ボタンもリストのセルも全部コードで組んでます。今どきの NSToolbar を Tiger〜Snow Leopard時代の
Finderのツールバーっぽく見せて動かそうとすると、思ってた以上に AppKit のレイアウトの仕組みと喧嘩する
ことになりました。その一部を紹介します。
ボタンをNSToolbarItemの外に浮かせている理由
戻る/進むボタンと表示モードボタン(ClassicSegmentedControl)は、実は本物のNSToolbarItemじゃないんです。
ただのNSViewをツールバーの上に浮かせて、位置を手動で計算してるだけです。最初はもっと素直なやり方を
試してたんですが、それがなぜ変わったかは下のクラッシュの話を見てください。この方式のデメリットは、
位置に関わること全部(ウィンドウの最小幅も含めて。2つのボタン自身の固定サイズとマージン、検索フィールドを
アイコンだけまで縮めた分の余白から計算してます)を、AppKitのレイアウトエンジンに任せず自分で追いかけないと
いけないことです。
アイコン読み込みとスクロール
以前はセルが最初に描画されるタイミングでLaunch Services経由(そんなに速くない)で同期的にアイコンを
探してたので、ファイルが多いフォルダを開くとアイコンがポツポツ後から出てくるのが見えてました。
IconCacheをNSCacheに移して、フォルダの一覧が返ってきた時点でバックグラウンドで先読みするようにして
あります。Quick Lookのサムネイル読み込みも、スクロール中にセルが再利用されたタイミングでキャンセル
するようにしたので、大きいフォルダを素早くスクロールしても、もう画面に出てないセルのためのサムネイル
デコードが溜まり続けることはなくなりました。
ハマった点
ツールバーをまたぐ制約でクラッシュ。 最初は、あるツールバーアイテムの中のボタンから、
別のツールバーアイテムに入ってる検索フィールドへ、普通のAuto Layoutの制約を直接張ってたんです。これが
起動するたびに毎回クラッシュしてました。NSToolbarItemViewer は、そのアイテム自身のviewの外にある
viewを参照する制約が一つでも触れているレイアウトエンジンをホストすることを完全に拒否していて、
ウィンドウが出てくる前に例外を投げるんですよね。そこで、ツールバーアイテムをまたぐ制約は一切使わず、
ただのNSViewを浮かせて手動で位置を計算する今の方式に変えました。
同じグレーなのにMacによって見え方が違う。 ツールバーの縁取りに最初は
NSColor(calibratedWhite:) を使ってたんですが、まったく同じ描画コードなのにMacによって微妙に
明るさが違って見えてたんです。calibratedWhite はディスプレイ自身のキャリブレーション/Generic Gray
という色空間を経由して解決されるので、同じ数値でもディスプレイのプロファイル次第で実際の明るさが
変わっちゃうんですよね。全部 srgbRed/green/blue の指定に変えました。これは固定された絶対色空間なので、
指定した値がそのまま描画されます。
カラム表示のリネームで、編集欄が空っぽになる。 カラム表示でファイル名をリネームしようと
すると、中身が空の編集ボックスが開いちゃうバグがありました。原因は、ファイルアイコンを表示するために
ブラウザセルの image を設定すると、Appleの仕様通りNSCellの type が黙って .imageCellType に切り替わって
しまうことでした。リネームの編集欄はテキストタイプのセルから初期文字列を読み込む仕組みなので、セルが
静かに画像セルになった時点で読み込む元が無くなってたんです。おまけに、Returnキーでのリネームは
NSBrowser内部の非公開な列ごとの NSMatrix の中で処理されていて、NSBrowserの公開メソッドを一切経由
しないので、外側から直しようがなかったんです。両方とも FileBrowserCell 自身の中で直しました。
image を設定した直後に type を .textCellType に戻すのと、edit(withFrame:in:editor:delegate:event:) を
オーバーライドすることで(これはどんなきっかけでリネームが始まっても必ず通る唯一の場所でした)
対応しました。
ダブルクリックが一度だけ無反応になる。 起動していきなりアイコン表示かリスト表示のまま、
一度もカラム表示に切り替えずにフォルダをダブルクリックすると、何も起きないんです。エラーも出ない、
ただ無反応。原因は、カラム表示側の setRoot() が、まだ一度も view が読み込まれてない(なので delegate も
nilのまま)NSBrowser に対して browser.selectionIndexPath をセットしようとしてたことでした。これは
Swiftからは捕まえられないObjective-Cの例外を投げるんですが、たまたま AppKit自身のマウストラッキングの
ループがそれを飲み込んでしまって、アプリごとクラッシュする代わりに navigate(to:) が途中で静かに
止まる、っていう挙動になってました。直し方は、触る前に browser の view を強制的に読み込ませるだけ。
ちゃんとクラッシュしてくれた方が、まだ見つけやすかったです。
ソースコードはGitHubにあります。