koogawa blog

iOS、Android、foursquareに関する話題

CLI 版 Bitrise で快適ビルド生活

こんにちは。koogawa です。

f:id:koogawa:20180505110747j:plain

さて皆さま、Bitrise と言えば CI サービス bitrise.io の方を想像する人がほとんどだと思いますが、実は CLI 版が用意されているのはご存知でしょうか。

今回はこの CLI 版 Bitrise を使ってiOSアプリを Deploy Gate に配信する方法を紹介したいと思います。

目次

実行環境

  • Xcode 9.3
  • Bitrise 1.16.0
  • CocoaPods 1.5.0

すでに CocoaPods を使用したサンプルプロジェクトが作成済みである前提で話を進めます。

まずはインストール

Bitrise CLIHomebrew から簡単にインストールできます。

$ 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

f:id:koogawa:20180510170455p:plain

ちょっとわかりにくいですが、ちゃんと “Hello My Name!” が表示されていますね。

CocoaPods

次はライブラリ管理ツール CocoaPodspod 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 が生成されていると思います。

f:id:koogawa:20180510170343p:plain

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 APIcurl で叩いているのがわかると思います。ここでも before_run を使用し、事前に ipa ファイルのエクスポートを行っています。

$ bitrise run deploy

を実行してみましょう。成功すれば、DeployGate のダッシュボードにアプリが追加されているはずです。

***

今後は $ bitrise run deploy と打つだけで

  1. pod install
  2. archive および ipa ファイルのエクスポート
  3. 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

例えば、ベニュー検索APIhereNow (今何人そこにいるか)や specials (チェックイン特典などがあるか)が取得できることを前提にプログラムされているアプリは注意が必要ですね!

【iOS】既存のソースコードを Embedded Framework に切り出して複数のターゲットから利用する

こんにちは。koogawa です。

さて、一つのプロジェクトで複数のアプリを開発していると、共通部分をフレームワークに切り出して再利用したくなりませんか?

私はなります。

というわけで、今回は Xcode 6 から導入された Embedded Framework という仕組みを使って、フレームワークを作成する方法を紹介します。

目次

実行環境

プロジェクト構成

A と B、2つのターゲットがあり、ターゲットAの Client クラスをフレームワークに切り出して、ターゲットA、Bの両方から利用可能にするケースを考えます。

f:id:koogawa:20180412132654p:plain

Xcode 上は次のようになっています。

f:id:koogawa:20180412133207p:plain

ターゲットAのソースファイルは A ディレクトリに、ターゲットBのソースファイルは B ディレクトリに格納します。

f:id:koogawa:20180412133218p:plain

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」を選択すると、次の画面が表示されます。

f:id:koogawa:20180412133006p:plain

Cocoa Touch Framework」を選択します。

f:id:koogawa:20180412133040p:plain

「Product Name」は "Client" にしておきます。他の項目を適切なものにセットして「Finish」を押しましょう。

f:id:koogawa:20180412134559p:plain

Project Navigator に「Client」が追加されたと思います。このディレクトリにフレームワークのソースファイルを追加していきます。

ソースファイルを追加

Client.swift をフレームワークに切り出したいので、ソースファイルをドラッグアンドドロップします。

f:id:koogawa:20180412133702g:plain

切り出したクラスやメソッドは、外からもアクセスできるように 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 を追加します。

f:id:koogawa:20180412134639p:plain

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 してビルドしてみます。ビルドターゲットを切り替えるのを忘れずに。

f:id:koogawa:20180412134713p:plain

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

「おうちではじめるプログラミングの授業」を読んだ

クラスメソッドさんのこの記事を読んでさっそくポチりました。

そして、上記のツイートをしたところ、何人かの方から「読んだ感想を聞きたい(良さそうだったら買いたい)」と反応を頂いたので、自分なりの感想をメモします。

TL;DR

良い本でした。1日で読了できるボリュームです。

この本をおすすめしたい方

  • プログラミング教育を小学校でやる理由・目的が知りたい方
  • 子どもにプログラミングを教えてみたいけどプログラミングはまったく未経験の方
  • 幼稚園〜小学生のお子さんをお持ちの方

各章の内容

感想も交えて順に解説していきたいと思います。

第1章 どうしてプログラミング教育を小学校でやるの?――文科省の資料から読み解く実態

私が一番知りたい内容でした。

  • 2020年から始まるプログラミング教育では、プログラミング言語(例えばRuby等)を記述して、プログラムを動かすことは行わない
  • コンピュータに意図した処理を行わせるために必要な論理的思考力を身につけることが目的
  • 具体的な教育方法は不明確

といったことが書かれています。

目的は決まっているけど、具体的な方法は特に決まっていないのですね…。このあたりは各小学校がそれぞれ決めていくのでしょうね。

第2章 保護者は何もしなくてよい? 「プログラミング教育必修化」で変わること、変わらないこと

では、保護者はそれまでに何をするべきなのか?その答えとして

  • 特別に何かすべきことはない
  • 押し付けるのではなく、興味を持ってもらうこと

といった内容が書かれています。

そして、実際に子供がプログラミングに興味をもったときに使える教材も紹介されています。私は Scratch しか知らなかったので、色々と参考になりました。

第3章 プログラミングは意外と身近でシンプル! 日常にあふれているプログラムを理解しよう

この章で

コンピュータが動く仕組みは「順次」「分岐」「反復」の3つだけ

という、プログラマーにとってはおなじみの話が出てきます。私自身もプログラマーなのでここはサラッと流しました。章末では人工知能についても少しだけ触れられています。

第4章 親子でプログラミングをやってみよう! 子どもの好奇心をくすぐる進め方

この章から幼稚園児、小学生を対象とした実践的な内容になってきます。我が息子はまだ1歳なので、数年後の成長を楽しみにしながら読みました。

教育用コンピュータとして IchigoJamプログラミング言語は N88-BASICが登場します。思えば私が生まれて初めて目にしたプログラミング言語もこの言語でした。

ちなみに IchigoJam のセットアップ方法は読んでいてとてもワクワクしました。

第5章 お父さんが教えるプログラミング実践編

この章から実際にコードを書いていきます。

PRINT 123

のような基本的な内容から始まり、最終的には IF 文や GOTO 文を組み合わせて簡単なゲームを作成します。

変数の概念や「分岐」「反復」処理が出てくるので、プログラミングを経験したことがない方にとってはやや難しい内容かもしれません。

個人的にこの章で一番大事だと思ったのは「プログラムを少し改造するとプログラムの動きが変わる楽しさを体感する」ことでした。

第6章 子どもが「プログラミングをやりたい」と言い出したら?――中学校・高等学校でのプログラミング教育

この章から中高生向けのプログラミング教育の話になってきます。 ある日子供が「家でプログラミングをやってみたい」と言ってきたとき、親として準備できる環境にはどのようなものがあるのか、とても詳しく書かれています。

インターネットに接続されたパソコンを買い与えるのが最も理想的ですが、最近ではタブレットを使ったり、クラウド上でもプログラミング環境を用意できるみたいですね。ちなみに、Nintendo 3DSWii でもBASIC言語を実行できるのは知りませんでした。

第7章 「情報モラル教育」は避けて通れない――子どもたちとITの適切な関係性

インターネットを通じた詐欺や、SNSでの被害にあわないようにするためにはどうしたらよいのか?といったことが書かれています。この辺の内容はやはり親としてはとても気になるところです。本章では実際に利用できるフィルタリングサービスや、動画教材へのリンクも紹介されているので、とても参考になりました。

まとめ

冒頭にも書きましたが、結論としては「買ってよかった」と思える内容でした。 私の息子が幼稚園ぐらいの歳になったら、一緒に IchigoJam を買ってプログラミングを楽しむ、という夢ができました。

将来必修化されるプログラミング教育に不安を抱いている親御さんや、純粋に子どもにプログラミングを教えてみたい方にオススメの一冊です。

本当の意味で仲が良い人

数日前にこんなことをつぶやいたのだけど、なんとなく答えが出たのでメモしておく。

結論から言うと、それは本当の意味で仲が良いとは言えないと思う。適当な距離を置きながら付き合ってうまくやれたとしても、それは所詮、建前上の関係なんだと思う。

じゃあ、「本当の意味で仲が良い」とはどういうことなのか?

ひとつは仕事で長い間(少なくとも半年)一緒に働いてもうまくやれている人。人は一緒に働くと、だんだんその人の悪い部分が見えてくる。逆に言うと、しばらく一緒に働いてみないとその人の悪い所は見えないと思っている。(だから採用活動というのは難しいんだろうな)

もちろん悪いところがひとつもない人間なんて滅多にいないだろう。お互い悪いところを認めた上で、時には衝突しながらもうまくやれている人は仲が良い関係なんじゃないだろうか。

一方で、一緒に仕事をする前はすごく仲が良かったのに、同じチームで仕事をしてみたら本当にいろいろと合わなくて、最終的に仕事以外ではお互いを避けるようになってしまった人もいる。

「この人と一緒に働いてみたい」とずっと憧れの存在だったのに、いざ一緒の会社で働いてみたらずいぶん印象が違ってがっかりした、なんてこともあるかもしれない。この場合は最初から無理に近づこうとはせずに、ずっと憧れの存在のままでいられたほうがお互いにとって幸せだったのかもしれない。

なんか薄っぺらい記事になってしまったけど、今日書きたいことは以上です。