koogawa blog

iOS、Android、foursquareに関する話題

【Stack Overflow活動記】reputationが5,000に!Tag Wiki 編集の承認権限が付与されました

Stack Overflow活動中 の koogawa です、こんにちは。

昨日ついに reputation(Stack Overflowにおける信頼度)が 5,000 に到達しました🎉

f:id:koogawa:20181007020821p:plain

今年の初めに設定した目標 が「Stack Overflowで5000 reputationを目指す」だったので、無事達成できたことになります。

ちなみに、エンジニアアウトプットランキング Stargzr によると、日本で reputation 5,000 以上のユーザーは現在3人しかいないようです *1。ちなみに、1位の id:KishikawaKatsumi さんは 8,000 reputation を超えていらっしゃるので本当にすごいですね!

そして、同時に Approve Tag Wiki Edits 権限が付与されました。これは Tag Wiki の編集申請を承認できる権限になります。

Tag Wiki とは

Stack Overflow で質問する際には ios, swift, xcode などの Tag を設定することができます。

各々の Tag には専用のページが用意されており、Tag の概要文やその Tag における上位回答ユーザー、最近のベストな回答などが掲載されます。

f:id:koogawa:20181007022029p:plain

すべてのユーザーは Tag 概要文を編集することができますが、Approve Tag Wiki Edits 権限(今回私に付与された権限)を持つユーザーに承認されるまでサイトには反映されません。

Tag Wiki 編集が承認されるとどうなるか

初めて編集が承認されたユーザーは「Tag Editor」バッジ(銅)を獲得できます。

f:id:koogawa:20181007022042p:plain

さらに、50回編集が承認されると「Research Assistant」バッジ(銀)を獲得できます!

f:id:koogawa:20181007022053p:plain

次なる目標

次は 10,000 reputation で付与される Access To Moderator Tools 権限獲得を目指します💪

私の Stack Overflow 活動はこれからも続きますよ!

*1:もちろん実際はもっといるんでしょうけどね

iOSDC Japan 2018 前夜祭に参加してきたよ #iosdc

飛行機、電車を乗り継ぎ、iOSDC Japan 2018会場へ!2年ぶりの参加です。

ここは WWDC か!と思いました。

ビールもたくさんデプロイされていました。途中、ビールが足りなくなるというハプニングもありましたが、スタッフさんが近くのコンビニなどで補充してくれました。感謝しかない🙏

前夜祭では次のトークを聴講しました。

ひとつだけピックアップするとRyo Usamiさんの「標準アプリから学ぶ、HIGが教えてくれないiOSデザインのこと」がとても印象に残りました。

  • 広く利用されるものを利用する
  • 同じ見た目のものは場所が違えど同じふるまいをしよう
  • 新しい標準が登場したときはその背景、使い方を知ろう

という内容が一貫しており、みんな日常的に使っている「ドア」の例えが非常にしっくりきました。

「ドア」の使い方をあまり意識しないのは何度も使ってるからであり、「ドア」であれば同じふるまい・利用のされ方をするからである。そこに突然「同じドアなのに同じ動きをしない」ドアが現れると人は戸惑う、と。

***

ノベルティもたくさんいただきました!

今日も楽しんでいきます!

PHPカンファレンス福岡 2018 #phpconfuk に参加してきたよ

今年も行ってきました!PHPカンファレンス福岡2018!

phpcon.fukuoka.jp

今回で2回目の参加になります。

会場はおなじみ福岡ファッションビル

f:id:koogawa:20180616101710j:plain

朝5時半に高速バスで出発したにも関わらず、会場まで200km以上離れていたこともあり、ちょっと遅刻してしまいました。

今年もオシャレなトートバッグとTシャツを頂きました!嬉しい!

f:id:koogawa:20180616102229j:plain

(昨年頂いたTシャツも毎週のように着ています!)

ノベルティもたくさん頂いてしまいました。

f:id:koogawa:20180616124828j:plain

今年も勉強になるセッションが盛り沢山でした。そのうちいくつかをピックアップさせていただきたいと思います。

ログの設計してますか?PSR3とログ設計の話

登壇者:富所 亮(@hanhan1978)さん

このセッションでは「何」を「何故」「どのように」ログに残すのか、ログを出力することによるリスク、そしてログを出力する前に何を決めておけばよいのか?という話がメインでした。

個人的には、スピーディーに var_dump を書いたり消したりする新人さんの話がツボでしたw 自分もよくやっていたなーと。

未経験からの挑戦!超速ネイティブアプリ開発

登壇者:株式会社ハシゴ 松本 拓也(@skycat_me)さん

hasigo@ というモバイルアプリ開発のお話でした。技術選定として、iOS/Android エンジニアが不在だったため Flutter を採用されたそうです。最近 Flutter の採用事例が増えてきたなー、と興味深く聴かせていただきました。

エンジニアの循環ってgood_or_bad_.pdf

登壇者:中村剛(@nakamura_tsuyo4)さん

創業から2,3年、たくさんのエンジニアの入れ替わりを見てきた中村さんによる、エンジニアの流動性とそれをどう乗り切ってきているか、についてのお話でした。

個人的に印象的だったのが、退職者が続く場合、本人に辞める理由を聞いてみるのが一番だけど、辞めていく人は波風立てたくないので本音を語ってくれないよね、という話。その場合、出戻ってくる人がいるか?というのがひとつのバロメータになると中村さんは語っていました。私自身も退職者が後を絶たない環境にいたことがあるので、とても興味深く聴かせていただきました。

ソフトウェアエンジニアが英語に慣れ親しむ方法

登壇者:永冨隆之(@tommy6073)さん

初っ端の「日本に居ながら世界中にアクセスできるのがインターネットなのに、英語のコンテンツに触れないのは勿体無い」という話が心に刺さりました。ホントそのとおりですよね。

永冨さん個人の昔話で、海外ゲームを遊び尽くしたところ、TOEIC初受験で960点取れてしまった話はとても説得力があるものでした。私もなるべく普段から英語に触れるために Stack Overflow 活動なるものを進めているのですが、もっと頑張らないとなーと思いました。

PHP歴3か月だけど沖縄でフルリモート開発してる話

登壇者:嘉数 侑起(@kkznch)さん

スライドはまだアップされていないようですが、ビーチの上で開発するBDD(ビーチ駆動開発)というのが沖縄らしくて良いなーと感じましたw 波に乗りながら開発するスタイルも斬新でしたが、MacBookを落とさないかちょっと心配になりました😆

なぜPHPカンファレンスに参加するのか

私はスマートフォンアプリ開発を軸としているため、普段PHPは使いません。じゃあ、なんでPHPカンファレンスに毎年参加しているかというと

これが理由です。*1

実際、昨年このカンファレンスで知った Payment Request API や PWAなどの知識も現在役に立っています。

さいごに

PHPカンファレンス関係者の皆様、今年も楽しいイベントをありがとうございました!

f:id:koogawa:20180616180212j:plain

また来年会いましょう〜😄

*1:スティーブ・ジョブズのあの有名なスピーチに影響されてます

初心者をググれカスと突き放すのは割と酷なのではないかという話

こんにちは koogawa です。最近は Stack Overflow だけにとどまらず、エンジニア向けQAサイト teratail でも回答しております。teratail はスコアが上がっていくと色んなバッジをゲットできるので気に入っています。

teratail【テラテイル】|思考するエンジニアのためのQAプラットフォーム

ところで今日は次の質問に回答しました。

teratail.com

これ、めちゃくちゃ良い質問だと思うんです。何より自分がわからないことをちゃんと言語化できている。

すでに回答もいくつか付いていたので内容を見てみると。。

  • ぐぐる。これに尽きます
  • 普通にググれば見つかるのに
  • 何がわからんの?

だいたいこんな感じでした。

うーん、皆さんなかなか手厳しい回答です。。これだと質問者の方も、ここで挫折してしまうのではないでしょうか。

回答してみた

というわけで「自分ならどうググるか?」という視点で回答してみました。詳細は teratail のサイトでご覧ください。

https://teratail.com/questions/127346#reply-193795

(気づいたら1,600文字ぐらい書いていた・・)

結果的には喜んでもらえたようなので良かったんだと思います。

プログラミング初心者に僕らがしてあげられること

プログラミングに慣れてくると、わかることが当たり前の状態になってくるので、

  • なんでわからないのかわからない
  • とにかくググれ

的なことを言ってしまいがちです。しかし、初心者にとってはどうググって良いのかさえもわからないことが多いのです。

僕らに必要なのは「なぜわからないのか」を汲み取り、調べ方のコツなどを教えてあげることなのではないでしょうか。

経験者は1分で調べられるという誤解

質問者のコメントの中で印象的だったのが

経験者がピンポイントでドキュメントやらリファレンスを1分で調べてることを何時間もかけて調べてるんじゃないか?

と思い込んでいたことです。実際そうなのかというと、全くそんなことはないですよね。

ただ、ピンポイント率が上がるというのは確かにあるかもしれません。いろいろと調べているうちに、「ググり方」がうまくなっていく実感はあります。*1

***

まとめると、

  • 「ググれ」と突き放すのではなく、ググり方を教えてあげる
  • なぜわからないのか?を汲み取る

ということを書きました。プログラミング学習を挫折してしまう人がちょっとでも減ることを願っています。

今日書きたいことはそれくらいです。

*1:例えば「iOS ○○」ではなく「swift ○○」で検索したほうがプログラミングに関するサイトがヒットしやすい等

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:サンプルプログラムにつき、実用性は全く考えておりません