SimpleAppsシリーズ(仮称)始めました
お久しぶりの投稿になります。中川@Nkznです。
近年は弊社メンバーの主戦場がQiitaになってきており、こちらの更新をする頻度が減ってきておりました。
(EXCEL・R勢の更新頻度が高いのでWeb・モバイル勢も頑張ろうな……!)
今回は会社色の強い内容になったため、久々にこちらを稼働させることにしました。
SimpleAppsシリーズ(仮称)とは
※React Nativeにしか興味が無い人は読み飛ばしてください
特定の小さいドメイン(使用目的)に寄り添った小機能なアプリです。社内的には「単機能アプリ」と呼んでいることが多いのですが、味気ないので一部ではSimpleAppsと呼ばれています。
費用対効果の高い新事業を模索する一環として始まった、社長直轄プロジェクト*1です。
今回は次の3つのアプリをAndroidとiOSそれぞれに向けてリリースしました。
- 水門アプリ
- 面積計算アプリ
- 距離計算アプリ
これらのアプリがどんなモチベーションで作られたのか、ご紹介していきます。
水門アプリ
稲作農家にとって、水管理は収穫量や味を左右する重要なファクターです。水門の開け閉めによって、水位や水温の調整を行い、稲の順調な生育を促します。
しかし人間は忘れる生き物です。水門の開け忘れや閉め忘れにより、水位が過剰になったり、田んぼが干上がってしまったりする事故は往々にして起こってしまいます。
このアプリはそういったミスを防ぐために、水門の位置と開閉状態をマップ上でメモする備忘録です。
- スクリーンショット(Android / iOS)
面積計算アプリ
近年は農業人口の減少に伴い、経営体としては集約され、ひとつひとつの農業生産組織は大規模化しています。近年では500筆や1000筆の農地を管理する組織も珍しくありません。
農薬や肥料を散布する際には、「反あたり○○リットル」(反≒10アール)のような数字を目安にして、分量を決定します。つまり、農地の大きさが分からないと、その日どのくらいの量の農薬や肥料を納屋から持ち出せばいいのか決定できません。
ここで問題になるのが、農地の数です。500も1000もある農地の面積をいちいち覚えていられません。ベテランの農家さんになると結構覚えている方もおられるので、人類すごいな~と思うこともありますが、限界がありますよね。
この課題を真っ向から解決するのが、農地管理Webアプリのプロトタイピングをスタート地点として始まったアグリノートです。
農地管理に困る農家さんすべてにアグリノートを使っていただければ、現場でもモバイルアプリを使って農地面積を確認していただけるのですが、既に他所様の農業ICTサービスを使っている方には難しい選択肢です。
こういった背景から、農家さんがふと農地の面積を知りたくなったときに役立つ面積計算のアプリを作りました。
類似のアプリはたくさんあるのですが、面積の単位を換算する際の選択肢に「a(アール)」と「反(10アール)」と「町(1ヘクタール)」があるアプリは滅多にないのではと自負しております。
- スクリーンショット(Android / iOS)
余談になりますが、いろいろ面積を測って遊んでいたら、北海道の某所に、1筆で9ヘクタールを超えるとんでもない広さの農地を見つけました。噂によると10ヘクタール超えの農地もあるそうです。試される大地すごいですね。
距離計算アプリ
見た目は面積計算アプリから面積計算の機能を省いただけのものです(実装もそんな感じです)が、こちらはどちらかというと水門アプリに近いモチベーションで作られています。
「農家さん」という牧歌的なイメージを抱く言葉を使っていると忘れそうになるときもありますが、農業経営体は営利組織です。コストを下げ、利益を伸ばし、効率を追い求めること無関係ではいられません。
そんな中で、時間と人件費がかかる作業のひとつが「見回り」です。近年ではセンサーやカメラの設置などによって省力化が図られていますが、まだまだ普及は進んでいないように思います(※筆者の主観です)。水門アプリの主戦場でもある水管理においては、稲作農家の経営コストの30%近くを水門の見回りと開け閉めに関する労働費に費やしている方もおられるそうです。
見回りそのものが避けられないなら、せめてその経路だけでも短くできないか。そんな想いから、距離計算のアプリは生まれました。どんなルートで見回りをすれば軽トラの燃料を余計に使わずに済むのか、そんなコスト意識の高い農家さんに是非使ってほしいアプリです。
- スクリーンショット(Android / iOS)
技術的な話:React Native使ってみたよ
ここからはエンジニアブログらしい話です。
今回は「仕様も目的も小さいアプリなら数日で作れる?」というボスの無茶振りに敢えて応えてみるという、実験的な意味合いもあるプロジェクトでした。例によって、「AndroidとiOS両方ほしい」もセットでくっついてきますので、本来ならば工数が倍以上になる案件です。
技術選択(開発ツール)
- 作るアプリは3つ(うち2つは酷似)
- マップ使うならネイティブ一択でしょ(こだわり)
- 多少のリスクを払ってでもクロスプラットフォーム開発しよう
- Cordova + React + Redux + material-ui + cordova-plugin-googlemapsなら経験もあるけど、今回はもうちょっとチャレンジングな選択をしたいな
- アサインできるメンバーは2人
- Androidできる、iOS苦手、Reactできる、React Native経験あるマン
- Androidできる、iOSできる、React苦手、React Native興味津々マン
片方の人がReact Nativeをやってみたがっていたのと、このメンバーならReact Nativeのハマりどころを乗り越えられる素養をそれぞれが十分に持っているな、という判断もあり、React Nativeを採用してみることにしました。
弊社モバイルチームではReact Nativeとちょくちょく近づいたり離れたりしてきましたが、今回また近づいた形になります。これまでの評価や試行の歴史が気になる方は下記の資料を御覧ください。
www.slideshare.net
技術選択(ライブラリ)
実は技術選択と言えるほど選択肢がないので、スターが多めのライブラリをそれとなく選んでいきました。
react-native-maps
まずはメイン機能のマップ。Airbnbさんが作ってくれていたものを使いました。Android向けのPlay ServicesのGoogleマップと、iOS向けのMapKit、それからiOS向けのGoogleマップをサポートしています。
Realm
水門の配置情報や開閉状態の保存にはRealmを使いました。他のネイティブアプリで使ってみて良い感じに動いていましたし、JS版のインターフェースも好みだったので採用した形です。
JS側にオブジェクト定義を行うと永続化ができるのはもちろんですが、同じ型定義をJavaやObjC側に用意すると、ネイティブ側からもJSと同じDBに触れるという知見を得ました。もちろんJS<=>Java/ObjCの間でトランザクションを張れるわけではないので、ネイティブ側からはReadOnlyで扱っています。
react-native-router-flux
React Nativeでまだデファクトスタンダードが出てきていないのが画面遷移です。AndroidはActivityごと遷移するのに対して、iOSはUINavigationControllerやUITabBarControllerの中を差し替える形で遷移を実現するため、思想がかなり違っています。この差異を上手いこと埋めてくれるライブラリがまだ登場していないのです。
今回は色々触ってみてインターフェースが一番しっくりきたreact-native-router-fluxにしました。検証するのがもう少し後だったら、React Navigationにしていたかもしれません。
NativeBase
UIコンポーネントのライブラリがなにか欲しいと思い、とりあえず見た目が良さそうだったNativeBaseを採用しました。
実際にはIoniconとToolbarくらいしか使わなかったので、react-native-vector-icons+自作ヘッダーだけでもよかったかなあと思います。
react-native-firebase
Firebase Analyticsを使いたかったので、ネイティブのFirebaseライブラリをラップしているやつを入れました。インターフェースをJS版のFirebase SDKに寄せてあるのと、ちゃんとFirebaseのほぼ全サービスをサポートしてくれているのが気に入りました。水門アプリでは将来Firebase Databaseを使う予定があるので、そのへんも見据えて導入しています。
本当はAnalyticsのみを入れたかったので、全モジュールが入ってしまう仕組みは少し不満でした。
スケジュール振り返り
スピード感を共有するために、これまでの出来事を振り返りたいと思います。
日付 | 出来事 |
---|---|
4月16日 | ボスから無茶振りをもらう |
4月17日 | 無茶振りをメンバーに伝える |
4月18, 19日 | ひととおりのライブラリで素振りしつつ、何となく作り始める |
4月21日 | 水門アプリがそれとなく動いたのでFabric Betaにデプロイして社内公開(v1.0.0-build0) |
4月24日〜5月1日 | ボスとやりとりしながら水門アプリのUIを微調整 |
4月28日 | 面積計算アプリがそれとなく動いた(v1.0.0-build0) |
距離計算アプリがそれとなく動いた(v1.0.0-build0) | |
5月1日 | 面積計算アプリ、距離計算アプリが実装完了(あとはストア向けのリソース準備のみ) |
5月2日 | 水門アプリv1.0.0完成、AppStore審査提出 |
水門アプリv1.1.0向けのアラーム機能を開発開始 | |
5月3日 | 水門アプリv1.0.0 AppStore審査通過 |
GW中 | おやすみ |
5月8日 | 社内調整が完了し、水門アプリv1.0.0をPlayストア、AppStoreにリリース |
5月9日 | 水門アプリv1.1.0のAndroid版が実装完了、iOS版の実装に入る |
5月12日 | 面積計算アプリv1.0.0完成、距離計算アプリv1.0.0完成、AppStore審査提出 |
5月13日 | 面積計算アプリv1.0.0 AppStore審査通過 |
5月15日 | 面積計算アプリv1.0.0をPlayストア、AppStoreにリリース |
距離計算アプリをv1.0.0をPlayストアにリリース | |
5月16日 | 距離計算アプリv1.0.0 AppStore審査通過、AppStoreにリリース |
水門アプリv1.1.0のiOS版が実装完了、AppStore審査提出(予定) |
こうして振り替えると、ボスの無茶振りから1ヶ月経ってたんですね。GWを挟んだので19営業日でした。面積計算と距離計算を担当したメンバーは途中で別の作業に移ってもらったので、実際の工数だと50人日くらいかなと思います。うーん、多いのか少ないのか。
マップやFastlaneでハマっていた時間がそこそこあったので、次に似たようなことをやるときにはもう少し短くできそうな気もします。
よかったこと
- やっぱり短期間で開発できた
- メンバーのスキルセットの苦手部分を触らざるをえない環境に放り込むことで、それとなく苦手意識を克服できた
- react-native-maps v0.14.0のドキュメント不備に戸惑う子羊たちを導いたり、闇に埋もれそうになったPullReqを救済できた
- 細々したUIの改善をしていくときにWrite Once, Run Anywhereできる部分が多くて助かってます
こまったこと
ちょっと多いので見出しを分けますが、ほとんどはネイティブアプリ開発で普通にありうる問題ばかりで、React Native固有の問題はほとんどありませんでした。リリースエンジニアリングを担当した筆者がiOS慣れしていなかったことで、CocoaPodsとxcodeprojの挙動に悩まされることが一番多かったと思います。
react-native-mapsがハマりやすかった
- react-native-maps v0.14.0で
react-native link
が動かなくなっていた- Androidは自力でネイティブライブラリの接続を行った
- iOSは存在しないファイルへのリンクが行われたり、必要なファイルが足りなかったりしたので調整した
- これが今回唯一のReact Native固有の問題だった
- react-native-mapsでiOS版Googleマップを使うためのガイドで示されたPodfileを参考にCocoaPodsを設定すると、「DebugビルドではxcodeprojにリンクしたReactライブラリが採用される」「ReleaseビルドではCocoaPodsが提供するReactライブラリとxcodeprojにリンクしたライブラリが両方採用される(落ちる)」という謎の挙動に見舞われた
- ガイドを無視して、Podfileで管理するライブラリをGoogleMapのみにし、その他のライブラリはxcodeprojにリンクして解決した
- iOSベテラン勢にもレビューしてもらったけど他の解決策が見つからなくて謎だった……
- 弊社はメンバーのiOS/Android力が高かったので乗り切れたが、リポジトリのIssueやPRが阿鼻叫喚になっていた……
リリースが大変だった
- この2週間でPlayストアとAppStoreに合わせて6つのアプリをリリースしたことになります
- ic_launcherとかAppIconとか、LaunchScreenとか、スクリーンショットとか、審査メモ作成とか、Crashlytics導入によるBeta配信とか、バージョン更新の半自動化とか、継続的デリバリーとか、etc...
- あまりに開発期間が短すぎて、上記のような普通なら「アプリケーションの開発をしているうちにのんびり済ませればいいリリースエンジニアリング作業」が、怒濤のようにに押し寄せてきました
- Fastlaneがなかったら死んでた
AndroidとiOSの差異に苦しんだ
- 水門アプリにアラーム機能を付けようとした
- 定時に水門の開閉状態をチェックし、開きっぱなし・閉めっぱなしのものがあれば通知を出す
- もちろんニッチすぎる機能なのでネイティブモジュールを自作した
- AndroidはGcmNetworkManager+NotificationCompatで自作できた
- iOSもiOS10縛りと引き換えに、User Notifications Frameworkで時限式のアラームを実現して自作した
- 解決したかに思われたが、User Notificationsはバックグラウンドプロセスを一瞬たりとも持たせてもらえないので、「定時に水門の開閉状態をチェック」ができない
- おそらく正攻法は「サーバー側で時刻を記録してプッシュ通知を行い、バックグラウンドプロセスを起動する」あたり
- 流石にプッシュ通知はコストが高すぎるのでパス
- ひとまずUser Notificationsの通知は定時に必ず出すことにして、それを押してアプリを開くと水門の開閉チェックが行われるようにした
不安なこと
- 今後のReact Nativeやライブラリ群のバージョンアップにどこまで追従できるか
- いつReact Nativeは1.0.0になるのか(あるいはv100.0.0くらいからスタートするのか)
やってみたくなったこと
- Web勢がReactを書けるので、UIのメンテに巻き込みたい(要Android/iOS SDK)
まとめ
- 小さい価値をたくさん提供していくSimple Appsシリーズ、今後もやっていけるといいですね
- React Native今のところ良いです
- iOSアプリのリリースエンジニアリング担当の人って大変なんだなあ……
*1:実は社長が付かない"代表取締役"なので当人は社長と呼ばれると嫌がるんですが、このほうが通りがいいので勘弁してください