作りながら学ぶ！SwiftPackageManagerでOSSを公開しよう！

# はじめに

この記事は [iOS Advent Calendar 2020](https://qiita.com/advent-calendar/2020/ios) の 24 日目の記事です。
昨日は[アイカワ](https://qiita.com/kalupas226)さんの[「Numbers API を利用した実践的なアプリで学ぶ SwiftUI(UIKit) + TCA」](https://qiita.com/kalupas226/items/fb67003d43df8ad057f7)でした。

今年初めて自分でライブラリを作ってOSSとして公開しました！
SwiftUIでニューモフィズムというデザインを表現できるライブラリです。
ありがたいことに、現在スターが120以上いただいております。
https://github.com/tsuzukihashi/NeumorphismUI

こちらはSwiftPackageManager(SPM)というライブラリの管理ツールに対応しています。
SwiftPackageManager(SPM)は他のライブラリ管理ツールに比べ、とても簡単に利用することができるのとappleの公式のものなので安心して使うことができます。
しかし、それでもいくつか注意しなくてはいけないポイントがいくつかあったので初心者の自分が釈迦に説法かと思いますが、実際にライブラリを公開しながら解説していきたいと思います。

環境: macOS Big Sur 11.0.1 (Apple M1)
Xcode: 12.2

ちなみに最終的な成果物はこちら
https://github.com/tsuzukihashi/IndicatorKun

# 題材
以前私が書いた記事でSwiftUIでオリジナルのインジケーターを作りました。
https://qiita.com/tsuzuki817/items/2273294c1a7d75024422
ですのでそれをいつでも利用できるようにSwiftPackageManagerを使ってOSSとして公開してみようかと思います。

今回OSSにするインジケータ
![Simulator Screen Shot - iPod touch (7th generation) - 2020-12-22 at 23.37.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/787c5487-6c6b-d367-eacc-bf658c8de02b.png)

# try
Xcodeから新規プロジェクトを作ります。
`Multiplatform`に`Swift Package`がありますのでそれを選択します。
![スクリーンショット 2020-12-22 20.34.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/0442da6e-7680-5734-9e71-fbfb53a141f8.png)

好きな名前をつけたら、プロジェクトが開くことを確認します。
![スクリーンショット 2020-12-22 20.41.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/31449c5c-fb08-4da9-aac4-064af7e17496.png)

基本的にこの`Sources`の中にコードを書いていきます。

![スクリーンショット 2020-12-23 0.12.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/20ad7a3f-e32e-aa24-31cd-2d010f96ed38.png)

`IndicatorKun.swift`にコードを書きました！

```swift
import SwiftUI

@available(iOS 13.0, *)
@available(tvOS 13.0, *)
@available(watchOS 6.0, *)
@available(OSX 10.15, *)
public struct IndicatorKun: View {
    @State var isAnimation = false
    let title: String
    let backgroundColor: Color
    let backSize: CGSize
    let circleColors: [Color]
    let circleSize: CGSize
    let font: Font
    
    public init(
        title: String = "読み込み中",
        backgroundColor: Color = .gray,
        backSize: CGSize = .init(width: 200, height: 120),
        circleColors: [Color] = [.gray, .white],
        circleSize: CGSize = .init(width: 48, height: 48),
        font: Font = .system(size: 12, weight: .medium, design: .rounded)
    ) {
        self.title = title
        self.backgroundColor = backgroundColor
        self.backSize = backSize
        self.circleColors = circleColors
        self.circleSize = circleSize
        self.font = font
    }
    
    public var body: some View {
        ZStack {
            RoundedRectangle(cornerRadius: 8)
                .frame(width: backSize.width, height: backSize.height, alignment: .center)
                .foregroundColor(backgroundColor)
            
            VStack {
                Spacer()
                Circle()
                    .trim(from: 0, to: 0.6)
                    .stroke(
                        AngularGradient(gradient: Gradient(colors: circleColors), center: .center),
                        style: StrokeStyle(
                            lineWidth: 8,
                            lineCap: .round,
                            dash: [0.1, 16],
                            dashPhase: 8
                        )
                    )
                    .frame(width: circleSize.width, height: circleSize.height)
                    .rotationEffect(Angle(degrees: self.isAnimation ? 360 : 0))
                    .onAppear() {
                        withAnimation(
                            Animation
                                .linear(duration: 1)
                                .repeatForever(autoreverses: false)) {
                            self.isAnimation.toggle()
                        }
                    }
                
                Text(title)
                    .foregroundColor(.white)
                    .font(font)
                    .lineLimit(1)
                    .padding(.top)
                Spacer()
            }
        }
    }
}
```

軽く説明をします。

```swift
@available(iOS 13.0, *)
@available(tvOS 13.0, *)
@available(watchOS 6.0, *)
@available(OSX 10.15, *)
```

こちらは、SwiftPackageManagerはマルチプラットフォームに対応していますのでSwiftUIが使えるOSのバージョンまで上げておく必要があります。

また、`sturct`や`init`に`public`を付けてあげます。
`public`をつけなかったり、`init`がない場合以下のようなエラーが表示されますので注意しましょう。

![スクリーンショット 2020-12-23 23.35.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/13e9b2c9-a9df-a511-be80-2869e61f4e8b.png)

![スクリーンショット 2020-12-23 23.36.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/cd9656ad-0637-51f3-1aae-338bcf58fc29.png)

また、外からタイトルやフォントを指定できるようにしてあります。

ここで一旦githubにpushしておきます。
この時リポジトリはpublicにしておく必要があります。

![スクリーンショット 2020-12-22 21.13.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/72364a40-fff4-bc2e-3a4e-cda97ccb92cf.png)

また、忘れないうちにライセンスを定義しておきましょう！
これにより、他の人が自由に改変することができるようになります。

`Add file` -> `Create new file` から新しくファイルを作ります。
![スクリーンショット 2020-12-22 22.37.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/15a137e4-de40-806b-a3b7-b81a13978811.png)

`LICENSE`と入力すると、テンプレートを選ぶことができます。
![スクリーンショット 2020-12-24 0.19.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/678bfd96-8009-ce81-3f88-6233b76aa4f1.png)

MITライセンスを選択しました！
![スクリーンショット 2020-12-22 22.37.21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/c5dee156-5d3e-6469-53cd-9824c30d4fc4.png)

次に`tags`より新しいリリースを作ります。

![スクリーンショット 2020-12-22 21.13.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/84606688-55f4-a208-4ea0-b1201079ae78.png)

この時、バージョンを0.1や1.0などで作ってしまうと、SwiftPackageManagerでは読み込むことができず、以下のようなエラーが出てしまうので気をつけましょう！
バージョン指定は0.0.1や1.0.0で作る必要があります。

![スクリーンショット 2020-12-22 21.18.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/485d8e4c-28d8-40dd-ba2c-1fdac16381fc.png)

試しにバージョンを0.0.1にしてリリースすると、無事サンプルアプリから見ることができました！

![スクリーンショット 2020-12-22 21.19.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/3066ea10-9f79-7ea8-cbb7-89052ec93d1f.png)

サンプルアプリで`import IndicatorKun`をして試してみます。

```swift
import SwiftUI
import IndicatorKun

struct ContentView: View {
    var body: some View {
        IndicatorKun(title: "ぐるぐる...")
    }
}
```

無事インジケータが表示されることが確認できました！

![Simulator Screen Shot - iPod touch (7th generation) - 2020-12-24 at 00.03.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171702/3acc73ef-263a-b27b-6c52-75339737fe0a.png)


# おわりに
最後まで見てくださりありがとうございました。
以上のようにSwiftPackageManagerを使うことで非常に簡単にライブラリを公開することができました。
ぜひ皆さんも便利なライブラリを作って公開してみてください！