仕事用と個人用でMacのデフォルトブラウザをRaycastから切り替える

仕事では主にMicrosoft Edge、Safariを使い、個人の作業ではCometやGoogle Chromeを使っています。

意識して使い分けているため通常利用には問題ないのですが、ちょいちょい困るのが別のアプリから直接開いて認証を行うようなケースです。 これまではリンクを開いてから「違う、この認証するならこっちのブラウザだった」とやり直すことがしばしばありました。macOSの設定からデフォルトブラウザを変えることもできますが、何度も切り替えるには少々手間です。 仕方ないのでリンクをコピーして適切なブラウザに貼り付けるなどを運用をやってきましたが、今回AIパワーを借りて見直すことにし、無事解決したのでブログします。

解決策として実装したのが、Raycastからワンアクションでリンクを開くブラウザを切り替えられるようにしました。

最初はmacOSのデフォルトブラウザそのものを変更しようとしたのですが、確認ダイアログと権限まわりに苦労しました。最終的にはFinicky をmacOSのデフォルトブラウザに固定し、Finickyの転送先だけを切り替える構成にしています。

この記事では完成形と、そこへ至るまでにハマったところをまとめます。

最初にまとめ

  • macOSのデフォルトブラウザはFinickyに固定する
  • EdgeやCometなど、実際にリンクを開くブラウザは ~/.finicky.js で指定する
  • RaycastのScript Commandから設定を書き換え、Finickyを再起動する
  • 切り替えのたびにmacOSの確認ダイアログは出ない
  • Raycastやターミナルへのアクセシビリティ、オートメーション権限も不要
  • 手元の構成一式はGitHubで公開 している

最終的なリンクの流れはシンプルです。

リンクをクリック → Finicky → 現在選択しているブラウザ

macOSから見るとデフォルトブラウザはずっとFinickyのままです。「ブラウザを切り替える」といっても、実際にはFinickyの転送先を変更しています。

やりたかったこと

今回の要件は次のとおりでした。

  • 普段はMicrosoft Edgeでリンクを開く
  • 一部の作業はCometを使う
  • 必要に応じてGoogle Chromeにも直接切り替えたい
  • Raycastから一瞬で操作したい
  • ブラウザごとにリンクを右クリックして選ぶのではなく、その時間帯のモードとして切り替えたい

ブラウザを振り分けるだけなら、URLのドメインごとにルールを書く方法もあります。ただ、今回は「今は仕事」「今は個人」という自分の状態に合わせて全部まとめて切り替えたかったため、トグルできるコマンドを用意しました。

最初はOSのデフォルトブラウザを直接変えようとした

最初に試したのは、defaultbrowser というCLIツールです。

brew install defaultbrowser
defaultbrowser comet

コマンドだけを見ると、これで終わりそうです。しかし、検証したmacOS 15.7.7ではデフォルトブラウザを変更するたびに確認ダイアログが表示されました。

毎回ダイアログを手で押すのではRaycastから切り替える意味が薄れるので、AppleScriptとSystem Eventsで自動クリックする方法も試しました。ところが、そのためには呼び出し元のターミナルやRaycastへアクセシビリティとオートメーションの権限が必要になります。

ターミナルへアクセシビリティ権限を与えるのは、他のアプリを操作できる広い権限を渡すことでもあります。日常的に使う業務用Macで、ブラウザを切り替えるためだけに付与するのは割に合わないと判断しました。

さらに確認ダイアログを出す CoreServicesUIAgent の現れ方にもタイミング差があり、ポーリングして自動クリックする実装は安定しませんでした。

defaultbrowserの現在値判定でもハマった

調査中に、切り替えは成功しているのにスクリプトが失敗と判定することがありました。

手元の環境で調べたところ、defaultbrowser はBundle IDを書き込む際に小文字化する一方、現在値の照合では大文字と小文字を区別していました。LaunchServices側は区別しないため、切り替えそのものは成功します。しかし、defaultbrowser は自分で書いた値を現在値として認識できず、選択中を示す * を表示しません。

影響を受けたのは、Bundle IDに大文字を含むブラウザでした。

ブラウザBundle ID手元での判定
Microsoft Edgecom.microsoft.edgemac正常
Cometai.perplexity.comet正常
Firefoxorg.mozilla.firefox正常
Google Chromecom.google.Chrome現在値を報告できない
Safaricom.apple.Safari現在値を報告できない
Bravecom.brave.Browser現在値を報告できない

このため一時期、「切り替えに失敗している」と思っていた処理が、実際には成功していたこともありました。なかなか味わい深いデバッグでした。

結局、OSのデフォルトブラウザを直接変更する方式はやめることにしました。

Finickyをデフォルトブラウザに固定する

採用したのがFinickyです。FinickyはmacOSのデフォルトブラウザとしてリンクを受け取り、設定ファイルのルールに従って別のブラウザへ転送してくれます。

GitHub - johnste/finicky: A macOS app for customizing which browser to startA macOS app for customizing which browser to start - johnste/finicky GitHub https://github.com/johnste/finicky

インストールはHomebrewで行えます。

brew install --cask finicky

初回だけFinickyのメニューバーアイコンから Set as default browser を選び、macOSの確認ダイアログを承認します。また、ログイン後も常駐するように Start at login を有効にします。

設定ファイル ~/.finicky.js は次のようにしました。

const DEFAULT_BROWSER = "Microsoft Edge"; // finicky-managed

export default {
  defaultBrowser: DEFAULT_BROWSER,

  handlers: [],
};

切り替えスクリプトは finicky-managed の印がある行だけを書き換えます。

sed -i '' "/finicky-managed/s/\"[^\"]*\"/\"$app\"/" ~/.finicky.js

これならmacOSのデフォルトブラウザは変更しないため、切り替えるたびに確認ダイアログが出ることはありません。アクセシビリティ権限もオートメーション権限も不要になりました。

Finicky 4.2.2は設定を自動で読み直さなかった

ここまでで完成かと思いましたが、設定ファイルを書き換えてもリンクの転送先が変わりませんでした。

FinickyのREADMEには設定変更時に自動リロードされる旨の記載がありますが、手元のFinicky 4.2.2では反映されませんでした。

ファイル監視がinodeを追っていて sed -i による置き換えを見失っている可能性も考えました。そこでinodeを維持する書き込みも試しましたが、結果は同じでした。

  • sed -i による書き換え: 反映されない
  • inodeを保つ書き換え: 反映されない
  • Finickyを再起動: 反映される

そのため、設定を書き換えたあとにFinickyを再起動しています。

pkill -x Finicky
open -gj -a Finicky

手元では設定変更から再起動まで約0.7秒で終わりました。

設定ファイルの値だけではなく、未起動のSafariやFirefoxを転送先に指定してからURLを開き、実際にそのブラウザが起動するところまで確認しました。今回のデバッグでは「設定値が変わった」ではなく「リンクが狙ったブラウザで開いた」を成功条件にしたことが大切でした。

Raycastから切り替える

RaycastにはScript Commandとして次の5つを登録しました。

コマンド動作
Default Browser: Toggle Work/PersonalEdgeとCometを切り替える
Default Browser: EdgeEdgeへ切り替える
Default Browser: CometCometへ切り替える
Default Browser: ChromeChromeへ切り替える
Default Browser: Show現在の転送先を表示する

トグル用スクリプトは次のような薄いラッパーです。

#!/usr/bin/env bash

# Required parameters:
# @raycast.schemaVersion 1
# @raycast.title Default Browser: Toggle Work/Personal
# @raycast.mode compact

# Optional parameters:
# @raycast.icon 🔄
# @raycast.packageName Default Browser

export WORK_BROWSER=edge
export PERSONAL_BROWSER=comet

exec "$HOME/.local/bin/set-default-browser" toggle

Raycastの設定から ~/.config/raycast/scripts をScript Commandsのディレクトリとして追加し、Default Browser: Toggle Work/Personal に好みのホットキーを割り当てれば完成です。

シェルから直接操作することもできます。

set-default-browser            # 現在のブラウザを表示
set-default-browser comet      # Cometへ切り替え
set-default-browser chrome     # Chromeへ切り替え
set-default-browser toggle     # EdgeとCometを切り替え
set-default-browser --check    # 導入状態を確認

対応しているのはEdge、Comet、Chrome、Safari、Firefox、Braveです。トグルの組み合わせは環境変数 WORK_BROWSERPERSONAL_BROWSER で変更できます。

ドメイン単位の振り分けもできる

Finickyを挟む方式には、モード切り替え以外の利点もあります。

たとえば個人モード中でも、TeamsやSharePointのリンクだけは常にEdgeで開く、といったルールを handlers に追加できます。

handlers: [
  {
    match: ["teams.microsoft.com/*", "*.sharepoint.com/*"],
    browser: "Microsoft Edge",
  },
],

handlers のルールは DEFAULT_BROWSER より優先されます。なお、手で ~/.finicky.js を編集した場合も、手元のFinicky 4.2.2では再起動が必要でした。

構成一式をGitHubに保存した

完成したスクリプト、Raycastのコマンド、Finicky設定の雛形、別のMacへ導入するためのスクリプトは、個人のインフラ管理リポジトリへ保存しました。

GitHub - morihaya/morihaya-infra: mac/default-browser

mac/default-browser/
├── README.md
├── bin/set-default-browser
├── raycast/
├── finicky.js.example
└── install.sh

実際の ~/.finicky.js は追跡せず、雛形だけを公開しています。ドメイン単位のルールへ社内固有のホスト名を追加した場合、それを誤って公開しないためです。

新しいMacでは次のように導入できます。

cd mac/default-browser
./install.sh

スクリプト本体とRaycastコマンドはリポジトリへのシンボリックリンクになり、変更をGitで追跡できます。~/.finicky.js だけはマシン固有のファイルとしてコピーされます。

おわりに

完成してしまえば、やっていることは「Finickyの設定を1行変えて再起動する」だけです。Raycastから一瞬で仕事用と個人用を切り替えられるようになり、リンクを開き直す小さなストレスがなくなりました。

一方、そこに至るまでは確認ダイアログの自動操作、macOSの権限、Bundle IDの大文字と小文字、設定ファイルのリロードと、思った以上に多くの落とし穴がありました。

今回の一連の調査と実装は生成AIとの対話で進めています。途中では「成功しているのに失敗と判定していた」「設定は変わったのに実際の動作は変わっていなかった」という誤判定もありました。最後に未起動のブラウザが本当に起動するかまで確かめたことで、ようやく完成と言える状態になりました。

自動化では、設定値を見るだけでなく、利用者が期待する最終的な動作まで確認することが大切だと改めて感じました。

それではみなさんEnjoy Finicky and Change Dfault browsers!