Swiftで書いていたiOSアプリをReactNativeで書き直した

以前書いていた

h3poteto.hatenablog.com

iOSアプリをReactNativeで書き直した.なんのことはない,手持ちのスマートフォンAndroidに変えたので,アプリもAndroid対応をする必要があっただけなのだが.

github.com

流石にSwiftで作っていたUIをそっくりそのままは移せなかったので(頑張ればいけるかもしれないけど,そこまでやる必要ないでしょ),ちょっと変わった部分もあるが,基本的に仕様はほとんど変えていない. 割と面白い体験だったので感想を書いておく.

ReactNative意外と生きてるし動く

巷ではFlutterが話題で,あまり話を聞かなくなってきてしまったけど,普通に生きてるし普通に動く.

reactnative.dev

公式の手順に従ってセットアップすれば,かなり簡単にアプリ自体は立ち上がる.そして中身はマジでjsでありReactだった.

ちなみに,ReactNativeをやるとExpoというのをよく聞くと思う.

expo.io

これはReactNativeの開発ツールの一つではあるが,XcodeやらAndroid Studioなしで検証できるようになる.何言ってるのかよくわからないと思うが,XcodeAndroid Studioが用意する端末のシミュレータを使わずにアプリケーションを実行できる. 実行は - ブラウザ上の端末シミュレータで実行 - 実端末で実行

のどちらでも選べる.おそらくかなり気軽に始められるのでおすすめだろうけど,そもそも俺はXcodeiOSアプリ開発をしていたので,そういう気軽さは求めてなかった. というわけでReact Native CLIを使っており,Expoは使っていない.

ライブラリを探すときに,サンプルがExpoで実装されていることが多いので,一応動かしたことはあるけど.

なお,React Native CLIを使う場合,templateの指定ができるのだが,俺はTypeScriptが書きたくてしょうがなかったので,

npx react-native init Fascia --template react-native-template-typescript

こんな指定をしている.これでほぼTypeScriptで書かれたテンプレートが吐き出されるので,以降は .ts.tsx を追加していけば良い.

開発環境とか

Android

Android Studioが入れば,WindowsでもmacでもLinuxでも開発できる.Linuxで開発できるのは最高だ.

ちなみにエディタは愛用のEmacsを使っている.ReactNativeだろうがReactだろうが,typescript-modeとtideがあれば開発できるので,今回ReactNative用になにか追加でセットアップはしてない.

で,実行は

$ yarn run start

した状態で,別のターミナルを開き,

$ yarn run android

するとコンパイルされ,Android Studioに付属するAndroid Simulatorが起動し,開発したアプリが起動する.yarn run startしたサーバを立ち上げっぱなしにしておけば,あとはコードを変更してもLive Reloadされる.

stagingビルドの配布や,releaseビルドは,まずandroid/app/build.gradleを編集する. 編集する箇所は,

qiita.com

reactnative.dev

あたりを参考にする.

で,

cd android && ./gradlew assembleStaging

とか

cd android && ./gradlew bundleRelease

とかやるとバイナリが生成される.assemble*bundle* の違いは,生成したい成果物のファイル形式だ.

  • assemble* -> apk
  • bundle* -> aab

何が違うかは公式の説明とかを見るといい.

developer.android.com

これらのファイルが,android/app/build/outputs の下に生成されるので,このファイルをDeployGateやPlayStoreにアップロードするなりして配布する.

iOS

もともとSwiftでiOSアプリを書いていたのでこちらは慣れていた.

$ npx pod-install

すると必要なpodがPodfileに書かれてインストールされる.それと同時に ios/.xcworkspace ができるので,こいつをXcodeで開く.

あとは,デバッグビルドすればiOSシミュレータで動く.

リリースもSwiftと同じく,XcodeからReleaseビルドしてAppStoreにアップロードする.ProvisioningProfileの設定もReactNativeだから特別なことはなくて,普通のiOSアプリと同様の設定をXcodeから行えばよかった.

Androidが,案外デバッグにもリリースにもAndroid Studioをほとんど使わなかったので(起動しておく必要はあるけど,Android Studio側で設定したりビルドしたりする必要がない),iOSも同じ感じでいけるかと思っていたら,そうでもなかった. デバッグはyarnから発火できるけど,リリースビルドやProvisioningProfileの設定,アップロードはXcodeを使う必要があった.

[余談]なんでFlutterじゃないの?

なんとなく観測範囲での流行りはやっぱりFlutterだし,話を聞くことも多いので,Flutterはだいぶ迷った. というか,初期画面,ログインあたりまではReactNative, Flutterの両方で作ってみた上で,ReactNativeを選んでいる.

まず,基本的に俺はWebフロントエンドとしてのReactの経験がそこそこある.なので,ReactだったりReduxだったりするものに関しては,そもそもかなり慣れている. Flutterは触ったことがなかったので,今回が初である.

ReactNative所感

  • ReactNativeは,とにかくReact自体の思想,コミュニティ,それによって提供されている機能が素晴らしい
    • 最近は全部Functional Component,Hooksあたりが入って最高
    • 理想とするstateを定義して,その差分だけを差分レンダリングするという仕組みも気に入っている
    • Reduxやrouter等,Reactで使っていたライブラリで,そのまま使えるものが多い
    • これのおかげで,「UIを変更するロジック」をほとんど書かなくて済むのは最高
  • ネイティブのコンポーネントを利用する
    • これは良いことも悪いこともあって
      • 必然的にiOSAndroidでちょっと違うUIになることがよくある
      • iOSAndroidで違うのは,そりゃ当然なのでこれはこれで自然
      • だけど,どうしてもiOS/Androidだけではこれが必要/不要というものが出てくる
      • 例えばNavigationControllerのボタンとかね……
  • ReactNative自体が提供するコンポーネントはそこまで豊富ではない
    • 必然的に3rd partyのライブラリを利用する必要がある
    • それなりに枯れてきているので,どうしても古いライブラリは動かなかったりする
    • 放置されているものもそれなりにある
  • StyleSheetが書けるのはマジで最高
    • ネイティブアプリのレイアウトをcssで維持れるのは良い
  • 設計におけるベストプラクティスがそもそも存在する
    • Reduxを入れるかとか迷うところはあるけれど,そもそも迷う幅がかなり限定される

Flutter所感

  • googleが推してるだけあって,Android Studioからはすんなり環境構築できる
  • 独自のビューを使う
    • これも良いところも悪いところもある
      • ReactNativeみたいに,3rd partyのライブラリが放置されていて,最新のOSで動かないというようなことはあまりない(あまり
      • UIはiOS/Androidで同じになる
      • でもそれって自然か?iOSAndroid風のアプリ動かすのは,イマイチじゃない?
  • パフォーマンスはいいらしい
    • 今回求めてなかったので真面目に計測してないが
  • Dartを書きたいか?
    • 書きたくないでござる
    • Functional Componentが書きたい
    • というかもうextendsしたくない
    • なんでinterfaceないの,もうヤダ
    • 静的型付?本当に?これで?TypeScriptの方が良くない?
  • FlutterはWidgetを重ねていくという思想が,そもそもGUIを構築するのにスマートな手法なのか甚だ疑問
    • これ微妙なスタイル調節はどうしているの?css書かせてくれた方が楽じゃない?
  • 設計が謎
    • BLoCだ!って言ってる記事は見かける
    • BLoCわけわからなくなるって言ってる記事も見かける
    • RxDartも存在するし,それなりに良いとは思うんだけど,やっぱりUIを変更するロジックをかなりかかなきゃいけない

ちなみにSwiftはRxSwiftで,BLoCで書いてた

これはこれで面白かった. ただDartと違うのは,Swiftは初期からかなり良い静的型付言語だった.Optionaもあったしね.それと,RxSwift, RxCocoaを両方使うと,大部分のアクションはrxにできたのでこれは良かった.

BLoCをもう一度設計したいかと言われると,これはイマイチ……としか言いようがなかった.が,Reactは何度でも書ける気がした. この辺が一番大きい.

まとめ

ちなみに普段は,SREだったりインフラだったりするものを触ることが多いので,フロントエンドはそんなに得意ではないし,ネイティブアプリはもっと得意ではない.趣味だ.

そしてそういう経歴から,Reactの思想はKubernetesのReconcile Loopに近いものを感じている. あるべき姿を記述して,そこと現状との差分を埋めるという思想が,非常に親しいものではないだろうか.

Reconcileは,現状のStateを定義されたSpecに近づけるための処理を行う.今の所,Kubernetesのあるべき姿(yaml)は,手で書いたりhelmだったりkustomizeだったり,そういうもので記述されることが多い. それに対して,Reactのstateはたいていの場合ユーザの操作だったり,APIのレスポンスだったりするので,あまり手で書いていたり生成したりするものではないだろう.なので,そこは全然違うのだが…….

あるべき姿の定義方法を除けば思想的には近いのではないだろうか.それ以外の部分の思想がかかなり近い気がしていて,しっくりくる.

BLoCだったりRxだったりするものは,進化はしているんだけど,MVCでControllerでViewを変更するコードを山ほど書いて,それとModelをつなげて,ModelにはModel側にオブジェクトとしてのロジックがあって……という世界から,そこまで大きく変わっている感じがしない.どちらかというと,イベントに応じて必要な処理をするという形であり,あるべき姿を記述する思想とは真逆なんじゃないかと思っていたりする. ちなみに,どちらが優れているとか言うわけではなく,これらは両方共必要なことではある.だからReactはHooksを入れているし,KubernetesにもAdmissionWebhookがあったりするのだと思う. あくまで,どちらを主眼に置くかという話でしかない.

参考

hachibeechan.hateblo.jp