🕌

(macOS)Safari App Extensionの作り方

2024/08/14に公開

はじめに

この記事ではSafari App Extensionの作り方を説明します。Google Chromeなどと互換性のあるSafari Web Extensionとは異なりますのでご注意ください。

対象読者はiOSアプリなどAppleプラットフォームのネイティブアプリを作成した経験がある方です。Xcodeの使い方やBundle IDとは何か、といった説明はしませんのでご容赦ください。

環境

記事の投稿にあたり、以下の環境にて動作確認を行いました。

  • macOS Monterey 12.7.5
  • Safari Version 17.5 (17618.2.12.111.5, 17618)
  • Xcode Version 14.2 (14C18)

Safari App ExtensionとSafari Web Extensionの違い

どちらもSafariブラウザを拡張する手段です。実現可能な機能の観点から、それぞれの手段にほぼ差はありません。

ただし、Safari App Extensionは以下の機能が実現可能です。実装はSwiftで行います。Webサイトのパフォーマンスには影響しません。

  • Webサイトに繊維(新しいURLに移動)をトリガーに処理を発火させる
  • Webサイト上で右クリックしたときに表示されるコンテキストメニューに項目を追加する
  • Safariのツールバーに表示されるアイコンのクリックをトリガーに処理を発火させる

上記に加えて、任意のWebサイトにJavaScriptを注入し、そのJavaScriptとネイティブ拡張との間で通信することも可能です。Safari App ExtensionはSafari Web Extensionの上位互換だと考えて差し支えありません。

作り方

ここでは例として以下の拡張機能を作成します。

  • Webサイト上で右クリックしたときに表示されるメニューに以下の項目を追加する
    • Copy Link as Markdown: [Title](URL)形式の文字列をクリップボードにコピーする
    • Copy Link as HTML: <a href="URL">Title</a>形式の文字列をくりぷボードにコピーする

機能的にはSafari Web Extensionでも実現可能です。ここではSwiftで実装する方法を示すのが目的ですので、その点は気にしないでください。

プロジェクトの作成

  1. Xcodeを起動します。メニューのFile→New→Projectを選択します。
  2. プラットフォームとしてmacOSを選択します。
  3. テンプレートから「Safari Extension」を選択してNextをクリックします。
  4. 拡張機能の名前を入力します。ここでは仮に「CopyLink」とします。
  5. Typeをクリックします。選択肢としてSafari Web ExtensionとSafari App Extensionが表示されるので、Safari App Extensionを選びます。
  6. Bundle IDやTeam IDなど、その他の項目を入力します。
  7. プロジェクトが作成できたら完了です。

プロジェクトが作成できたら、Command + B`キーを押してビルドしてみてください。通常はビルドが成功します。

もし何も変更を加えていないのに、プロジェクト作成直後の状態でビルドが失敗する場合は設定に不備があるかもしれません。この時点での不具合の対処法は解説の対象外ですので、各自でXcodeを最新に更新するなどして解決してください。

プロジェクト作成直後のディレクトリ構成

プロジェクトのルートには以下3つのディレクトリがあるはずです。CopyLinkは仮の名前です。

  • CopyLink
  • CopyLink Extension
  • CopyLink.xcodeproj

末尾にExtensionとあるのがSafari拡張の本体です。これから編集するファイルはこのディレクトリの中にあります。

それとは別にCopyLinkという名前のディレクトリがあります。こちらはSafari拡張とは独立したアプリであり、ホストアプリと呼ばれます。初回のインストールで表示されるウィンドウの管理などを担当します。

適当なテキストエディタでCopyLink Extension/Info.plistを開きます。以下の内容を<key>SFSafariToolbarItem</key>の前に追加してください。

<key>SFSafariContextMenu</key>
<array>
	<dict>
		<key>Text</key>
		<string>Copy Link as Markdown</string>
		<key>Command</key>
		<string>Markdown</string>
	</dict>
	<dict>
		<key>Text</key>
		<string>Copy Link as HTML</string>
		<key>Command</key>
		<string>HTML</string>
	</dict>
</array>

SafariExtensionHandler.swiftの編集

以下のように、SafariExtensionHandlerクラスにcontextMenuItemSelectedメソッドを追加してください。

import AppKit // 追加
import SafariServices

class SafariExtensionHandler: SFSafariExtensionHandler {
  // 省略

  override func contextMenuItemSelected(
    withCommand: String, in page: SFSafariPage, userInfo: [String: Any]?
  ) {
    page.getPropertiesWithCompletionHandler { property in
      guard let property = property else {
        return
      }

      let title = property.title ?? ""
      let url = property.url?.absoluteString ?? ""
      let pasteboard = NSPasteboard.general

      switch withCommand {
      case "Markdown":
        pasteboard.clearContents()
        pasteboard.setString("[\(title)](\(url))", forType: .string)
      case "HTML":
        pasteboard.clearContents()
        pasteboard.setString("<a href=\"\(url)\">\(title)</a>", forType: .string)
      default:
        break
      }
    }
  }

  // 省略
}

動作確認

以上で編集は完了です。Command + Rキーを押して実行してみてください。「Quit and Open Safari Extensions Preferences…」と書かれたウィンドウが表示されるはずです。

Safariを起動したら、作成した拡張を有効にしてください。デフォルトではexample.comドメインのみで利用可能です。これで右クリックメニューにCopy Link as MarkdownとCopy Link as HTMLが表示されるようになります。

Safari拡張の許可対象ドメインは先ほど編集したInfo.plistのAllowed Domainsに定義されています。詳細については参考資料を参照してください。

参考資料

  1. Building a Safari app extension - Apple Developer Documentation
  2. Safari app extension information property list keys - Apple Developer Documentation
  3. SFSafariExtensionHandling - Apple Developer Documentation

Discussion