CLI 版 Bitrise で快適ビルド生活
こんにちは。koogawa です。
さて皆さま、Bitrise と言えば CI サービス bitrise.io の方を想像する人がほとんどだと思いますが、実は CLI 版が用意されているのはご存知でしょうか。
今回はこの CLI 版 Bitrise を使ってiOSアプリを Deploy Gate に配信する方法を紹介したいと思います。
目次
実行環境
- Xcode 9.3
- Bitrise 1.16.0
- CocoaPods 1.5.0
すでに CocoaPods を使用したサンプルプロジェクトが作成済みである前提で話を進めます。
まずはインストール
Bitrise CLI は Homebrew から簡単にインストールできます。
$ brew update && brew install bitrise
インストール後、bitrise
コマンドが使用できることを確認してください。
$ bitrise -v 1.16.0
セットアップ
Bitrise でのビルドに必要なすべてのプラグインやツール群をダウンロードするために bitrise setup
をおこないます。
$ bitrise setup ██████╗ ██╗████████╗██████╗ ██╗███████╗███████╗ ██╔══██╗██║╚══██╔══╝██╔══██╗██║██╔════╝██╔════╝ ██████╔╝██║ ██║ ██████╔╝██║███████╗█████╗ ██╔══██╗██║ ██║ ██╔══██╗██║╚════██║██╔══╝ ██████╔╝██║ ██║ ██║ ██║██║███████║███████╗ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝╚══════╝╚══════╝ version: 1.16.0 Setup Full setup: false Clean setup: false Detected OS: darwin Checking Bitrise Core tools...
ロゴがカッコイイですね!
bitrise.yml 作成
セットアップが完了したら、今度は Bitrise の設定ファイルである bitrise.yml を作成していきます。
まずは "Hello My Name" とだけ表示する yml を書いてみます。次のように入力したら Xcode プロジェクトのルートに配置してください。
format_version: 1.3.1 default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git app: envs: - MY_NAME: My Name workflows: test: steps: - script@1.1.3: inputs: - content: echo "Hello ${MY_NAME}!"
最初の2行で設定ファイルのフォーマットバージョン指定、使用するライブラリの指定を行っています。
app:
では環境変数のセットをしています。この例では MY_NAME
という環境変数に "My Name” という値をセットしています。ここでセットした環境変数は以下で説明するワークフロー内で ${MY_NAME}
のように使用することができます。
workflows:
でワークフローを追加していきます。ワークフローはひとつひとつのステップをひとつにまとめたものです。この例では test
というワークフローの中で echo "Hello ${MY_NAME}!”
というスクリプトを実行するようにしています。
それではワークフロー test
を実行してみましょう。
$ bitrise run test
ちょっとわかりにくいですが、ちゃんと “Hello My Name!” が表示されていますね。
CocoaPods
次はライブラリ管理ツール CocoaPods で pod install
を実行してみましょう。
workflows: pod_install: steps: - script@1.1.3: title: 'pod install' inputs: - content: pod install --repo-update
pod_install
というワークフローを作り、ステップの中で pod install --repo-update
を実行しているだけですね。
$ bitrise run pod_install
を実行すると、いつものように pod install
が動き出すと思います。正常にライブラリのインストールが行われているか確認してください。
アーカイブ
次に Xcode プロジェクトをアーカイブして .ipa ファイルを生成してみましょう。
workflows: archive: before_run: - pod_install steps: - xcode-archive@2.4.3: inputs: - output_tool: xcodebuild - export_method: development - output_dir: . - project_path: “./Sample.xcworkspace" - scheme: Sample
archive
というワークフローを作り、Bitrise ライブラリで提供されているアーカイブ用の xcode-archive@2.4.3:
というステップを実行しています。今回は Sample
という Xcode プロジェクトを xcodebuild ツールでアーカイブし、開発用*1としてエクスポートしてみました。
before_run
は名前の通り、各ステップがスタートする前に実行されます。このタイミングで先ほど作成した pod_install
を呼んでいるのがポイントになります。こうすることによって、アーカイブ前にライブラリのインストールが完了していることを保証できるわけですね。
$ bitrise run archive
を実行してみましょう。成功すれば同じディレクトリに Sample.ipa が生成されていると思います。
DeployGate
最後にアプリ配布プラットフォームである DeployGate に、先ほど作成した ipa ファイルを配布してみます。
workflows: deploy: before_run: - archive steps: - script@1.1.3: title: 'upload to deploygate' inputs: - content: |- curl \ -F “token=XXXXXXXX" \ -F "file=@Sample.ipa" \ -F "message=commit: $(git rev-parse HEAD)" \ -F "disable_notifiy=true" \ https://deploygate.com/api/users/hoge/apps
deploy
というワークフローを作り、ステップの中で deploygate API を curl で叩いているのがわかると思います。ここでも before_run
を使用し、事前に ipa ファイルのエクスポートを行っています。
$ bitrise run deploy
を実行してみましょう。成功すれば、DeployGate のダッシュボードにアプリが追加されているはずです。
***
今後は $ bitrise run deploy
と打つだけで
- pod install
- archive および ipa ファイルのエクスポート
- DeployGate に配信
まで自動的にやってくれます。快適ですね!
まとめ
CLI 版 Bitrise を使ってiOSアプリを Deploy Gate に配信する方法を紹介しました。意外と簡単だったのではないでしょうか。
また、この他にも Xcode Unit Test を実行するなど様々なワークフローが作れるので、興味があればぜひ試してみてください!
*1:他に ad-hoc, appstore などが設定可能
Foursquare Places API の仕様が変わるようです
Foursquare Developer サイトに Announcements が出ていたので和訳してみます。雑ですみません。
4月12日までにFoursquare Places APIに登録した開発者へ:
5月31日から、APIの簡素化、開発者コミュニティの成長に伴うサービスクォリティの維持を目的に、以下5つの変更を行います。
- Venue あたりの写真とTipsの数は、Sandbox Tier では1、Personal Tierでは2に変更されます
- チェックイン回数、訪問回数、チェーン店の詳細、および key tastes (訳注:よくわかっていない)へのアクセスはできなくなります
- Venue search、explore、trending、similar、次のエンドポイントは、Venue名、Venue ID、住所、緯度/経度、およびカテゴリのフィールドを返すようになります。各Venueの追加コンテンツにアクセスするには、Venue IDをパラメータとして詳細(venues / x)エンドポイントを呼び出してください。
- 通常のエンドポイントは、Personal Tier の場合(訳注:Sandbox TierのTYPOでは?→指摘したところ、やはりTYPOでした)は1日あたり950コール、Personal Tier の場合は1日あたり99,500コールの回数を持ちます。Premium エンドポイントのSandbox Tierの1日あたりのコール数は50コール、Personal Tierの1日あたりのコール数は500コールです。エンドポイントに関する詳細は、こちらをご覧ください。
- キャッシングの時間枠は24時間に短縮されました。詳細はこちらを参照してください。
アプリケーションがスムーズに実行されるようにするには、5月31日までに必要な修正をしてください。ユーザーへのサービス中断を防ぐためにも。
理解しておきたい用語
- Places API - ここに載っているAPIのこと。ベニュー検索したり、チェックインしたり、ユーザー情報を取得したり(つまり全部?)
- Sandbox / Personal Tier - アプリケーションを追加するときにTier(種類みたいなもん?)を選択する。非商用の Sandbox、Personal(クレジットカード認証が必要)、商用の Start-Up(有料)がある。
- Regula / Premium endpoint - Endpoint 毎に Type が決まっている。詳細はこちら
所感
つまり「できることが少なくなる」わけですなw
例えば、ベニュー検索APIで hereNow
(今何人そこにいるか)や specials
(チェックイン特典などがあるか)が取得できることを前提にプログラムされているアプリは注意が必要ですね!
【iOS】既存のソースコードを Embedded Framework に切り出して複数のターゲットから利用する
こんにちは。koogawa です。
さて、一つのプロジェクトで複数のアプリを開発していると、共通部分をフレームワークに切り出して再利用したくなりませんか?
私はなります。
というわけで、今回は Xcode 6 から導入された Embedded Framework という仕組みを使って、フレームワークを作成する方法を紹介します。
目次
実行環境
- Xcode 9.3
- Swift 4.1
プロジェクト構成
A と B、2つのターゲットがあり、ターゲットAの Client
クラスをフレームワークに切り出して、ターゲットA、Bの両方から利用可能にするケースを考えます。
Xcode 上は次のようになっています。
ターゲットAのソースファイルは A ディレクトリに、ターゲットBのソースファイルは B ディレクトリに格納します。
Client
クラスは API と通信し、レスポンスデータを String 型にして返す request
メソッドを持ちます。*1
import Alamofire class Client { init() { } func request(_ complete: @escaping (String?) -> Void) { Alamofire.request("https://httpbin.org/get").responseJSON { response in var responseString: String? = nil if let data = response.data { responseString = String(data: data, encoding: .utf8) } complete(responseString) } } }
見ておわかりの通り、通信ライブラリである Alamofire を利用しています。
ライブラリ管理は CocoaPods で行ないます。
Podfile:
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'A' do pod 'Alamofire', '~> 4.7' end
ターゲットAでの作業
それでは Client
クラスをフレームワークに切り出していきましょう。
Cocoa Touch Framework を追加
Xcodeのツールバーから「File」 → 「New」 → 「Target」を選択すると、次の画面が表示されます。
「Cocoa Touch Framework」を選択します。
「Product Name」は "Client" にしておきます。他の項目を適切なものにセットして「Finish」を押しましょう。
Project Navigator に「Client」が追加されたと思います。このディレクトリにフレームワークのソースファイルを追加していきます。
ソースファイルを追加
Client.swift をフレームワークに切り出したいので、ソースファイルをドラッグアンドドロップします。
切り出したクラスやメソッドは、外からもアクセスできるように public
修飾子をつけておきます。
public class Client { public init() { } public func request(_ complete: @escaping (String?) -> Void) { Alamofire.request("https://httpbin.org/get").responseJSON { response in var responseString: String? = nil if let data = response.data { responseString = String(data: data, encoding: .utf8) } complete(responseString) } } }
インポートして使ってみる
ターゲットAから使ってみましょう。Client
を import するだけで使えるようになります。
import Client class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let client = Client() client.request({ responseString in if let responseString = responseString { print(responseString) } }) } }
この時点でいったんビルドしてみると
/Path/To/Sample/Client/Client.swift:10:8: No such module 'Alamofire'
のようなエラーが出ると思います。どうやらフレームワークから Alamofire が読み込めていないようなので、Podfile を次のように書き換えてみましょう。
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'Client' do pod 'Alamofire', '~> 4.7' end
再度 pod update
してビルドしてみましょう。今度はビルドが通りましたね。
今度は ⌘R
で Run してみましょう。
dyld: Library not loaded: @rpath/Alamofire.framework/Alamofire
おや、クラッシュしましたね。まだ Alamofire が読み込めていないようです。今度は Podfile を下記のように書き換えてリトライしてみましょう。
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'A' do pod 'Alamofire', '~> 4.7' end target 'Client' do pod 'Alamofire', '~> 4.7' end
今度はクラッシュしませんでしたね!
このように CocoaPods を使う場合は、フレームワークだけでしか利用していないライブラリもメインターゲットにインストールする必要があるので注意してください。
ターゲットBでの作業
次はターゲットBからもフレームワークを使えるようにしていきましょう。
Embedded Binaries にフレームワーク追加
TARGET から「B」を選択し、General の中にある「Embedded Binaries」に Client.framework
を追加します。
Podfile 更新
ターゲットBにも Alamofire をインストールします。
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! target 'A' do pod 'Alamofire', '~> 4.7' end target 'B' do pod 'Alamofire', '~> 4.7' end target 'Client' do pod 'Alamofire', '~> 4.7' end
これでも動くのですが、ターゲットごとに同じライブラリ名を記述するのは冗長なので、次のように abstract_target
でまとめるのが良いでしょう。
source 'https://github.com/CocoaPods/Specs.git' platform :ios, '10.0' use_frameworks! abstract_target 'All' do pod 'Alamofire', '~> 4.7' target 'A' do end target 'B' do end target 'Client' do end end
インポートして使ってみる
Client
を import してビルドしてみます。ビルドターゲットを切り替えるのを忘れずに。
import Client class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() let client = Client() client.request({ responseString in if let responseString = responseString { print(responseString) } }) } }
ビルドできましたね。
これでターゲットBからもフレームワークが使えるようになりました!
トラブルシューティング
フレームワークがインポートできない場合は次のことを確認してみてください。
- フレームワークのクラス宣言やメソッドに
public
修飾子は付いていますか? - Xcode のキャッシュが原因の場合もあるのでクリーンビルドすると解決することがあります
- 再度
pod update
することで解決することもありました
さいごに
Embedded Framework を使って、フレームワークを作成する方法を紹介しました。少しだけハマりポイントもありましたが、意外と簡単だったのではないでしょうか。
また、今回は触れませんでしたが、Apple Watch アプリや Today Widget などの App Extentions を持つアプリの場合、メインターゲットと Extension 間のコード共有も Embedded Framework で可能になりますのでぜひ活用してみてください。
*1:サンプルプログラムにつき、実用性は全く考えておりません
Foursquare API “Consumer Disabled” error
Summary
I have been using the foursquare API, but suddenly I get "Consumer disabled" error responses.
The call I am making this to get venues will be look like:
https://api.foursquare.com/v2/venues/search?v=20180101&ll=35.6662026,139.7312591&oauth_token=XXXXX
I have the issue currently all my API calls to foursquare venues are failing with:
{ code":403, "errorType":"not_authorized", "errorDetail":"Consumer disabled.” }
response.
Did I do something wrong? 😭
Solution
I found the same question on StackOverflow.
But that did not work. So I contacted the foursquare API support team.*1 A few hours later the reply that we re-enabled your key was returned. Thus, the issue was resolved. They are now under the investigation of the causes. 🤔
*1:Please look for support e-mail on your own. It is on the https://developer.foursquare.com
「おうちではじめるプログラミングの授業」を読んだ
クラスメソッドさんのこの記事を読んでさっそくポチりました。
届いた pic.twitter.com/8YNW2TtVms
— Og🌗エンジニア🏝宮崎 (@koogawa) 2018年3月26日
そして、上記のツイートをしたところ、何人かの方から「読んだ感想を聞きたい(良さそうだったら買いたい)」と反応を頂いたので、自分なりの感想をメモします。
TL;DR
良い本でした。1日で読了できるボリュームです。
この本をおすすめしたい方
- プログラミング教育を小学校でやる理由・目的が知りたい方
- 子どもにプログラミングを教えてみたいけどプログラミングはまったく未経験の方
- 幼稚園〜小学生のお子さんをお持ちの方
各章の内容
感想も交えて順に解説していきたいと思います。
第1章 どうしてプログラミング教育を小学校でやるの?――文科省の資料から読み解く実態
私が一番知りたい内容でした。
- 2020年から始まるプログラミング教育では、プログラミング言語(例えばRuby等)を記述して、プログラムを動かすことは行わない
- コンピュータに意図した処理を行わせるために必要な論理的思考力を身につけることが目的
- 具体的な教育方法は不明確
といったことが書かれています。
目的は決まっているけど、具体的な方法は特に決まっていないのですね…。このあたりは各小学校がそれぞれ決めていくのでしょうね。
第2章 保護者は何もしなくてよい? 「プログラミング教育必修化」で変わること、変わらないこと
では、保護者はそれまでに何をするべきなのか?その答えとして
- 特別に何かすべきことはない
- 押し付けるのではなく、興味を持ってもらうこと
といった内容が書かれています。
そして、実際に子供がプログラミングに興味をもったときに使える教材も紹介されています。私は Scratch しか知らなかったので、色々と参考になりました。
第3章 プログラミングは意外と身近でシンプル! 日常にあふれているプログラムを理解しよう
この章で
コンピュータが動く仕組みは「順次」「分岐」「反復」の3つだけ
という、プログラマーにとってはおなじみの話が出てきます。私自身もプログラマーなのでここはサラッと流しました。章末では人工知能についても少しだけ触れられています。
第4章 親子でプログラミングをやってみよう! 子どもの好奇心をくすぐる進め方
この章から幼稚園児、小学生を対象とした実践的な内容になってきます。我が息子はまだ1歳なので、数年後の成長を楽しみにしながら読みました。
教育用コンピュータとして IchigoJam、プログラミング言語は N88-BASICが登場します。思えば私が生まれて初めて目にしたプログラミング言語もこの言語でした。
ちなみに IchigoJam のセットアップ方法は読んでいてとてもワクワクしました。
第5章 お父さんが教えるプログラミング実践編
この章から実際にコードを書いていきます。
PRINT 123
のような基本的な内容から始まり、最終的には IF 文や GOTO 文を組み合わせて簡単なゲームを作成します。
変数の概念や「分岐」「反復」処理が出てくるので、プログラミングを経験したことがない方にとってはやや難しい内容かもしれません。
個人的にこの章で一番大事だと思ったのは「プログラムを少し改造するとプログラムの動きが変わる楽しさを体感する」ことでした。
第6章 子どもが「プログラミングをやりたい」と言い出したら?――中学校・高等学校でのプログラミング教育
この章から中高生向けのプログラミング教育の話になってきます。 ある日子供が「家でプログラミングをやってみたい」と言ってきたとき、親として準備できる環境にはどのようなものがあるのか、とても詳しく書かれています。
インターネットに接続されたパソコンを買い与えるのが最も理想的ですが、最近ではタブレットを使ったり、クラウド上でもプログラミング環境を用意できるみたいですね。ちなみに、Nintendo 3DS や Wii でもBASIC言語を実行できるのは知りませんでした。
第7章 「情報モラル教育」は避けて通れない――子どもたちとITの適切な関係性
インターネットを通じた詐欺や、SNSでの被害にあわないようにするためにはどうしたらよいのか?といったことが書かれています。この辺の内容はやはり親としてはとても気になるところです。本章では実際に利用できるフィルタリングサービスや、動画教材へのリンクも紹介されているので、とても参考になりました。
まとめ
冒頭にも書きましたが、結論としては「買ってよかった」と思える内容でした。 私の息子が幼稚園ぐらいの歳になったら、一緒に IchigoJam を買ってプログラミングを楽しむ、という夢ができました。
将来必修化されるプログラミング教育に不安を抱いている親御さんや、純粋に子どもにプログラミングを教えてみたい方にオススメの一冊です。
株式会社はてなに入社しました
所属は はてなモノリス 開発チームです。よろしくお願いします。
本当の意味で仲が良い人
一定の距離を置いて付き合った方が仲良くできる人もいるけど、それって本当の意味で仲が良いと言えるのだろうか🤔 なんて考えてる
— Og🌗エンジニア🏝宮崎 (@koogawa) 2018年2月8日
数日前にこんなことをつぶやいたのだけど、なんとなく答えが出たのでメモしておく。
結論から言うと、それは本当の意味で仲が良いとは言えないと思う。適当な距離を置きながら付き合ってうまくやれたとしても、それは所詮、建前上の関係なんだと思う。
じゃあ、「本当の意味で仲が良い」とはどういうことなのか?
ひとつは仕事で長い間(少なくとも半年)一緒に働いてもうまくやれている人。人は一緒に働くと、だんだんその人の悪い部分が見えてくる。逆に言うと、しばらく一緒に働いてみないとその人の悪い所は見えないと思っている。(だから採用活動というのは難しいんだろうな)
もちろん悪いところがひとつもない人間なんて滅多にいないだろう。お互い悪いところを認めた上で、時には衝突しながらもうまくやれている人は仲が良い関係なんじゃないだろうか。
仕事で関わらなければうまくやれただろうなぁ、って人もたくさんいる
— Og🌗エンジニア🏝宮崎 (@koogawa) 2018年2月8日
一方で、一緒に仕事をする前はすごく仲が良かったのに、同じチームで仕事をしてみたら本当にいろいろと合わなくて、最終的に仕事以外ではお互いを避けるようになってしまった人もいる。
「この人と一緒に働いてみたい」とずっと憧れの存在だったのに、いざ一緒の会社で働いてみたらずいぶん印象が違ってがっかりした、なんてこともあるかもしれない。この場合は最初から無理に近づこうとはせずに、ずっと憧れの存在のままでいられたほうがお互いにとって幸せだったのかもしれない。
*
なんか薄っぺらい記事になってしまったけど、今日書きたいことは以上です。