はじめに
僕は本業ではWebアプリ開発を中心として、主にバックエンド側やインフラ(少し)をやっています。フロントエンド側はjs(Vue.js)やCSS(少し)にちょっと触ったことがありますが、ネイティブアプリの開発は全く経験がありませんでした。
最近、会社のサービスの共有認証システムという担当しているシステムはFacebookといったソーシャルログインを導入しようとした時に、Facebookの規約によると、ネイティブでFacebookの専用SDKを利用しなければならないので、ネイティブ側の実装が必要になります。また、共有のシステムで現在複数のサービスに提供していて、それぞれのサービスに対するネイティブアプリがあり、別々に実装したら、効率が悪くて、メンテナンスの面も大変だと思うので、共有のライブラリー(SDK)を作ることにしました。
iOSネイティブアプリの開発は全く経験がなかったけど、学びながらチャンレンジしてみました。(もちろん、ネイティブアプリの経験者の方にサポート、フローしていただきました。)
今回はその経験について書きたいと思います。
準備
使っていた環境
- macOS 10.15.7
- XCode 12.3
- Swift 5
- Cocoapods 1.9.3
知識
- Swift概要(基本的な知識)
ライブラリーを作成するのに、言語は一番重要ですね。
なので、まずSwift言語基本的な知識を勉強しましょう!
Swiftを勉強するには、Swiftの公式サイトを使いました。具体的はSwift TourとLanguage Guideより勉強しまた。
- iOSネイティブアプリの開発
iOSネイティブアプリ用のライブラリーを作るため、iOSネイティブアプリの開発についても身に付ける必要ですね。
ゼロからアップルストアに公開できるiOSアプリの開発まで学ぶ必要わけではないけど、iOSアプリの開発の基本知識を学ぶべきです。以下はApple公式のチュートリアルとudacityの無料コース(両方とも英語)はおすすめです。
pod開発
概要は以下のようです。
- Xcodeでプロジェクトを作成し、設定する
- podを実装する
- gitと連携する
- アプリに組み込む
Xcodeでプロジェクトを作成し、設定する
- 新しくプロジェクトを作成する
Xcodeを開いて、新しくプロジェクトを作成する。
CocoaPodsライブラリーを作りたいので、Frameworkを選択する。
MySwiftLib
プロダクト名を入力して、ユニットテストのため「Include Tests」チェックボックスをチェックする
- ライブラリーの使い方を紹介するためデモアプリを追加する
XcodeのメニューからFile > New > Target
、「App」というテンプレートを選択する
MySwiftLibExamples
というプロダクト名を入力して、デモアプリでユニットテストが要らないため、「Include Tests」チェックボックスを外します。
プロジェクトの構成は以下のようです。
podを実装する
podspecファイルを作成する
podspecファイルはバージョン、ソース箇所やメーター情報などは定義されるところです。
簡単なpodspecは以下のようです。
まず、プロジェクトのディレクトリに以下のコマンドでpodのspecを作成します。
$ pod spec create MySwiftLib
Pod::Spec.new do |spec|
# ――― Spec Metadata ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.name = "MySwiftLib"
spec.version = "0.0.1"
spec.summary = "My First CocoaPods Library written in Swift"
spec.homepage = "https://github/username/MySwiftLib"
# ――― Spec License ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.license = { :type => "MIT" }
# ――― Author Metadata ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.author = { "trandoantan" => "tan.tran@example.com" }
# ――― Platform Specifics ――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.platform = :ios
# ――― Source Location ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.source = { :git => "https://github/username/MySwiftLib.git", :tag => "#{spec.version}" }
# ――― Source Code ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
spec.source_files = ["MySwiftLib/**/*.swift", "MySwiftLib/MySwiftLib.h"]
# ――― Project Settings ――――――――――――――――――――――――――――――――――――――――――――――――――――――――― #
# spec.dependency "FacebookCore"
# spec.dependency "FacebookLogin"
end
-
Metadata
(必須): Pod名、バージョン、サマリー、ホームページ - ライセンス(必須): 非公開のPodなら、ライセンスのタイプの指定だけでいいです。
- 作者情報(必須)
-
platform
(任意): 利用可能のプラットフォーム -
source
(必須): gitのリポジトリを指定し、バージョンニングのためのタグを指定する(新しいバージョンをリリースした際に、gitのタグを使って指定する) -
source_files
(必須): ライブラリーに含むソースコードファイル。上記の例ではヘッダーファイルや全てSwiftのファイル -
dependency
: ライブラリー内に外部のパッケージを使いたい場合、これで指定する
ライブラリーの実装
MySwiftLib
に新しくSwiftファイルを追加する。
enum Language: String {
case japanese = "ja"
case english = "en"
var greetingTemplate: String {
switch self {
case .japanese:
return "こんにちは、%@!"
case .english:
return "Hello, %@!"
}
}
}
public class MySwiftLib {
var defaultLang: Language
public init(lang: String) {
if let language = Language.init(rawValue: lang) {
defaultLang = language
} else {
defaultLang = .english
}
}
public func greetingMessage(userName: String) -> String {
return String(format: defaultLang.greetingTemplate, userName)
}
}
サンプルなので、とても簡単ですね。
ユニットテストを書く
次、上記のMySwiftLib
に対するユニットテストを書きましょう。
-
MySwiftLibTests
にあるMySwiftLibTest.swift
ファイルを以下のように編集します。
import XCTest
@testable import MySwiftLib
class MySwiftLibTests: XCTestCase {
func testGreetingMessageEnglish() {
let mySwiftLib = MySwiftLib(lang: "en")
XCTAssertEqual(mySwiftLib.greetingMessage(userName: "John"), "Hello, John!")
}
func testGreetingMessageJapanese() {
let mySwiftLib = MySwiftLib(lang: "ja")
XCTAssertEqual(mySwiftLib.greetingMessage(userName: "Alice"), "こんにちは、Alice!")
}
func testGreetingMessageDefaultEnglish() {
let mySwiftLib = MySwiftLib(lang: "hogehoge")
XCTAssertEqual(mySwiftLib.greetingMessage(userName: "John"), "Hello, John!")
}
}
- ユニットテストを実行する
Examples実装
次、デモのため、MySwiftLibExamples
を実装します。
-
Main.storyboard
にLabelを追加して、ViewController
は以下のように編集します。
import UIKit
import MySwiftLib
class ViewController: UIViewController {
//MARK: Properties
@IBOutlet weak var greeting: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let mySwiftLib = MySwiftLib(lang: "ja")
self.greeting.text = mySwiftLib.greetingMessage(userName: "Tan")
}
}
-
MySwiftLibExamples
をビルドしてみたら、以下のようです。
gitと連携する
- githubとかで
MySwiftLib
リポジトリを作成する - プロジェクトのディレクトリーにgitを初期化して、作成したリポジトリにコードをプッシュする
$ cd /your/project/path
$ git remote add origin git@github.com:username/repo-name.git
$ git add .
$ git commit -m "initial commit"
$ git push origin master
- (必要であれば)作成したリポジトリによって
podspec
を更新する
spec.homepage = "https://github.com/username/repo-name"
spec.source = { :git => "https://github.com/username/repo-name.git", :tag => "#{spec.version}" }
- タグを付けて、最新のコードをプッシュする
$ git tag 0.0.1
$ git push origin --tags master
こちらは個人使用のpodなので、podを公開しない。
podを公開したい方はここに参考してみてください。
アプリに導入
- podをアプリに導入するには、
Podfile
に以下のコードを追加する
# for https: pod 'MySwiftLib', :git => 'https://github.com/username/repo-name.git'
pod 'MySwiftLib', :git => 'git@github.com:username/repo-name.git'
こちらのpodは公開しないので、gitでpodを指定する
開発中に、git
を使ったら、毎回install/updateコマンドで更新を反映させるのは不便なので、podを導入先のアプリの同じディレクトリーに置けば、以下のような設定でパスでpodを指定できて、更に更新をすぐ反映されます。
# for https: pod 'MySwiftLib', :git => 'https://github.com/username/repo-name.git'
# pod 'MySwiftLib', :git => 'git@github.com:username/repo-name.git'
pod 'MySwiftLib', :path => '../MySwiftLib'
- 以下のコマンドを実行して、アプリにpodをインストールする
$ pod install
# 更新の場合
$ pod update MySwiftLib
インストールした後に、MySwiftLibExamples
のように、モジュールをimport
したら、使えます。
終わり
今回はCocoapodを使って、簡単なpodのライブラリーを作成する方法を紹介しましたが、iOSアプリの開発にまだ初心者ですので、こちらの記事に何か間違いがありましたら、ご指摘いただければ幸いです。
ご拝読いただきありがとうございます!