SwiftUI製のiPhoneアプリをReact Nativeに移行した
僕が日曜開発しているプロジェクトに、自分の家族内で使う家庭内iPhoneアプリがある。
そもそもその存在についてブログに書いたことが無かったのだが、もともとはかなり昔にKyashがクレジットカードから送金できなくなった1とき、その機能に頼っていた家庭内のお金のやりとりの移行先として自前で用意したものだ。
家庭内(擬似)送金アプリの開発をやらさ^H^H^Hすることになりそう
— Hirokazu NISHIOKA (@nisshieeorg) August 28, 2020
Twitterを遡ってみると、2020年の後半に開発を始めていたらしい。
サーバサイドにRust + GraphQL + CQRS-ESを、クライアントサイドにSwift + SwiftUIを採用して、PS5で遊びながら作ったようだ。
合間時間に、PS5に時間吸われたりしながらちまちまと開発して、ようやく使えるぐらいになったかなー https://t.co/wJJaOuyKvy pic.twitter.com/KVhUO9uL7R
— Hirokazu NISHIOKA (@nisshieeorg) November 30, 2020
機能を追加したり調整したりしながら2年弱運用してきたわけだが、この度、クライアント側をReact Nativeでフルスクラッチで作り直した。ので、その感想なんかを記しておこうと思う。
なぜReact Nativeに移行したのか
予め断っておくが、「SwiftUIよりReact Nativeの方が優れている!!」みたいな理由ではない。
いや、まぁ正直に言うと、SwiftUIの「なぜか構造体のinitで与えるプロパティとmutableメソッドコールで与えるプロパティがあって、その違いはよくわからん」という点について愚痴を言うことはあるけれども、だからSwiftUIは駄目だとか言う気はない。
ではなぜReact Nativeにしたかというと、1つはいつもの「やってみたかったから」ではあるが、今回は、「業務でReact使っているし圧倒的に慣れているから」である。あまり面白くなくて申し訳ない。
ただ、どうしても「アプリの構造をガッツリ作り直したいなぁ」と思ったときに、SwiftUIに慣れてなすぎて「どこでどうやってstateを保持して、どれを反映させて画面を遷移させてるんだっけ?」みたいなのがパっと分からなかったり、BindingとかObservableObjectとか忘れてて、「こんな感じだっけな?」って雰囲気で書いてみても思ったように動かなかったりする。普段から触ってないからしょうがない。フレームワークなんてそんなもんだ。
でもWebのReactは普段から触っているので、何をどう書いたらどうなるか、動かさなくてもだいたい想像できるぐらいには練度が高い。日曜開発なので慣れていないものに触るという素振りも大事だが、今回のアプリに関しては、「普通に家庭内で使っていて、普通に運用や改善をしたい」という要求を満たすために、効率も取りたかったというわけだ。
よかったこと
めっちゃ早く作り替えが完了した
だいたい検証1週間、開発2週間ぐらいで、React Native製の方を稼働に乗せた。一部まだ機能を作っていなかったり(初回サインアップをまだ作ってない・・・)、使ってないから省いた機能なんかがあったりするし、そもそも作るもの次第で2週間てのが早いか遅いかわからんとは思うがw ただ、やり始める前に僕が想定していたよりはずっと早いのは間違いない。
やってみて、やはりWeb Reactの練度をそのまま活かせたという感覚が非常に強い。
- 認可情報をContextに入れてComponentから取得して使う構成なんかは、完全にWebと同じ設計を持ち込んだものが想定通りに動いて感動した
- Apollo Clientのインメモリキャッシュ表示、
loading
の表示、mutation時のキャッシュ更新なんかもそのまま使えた- むしろ前バージョンではキャッシュ機構を利用しなかったのでこの点はユーザビリティの改善にもなった
ただし、React Navigationだけは事前にドキュメント読み込んだり検証したりして設計方針をある程度固めた。これは奏功したと思う。
「なんか思うように動かんなぁ」みたいな時間浪費をしたのは、React Native Flex Layoutぐらい。
あと、React Native関係ないところも一応挙げておくと、サーバサイドをしっかり作ってるからというのはある。GraphQL上の型をそのままFragmentにしてTypeScript上の型に落とし込めが基本うまく行くのはAPI設計次第だというのが良く分かった。
さくっと運用投入できた
GraphQLの認証に使うトークンは、前バージョンではKeychain Swiftを使っていたが、その値をreact-native-keychainで読めた。
なので、前バージョンをv1.0、新バージョンをv2.0にしておけば、両方共TestFlightで有効になり、もし新で不具合があってもv1.0に戻すだけですぐ使えるようになることを保証できた。
エディタに縛られなくなった
XCodeでコード書きたいWebエンジニアおらんやろ(主語デカ暴言)
よくなかったこと
ビルド時間が増えた
しょうがない・・・
Intel macは寿命か・・・?
ビルド中はクリスタルコンフリクトをしている。
インストールサイズが増えた
これも仕組み的には仕方ない。ちなみにインストールサイズで、SwiftUI: 約2.4MB、React Native: 約7.8MBだった。とは言っても機能がとても少なくアプリアイコン以外のアセットは含まない本アプリでこの程度の差なので、実質気にならないんじゃないかな。
クロスプラットフォームにはならなかった
前バージョンと比べて悪化はしていないが、React Nativeでもクロスプラットフォームにはならなかったというかしなかった。
いや、やろうと思えばできるかも、という気はするぐらいにはReact Nativeがんばってると思う。でも家族にはAndroidユーザいないからね・・・
一応、Windows + WSL2で開発できると嬉しいというのはあるのでそのうち挑戦してもいいとは思うけど、動作確認やリリース作業はmacでやるしかないので、そこまで乗り気ではない。
まとめ
- SwiftUI製の家庭内アプリをReact Nativeに移行した
- 総じて、良かった
- これから、ユーザビリティ向上のためにアプリに改善を加えていく予定なので、それが良い感じかどうかはまた後日
Footnotes
今どうなったかは知らないのでご注意を。 ↩