Build Tool Plugin で swift-format をビルド時実行させる
はじめに
筆者はiOS開発に2年以上のブランクがあり、ビルドスクリプトは Build Phases > Run Script でしか定義したことがありませんでした。
Xcode15以降はENABLE_USER_SCRIPT_SANDBOXING=YESがデフォルトのようです。
これを NO にすれば従来の Run Script でも動作はしたのですが、セキュリティ上 YES が推奨されている背景もあり、設定を変更せずに安全にビルド時ワークフローを定義できる Build Tool Plugin を導入することにしました。
USER_SCRIPT_SANDBOXING については、以下の記事が参考になりました。🙏
Build Tool Plugin とは
Xcode14から導入された、Swiftを使ってビルド時のワークフローを定義できる仕組みのことです。
Swift Package Manager で設定可能です。
.swift-format を作成する
今回はビルド時にリント解析をかけたかったので、Apple公式のフォーマッター/リンターである swift-format を採用しました。
Xcode 16以降であれば、特別なインストールをしなくてもツールチェーンに組み込まれているようです。
.swift-formatはルール適用のための構成ファイルです。
プロジェクトルートに.swift-formatを作成します。
デフォルトの設定は以下のコマンドで出力できます。
swift format dump-configuration
swift-format 用 Build Tool Plugin を作成する
メニューから File > New > Package > Build Tool Plug-in を選択して作成します。

コマンドラインからは以下を実行します。
swift package init --type build-tool-plugin --name ${YOUR_PLUGIN}
Pluginのパッケージが作成されたら、Plugins/YourPlugin.swiftファイルに実行したいコマンドを書いていきます。
以下がXcodeプロジェクトビルド時に実行される関数になります。
extension YourPlugin: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
// ここにビルドコマンドの組み立てを記述していく
}
}
swift-format用に書いた実際のプログラム
import PackagePlugin
import struct Foundation.URL
@main
struct SwiftFormatPlugin: BuildToolPlugin {
func createBuildCommands(context: PluginContext, target: Target) async throws -> [Command] {
// SwiftPMターゲット用のダミー(今回はXcodeプロジェクトでのみ動かすため空配列を返している)
return []
}
}
#if canImport(XcodeProjectPlugin)
import XcodeProjectPlugin
extension SwiftFormatPlugin: XcodeBuildToolPlugin {
func createBuildCommands(context: XcodePluginContext, target: XcodeTarget) throws -> [Command] {
let directoryURL = context.xcodeProject.directoryURL;
let swiftFormatFile = directoryURL.appending(path: ".swift-format")
// ⚠️ ご自身のプロジェクトのソースコードが格納されているフォルダ名に書き換えてください
let sourceFiles = directoryURL.appending(path: "YourApp")
return [
.buildCommand(
displayName: "Run swift-format",
executable: try context.tool(named: "swift").url,
arguments: [
"format",
"lint",
"--strict",
"--configuration",
swiftFormatFile.path(),
"-r",
sourceFiles.path(),
],
inputFiles: [],
outputFiles: []
)
]
}
}
#endif
Xcode Project に作成した Build Tool Plugin を組み込む
最後に、アプリのターゲット設定を開き、Build Phases > Run Build Tool Plug-ins に先ほど作成した Build Tool Plugin を追加します。
XcodeGenを採用している場合は、project.ymlに以下を追加します。
packages:
+ SwiftFormatPlugin:
+ path: {YOUR_PACKAGE_PATH}/SwiftFormatPlugin #Package.swiftへの相対パス
targets:
YourApp:
+ buildToolPlugins:
+ - plugin: SwiftFormatPlugin
+ package: SwiftFormatPlugin #packagesで定義したパッケージ名
これでプロジェクトをビルド(⌘ + B)した際、自動的に swift-format が走り、規約違反があればXcode上に直接エラーが表示されるようになりました!🎉
Discussion