EDIT MODE

モバイルアプリ開発に関することを書いています

Zaim 開発合宿を開催しました

5月10日、11日の1泊2日で Zaim メンバーにて、開発合宿を行いました。 合宿地は、湯河原温泉にある「おんやど恵」という旅館です。

会議室を借りることが出来るので、そこで「普段気になってるけど中々実行出来ないタスクをやる」というコンセプトで、各メンバー取り組みました。

f:id:androhi:20160511171850j:plain

合宿で何をやったか?

合宿中にやるタスクについては、各々事前にいくつか候補を出しておきました。 合宿開始時に、実際にやるタスクを発表し、途中で進捗報告の発表も入れながら、メンバーが何をやっているのか共有するようにしました。

ちなみに合宿の大まかなスケジュールは、このような感じでした。

1日目

時間 内容
10:30 湯河原駅にて集合
11:00 おんやど恵に到着
会議室にて合宿開始
13:00 昼食
14:00 足湯などしつつ午後の部開始
18:30 夕食
20:00 温泉
21:30 ボードゲーム大会
??:?? 力尽きた者から就寝

2日目

時間 内容
08:00 朝食
09:00 午前の部開始
13:00 昼食
14:00 足湯などしつつ午後の部開始
18:00 合宿終了
18:40 湯河原駅にて解散

旅館はどうだったか?

今回宿泊した「おんやど恵」さんで、僕の主観ですが良かったな〜と感じた点を紹介します。

1. 足湯が気持ちいい

素敵な中庭を眺めながら、足湯に浸かることが出来ます。 さらにその中庭を見ながら、朝食や夕食を取ることが出来るので、とても癒やされました。

f:id:androhi:20160511171939j:plain

f:id:androhi:20160511172226j:plain

2. ボードゲーム標準装備

フロントで申し込むと、ボードゲームを借りることが出来ます。 Zaim にはボードゲームにかなり詳しいメンバーがいることもあり、1日目の夜はボードゲーム大会で盛り上がりました。

3. 会議室にBluetooth対応スピーカーがある

運が良かったことに、我々が合宿をする一月前から会議室にスピーカーが設置されたようです。しかも会議室利用者なら無料で使えます。

Bluetooth対応なので、作業中のBGMをスマートフォンからも流せます。(僕は全然スピーカーに詳しくないのですが、ハーマン・カードン社といえばオーディオ機器では有名みたいです。) Zaim の合宿でも、このスピーカーで音楽を流しながら作業しました。

感想

開発合宿についての、個人的な感想です。

「普段気になってるけど中々実行出来ないタスク」が出来たことは、思っていた以上に有意義な時間でした。加えて合宿という形式で作業するのも、良い気分転換になりました。ボードゲーム大会楽しかったです。

僕は開発合宿というものは初めてだったのですが、感覚としては通常勤務と社員旅行の中間みたいな感じがしました。 Zaim では今回が第1回目となる開発合宿でしたが、良い合宿だったと思います。ぜひ第2回目も開催できればなと思っています。

Kotlin/Pluginもくもく会を開催しました

先日、Kotlin や IntelliJ Plugin をテーマにもくもく会を開催しました。

もくもく会の様子

当日は、簡単な自己紹介をした後、1名飛び込みで LT をしていただいたりしました。

その後、Kotlin グループと Plugin グループとで何となく分かれ、開発を始めたのですが、 飲み物とピザをサムライズム山本さんが用意して下さってので、飲んだり食べたりしながら楽しくもくもく出来ました!

ちょっと写真が無くて申し訳ないのですが、サムライズムさんはプロジェクターやマイク、電源、WiFiと何でも揃っているので最高でした。

僕は Plugin グループでもくもくしてたのですが、意見交換とかも出来て楽しかったです。 Kotlin グループも Kotlin エヴァンジェリスト?のたろうさんも来て下っていたし、ちょこちょこ会話も聞こえてきて楽しそうでした。

同じ目的でもくもくするのって、やっぱりいいですね。

会を終えて思ったこと

過去2回やった Plugin 勉強会でも思ったのですが、少人数開催とはいえ初対面の方や開発中に声かけづらいとかもあり、コミュニケーション取るの難しいなと思っていました。

そのため今回は、参加者のみなさんに簡単な自己紹介をお願いして、コミュニケーションしやすくなればいいなと思ったのですが、 もしかしたらあまりプラスに働かなかったかもしれません。

他に何か良い方法は無いかなと考えたところ、slack のグループがあったらいいのかもと思いました。

Kotlin を始め、メジャーなテーマでは既に slack の公開グループがいくつかありますが、Plugin 開発は無さそうでした。 今後も勉強会やもくもく会でコミュニケーションが円滑になったり、継続して情報交換が出来るようになればいいなと思い、Plugin 開発をテーマとした slack グループを作成しました。

だいぶニッチかもしれませんが、興味ある方は誰でも参加可能ですので、もしよろしければ以下のリンクから参加申請してみてください。

IntelliJ Plugin Developer への参加申請リンク

勉強会 or もくもく会の方も、都合が悪く参加出来なかった方もいらしたので、ぜひまた次回開催できればいいなと思っています。

Rx Ja Night 2016 #1 に参加しました

最高のイベントでした。 RxJavaがメインではありましたが、他のReactiveXでも適用できる内容だったと思います。

主催の @fushiroyamaさん 、発表者のみなさま、会場を提供してくださったVOYAGE GROUPさま、ありがとうございました!!

15分セッション

1. 実際のアプリ開発で使った Rx を紹介 ( bl_lia さん)

2. ReactiveX のドキュメントにある図の見方の解説 ( yanzm さん)

3. RxJava + Vert.x + jOOλ で Microservice 的な何かを作ってみた(業務的に)( chimerast さん)

4. Tapping Retry ( hydrakecat さん)

10分LT

1. Subject 入門 ( fushiroyama さん)

2. iOS の Reactive 系ライブラリ ( wm3 さん)

3. TestSubscriver ( yuyakaido さん)

上記以外で参考になったこと

みんな新しい Operator を試すときにどうやってるのかなーと思ったのを聞いてみたところ、RxJava だと IntelliJ で Java のプロジェクトを作って、その中でミニマムな実装で動きを確認するという話しを聞きました。

他にも RxSwift だと playground で試せるっぽい話も。

まとめ

個人的に今日心に焼き付けたいことTOP3です

  • marble diagram で operator をしっかり理解しよう
  • テスト書こう
  • retryWhen 便利っぽいので使いこなせるようにしよう

DroidKaigi2016にスタッフ&スピーカーとして参加したのでKPTしました

DroidKaigiの運営では、2015のときもそして今回もイベント終了後に全員でKPTによる振り返りを行っています。 それにあやかって、僕個人に対してもKPTをしてみようと思いました。

Keep

  1. 発表のシミュレーションを繰り返し行う
  2. 事前にイベント会場を下見する

1については、今回初めて50分という持ち時間に挑戦しました。これまでは30分が最長だったため、資料を作っていても時間配分のイメージが全く湧きませんでした。細かい内容は今までの経験上、当日ちょっと変わる可能性もあったので、大まかにですが全体を流すように発表のシミュレーションをするようにしました。

シミュレーションをすることで、資料を作っているときには気づけなかった点に気づくことができ、資料にメリハリをつけられるようになったと思います。1つ注意点としては、いろんなところが気になってしまい、何度もシミュレーションと修正を繰り返し、無限に時間が吸われていったことです。

2は、スタッフとしての視点です。一応念のためくらいの軽い気持ちで、2週間ちょっと前くらいに他のスタッフと一緒に会場の下見に行ったのですが、今思うと行っておいて大正解だったなという感じです。

当日朝の集合時間が早かった(朝8時現地集合)のですが、会場までの道のりは経験済みだったため余裕を持って移動できたし、イベント中も会場となる大学内を1人で移動するのも不安はありませんでした。イベント1ヶ月前とかまでは、誘導担当でも無いし下見しなくていいかなと考えていましたが、下見は重要でした。

Problem

  1. スタッフとスピーカーの兼任はリソース配分をよく考える
  2. 備品はケチらない

1はそもそも兼任しないのがいいなという結論なのですが、それでも兼任するならどうすれば良かったのかを書こうと思います。 当たり前と言えば当たり前ですが、イベント日が近づくにつれ、スタッフ業務もどんどん忙しくなっていきます。時には予定外の作業も発生します。そのときに資料作成も佳境に入っていたのでは、睡眠時間を削るしかなくなっていきます。(実際にそうでした。)

ではどうするべきだったか。スタッフ業務の忙しさは自分ではコントロールできないので、資料作成のピークをスタッフ業務のピークと反比例するようなスケジュールを立てるべきだったと思います。今だから言えることで、実際にやるのは大変そうですが...。

2については、僕は今回のDroidKaigiで各会場で使用する電源タップの発注を担当したのですが、全体の約半数を型落ちの安価な品で購入しました。一応販売会社のレビューとかもチェックして、粗悪品を掴まないようにと気にしてはいたのですが、現実には安価な方の2個が初期不良で、別の2個がイベント中に大破するという結果でした。

もう半数の品は1個も壊れることなくイベントを終えたので、まさに「安物買いの銭失い」を地でいってしまうことになってしまいました。必要なものは、きちんと相場と同程度の金額を掛けるのが安心だと思いました。(幸い別のスタッフが1日目終了時に、電源タップを追加購入してくれたおかげでイベントに支障はでませんでした。)

Try

  1. 海外スピーカーの方に質問する

これは本当は今回のDroidKaigiで挑戦したかったのですが、完全に自分自身をコントロールできなくなって資料作成とスタッフ業務で手一杯となって、英語学習が日に日に疎かになったため、実行する勇気が出ませんでした。 ただ今回、スタッフとして海外スピーカーと接する機会があったのに、「Yes」しか言えなかった悔しい体験をしたので次こそは...。

他にもTryな項目を考えたのですが、次回スピーカーをやりたいのかスタッフをやりたいのか、まだ全然決められないので、今の時点としては1つだけにしました。

まとめ

Problemにも書きましたが、もし次のDroidKaigiがあって関わりたいのであれば、スタッフとスピーカーはどちらかにして、今回の教訓を活かしてもっとクオリティの高いアウトプットをしなければいけないなと思いました。

最後になりましたが、素晴らしいスタッフの面々と一緒にDroidKaigi2016に携われたことが、とても嬉しいです。本当にお疲れ様でした!&ありがとうございました!

f:id:androhi:20160219202842j:plain

@mgmix5さんの写真より

0 から Android アプリ開発を学びたい人へ

先日「Androidアプリ開発って、どうやって勉強したらいいですかね?」という質問を受けたので、そのときに話した内容に少し追加して、まとめてみました。

ネット上の情報だと断片的で、体系的な学習に使えそうなものが少ないですし、書籍だと何を買ったらいいか選ぶのも難しく、かつ値段も高いという悩みが多いと思います。そのあたりの敷居を下げつつ、きちんとした内容で学習できそうなものを、独断と偏見でピックアップしました。

続きを読む

"WebエンジニアのためのiOSデバッグ速習会"で学んだことのまとめ

WebエンジニアのためのiOSデバッグ速習会@Wantedly に参加してきたので、内容を忘れないようまとめました。

wantedly.connpass.com

参加者は事前に Xcode を自分の PC にインストールしておき、講師の人が説明した後に実際に手を動かして確認していく、というスタイルでした。

また速習会中は、Sync を使って参加者同士がコミュニケーションを取るというのは、独特で面白かったです。

講師は @hedjirog さんでした。

やったこと

講師の方が資料を用意してくださったので、それに沿って以下のようなことをやりました。

テーマは iOS アプリのデバッグです。 使用したのは Xcode 7.1.1 です。

  1. 題材アプリ Artsy のインストール
  2. ブレークポイントを配置して任意のコードで実行を止める
  3. ビューデバッガでビュー構造からクラスなどを特定する
  4. chisel を使って LLDB コマンドでデバッグする
  5. ExceptionBreakpoint でアプリのクラッシュをデバッグする

おまけ: PonyDebugger を利用して通信内容を確認する

題材アプリ Artsy のインストール

デバッグ対象とするアプリは OSS で公開されている Artsy を使いました。 README にも書かれている通り、以下の手順でインストールできます。(結構時間かかります。)

git clone https://github.com/artsy/eigen.git
cd eigen
bundle install
make oss
bundle exec pod install
open Artsy.xcworkspace

注意点として普段 Ruby を使っていない PC だと、bundler がインストールされていないかもしれません。 そのときは、以下のコマンドでインストールされているか確認し、

gem contents bundler

見つからなければ、以下のコマンドでインストールします。

gem install bundler

パーミッションで怒られたら管理者権限で実行します。

sudo gem install bundler

Breakpoint を配置して任意のコードで実行を止める

普段何かしらの IDE を使っていれば、おなじみのデバッグ方法ですね。

Breakpoin の配置は、行番号のあたりをクリックするだけです。セットした Breakpoint は、左側の Breakpoint Navigator にリスト化されていきます。

f:id:androhi:20151127170505p:plain

さらに Xcode の場合は、セットした Breakpoint に任意のコマンド実行などを追加出来るとのこと。

これを使えば Breakpoint に到達したときに、音を鳴らすとかも簡単に出来るようです。

f:id:androhi:20151127170537p:plain

Breakpoint の削除は、Breakpoint をドラッグして離せば消えます。

ビューデバッガでビュー構造からクラスなどを特定する

ビューデバッグを開始(アプリ実行中にカルーセルみたいなボタンをクリック)すると、IDE 内にビュー構造を表したオブジェクトが立体表示出来ます。 (iOS エンジニアの人に聞いたら、割りと最近追加されたものらしいです。)

f:id:androhi:20151127170818p:plain

f:id:androhi:20151127170608p:plain

UI をクリックすると、その UI が何のクラスなのか分かります。そして、右側にはそのコンポーネントの詳細な情報が、確認出来るようになっています。

f:id:androhi:20151127170801p:plain

似たもので Reveal という、有償のビュー構造解析ツールがあるようです。(そっくりですね。こっちの方がサクサク動くらしい。)

AndroidStudio にも、この機能欲しいですね。

chisel を使って LLDB コマンドでデバッグする

chisel というデバッグツールがあるとのことです。 facebook 社が OSS として公開しています。

Chisel is a collection of LLDB commands to assist debugging iOS apps.

これを活用したデバッグ方法です。(*1

chisel は Homebrew でインストールできます。

brew update
brew install chisel

chisel を使うには、設定ファイルが必要です。ホームディレクトリ下に、 .lldbinit というファイルが無ければ作成します。 .lldbinit ファイルには、以下を記述しておきます。

command script import /path/to/fblldb.py

/path/to の部分は環境によって変わります。自分の環境下でのパスを確認するには、以下で出力されます。

brew info chisel

chisel を使う手順は、アプリを実行したら || ボタンで止めて、コンソールでコマンドを実行します。 コマンドの説明は chisel の README に載ってます。

今回試したのは、以下のコマンドです。

pviews

コマンドを叩くと、以下の様なテキストベースのビュー構造を返してくれます。 (長いので途中省略しています。)

<ARWindow: 0x7fdf40c1e960; baseClass = UIWindow; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fdf40c20e30>; layer = <UIWindowLayer: 0x7fdf40c1c760>>
   | ARTopMenuViewController:0x7fdf40d17cb0 1c.[ARNavigationController 0x7fdf41890000: ] <UIView: 0x7fdf40e3af30; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x7fdf40cc4ae0>; layer = <CALayer: 0x7fdf40e78c70>>
   |    | <UIView: 0x7fdf40ebb230; frame = (0 621; 375 46); layer = <CALayer: 0x7fdf40ebb3a0>>
   |    |    | <ARNavigationTabButton: 0x7fdf40eaed20; baseClass = UIButton; frame = (0 0.5; 46 45.5); opaque = NO; layer = <CALayer: 0x7fdf40ea9e30>>
   ...
   |    |    |    |    | <UIImageView: 0x7fdf40c1f910; frame = (10 10; 20 20); clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO; layer = <CALayer: 0x7fdf40c55750>>
   |    |    |    |    | XX (<UIButtonLabel: 0x7fdf40d1f100; frame = (20 10.5; 0 19); hidden = YES; opaque = NO; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x7fdf40d10790>>)
   |    | XX (<NPKeyboardLayoutGuide: 0x7fdf40ec8e90; frame = (0 667; 0 0); hidden = YES; layer = <CALayer: 0x7fdf40ec7a60>>)

f:id:androhi:20151127170939p:plain

taplog

コマンドを叩くと、シミュレーター(もしくは実機)がアクティブになります。

この状態でアプリ上のどこかをタップすると、そのイベントの開始位置で再び止まり、エディタには該当のコードを表示してくれます。

f:id:androhi:20151127170956p:plain

border

コマンドの後に、UI コンポーネントのアドレスを渡してあげると、シミュレーター(もしくは実機)の該当する UI 部分が赤枠で囲われます。

f:id:androhi:20151127171016p:plain

ExceptionBreakpoint でアプリのクラッシュをデバッグする

アプリがクラッシュしたときに、以下のように通常コンソールに出力される情報だけでは、発生元を特定するのが大変です。

f:id:androhi:20151127171042p:plain

そういうときは ExceptionBreakpoint を使うと、例外が発生した箇所で実行を止めてくれるとのことです。

使い方は、左側の Breakpoint Navigator に切り替え、アプリを実行させます。 その状態で、左下のプラスボタンから「Add Exception Breakpoint...」をクリックし、ExceptionBreakpoint を設定します。

f:id:androhi:20151127171101p:plain

実際にクラッシュを起こすと、以下のように例外が発生した場所のコードが表示され、そこで実行が止まります。

f:id:androhi:20151127171115p:plain

PonyDebuggerを利用して通信内容を確認する

Square 社が OSS で公開している PonyDebugger という、iOS 用の通信デバッグツールとのことです。

Remote network and data debugging for your native iOS app using Chrome Developer Tools

これは時間が足りず試せませんでした。 GitHub の README を見れば分かりますが、ブラウザで通信のリクエストやレスポンスが確認出来るようです。 数行アプリにもコードを書かないと行けないので、導入するときは一手間必要そうですね。

(ただ Android アプリ開発も行う人とかは特に、charles とか wireshark とかのツールで、両方ともカバーした方が便利かなと思いました。)

まとめ

  • 特定のコードでアプリを止めたい時は Breakpoint を設定する
  • Breakpoint はアクションを追加できるので必要に応じて活用する
  • UI まわりはビューデバッガを使うと便利
  • より細かいデバッグには chisel を活用すると便利
  • クラッシュ発生源の特定には ExceptionBreakpoint を使う

個人的な感想として僕は普段 Android アプリの開発がメインで、IDE は AndroidStudio を使うことが多いのですが、View まわりのデバッグXcode の方が良く出来てるなと感じました。

余談

懇親会中 wantedly 社の方にオフィスを案内してもらったのですが、とにかくお洒落すぎて素敵なオフィスでした。会議室の名前が全部ジョジョのスタンド名で、とにかくかっこいいです。

それとこちらで販売してる wantedly パーカーいいですねっていう話しになったのですが、高いだけあって物がいいらしいので気になってきました。

*1:なお chisel については、こちらのブログが詳しいようです。 yidev@恵比寿勉強会 で chisel について発表してきた (動画付き)

API level 23 未満を考慮した指紋認証 API の実装

前回、指紋認証 API のサンプルコードをざっと見てみたのですが、そのときに FingerprintManagerCompat クラスが Support Library v4 にあるのを見つけました。

androhi.hatenablog.com

このクラスを使えば Android 6.0 (API level 23 未満) も含め、スッキリと実装できるんじゃないかなと思い調べてみました。

FingerprintManager のインスタンス取得

前回のGoogleのサンプルコードでは、以下のようなコードでインスタンスを取得していました。

FingerprintManager manager = context.getSystemService(FingerprintManager.class);

ところが以下の2点で API level 23 未満では、getSystemService() 経由だと使えません。

  1. Context.getSystemService(Class<T>)API level 23から追加されたメソッド
  2. Context.getSystemService(String) だと引数のサービス名に Fingerprint は無い

そのため FingerprintManagerCompat では、別途 Context を使った方法が用意されていました。

// contextはActivityなど
FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(context);

FingerprintManagerCompat のソースコードを辿って行くと、内部で Build.VERSION.SDK_INT をチェックしていて、23 以上だと Api23FingerprintManagerCompatImpl 内部クラスを、23 未満だと LegacyFingerprintManagerCompatImpl 内部クラスを、それぞれインスタンス化していました。

指紋センサーの判定など

FingerprintManager では、端末に指紋センサーのハードウェアがあるか?や、指紋の登録があるか?などを判定するメソッドを提供しています。

まったく同じメソッドが、FingerprintManagerCompat クラスにも実装されていますが、どのような挙動になるのか確認してみました。

結論から書くと、API level 23 以上だとちゃんと FingerprintManager 経由で判定し、23 未満だと固定で false を返していました。

API level 23 未満

    private static class LegacyFingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {

        public LegacyFingerprintManagerCompatImpl() {
        }

        @Override
        public boolean hasEnrolledFingerprints(Context context) {
            return false;
        }

        @Override
        public boolean isHardwareDetected(Context context) {
            return false;
        }

        ...
        }
    }

API level 23 以上

    private static class Api23FingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {

        public Api23FingerprintManagerCompatImpl() {
        }

        @Override
        public boolean hasEnrolledFingerprints(Context context) {
            return FingerprintManagerCompatApi23.hasEnrolledFingerprints(context);
        }

        @Override
        public boolean isHardwareDetected(Context context) {
            return FingerprintManagerCompatApi23.isHardwareDetected(context);
        }
        
        ...
public final class FingerprintManagerCompatApi23 {

    private static FingerprintManager getFingerprintManager(Context ctx) {
        return ctx.getSystemService(FingerprintManager.class);
    }

    public static boolean hasEnrolledFingerprints(Context context) {
        return getFingerprintManager(context).hasEnrolledFingerprints();
    }

    public static boolean isHardwareDetected(Context context) {
        return getFingerprintManager(context).isHardwareDetected();
    }
    
    ...

分かりやすくいいですね。

指紋認証

実際に指紋センサーから指紋を読取るときは、 FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) メソッドを使ってましたが、これも先ほどと同じ形でした。

API level 23 以上では、FingerprintManager 経由で処理し、23 未満では何もしません。

API level 23 未満

    private static class LegacyFingerprintManagerCompatImpl
            implements FingerprintManagerCompatImpl {
        ...

        @Override
        public void authenticate(Context context, CryptoObject crypto, int flags,
                CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
            // TODO: Figure out behavior when there is no fingerprint hardware available
        }
    }

API level 23 以上

    private static class Api23FingerprintManagerCompatImpl implements FingerprintManagerCompatImpl {
        ...
        @Override
        public void authenticate(Context context, CryptoObject crypto, int flags,
                CancellationSignal cancel, AuthenticationCallback callback, Handler handler) {
            FingerprintManagerCompatApi23.authenticate(context, wrapCryptoObject(crypto), flags,
                    cancel != null ? cancel.getCancellationSignalObject() : null,
                    wrapCallback(callback), handler);
        }
public final class FingerprintManagerCompatApi23 {
    ...
    public static void authenticate(Context context, CryptoObject crypto, int flags, Object cancel,
            AuthenticationCallback callback, Handler handler) {
        getFingerprintManager(context).authenticate(wrapCryptoObject(crypto),
                (android.os.CancellationSignal) cancel, flags,
                wrapCallback(callback), handler);
    }

まとめ

当分 API level 23 以上でアプリを開発出来る状況は来ないので、開発しているアプリに指紋認証を導入したいときは、この FingerprintManagerCompat を使うのが良さそうです。

今まで割と自力で API level 判定して処理を分けていたようなところも、xxxCompat クラスがいい感じに内部で切り替えてくれるケースが増えてきた気がします。

新しい機能が出てきたら、まずは xxxCompat クラスも一緒に探すと、既存アプリへの導入が楽になりそうですね。