1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Kotlin Multiplatform で作ったライブラリを Swift Package Manager 向けに配布する

Last updated at Posted at 2024-09-30

経緯

Kotlin Multiplatform で iOS / Android 両方から使える小さなライブラリを作成しました。Google Analytics for Firebase でイベントを送るにあたり、iOS / Android でイベントが違うことを防ぐために、Kotlin というワンソースでイベントをクラスとして定義して、iOS / Android アプリから使うことを意図しています。
Google Analytics for Firebase の基礎知識やこのライブラリで解決したい課題については、こちらの DroidKaigi 2024 登壇資料をご参照ください。

今回紹介するライブラリや GitHub Actions のワークフローは、こちらのリポジトリです。

Gradle プロジェクトおよびライブラリを作成

Android Studio Koala に Kotlin Multiplatform プラグインをインストールしました。Kotlin Multiplatform プロジェクトは New Project → Kotlin Multiplatform Library から作ります。

スクリーンショット 2024-09-29 12.32.48.png

ライブラリの名前を Shared Module Name に設定します。
iOS framework distribution は XCFramework にします。

スクリーンショット 2024-09-29 13.54.37.png

そうするとモジュールの build.gradle には XCFramework を作るための設定が記載されます。

build.gradle.kts
kotlin {
    // 略 
    val xcf = XCFramework()
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach {
        it.binaries.framework {
            baseName = "ga913kmp"
            xcf.add(this)
            isStatic = true
        }
    }    
    // 略
}

ライブラリのソースコードは ga913kmp/src/commonMain/kotlin に作ります。

スクリーンショット 2024-09-29 12.46.17.png

jvmMain jvmTest はローカル PC で動作するバリデーションとその単体テストで、記事の主題とは無関係です)

Swift Package Manager の使い方

次は Xcode で GitHub から Swift Package Manager 向けに配布されているライブラリを使用する方法を紹介します。Xcode は 16.0 を使っています。

ライブラリを使いたいプロジェクトを開いた状態で上部メニューの File → Add Package Dependency を選択します。
右上のテキスト検索欄にライブラリの GitHub ページの URL - 例えば https://github.com/tfandkusu/ga913-kmp を入力するとライブラリの情報が表示されます。ライブラリバージョンも指定できます。次に Add Package ボタンを押します。

スクリーンショット 2024-09-29 20.56.18.png

最後に Target を選んで Add Package ボタンを押すと、ライブラリを選ばれた Target で使えるようになります。

スクリーンショット 2024-09-30 1.37.38.png

Swift Package Manager から使えるようにライブラリを配布する

前述の方法で使用できるように、GitHub Actions を使いライブラリを自動配布します。
配布のためのワークフローはこちらになります。

VERSION ファイル0.1.2 等のようにバージョンを書き込み、release ブランチに PUSH すると、ソースコードがビルドされ、ライブラリが配布されます。

ワークフローの内容を解説します。

まず Gradle タスクで XCFramework を作成します。

./gradlew assembleXCFramework

今回のモジュール名は ga913kmp なので ga913kmp/build/XCFrameworks/release/ ディレクトリに作成されます。シミュレータ用と実機用のバイナリが生成されたことを確認できます。

cd ga913kmp/build/XCFrameworks/release/ga913kmp.xcframework/
find . -type f
./ios-arm64_x86_64-simulator/ga913kmp.framework/ga913kmp
./ios-arm64_x86_64-simulator/ga913kmp.framework/Headers/ga913kmp.h
./ios-arm64_x86_64-simulator/ga913kmp.framework/Modules/module.modulemap
./ios-arm64_x86_64-simulator/ga913kmp.framework/Info.plist
./ios-arm64/ga913kmp.framework/ga913kmp
./ios-arm64/ga913kmp.framework/Headers/ga913kmp.h
./ios-arm64/ga913kmp.framework/Modules/module.modulemap
./ios-arm64/ga913kmp.framework/Info.plist
./Info.plist

次に生成された XCFramework を ZIP で固めます。

zip -r ga913kmp.xcframework.zip ga913kmp.xcframework

Swift Package Manager は Package.swift を読みに行くので Package.swift ファイルを作ります。最終的にはこちらのファイルが作られます。

// swift-tools-version:5.5
import PackageDescription

let package = Package(
    name: "ga913kmp",
    products: [
        .library(
            name: "ga913kmp",
            targets: ["ga913kmp"]
        ),
    ],
    dependencies: [],
    targets: [
        .binaryTarget(
            name: "ga913kmp",
            url: "https://github.com/tfandkusu/ga913-kmp/releases/download/0.1.0/ga913kmp.xcframework.zip",
            checksum: "54b04d1cad6dce83e100a387e8d54962cdbae7d34e4edb5b3790be84492b81c9"
        ),
    ]
)

url フィールドに ZIP で固めた XCFramework のダウンロードパスがあり、そのチェックサムが checksum フィールドに設定されます。urlchecksum はバージョンごとに異なるので、新バージョンの配布ごとに作成する必要があります。

urlGitHub Release の Asset の URL です。

checksum はこちらのコマンドで作ります。

swift package compute-checksum ga913kmp/build/XCFrameworks/release/ga913kmp.xcframework.zip

Package.swift ファイルは ejs テンプレートから作るようにしました。

Package.swift.ejs
// swift-tools-version:5.5
import PackageDescription

let package = Package(
    name: "ga913kmp",
    products: [
        .library(
            name: "ga913kmp",
            targets: ["ga913kmp"]
        ),
    ],
    dependencies: [],
    targets: [
        .binaryTarget(
            name: "ga913kmp",
            url: "https://github.com/tfandkusu/ga913-kmp/releases/download/<%= version %>/ga913kmp.xcframework.zip",
            checksum: "<%= checksum %>"
        ),
    ]
)
VERSION=$(cat VERSION)
CHECKSUM=$(swift package compute-checksum ga913kmp/build/XCFrameworks/release/ga913kmp.xcframework.zip)
npx ejs Package.swift.ejs -i '{"version": "'$VERSION'", "checksum": "'$CHECKSUM'"}' -o Package.swift

Package.swift ファイルを追加するコミットを作ります。
[skip ci] をコミットメッセージに含めると、それについては GitHub Actions が動きません。

git config user.name "github-actions"
git config user.email "github-actions@github.com"
git add Package.swift
git commit -m "[skip ci]Package.swift を更新"
git push origin HEAD

VERSION ファイルの内容をタグ名として PUSH し、リリースを作ります。

echo version=`cat VERSION` >> $GITHUB_ENV
# ${{ env.version }} に VERSION ファイルの内容が設定されている
git tag -a ${{ env.version }} -m "${{ env.version }}"
git push origin ${{ env.version }}
gh release create ${{ env.version }} -t ${{ env.version }} ga913kmp/build/XCFrameworks/release/ga913kmp.xcframework.zip

これで完了です。GitHub にはリリースが作られ、Swift Package Manager から使うことができます。

スクリーンショット 2024-09-30 2.39.52.png

参考資料

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?