はじめに
iOS,macOS両対応のSwiftライブラリを作りたいと思い立ったのですが,それってどうやって作れば良いのだろう。
今回はRxSwiftに依存したものを作りたかったので,RxBluetoothKitを紐解きつつ作成手順を記します。
結構長いので覚悟してついてきて下さい。
環境
- macOS High Sierra 10.13.6
- Xcode 9.4.1
本記事完了時点でのディレクトリ
2018/08/23現在のRxBluetoothKit masterの様子 -> 69c1d18
主要ディレクトリおよびファイルを抜粋したものです。ここまでを目指します。
ExampleApp/
├ ExampleApp.xcodeproj/
├ ExampleApp.xcworkspace/
├ ExampleApp/
└ Podfile
RxBluetoothKit.xcodeproj/
Source/
Tests/
└ Info.plist
docs/
└ index.html
scripts/
└ all-tests.sh
.gitignore
.jazzy.yaml
.swift-version
.swiftlint.yml
.travis.yml
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
RxBluetoothKit.podspec
ディレクトリの作成
最初にgitから作成します。今回は中~大規模を想定していますので,Git-flowを利用することにします。
$ mkdir <foo>
$ cd <foo>
$ git init
$ git flow init
ここまでのディレクトリ構成
以降は.git
は省略します。
.git
参考
ソースファイルの作成
Swift Package Managerを利用してプロジェクトを作成します。今回はライブラリ形式で作成するので,--type library
のオプションを付けています。
$ swift package init --type library
ここまでのディレクトリ構成
Source/
└ <foo>/
└ test.swift
Tests/
├ <foo>Tests/
│ ├ <foo>Tests.swift
│ └ XCTestManifests.swift
└ LinuxMain.swift
.gitignore
Package.swift
README.md
一気にそれっぽくなってきました。
この辺りで.gitignore
やREADME.md
の整理をすると良いでしょう。LICENSE
の追加をしても良いです。
LinuxMain.swift
XCTestManifests.swift
は不要なので削除します。
参考
xcodeproj の作成
$ swift build
$ swift package generate-xcodeproj
ここでようやくXcodeから開くことができるようになります。
Xcodeで開くとSources
とTests
が参照無しのGroup(Group without Folder)となっているのでここで直しておきましょう。
ここまでのディレクトリ構成
<foo>.xcodeproj/
Source/
└ <foo>/
└ test.swift
Tests/
└ <foo>Tests/
└ <foo>Tests.swift
.build/
.gitignore
LICENSE
Package.swift
README.md
参考
参考
TARGETの作成
Xcodeでの作業です。自動生成されたTARGETを削除し,必要なものを作成します。
今回はiOS (Cocoa Touch Framework) とmacOS (Cocoa Framework) を用意しました。
ここでいくつかのファイルが自動生成されます。
OS毎に共通したInfo.plist
があれば良いので,Framework用とTest用で1つずつ用意します。テストファイルも共通化しましょう。それ以外のファイルは削除します。
Info.plistの移動
- Framework用のInfo.plistの移動
Framework用のInfo.plistはSource以下に配置し,
一旦Remove Reference
で参照を破棄します。
その後Xcode上のプロジェクト直下でNew Group without Folder
としてSupporting Files
を作成し,Info.plistを参照します。
この時TARGETSのBuild Phases / Copy Bundle Resources
にInfo.plistが存在すると正常にビルドできないため削除します。
ここで間違っている場合はTARGETSのIdentifyにChoose Info.plist File...
が表示されています。選択して直してあげましょう。
- Test用のInfo.plistの移動
こちらはそのままTests以下にTest用のInfo.plistを配置します。
しかし,テストの方はTARGETSのBuild Settings / Packaging / Info.plist File
をマニュアルで変更する必要があります。
ここまでのディレクトリ構成
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
.build/
.gitignore
LICENSE
Package.swift
README.md
Schemeの設定
XcodeのTARGETSを変更したのでSchemeが崩れています。調整しましょう。
Manage Schemes...
から不要なSchemeを削除し,残ったもののShared
にチェックを付けましょう。後にTravis CIで参照する際に必要となります。
TARGET Deviceの調整
ターゲットのデバイスも調整しましょう。現在はCocoa Touch Framework
で作成してもSchemeには反映されていません。
変更したいTARGETのBuild Settings / Architectures / Supported Platforms
を変更する必要があります。
Test実行
ここでビルドおよびテストを実行してみましょう。ビルドは通りますが,テストは通らないと思います。
原因はテスト共通化のために追加したTARGET名が@testable import
と異なることで発生しています。修正しましょう。
FrameworkのTARGETのBuild Settings / Packaging / Product Name
を共通する名前に変更しましょう(TestのProduct Nameの変更は不要です)。
テストが通るかと思います。
参考
依存ライブラリの組み込み
Carthageを利用します。Homebrewは以後も利用しますので,利用していない方は【Swift】Carthage導入手順等を元に導入しましょう。
$ brew install carthage
$ touch Cartfile
Vim等で編集します。今回はRxSwiftに依存させます。
github "ReactiveX/RxSwift" ~> 4.0
インストールします。
$ carthage update
New Group without Folder
を選択し,Frameworks
という名で作成します。
Framework用にProject直下に1つ,Test用にTests/
以下に1つ用意しましょう。
RxSwiftは各OS毎にBuild fileが分かれています。Frameworks
以下にiOS
macOS
というGroup without Folderを作成しましょう。
RxSwiftではRxTest
RxBlocking
がテスト用ですので必要に応じて取り込みます。
適切に設定できた場合は以下のようにBuild Phases / Link Binary With Libraries
に必要な分のみ参照されていると思います。
ここまでのディレクトリ構成
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
Carthage/
.build/
.gitignore
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
参考
サンプルアプリの作成
iOSサンプルを作成します。File / New / Project...
からExampleApp
という名のiOSプロジェクトを作成します。作成する場所はライブラリ直下 (.xcodeprojのある場所) です。
ここまでのディレクトリ構成
ExampleApp/
├ ExampleApp.xcodeproj/
└ ExampleApp/
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
Carthage/
.build/
.gitignore
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
CocoaPodsの準備
$ pod spec create <foo>
設定等は自前のライブラリをCocoaPodsで管理するメモなどを参考に,登録方法は左記ではなくSwiftでライブラリを公開するを参考に。
サンプルアプリはCocoaPods登録後は通常のアプリ開発と同様です。
ここまでのディレクトリ構成
ExampleApp/
├ ExampleApp.xcodeproj/
├ ExampleApp.xcworkspace/
├ ExampleApp/
└ Podfile
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
Carthage/
.build/
.gitignore
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
<foo>.podspec
参考
- 自前のライブラリをCocoaPodsで管理するメモ ( push方法は古いため注意)
- Swiftでライブラリを公開する
Swiftのバージョンを指定する
今回は4.0以上に設定します。.swift-version
を指定します。
$ echo 4.0 > .swift-version
ドキュメントの作成
Jazzyを利用します。Swiftソース上のドキュメントコメントからドキュメントを生成してくれるすごいやつです。
$ [sudo] gem install jazzy
$ touch .jazzy.yml
設定は[iOS][Swift] 「Jazzy」を使ってSwiftのソースファイルからドキュメントを生成する等を参考に。設定が完了したら以下のコマンドで生成できます。
$ jazzy -o docs
ここまでのディレクトリ構成
ExampleApp/
├ ExampleApp.xcodeproj/
├ ExampleApp.xcworkspace/
├ ExampleApp/
└ Podfile
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
docs/
└ index.html
Carthage/
.build/
.jazzy.yml
.swift-version
.gitignore
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
<foo>.podspec
参考
Linterの設定
realm/SwiftLint - GitHubを利用します。
.swiftlint.yml
を作成し,編集します。
日本語だとSwiftLintのRules全まとめ等を参考にしましょう。
$ brew install swiftlint
$ touch .swiftlint.yml
Xcode側ではrealm/SwiftLint - GitHubの説明の通りに
TARGETのBuild Phases
左上のボタンより,New Run Script
を選択して以下を入力して下さい。
if which swiftlint >/dev/null; then
swiftlint
else
echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi
ここまでのディレクトリ構成
ExampleApp/
├ ExampleApp.xcodeproj/
├ ExampleApp.xcworkspace/
├ ExampleApp/
└ Podfile
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
docs/
└ index.html
Carthage/
.build/
.jazzy.yml
.swift-version
.swiftlint.yml
.gitignore
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
<foo>.podspec
参考
CIの導入
Travis CIを利用します。OSSの範囲であれば無料で使えます。
GitHub連携後,.travis.yml
を作成します。設定はBuilding an Objective-C or Swift Projectを参考に。
$ touch .travis.yml
RxBluetoothKitではscriptにテストを書いているので参考に作成します。
$ mkdir scripts
$ touch ./scripts/all-tests.sh
ここまでのディレクトリ構成
ExampleApp/
├ ExampleApp.xcodeproj/
├ ExampleApp.xcworkspace/
├ ExampleApp/
└ Podfile
<foo>.xcodeproj/
Source/
├ <foo>/
│ └ <foo>.swift
└ Info.plist
Tests/
├ <foo>Tests/
│ └ <foo>Tests.swift
└ Info.plist
docs/
└ index.html
Carthage/
.build/
.jazzy.yml
.swift-version
.swiftlint.yml
.gitignore
.travis.yml
Cartfile
Cartfile.private
Cartfile.resolved
LICENSE
Package.swift
README.md
<foo>.podspec
参考
まとめ
ここでようやく終了です!お疲れさまでした!
でもここは終わりではなく始まりに過ぎません。
それでは皆様,良いOSSライフをお過ごし下さい!