SwiftUI

SwiftUI製の自作ライブラリを作る

今回はSwiftUIで作った自作のUIを外部からアクセスできるようにライブラリ化する方法について書きます。
SwiftUI用のライブラリを作成するためiOS 13 以上を想定しています。

手順

  1. Swift Package Manager を利用するのでPackage.swift を作る。
  2. アクセス修飾子に気をつける
  3. サポートOSに注意する
  4. タグ付けする
  5. 新しいSwiftUIのプロジェクトファイルを作成してSwiftPMでインポート

1. Swift Package Manager を利用するのでPackage.swift を作る。

まず始めにXcodeで自作ライブラリをつくる用のプロジェクトファイルを作成します。

Xcodeを開いて File < New < Swift Package を選択します。

新しいプロジェクトファイル名を今回はSampleViewと名付けて、「Create」を選択します。

最初は下のような感じのディレクトリ構成になっています。

  • Package.swift (依存関係や環境を記載する所)
  • Sources < SampleView < SampleView.swift (実際のライブラリのクラスファイル)

とりあえず、Sources < SampleView < SampleView.swift のSampleView.swift を開きます。

初期のコードはこちらです。

import SwiftUI

public struct SampleView {
    var text = "Hello, World!"
}

次以降でこのクラスを編集していきます。

2. アクセス修飾子に気をつける

このページを参考にして、Swiftの5つのアクセス修飾子を大まかに理解します。

アクセス修飾子 説明
open 別モジュールから呼び出せる。継承やオーバーライドが可能
public 別モジュールから呼び出せる。継承やオーバーライドが可能
internal 同モジュール内からのみ呼び出せる
fileprivate 同ファイル内からのみ呼び出せる
private 同スコープ内からのみ呼び出せる

注意することは、このアクセス修飾子を省略した場合はデフォルトとしてinternalが適用されます。
つまり、クラスや関数の定義でアクセス修飾子を省略してしまうと、ライブラリのユーザーはその省略されたクラスや関数を使えなくなります。
慣れないうちはopenpublicを多用すると思います。

試しにSampleView.swiftに次のコードを書いてみます。

SampleView.swift

import SwiftUI

public struct SampleView {
    var text = "Hello, World!"
}

struct SampleListView: View {
   var body: some View {
        List {
           // 一行目
           Text("item1")
           // 二行目
           Text("item2")
           // 三行目
           Text("item3")
        }
    }
}

外部からこのクラスを使用する場合SampleViewはアクセスできますが、SampleListViewにはpublicがついていないのでアクセスできません。

この場合は次のように修正します。

SampleView.swift

import SwiftUI

public struct SampleView {
    var text = "Hello, World!"
}

public struct SampleListView: View {
    public init() {
        
    }
    public var body: some View {
        List {
           // 一行目
           Text("item1")
           // 二行目
           Text("item2")
           // 三行目
           Text("item3")
        }
    }
}

3. サポートOSに注意する

自作ライブラリを作る上でよくわからないのがサポートOSの指定についてです。

Package.swiftにもバージョン指定できますし、クラスに@available(iOS 13.0, *)を記載するやり方もありますので的確なやり方がわかりませんでした。

これは

とSwiftの公式リファレンス

を見るとだいたい分かるようになりました。

今回はPackage.swiftSampleView.swiftそれぞれに記載します。

Package.swift

import PackageDescription

let package = Package(
    name: "SampleView",
    platforms: [
        .iOS(.v13)
        ],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "SampleView",
            targets: ["SampleView"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        // .package(url: /* package url */, from: "1.0.0"),
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "SampleView",
            dependencies: []),
        .testTarget(
            name: "SampleViewTests",
            dependencies: ["SampleView"]),
    ]
)

SampleView.swift

import SwiftUI

@available(iOS 13.0, *)
public struct SampleView {
    var text = "Hello, World!"
}

@available(iOS 13.0, *)
public struct SampleListView: View {
    public init() {
        
    }
    public var body: some View {
        List {
           // 一行目
           Text("item1")
           // 二行目
           Text("item2")
           // 三行目
           Text("item3")
        }
    }
}

 

このようにしました。

4. タグ付けする

これでSampleViewプロジェクト用にGithubでリポジトリを作成します。
commitとpushまで完了したら、タグ付けを行います。

タグはx.x.xの形でないといけないかもしれません。

今回は1.0.0のようにタグ付けします。

5. 新しいSwiftUIのプロジェクトファイルを作成してSwiftPMでインポートします

タグ付けが完了したら、新しいSwiftUIのプロジェクトファイルを作成します。今回はSampleLibという名前でプロジェクトを作成しました。
そこに今回作成した自作ライブラリをSwiftPMを使ってインストールします。

無事インストール、ContentView.swiftに試しに次のコードを書いてみます。

ContentView.swift

import SwiftUI
import SampleView

struct ContentView: View {
    var body: some View {
        ListView()
    }
}

struct ListView: View {
    var body: some View {
        SampleListView()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

着目すべきは

import SampleView

でサンプルで作ったSampleViewライブラリがインポートできるようになっています。

そして、

struct ListView: View {
    var body: some View {
        SampleListView()
    }
}

ということでViewを継承したListViewを作成してbodyにSampleListViewを宣言しました。

エラーが発生しないことを確認したらビルドすると画面が表示されます。

これで自作ライブラリのとあるモジュールを外部から呼び出せるようになりました。

参考文献

ABOUT ME
tamappe
都内で働くiOSアプリエンジニアのTamappeです。 当ブログではモバイルアプリの開発手法について紹介しています。メインはiOS、サブでFlutter, Android も対応できます。 執筆・講演のご相談は tamapppe@gmail.com までお問い合わせください。