現在地共有サービス第2弾を作った。

https://user-images.githubusercontent.com/11763113/37872124-f2a6d84c-303b-11e8-9ce8-319e818eee96.png

 

以前、 imakaraでやりたかったことなど - YusukeIwakiのブログ で作っていたものをベースに、

  • Androidアプリ側はKotlinを使ってみよう
  • サーバーサイドはRailsじゃなくてFirebaseで済ませちゃおう

ということをやってみたく、作ってみた。

github.com

github.com

Firebase Realtime DatabaseとFirebase Functions/Hostingがあれば趣味のアプリは大抵作れてしまう

imakaraでは練習目的でRailsでサーバーサイドを実装していた。サーバーサイドがRailsだと当然、Androidアプリ側も、

  • APIクライアントを実装したり
  • 非同期処理をいい感じにやったり

などなど、わりとお決まりの骨が折れるコードをいっぱい書かないといけなかった。

しかし、今回、Firebase Realtime DB + Firebase Functions/Hosting でやってみて衝撃。APIクライアント(というかHTTPクライアント)を一切使うことなくWebアプリが作れてしまった。 ざっくりどんな構成になってるか説明してみようと思う。

Androidアプリ側でGCMトークンが取得できたタイミングで、FirebaseUserIDに紐づけてDBに保存

f:id:YusukeIwaki:20180326223618p:plain

実装的にはこのへん: imacoco-android/DeviceRegistrationManager.kt at 10d3d22bcba4a71e6dd973d700e70a43e28d8de9 · YusukeIwaki/imacoco-android · GitHub

アプリで「FirebaseUserIDに紐づけてDBに保存」されたのをFirebase Functionsでリモート監視して、そのレコードに共有用URL値を付け加える

f:id:YusukeIwaki:20180326224943p:plain

実装的にはこのへん: imacoco-firebase/index.js at fa330011380bc6047b3c22a11f1a727419ecbb83 · YusukeIwaki/imacoco-firebase · GitHub

Androidアプリ側で、共有URLをリアルタイムに表示する

f:id:YusukeIwaki:20180326225929p:plain

実装的にはこのへん: imacoco-android/OverviewActivity.kt at 10d3d22bcba4a71e6dd973d700e70a43e28d8de9 · YusukeIwaki/imacoco-android · GitHub

共有用URLにアクセスが来たら(中略)測位要求を送る

f:id:YusukeIwaki:20180326231558p:plain

Firebase HostingでGoogleMap1枚ぺらのページを返す。ついでに、Realtime DBの位置情報をリアルタイムにsetCenter。さらについでに、マップのロード時に裏でこっそりFCMプッシュを送ってて、測位して下さいねー!ってAndroidアプリ側に要求がいくようになっている。

実装的にはこのへん: imacoco-firebase/index.html at fa330011380bc6047b3c22a11f1a727419ecbb83 · YusukeIwaki/imacoco-firebase · GitHub

Androidアプリ側でプッシュを受けたら、ワンショット測位して結果をDBに書く

f:id:YusukeIwaki:20180326232403p:plain

実装的にはこのへん: imacoco-android/OneShotPositioningService.kt at 10d3d22bcba4a71e6dd973d700e70a43e28d8de9 · YusukeIwaki/imacoco-android · GitHub

 

 

 


・・・というかんじで、リアルタイムDBに必要な情報は全部載せてしまって、あとはFunctionsでボットスクリプトみたいなのを書いてHostingで入り口を作れば趣味のアプリはできてしまう。

もう趣味でRails書く気は全く無くなってしまった。困った。

フレッツ光 "隼" とプロバイダ

まえおき

引っ越した。

マンションタイプのが安いよーってNTTのほうから提案があったので、それに乗り換えた。

開通工事が終わって、ネットが繋がった。

・・・あれ?

今までつかってたルーターのままでは繋がらなくなった。

・・・試しに、みんな大好きWindows PCからルーターを介さずPPPoE接続を試みた。

Connection failed 651

・・・。

・・・・・・・

おかしい!!

悩んだ3時間

最初はNTTに騙されたのかとおもったけど、ルーターのログを見るとconnectは完了してCHAPでコケていた。つまりプロバイダがおかしいということになる。

とはいえ、プロバイダは何も変えていない。

かれこれ3時間くらいパスワード変更してみたりルーターの設定変えてみたりいろいろやった。

・・・つながらん。

解決!

だめもとで、Windowsの接続エラーのぐぐってみた。

「gmobb 651」

f:id:YusukeIwaki:20180228023046p:plain

【GMO】GMOとくとくBB総合 その10 [無断転載禁止]©2ch.net

ここでようやく という文字が、NTTからの開通のお知らせあることに気づく。

そう、今まで使ってたフレッツ光ネクストとは別物の回線に変わっていたのだ!!

 

ということで、プロバイダの方を の専用のプラン(200円くらい高い)に切り替えてみた

f:id:YusukeIwaki:20180228022434p:plain

 

こうして今おれはブログを書いている。

結論

サービス名、もっとわかりやすくしてくれ

Kotlin歴が1ヶ月で、「あ、これは便利かも」と思えたKotlinの用法

まえおき

Kotlin歴が一週間の自分が、Kotlinのコードをレビューするときに指摘していること - YusukeIwakiのブログ を書いたあと、 id:suzan2go からコメントをいただいて、

Idiomatic Kotlin. Best Practices.

のページの存在を知ることになった。

業務でも「新しく作っていくものはKotlinで!」ってなったので、本格的に触り始めた。実際さわりはじめて「お!これはKotlinがいいかも」って思えてきたものを幾つか紹介してみる。

ちなみになんだかんだでJavaのほうがIDEが(速度的に)優秀なので、わりとJavaで書いてKotlinに変換してるんだけど、それは内緒。

SharedPreferenceをDelegated Propertyでread/writeする

「×ボタンを押したら二度と出さないようにする」みたいな制御をやるときには、かんたんなキャッシュとしてSharedPreferenceをささっと使いたい。ただ、経験上、SharedPreferenceは「ラッパークラスを作れば作るほど複雑化して、結局SharedPreferenceを生で使うのが一番いい」ということになりがちだった。

けど、KotlinのDelegated Propertyで、BooleanPref, StringPref, IntPref, LongPref, ... などなどうっっっっすーーーーーーいラッパークラスを用意してやることで

class HogeCache(val context: Context) {
  private val prefs get() = context.getSharedPreferences("hoge", Context.MODE_PRIVATE)

  var dontShowBanner: Boolean by BooleanPref(prefs)
}

みたいなクラスを作って

class HogeActivity: Activity {
  override fun onCreate(savedInstanceState: Bundle?) {

    ...

    buttonCloseBanner.setOnClickListener { _ ->
      hogeCache(this).dontShowBanner = true
    }

    if (hogeCache(this).dontShowBanner) {
      buttonCloseBanner.visibility = View.GONE
    }

みたいに書けるようになった。

github.com

可読性が上がって良いと思うので、適当にライブラリ化もしてみた。

(世の中には、↑をもっと汎用的にした chibatching/KotPref というライブラリもあったりする)

JSONArray#forEachを拡張関数で定義する

for (int i = 0; i < jsonArray.length(); i++) {
  JSONObject jsonObject = jsonArray.getJSONObject(i);

    ...
}

をKotlinでバカ正直に書くと

for (i in 0 until jsonArray.length()) {
  JSONObject jsonObject = jsonArray.getJSONObject(i);

    ...
}

みたいになる。

悪いコードじゃないんだけど、これでは可読性がやや低いと思う。

fun JSONArray.forEach(action: (JSONObject) -> Unit) {
  for (i in 0 until length()) {
    action(jsonArray.getJSONObject(i));
  }
}

という拡張関数を定義しておけば

jsonArray.forEach { jsonObject ->
  ...
}

のようにスッキリ書けて、可読性が上がる。

まだ試したことはないけど、ViewGroupとかでも同じことが言えると思う。

 

 

まとめ

Kotlinは「○○みたいなときには便利」みたいなしくみがアホみたいにたくさんある。

相変わらずKotlinは嫌いだけど、少しずつ勉強していくと可読性の高いコードが書けるようになっていきそう。