Upgrade to Pro — share decks privately, control downloads, hide ads and more …

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

USAMI Kosuke
September 10, 2022

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

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

USAMI Kosuke

September 10, 2022
Tweet

More Decks by USAMI Kosuke

Other Decks in Programming

Transcript

  1. SwiftPM
    のプラグイン機能を


    iOS
    アプリ開発に活用する
    宇佐見公輔
    /
    株式会社ゆめみ

    View Slide

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

    View Slide

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

    View Slide

  4. Swift Package
    Manager
    とは

    View Slide

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

    View Slide

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

    View Slide

  7. Package.swift
    import PackageDescription

    let package = Package(

    name: "MyLibrary",

    products: [

    .library(name: "MyLibrary", targets: ["MyLibrary"]),

    ],

    dependencies: [],

    targets: [

    .target(name: "MyLibrary", dependencies: []),

    ]

    )

    View Slide

  8. 配布されているパッケージの利用












    dependencies: [

    .package(url: "https://example.com/AwesomePackage", from: "1.0.0"),

    ],







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

    View Slide

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

    View Slide

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

    View Slide

  11. 余談:
    Swift Playgrounds App
    Swift Playgrounds
    でも開発可能、プロジェクト形式が異なる
    「ゆめみ大技林 '22
    」に書いた(技術書典で配布)

    これも面白いが、このトークではこれ以上述べない。

    View Slide

  12. Xcode
    プロジェクトと
    SwiftPM
    配布されているパッケージを利用する
    CocoaPods
    やCarthage
    で配布ライブラリを利用する代わりに、

    SwiftPM
    で配布ライブラリを利用する
    アプリのコード(の一部)をパッケージ化する
    コードをXcode
    プロジェクトの管理外に置ける

    View Slide

  13. Xcode
    で配布パッケージを利用する
    Xcode
    の「File
    →Add Packages…
    」で依存パッケージを追加できる

    ライブラリ管理の手法として有益だが、このトークではこれ以上述べない。

    View Slide

  14. アプリのコードをパッケージ化する
    ローカルのSwift
    パッケージをアプリでインポートする

    このトークでは、こちらの手法を扱う。

    View Slide

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

    View Slide

  16. Xcode
    プロジェクト内のソース
    App.swift
    import UIKit

    import AppFeature

    @main

    final class AppDelegate: AppFeature.AppDelegate {}

    final class SceneDelegate: AppFeature.SceneDelegate {}

    View Slide

  17. Swift
    パッケージ内のソース
    AppDelegate.swift
    import UIKit

    open class AppDelegate: UIResponder, UIApplicationDelegate {

    public final func application(_ application: UIApplication, ...) -> Bool {

    return true

    }

    }

    View Slide

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

    View Slide

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

    View Slide

  20. SwiftPM
    のプラグイン
    機能とは

    View Slide

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

    View Slide

  22. プラグイン機能の活用方法
    配布されているプラグインを使う
    配布されているものは、現時点では多くはない
    プラグインを自分で実装する
    独自の処理を行いたい場合はこの方法になる

    プラグインの実装方法はパンフレット記事を参照。

    View Slide

  23. ビルドツールプラグイン
    let package = Package(

    targets: [

    .target(

    name: "MyTarget",

    plugins: [

    .plugin(name: "MyPlugin"),

    ]

    ),

    .plugin(

    name: "MyPlugin",

    capability: .buildTool()

    ),

    ]

    )

    View Slide

  24. ビルドツールプラグインの処理内容
    以下の2
    つのタイミングで処理が実行される
    ビルド前(pre-build

    ビルド中(in-build

    プラグインであらかじめ定義された処理が実行される
    処理内容を自分で決めたい場合は、プラグインを自分で実装する

    View Slide

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

    View Slide

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

    View Slide

  27. Xcode

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

    View Slide

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

    View Slide

  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")

    ]

    ),

    ]

    )

    View Slide

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

    View Slide

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

    View Slide

  32. SwiftGen
    プラグインの利用
    (2)
    let package = Package(

    targets: [

    .plugin(

    name: "SwiftGenPlugin",

    capability: .buildTool(),

    dependencies: ["swiftgen"]),

    .binaryTarget(

    name: "swiftgen",

    url: "https://github.com/SwiftGen/SwiftGen/releases/...",

    checksum: "..."

    ),

    ]

    )

    View Slide

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

    View Slide

  34. 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: [:])]

    }

    }

    View Slide

  35. SwiftLint
    プラグインの利用
    let package = Package(

    targets: [

    .plugin(

    name: "SwiftLintXcode",

    capability: .buildTool(),

    dependencies: ["SwiftLintBinary"]

    ),

    .binaryTarget(

    name: "SwiftLintBinary",

    url: "https://github.com/realm/SwiftLint/releases/...",

    checksum: "..."

    ),

    ]

    )

    View Slide

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

    View Slide