SwiftPMのプラグイン機能をiOSアプリ開発に活用する

1K Views

September 10, 22

スライド概要

iOSDC Japan 2022: SwiftPMのプラグイン機能をiOSアプリ開発に活… / 宇佐見 公輔 - YouTube
https://www.youtube.com/watch?v=JBT8bdYOo6A

SwiftPMのプラグイン機能をiOSアプリ開発に活用する by 宇佐見 公輔 | トーク | iOSDC Japan 2022 - fortee.jp
https://fortee.jp/iosdc-japan-2022/proposal/4f56de04-0d5c-49ba-b2f8-12b25e36ad32

#iOSDC Japan 2022でSwiftPMプラグインの話をしました - usami-kの日記
https://usami-k.hatenablog.com/entry/2022/09/10/230930

profile-image

https://usami-k.github.io/

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

のプラグイン機能を iOSアプリ開発に活用する SwiftPM 宇佐見公輔 / 株式会社ゆめみ

2.

自己紹介 宇佐見公輔(うさみこうすけ) 株式会社ゆめみ / iOSテックリード このトーク以外にも、パンフレット記事を2つ書きました。

3.

このトークの内容 ( )とは iOSアプリ開発でSwiftPMを活用する SwiftPMのプラグイン機能とは iOSアプリ開発でSwiftPMプラグインを活用する SwiftPM Swift Package Manager を略してSwiftPMと呼ぶことにする。 ※ Swift Package Manager

4.

Swift Package Manager とは

5.

とは Swift Package Manager Swiftコードをパッケージとして管理する パッケージをビルドしてライブラリや実行プログラムを生成する ライブラリ:他のSwiftコードでインポートできるモジュール 実行プログラム:シェル上で実行できるCLIツールなど 他のパッケージを依存物として利用できる

6.

パッケージ パッケージはSwiftソースファイルと `Package.swift` で構成される

7.

Package.swift import PackageDescription let package = Package( name: "MyLibrary", products: [ .library(name: "MyLibrary", targets: ["MyLibrary"]), ], dependencies: [], targets: [ .target(name: "MyLibrary", dependencies: []), ] )

8.

配布されているパッケージの利用 import PackageDescription let package = Package( name: "MyLibrary", products: [ .library(name: "MyLibrary", targets: ["MyLibrary"]), ], dependencies: [ .package(url: "https://example.com/AwesomePackage", from: "1.0.0"), ], targets: [ .target(name: "MyLibrary", dependencies: []), ] )

9.

アプリ開発で を活用する iOS SwiftPM

10.

プロジェクト Xcode iOSアプリはXcodeプロジェクトを使って開発する

11.

余談:Swift Playgrounds App でも開発可能、プロジェクト形式が異なる 「ゆめみ大技林 '22」に書いた(技術書典で配布) Swift Playgrounds ※ これも面白いが、このトークではこれ以上述べない。

12.

プロジェクトと Xcode SwiftPM 配布されているパッケージを利用する CocoaPodsやCarthageで配布ライブラリを利用する代わりに、 SwiftPMで配布ライブラリを利用する アプリのコード(の一部)をパッケージ化する コードをXcodeプロジェクトの管理外に置ける

13.

で配布パッケージを利用する Xcode Xcodeの「File→Add Packages…」で依存パッケージを追加できる ※ ライブラリ管理の手法として有益だが、このトークではこれ以上述べない。

14.

アプリのコードをパッケージ化する ローカルのSwiftパッケージをアプリでインポートする ※ このトークでは、こちらの手法を扱う。

15.

アプリのコードをパッケージ化する 一部だけでなく、ほとんどのコードをパッケージに入れても良い

16.

プロジェクト内のソース Xcode App.swift import UIKit import AppFeature @main final class AppDelegate: AppFeature.AppDelegate {} final class SceneDelegate: AppFeature.SceneDelegate {}

17.
[beta]
パッケージ内のソース

Swift

AppDelegate.swift
import UIKit
open class AppDelegate: UIResponder, UIApplicationDelegate {
public final func application(_ application: UIApplication, ...) -> Bool {
return true
}
}

18.

パッケージ化のメリット プロジェクト(xcodeproj)でのソースコード管理が減る xcodeprojは、ファイルの追加や削除などでGitのコンフリクトを招く Swiftパッケージ管理だと、Gitのコンフリクトを起こしにくい アプリ内のモジュール分割が容易になる Swiftパッケージのほうが簡単に扱える Xcode

19.

パッケージ化で未解決の問題 ビルドスクリプトはXcodeプロジェクトで管理する必要がある SwiftGenでコード生成 SwiftLintでコードチェック 実はこの問題は、SwiftPMのプラグイン機能で解決できる

20.

のプラグイン 機能とは SwiftPM

21.

のプラグイン機能 SwiftPM 2022年3月のSwift 5.6で追加された機能 コマンドプラグイン ビルド以外のタスクを定義できる ビルドツールプラグイン ビルド時に行う処理を追加できる

22.

プラグイン機能の活用方法 配布されているプラグインを使う 配布されているものは、現時点では多くはない プラグインを自分で実装する 独自の処理を行いたい場合はこの方法になる ※ プラグインの実装方法はパンフレット記事を参照。

23.

ビルドツールプラグイン let package = Package( targets: [ .target( name: "MyTarget", plugins: [ .plugin(name: "MyPlugin"), ] ), .plugin( name: "MyPlugin", capability: .buildTool() ), ] )

24.

ビルドツールプラグインの処理内容 以下の2つのタイミングで処理が実行される ビルド前(pre-build) ビルド中(in-build) プラグインであらかじめ定義された処理が実行される 処理内容を自分で決めたい場合は、プラグインを自分で実装する

25.

外部ツールを使う プラグイン外のツールを実行できる Mac内のコマンドを実行できる 公開されているコマンドラインツールをダウンロードできる artifact bundle形式で公開されているバイナリが使える

26.

アプリ開発で プラグインを 活用する iOS SwiftPM

27.

と プラグイン Xcode SwiftPM XcodeでもSwiftPMプラグインは動作する Xcode 13.3以降で動作する Xcode 14でSwiftPM対応が改善されている(ビルドログなど) ただし、一部の動作に問題がある(後述)

28.

事例:SwiftGenプラグイン 公式から、プラグインとartifact bundleが提供されている ビルド前(pre-build)にソースコード生成処理が行われる 生成先は `${DERIVED_SOURCES_DIR}` 以下となる `swiftgen.yml` で定義する なお、ビルドツールだけでなくコマンドプラグインも提供されている SwiftGen

29.

プラグインの利用 SwiftGen (1) 注意:この方法が正式だが、現時点では問題がある let package = Package( dependencies: [ .package(url: "https://github.com/SwiftGen/SwiftGenPlugin", from: "6.6.2") ], targets: [ .target( name: "MyTarget", plugins: [ .plugin(name: "SwiftGenPlugin", package: "SwiftGenPlugin") ] ), ] )

30.

で発生する問題 Xcode 外部プラグイン利用時、Xcodeが重くなる XcodeのCPU使用率が100%以上になる Xcodeのエディタの動きがもたつく 外部プラグインの中でartifact bundleを使っていると発生する 外部ツールをダウンロードする機能 SwiftGenプラグインは `swiftgen` コマンドをartifact bundleで使用

31.

で発生する問題の回避方法 Xcode Xcodeの問題を回避するには、プラグインを自分で実装する artifact bundleの利用自体は問題ない 外部プラグインの中でartifact bundleが使われているとダメ ローカルプラグインの中でartifact bundleを使うのは大丈夫

32.

プラグインの利用 (2) SwiftGen let package = Package( targets: [ .plugin( name: "SwiftGenPlugin", capability: .buildTool(), dependencies: ["swiftgen"]), .binaryTarget( name: "swiftgen", url: "https://github.com/SwiftGen/SwiftGen/releases/...", checksum: "..." ), ] )

33.

事例:SwiftLintプラグイン 公式から、artifact bundleが提供されている これを利用して、自分でプラグインを実装すればよい SwiftLint

34.
[beta]
プラグインの実装

SwiftLint

struct SwiftLintPlugins: BuildToolPlugin {
func createBuildCommands(context: PluginContext,
target: Target) async throws -> [Command] {
return [buildCommand(
displayName: "Linting \(target.name)",
executable: try context.tool(named: "swiftlint").path,
arguments: [
"lint",
"--in-process-sourcekit",
target.directory.string
],
environment: [:])]
}
}

35.

プラグインの利用 SwiftLint let package = Package( targets: [ .plugin( name: "SwiftLintXcode", capability: .buildTool(), dependencies: ["SwiftLintBinary"] ), .binaryTarget( name: "SwiftLintBinary", url: "https://github.com/realm/SwiftLint/releases/...", checksum: "..." ), ] )

36.

まとめ ( )とは iOSアプリ開発でSwiftPMを活用する SwiftPMのプラグイン機能とは iOSアプリ開発でSwiftPMプラグインを活用する サンプル: Swift Package Manager SwiftPM https://github.com/usami-k/XcodeSwiftPMSample