- 投稿日:2020-08-09T23:23:18+09:00
【入門】iOS アプリ開発 #1
はじめに
新型コロナウィルス(COVID-19)の影響により、外出自粛が続いている。
どこへも出かけない夏休み、この機会に Mac を購入して iOS のプログラミングを勉強してみようと思う。
iPhone のアプリは Swift という言語で作られるようだ。アップルは Swift を「モダン、安全、高速、インタラクティブ」を特徴として謳っている。
これだけでは全くイメージつかないが、さぞかし簡単にアプリが開発できるに違いない。昔のゲームぐらいならば、さくっと作れて、軽快にサクサク動作するのであろう。
さらにタッチパネルやセンサーで操作できると面白そうだ。プログラミングすることよりも、何を作るか?どんな仕様するか?、企画や上流設計は悩みどころだ。
またキャラクターのデザインやサウンドなどを作るのも骨が折れる。色々調べてみるとパックマンの仕様書が公開されている。
これをもとに作ればプログラミングに専念できそうだ。パックマンのゲーム仕様書
下記の人工知能学会誌に仕様書が公開されている。
一度、何かを作ってしまえばノウハウが溜まり、自分が作りたいものが簡単にできるはずなので、
まずはパックマンを作ってみようと思う。仕様書をよく読むと、思ったよりも複雑な仕様になっているが、
高級言語 Swift で書けば、1万行もコーディングせずに出来るのではないか。
- 投稿日:2020-08-09T19:48:40+09:00
Flutter の iOS 向けビルドでハマったメモ
Flutter の iOS 向けビルド備忘録
とりあえず解決したことを列挙するだけの備忘録
Undefined symbols for architecture arm64
Create Bridging Header
で解決した
- Why linker link static libraries with errors? iOS
- Error when 'flutter run': Undefined symbols for architecture arm64: #41900
- Flutter Pluginの利用でSwiftエラーが出る場合の対処方法
domain/default pair of ... does not exist
プロジェクトのルートにアセットを置いているとビルドできない模様。
hoge を assets/hoge に移動して。pubspec.yaml の該当箇所も直せばOK。
- 投稿日:2020-08-09T19:02:08+09:00
[SwiftUI]EnvironmentObjectの罠
EnvironmentObject
を使っていたところ、以下のようなエラーに遭遇しました。Fatal error: No ObservableObject of type **** found. A View.environmentObject(_:) for * may be missing as an ancestor of this view.これは、直前に
} .sheet(isPresented: $isPresented) { ModalView(showingModal: self.$isPresented) }という操作を行っていました。ModalViewの中では呼び出し元と同じ
EnvironmentObject
を宣言していました。原因
こちらを参考にしました。
https://stackoverflow.com/questions/58743004/swiftui-environmentobject-error-may-be-missing-as-an-ancestor-of-this-view
https://github.com/peterfriese/Swift-EnvironmentObject-Demoこの記事によると、
sheet
によるモーダル表示は、rootとなるContentView
とは全く別のツリー構造となっているようでした。
- ContentView
- SubView
- SubView
- ChildView
- ModalView
というような感じです。
解決策
ここの
ModalView
でも同じEnvironmentObjectを使うためには、以下のようにして渡します。} .sheet(isPresented: $isPresented) { ModalView(showingModal: self.$isPresented) .environmentObject(someObject) }
- 投稿日:2020-08-09T17:04:23+09:00
不要になったUserDefaultsキーの管理方法
UserDefaultsについて
「ある画面を表示したかどうか」などの情報をアプリに保存する場合、UserDefaultsを利用する機会が多いと思います。
UserDefaultsを利用して値を保存することに目を向けがちですが、アプリ開発では機能追加だけでなく、利用しなくなった機能を削除することももちろんあります。
その際に機能を削除する際に不要となるUserDefaultsのキーを適切に扱わなければ、同一のキーを利用して意図しない動作につながってしまうケースがありますこの記事では既存の不要となったキーの管理方法についてまとめ、新しい管理方法についてまとめたものとなります。
既存の管理方法
1. キーごと削除する
不要となったキーを削除するパターンです。もし別の機能開発で全く同じキー名が利用されるケースがあった場合、未然に防ぐことができなくなるためあまりおすすめはできません。
2. prefix / suffix
利用していないキー名にprefixやsuffixを加えることで管理するパターンです。
利用されていないキーが明示的にはなりますが、キー名が増えてくると行数が増え見通しが悪くなります。
また、Active Compilation Conditions
を利用して、Release
ビルドでは含めないなどを設定しないとdeprecatedなキーが成果物に含まれてしまいます。static let isHoge = "isHoge" // deprecated keys static let deprecated_isFoo = "isFoo" . . .3. コメント化
使用されなくなったキーをコメントで管理するパターンです。
筆者はこのパターン方法で管理したことはないですが、コメントで管理することで視認性が落ちるのが気になります。static let isHoge = "isHoge" // deprecated keys // static let isFoo = "isFoo" . . .他にもこんな風に管理しているなどがあれば教えていただけるとありがたいです
どのような管理方法が理想か
上記のような管理方法を洗い出し、以下の用件が満たせていれば理想だと考えました。
- どのキーが使用されなくなったかがわかる状態
- 使用されいているキーと不要なキーの管理が分離されている
- 既に利用していないキー名を再度利用しようとした場合、ビルド時にエラー検知
新しい管理方法
ドットファイルとスクリプトで管理するパターンを考えてみました。
- 使用しなくなったキー名を
.unused_userdefaults_key
で管理- buildPhaseでスクリプトを実行し、使用していないキーを利用する場合エラーを出力
1. ドットファイルを用意
使用しなくなったキー名をまとめた
.unused_userdefaults_key
を用意しますis_hoge is_foo2. スクリプトファイルを用意
キーをまとめたswiftファイルを引数として、
.unused_userdefaults_key
と一致するものが含まれていればエラーを出力するスクリプトを用意しますunused_userdefaults_key.sh#!/bin/sh file_path=$1 index_array=`cat -n ${file_path}| nl -nln | grep -f .unused_userdefaults_key | cut -d " " -f1` if (( ${#index_array[@]} )); then for i in ${index_array[@]} do echo "${file_path}:${i}:0: error: It's a key name that's already in use." done exit 1 fi3. Build Phasesに組み込み
unused_userdefaults_key.sh
をBuildPhasesで実行するようにします
動作GIF
SwiftyUserDefaultsを利用した場合の動作GIFです。
GitHubにもプロジェクトを公開しているので、興味がある人は確認してみてください。
GitHub: https://github.com/funzin/UnusedUserDefaultsKeyExmapleまとめ
不要となったUserDefaultsキーの管理方法についてまとめてみました。
削除したキーが復活して事故を防ぐには有効だと思いますので、ぜひ参考にしてもらえるとうれしいです。
- 投稿日:2020-08-09T16:35:05+09:00
【Swift】deinitではwillSet/didSetが呼ばれないというお話
結論
init/deinit内でプロパティに代入を行っても、willSet/didSetは呼ばれないので注意しましょう。
ただし、スーパークラスのプロパティのwillSet/didSetは呼ばれるようです。公式ガイドの注意書き
公式ガイド(The Swift Programming LanguageのProperties)に、以下のような注意書きがあります。
NOTE
The willSet and didSet observers of superclass properties are called when a property is set in a subclass initializer, after the superclass initializer has been called. They are not called while a class is setting its own properties, before the superclass initializer has been called.1注意
サブクラスのイニシャライザ内で、スーパークラスのイニシャライザが呼ばれた後に、プロパティがセットされたとき、スーパークラスのプロパティのwillSetとdidSetのオブザーバーが呼ばれます。スーパークラスのイニシャライザが呼ばれる以前に、自身のプロパティをセットしている間は呼ばれません。2なるほど。スーパークラスのプロパティのdidSet/willSetについては、サブクラス内のイニシャライザでスーパクラスのイニシャライザを呼んだ後であれば、機能するということらしいです。
クラス自身で定義したプロパティのdidSet/willSetについては、イニシャライザで呼ばれないのは当然だろということか、記述が見当たりませんでした。コードで確認
確かにスーパークラスのプロパティのdidSetについては呼ばれました。
class Animal { var age: Int { didSet { print(#function, age, oldValue) } } init(age: Int) { self.age = age // -> 呼ばれない } } class Tiger: Animal { var family: String { didSet { print(#function, family, oldValue) } } init(age: Int, family: String) { self.family = family // -> 呼ばれない super.init(age: age) // -> 呼ばれない self.age += 0 // -> didSetが呼ばれる!! self.family += "" // -> 呼ばれない } deinit { print(#function) age = 0 // -> 呼ばれる family = "" // -> 呼ばれない } }どういうときに注意すべき?
例えば、Timerをdeinitでinvalidateしたいときに、以下のような書き方をすると呼ばれないので注意しましょう。
class ViewController2: UIViewController { var timer: Timer? { willSet { timer?.invalidate() } } deinit { timer = nil // nilを代入してもwillSetは呼ばれない! // -> timer?.invalidate() } ... }参考
Swiftでdeinit時にメンバ変数(property)のdidSetが呼ばれない気がした
Can I use didSet in deinit?
[The Swift Programming Language - Properties](https://docs.swift.org/swift-book/LanguageGuide/Properties ↩
太字による強調は訳者による ↩
- 投稿日:2020-08-09T16:30:58+09:00
Functionに関して、まとめた。【Swift】
Functionの初歩。
func(関数)を学んだので、簡単におさらい。
Functionを何故使うのか。
amazonのような買い物アプリにて、
ユーザーの買い物カゴの合計金額を計算する箇所が5つあるとき、
5箇所で同じコードを書くのは無駄。
コード量が増えて、プログラム自体が複雑で読みにくくなる。
処理が1回しかないものでも、functionには利点あり。
functionにしてマトめる
と、コード量がかなり多いとき読みやすい。function名
を適切につけて、判別しやすい。パラメータと引数の違い
意思疎通にはそれほど困らないけど・・・
「引数 == パラメータ」ではない
- パラメータ (仮引数)は、関数に受け渡されるものの宣言
- 引数は、関数に渡した実際の値
// Funtion with parameters func declare(name: String) { print(name) } declare(name: "Shimura") // 呼び出し declare(name: "Ken") // 呼び出し「志村」と「けん」が引数で、nameがパラメータ。
パラメータと引数の違い因みに、「ひきすう」と読みます。
関数3パターン、おさらい。
with no parameters?
func declareName() { print("MyName") } declareName() // 呼び出しwith parameters?
func declare(name: String) { print(name) } declare(name: "Shimura") // 呼び出し declare(name: "Ken") // 呼び出しwith a return value?
func 一日の秒数() -> Int { return 24 * 60 * 60 } let 秒数 = 一日の秒数() // 呼び出し & 代入 (=インスタンス化) print("一日は\(秒数)秒!") // 一日は86400秒!with parameters and a return value?
func createFullName(firstName: String, lastName: String) -> String { return firstName + " " + lastName } //let fullName = createFullName(firstName: String, lastName: String) let fullName = createFullName(firstName: "Suzuki", lastName: "Ichiro") // 呼び出し & 代入 (=インスタンス化) print(fullName) // Suzuki Ichiroreturnを使った関数
一方的にただ呼び出す関数も便利ですが、(上記2つのコード??)
関数の中でいろいろな処理をさせて、その「結果」を貰いたいときがあります。
要するに、呼び出しに対する「返事」が欲しいときです。with a return value?
with parameters and a return value?
戻り値を持つ関数。
書き方は、こんな感じ。func 関数の名前() -> 戻り値の型 { // 実行する処理 return 戻り値 }具体例。
func 一日の秒数() -> Int { return 24 * 60 * 60 }でも、上記コードだけでは実行されない。
「関数の呼び出し」
を、変数or定数に代入
。(=インスタンス化)let seconds = 一日の秒数() // インスタンス化 print("一日は\(seconds)秒!") // 一日は86400秒!
「
\()
」の中に変数を入れると、その内容が埋め込まれます。Swiftでは『戻り値』のデータ型を指定する 必要があります。
『->
データ型』で指定。これがないとエラー。{}内でreturnが実行されると 関数内の処理は終了なので、
関数{}の中の、一番最後に書く。func 一日の秒数() -> Int { // 今回はInt型。(Integer: 整数) return 24 * 60 * 60 print("Hello World") // エラー。 Code after 'return' will never be executed } let seconds= 一日の秒数() print("一日は\(seconds)秒!") // 『\()』を使って、変数secondsを埋め込み。おしまい。
参考サイト
- 投稿日:2020-08-09T16:26:33+09:00
Functionに関して、まとめた。【Swift】
Functionの初歩。
func(関数)を学んだので、簡単におさらい。
Functionを何故使うのか。
amazonのような買い物アプリにて、
ユーザーの買い物カゴの合計金額を計算する箇所が5つあるとき、
5箇所で同じコードを書くのは無駄。
コード量が増えて、プログラム自体が複雑で読みにくくなる。
処理が1回しかないものでも、functionには利点あり。
functionにしてマトめる
と、コード量がかなり多いとき読みやすい。function名
を適切につけて、判別しやすい。パラメータと引数の違い
意思疎通にはそれほど困らないけど・・・
「引数 == パラメータ」ではない
- パラメータ (仮引数)は、関数に受け渡されるものの宣言
- 引数は、関数に渡した実際の値
// Funtion with parameters func declare(name: String) { print(name) } declare(name: "Shimura") // 呼び出し declare(name: "Ken") // 呼び出し「志村」と「けん」が引数で、nameがパラメータ。
パラメータと引数の違い因みに、「ひきすう」と読みます。
関数3パターン、おさらい。
with no parameters?
func declareName() { print("MyName") } declareName() // 呼び出しwith parameters?
func declare(name: String) { print(name) } declare(name: "Shimura") // 呼び出し declare(name: "Ken") // 呼び出しwith a return value?
func 一日の秒数() -> Int { return 24 * 60 * 60 } let 秒数 = 一日の秒数() // 呼び出し & 代入 print("一日は\(秒数)秒!") // 一日は86400秒!with parameters and a return value?
func createFullName(firstName: String, lastName: String) -> String { return firstName + " " + lastName } //let fullName = createFullName(firstName: String, lastName: String) let fullName = createFullName(firstName: "Suzuki", lastName: "Ichiro") // 呼び出し & 代入 print(fullName) // Suzuki Ichiroreturnを使った関数
一方的にただ呼び出す関数も便利ですが、(上記2つのコード??)
関数の中でいろいろな処理をさせて、その「結果」を貰いたいときがあります。
要するに、呼び出しに対する「返事」が欲しいときです。with a return value?
with parameters and a return value?
戻り値を持つ関数。
書き方は、こんな感じ。func 関数の名前() -> 戻り値の型 { // 実行する処理 return 戻り値 }具体例。
func 一日の秒数() -> Int { return 24 * 60 * 60 }でも、上記コードだけでは実行されない。
「関数の呼び出し」
を、変数or定数に代入
。let seconds = 一日の秒数() // 呼び出し & 代入 print("一日は\(seconds)秒!") // 一日は86400秒!
「
\()
」の中に変数を入れると、その内容が埋め込まれます。Swiftでは『戻り値』のデータ型を指定する 必要があります。
『->
データ型』で指定。これがないとエラー。{}内でreturnが実行されると 関数内の処理は終了なので、
関数{}の中の、一番最後に書く。func 一日の秒数() -> Int { // 今回はInt型。(Integer: 整数) return 24 * 60 * 60 print("Hello") // エラー。 Code after 'return' will never be executed } let seconds= 一日の秒数() print("一日は\(seconds)秒!") // 『\()』を使って、変数secondsを埋め込み。おしまい。
参考サイト
- 投稿日:2020-08-09T16:18:50+09:00
[SwiftUI]EnvironmentObjectとBinding
EnvironmentObjectを使って他のViewを更新しようとしましたが中々できなく、数時間ハマってしまいました。
解決方法を見つけたので書いてみました。どのような場合か
親View・子View・もう一つのViewの構成で、もう一つのViewから子Viewを更新したい時。
始めにやっていたこと
- 親View:EnvironmentObjectを持つ
- 子View:Stateを持つ
- もう一つのView:EnvironmentObject
- EnvironmentObjectとして
ObservableObject
を継承したクラスを使っていた→もう一つのViewで値を変更しても、子Viewの値が更新されませんでした
解決策
- 親View:EnvironmentObjectを持つ
- 子View:Bindingを持つ
- もう一つのView:EnvironmentObject
- EnvironmentObjectとして
ObservableObject
を継承したクラス→子ViewのStateを
Binding
に変更しました実装
親View
ContentView.swiftstruct ContentView: View { @EnvironmentObject var countSetting: CountSetting var body: some View { NavigationView { List { NavigationLink.init(destination: AnotherView()) { ChildView(value: Binding.init(get: { self.countSetting.count }, set: { _ in })) } } } } }ポイントは
Binding
でChildViewに値を渡しているところです。子View
ChildView.swiftstruct ChildView: View { @Binding var value: IntEnvironmentObjectにするクラス
CountSetting.swiftclass CountSetting: ObservableObject { @Published var count: Int = 0 }ソース
ソースはこちら
https://gist.github.com/usk2000/95fdcd327c5fe22aa892d615721de0d9スクショ
親View もう一つのView もう一つのViewの「増やす」を押すと親Viewの「4」のところが変わります。
参考
https://qiita.com/shiz/items/6eaf87fa79499623306a#binding
https://stackoverflow.com/questions/59259921/binding-value-from-an-observableobject
- 投稿日:2020-08-09T09:37:21+09:00
Immutable value "number" was never used;
たまに見るやつ。
たまに見る警告。そして、自然と消えるやつ。⚠️
いちいち投稿するまでも無いかもだけど、一応まとめておきます。Immutable value "number" was never used;
for
構文とかで、まだ中身書いてない時に、
一時的に発生する警告。Immutable value "number" was never used; consider replacing with "_" or removing itfor number in 0...4 { // Immutable value "number" was never used; consider replacing with "_" or removing it // まだ中身書いてない。 }「"number"は使われてないから、"_"に置き換える、もしくは削除することも考え直したらどう?」
と、言われています。
「 _ 」 とは?
「その値は使用しない」
という意味らしいです。for number in 0...4 { print(number) }中身で”number”を使えば、警告は消えます。
おしまい。
- 投稿日:2020-08-09T09:37:21+09:00
Immutable value "number" was never used; consider replacing with "_" or removing it
たまに見るやつ。
たまに見る警告。そして、自然と消えるやつ。⚠️
いちいち投稿するまでも無いかもだけど、一応まとめておきます。Immutable value "number" was never used;
for
構文とかで、まだ中身書いてない時に、
一時的に発生する警告。Immutable value "number" was never used; consider replacing with "_" or removing itfor number in 0...4 { // Immutable value "number" was never used; consider replacing with "_" or removing it // まだ中身書いてない。 }「"number"は使われてないから、"_"に置き換える、もしくは削除することも考え直したらどう?」
と、言われています。
「 _ 」 とは?
「その値は使用しない」
という意味らしいです。for number in 0...4 { print(number) }中身で”number”を使えば、警告は消えます。
おしまい。
- 投稿日:2020-08-09T04:07:36+09:00
自作ライブラリ Carthage CocoaPods 公開を CI を利用して自動化
前提
Release
の作成 (=tag
作成) は手作業で行うものとします。
この記事で行う自動化は、Release 作成をトリガーとして行うものです。https://github.com/yuki0n0/WaveSlider/
解説するものは、こちらのライブラリを作成したときの情報に基づいています。
よかったら GitHub で Star ★ つけてね。https://qiita.com/yuki0n0/items/290c6ab753634e7395f5
ライブラリ公開の手続きなどはこちらで解説しております。CI は GitHub Actions を利用しています。
大したことはやってないのでお好きな CI で読み替えてくださいCocoaPods
今回やることは下記です。
pod trunk push
を CI で自動的に実行- push が行えるように認証情報を用意する
- バージョン情報を
tag
から取得1. トークンを取得
登録 (もしくはログイン) します。メールが来たらアクティベートしましょう。
# 登録済みの場合は Name は必要ありません pod trunk register mail@example.com Name
~/.netrc
に認証情報があるため、password
を確認します。~/.netrcmachine trunk.cocoapods.org login mail@example.com password 0000000a000000aaaaaaa0000aa00a0aこの
password
を GitHub Actions から利用できるように Secrets にセットします。
ここではCOCOAPODS_TRUNK_TOKEN
としておきます。
2. バージョンを環境変数から取れるようにしておく
.podspec
ファイルでバージョンを指定しますが、ここの値を外部から指定できるようにしておきます。
環境変数LIBRARY_VERSION
に1.0.0
のような値が入っていることを想定します。LibraryName.podspec# コードは一例です。お好きな方法で外部の値をとってこれるようにしましょう。 version = ENV["LIBRARY_VERSION"] exit 1 if version.to_s.empty? Pod::Spec.new do |spec| spec.name = "LibraryName" spec.version = version spec.source = { :git => "https://...git", :tag => spec.version } ... end今回でいう外部は、 git の
tag
名に基づいて指定したいということです。
つまり、必然的にtag
名は1.0.0
というような CocoaPods のバージョン名と一致することが求められます。3. GitHub Actions の Yaml ファイル
最低限の Yaml を下記に載せました。ポイントをまとめます。
- CocoaPods のトークン (
password
) を env として定義し忘れない- env
LIBRARY_VERSION
に tag 名を渡すgithub.event.release.tag_name
でタグ名を取れる! (これにたどり着くのに時間かかった)GitHub Actions の Yaml ファイルon: release: types: [published] jobs: job-name: runs-on: macos-10.15 env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} LIBRARY_VERSION: ${{ github.event.release.tag_name }} steps: - uses: actions/checkout@v2 - run: pod trunk push LibraryName.podspecソースコードはこちら
https://github.com/yuki0n0/WaveSlider/blob/1.0.2/.github/workflows/release_published.yamlCarthage
Carthage は公開を自動化するというより、
オプションとして行う「バイナリのアップロード」を自動化します。1. 前提知識
Release の Assets
https://docs.github.com/ja/github/administering-a-repository/about-releases
GitHub の Release には、ファイルを Assets として置いておける場所があります。
そして、ここにブラウザ上から手動でファイルをアップロードすることもできます。
このアップロードを自動化します。アップロードしたいバイナリ
下記コマンドを実行すると、
LibraryName.framework.zip
を作成できます。carthage build --archive
バイナリを Assets に置いておくメリット
ビルド済みのバイナリを置いておくことにより、ライブラリ利用者はこれを使用できます。
通常はソースコードを各利用者の環境でビルドするので、このビルド時間を省略1できます。2. バイナリを自動アップロード
最小限のコードを、コメントと共に掲載しておきます。
GitHub Actions の Yaml ファイルon: release: types: [published] jobs: job-name: runs-on: macos-10.15 env: GITHUB_TOKEN: ${{ github.token }} steps: - uses: actions/checkout@v2 # LibraryName.framework.zip を作成 - run: carthage build --archive # upload_url を取得するために使用させていただく - uses: bruceadams/get-release@v1.2.0 id: get # Release の Assets にファイルをアップロード - uses: actions/upload-release-asset@v1.0.2 with: upload_url: ${{ steps.get.outputs.upload_url }} asset_path: ./LibraryName.framework.zip asset_name: LibraryName.framework.zip asset_content_type: application/zipソースコードはこちら
https://github.com/yuki0n0/WaveSlider/blob/1.0.2/.github/workflows/release_published.yaml参考
- GitHub: Carthage Readme
https://github.com/Carthage/Carthage#supporting-carthage-for-your-framework- GitHub: 公式ドキュメント リリースについて
https://docs.github.com/ja/github/administering-a-repository/about-releases- GitHub Support Comunity: How to get just the tag name? - GitHub Actions
https://github.community/t/how-to-get-just-the-tag-name/16241/21- Qiita: GitHub Actions で 自作Cocoapodsライブラリを自動デプロイする
https://qiita.com/ry-itto/items/0fab3fdc4321bfbd3877
- 投稿日:2020-08-09T04:07:36+09:00
自作ライブラリ Carthage CocoaPods 公開を CI で自動化
GitHub Actions を利用し、Release 作成タイミングで、ライブラリ公開作業を自動化しましょう!
前提
Release
の作成 (=tag
作成) は手作業で行うものとします。
この記事で行う自動化は、Release 作成をトリガーとして行うものです。https://github.com/yuki0n0/WaveSlider/
解説するものは、こちらのライブラリを作成したときの情報に基づいています。
よかったら GitHub で Star ★ つけてね。https://qiita.com/yuki0n0/items/290c6ab753634e7395f5
ライブラリ公開の手続きなどはこちらで解説しております。CI は GitHub Actions を利用しています。
大したことはやってないのでお好きな CI で読み替えてくださいCocoaPods
今回やることは下記です。
pod trunk push
を CI で自動的に実行- push が行えるように認証情報を用意する
- バージョン情報を
tag
から取得1. トークンを取得
登録 (もしくはログイン) します。メールが来たらアクティベートしましょう。
# 登録済みの場合は Name は必要ありません pod trunk register mail@example.com Name
~/.netrc
に認証情報があるため、password
を確認します。~/.netrcmachine trunk.cocoapods.org login mail@example.com password 0000000a000000aaaaaaa0000aa00a0aこの
password
を GitHub Actions から利用できるように Secrets にセットします。
ここではCOCOAPODS_TRUNK_TOKEN
としておきます。
2. バージョンを環境変数から取れるようにしておく
.podspec
ファイルでバージョンを指定しますが、ここの値を外部から指定できるようにしておきます。
環境変数LIBRARY_VERSION
に1.0.0
のような値が入っていることを想定します。LibraryName.podspec# コードは一例です。お好きな方法で外部の値をとってこれるようにしましょう。 version = ENV["LIBRARY_VERSION"] exit 1 if version.to_s.empty? Pod::Spec.new do |spec| spec.name = "LibraryName" spec.version = version spec.source = { :git => "https://...git", :tag => spec.version } ... end今回でいう外部は、 git の
tag
名に基づいて指定したいということです。
つまり、必然的にtag
名は1.0.0
というような CocoaPods のバージョン名と一致することが求められます。3. GitHub Actions の Yaml ファイル
最低限の Yaml を下記に載せました。ポイントをまとめます。
- CocoaPods のトークン (
password
) を env として定義し忘れない- env
LIBRARY_VERSION
に tag 名を渡すgithub.event.release.tag_name
でタグ名を取れる! (これにたどり着くのに時間かかった)GitHub Actions の Yaml ファイルon: release: types: [published] jobs: job-name: runs-on: macos-10.15 env: COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }} LIBRARY_VERSION: ${{ github.event.release.tag_name }} steps: - uses: actions/checkout@v2 - run: pod trunk push LibraryName.podspecソースコードはこちら
https://github.com/yuki0n0/WaveSlider/blob/1.0.2/.github/workflows/release_published.yamlCarthage
Carthage は公開を自動化するというより、
オプションとして行う「バイナリのアップロード」を自動化します。1. 前提知識
Release の Assets
https://docs.github.com/ja/github/administering-a-repository/about-releases
GitHub の Release には、ファイルを Assets として置いておける場所があります。
そして、ここにブラウザ上から手動でファイルをアップロードすることもできます。
このアップロードを自動化します。アップロードしたいバイナリ
下記コマンドを実行すると、
LibraryName.framework.zip
を作成できます。carthage build --archive
バイナリを Assets に置いておくメリット
ビルド済みのバイナリを置いておくことにより、ライブラリ利用者はこれを使用できます。
通常はソースコードを各利用者の環境でビルドするので、このビルド時間を省略1できます。2. バイナリを自動アップロード
最小限のコードを、コメントと共に掲載しておきます。
GitHub Actions の Yaml ファイルon: release: types: [published] jobs: job-name: runs-on: macos-10.15 env: GITHUB_TOKEN: ${{ github.token }} steps: - uses: actions/checkout@v2 # LibraryName.framework.zip を作成 - run: carthage build --archive # upload_url を取得するために使用させていただく - uses: bruceadams/get-release@v1.2.0 id: get # Release の Assets にファイルをアップロード - uses: actions/upload-release-asset@v1.0.2 with: upload_url: ${{ steps.get.outputs.upload_url }} asset_path: ./LibraryName.framework.zip asset_name: LibraryName.framework.zip asset_content_type: application/zipソースコードはこちら
https://github.com/yuki0n0/WaveSlider/blob/1.0.2/.github/workflows/release_published.yaml参考
- GitHub: Carthage Readme
https://github.com/Carthage/Carthage#supporting-carthage-for-your-framework- GitHub: 公式ドキュメント リリースについて
https://docs.github.com/ja/github/administering-a-repository/about-releases- GitHub Support Comunity: How to get just the tag name? - GitHub Actions
https://github.community/t/how-to-get-just-the-tag-name/16241/21- Qiita: GitHub Actions で 自作Cocoapodsライブラリを自動デプロイする
https://qiita.com/ry-itto/items/0fab3fdc4321bfbd3877