Groupの大木です。Creator」の3つのスマホアプリをリリースしております。Nativeで置き換え、リリースしてみての話を、お伝え出来ればと思います。Creatorは、基本的にはWebViewで画面を表示するいわゆるガワネイティブアプリというものです。Webアプリとの違いは何処にあるかといいますと、商品が売れたり、購入者からメッセージが届くと、Push通知でお知らせ出来る機能があるところです。アプリを運用していて出て来た課題としては、下記の点です。現状、問い合わせによる不具合報告に対応するために、iOS/Androidのコードベースそれぞれを確認する必要があるスマホアプリは合計6つあり、チームメンバーも少数のため、WebViewベースのこのアプリは極力共通化したい。これらの課題を解決するために、クロスプラットフォーム開発フレームワークの検討をしました。NativeとFlutterでした。Nativeを採用しました。重要視するポイント既存技術を流用出来るか(社内、一般的なNative/Web技術含め)クロスプラットフォーム開発のノウハウが蓄積されているか特に重要視していないポイント統一されたガイドラインのようなものがある新しい技術で開発Flutterの方が後発で、挑戦してみたい気持ちもありました。Nativeを選択しました。置き換えてみてどうなったか結論から言うと、色々な良い影響をもたらすことが出来ました。アプリケーションロジックを共通化出来た最大の課題であった、iOS/Androidそれぞれのコードベースを一つにすることが出来、アプリケーションロジックを全てTypeScriptで記述することに成功しました。SDK用の初期化時コードくらいです。Nativeで開発するとなると様々なスキルセットを必要とするため、Pull-Requestベースでレビューをもらいながら開発していきました。workflow"と呼ばれます。workflow"と読んでます。workflow"でリリースする必要がありました。workflow"も素早く動作確認できる検証用環境として捨てがたいです。Re-Architecture実践の年で様々な改善をしていました。workflow"を使わなくても、Expoの便利モジュールを使えるようになりました。両方の動作環境を一つのプロジェクトで共存させるために、monorepoという仕組みを導入しました。この仕組みは、BabelやReactでも採用されています。リポジトリのディレクトリ構成は、最終的に次のようになりました。docker-binまた、分割したモジュールをどのように使うかの簡易的な概念図は次の通りです。workflow"で動作させるためのエントリポイントとなっております。このモジュールからDebugビルドのアプリを起動したり、ストアリリースのためにReleaseビルドを作成したりします。workflow"で動作させるためのエントリポイントとなっています。Nativeアプリを動作させるためには、色々なテクニックがいるのですが、長くなりそうなため、機会があれば別途解説記事を書ければと思っています。Nativeのコンポーネントを作成するに当たって、アプリケーションの特定の状態でしか発生しないUIの状態があり、その状況を再現したUIを素早く実装するためにStorybookを導入しました。Centerのサービスです。リリース後、特定の古いOSでアプリが動作しない不具合が発生した時に、これを導入していたおかげで緊急アップデートをすることができました。いうメソッドは使えません。次のように修正し、リリースした当日に緊急アップデートで対処することができました。Native環境でどの程度最新技術をサポートしているのか、限界はどこかということを知っておきたいと考え、色々な検証をしました。TypeScriptのDecorators導入JavaのAnnotationのようなものが使いたくなり、TypeScriptのDecoratorsを導入しました。MethodがGETなのかPOSTなのかを定義したりで、次のような感じで使っております。Native動作環境に対応するのであれば、当然使えるモジュールも違ってくることがありうると思いました。workflow"とでは、利用できるモジュール異なることもあります。そこで、I/Fと実装を紐付けるためにIoCコンテナを導入しました。実装すべき共通のインタフェースを定義します。Symbol.for('Splash');expo-starterでは、ExpoのSplashScreenが使えるので、次のように実装します。使うように実装します。Containerを使い、I/Fと実装を紐づけます。[...]});その他その他、試して導入した機能は、主に次の通りです。Nativeならではの辛さや問題にも遭遇しました。(2019年3月)他のタスクがひと段落したため、本格的に環境構築を開始しました。公式ドキュメントを参考にしながら、ほとんどつまづくことなく開発することができました。Jestを使ったスナップショットテストを導入したり、CircleCIでlintやスペルチェックを回して、少しづつ環境を整えていました。この時に使用した技術は次の通りです。Native本体のWebViewコンポーネントを使って動作確認しました。予想に反して、このコンポーネントには深刻な不具合があり、それにより、プロジェクトの存続すら怪しくなっていました。Communityに移管されることに決定していたようです。workflow"を利用しているため、すぐには移管されたWebViewは使えません。そのため、この環境を諦めるかどうかの選択に迫られました。Community版のWebViewに差し替えるという話があったため、他の開発をしながら、リリースを待つことにしました。Expoのアップデートを待つ間に、他の機能を開発(2019年4月-2019年6月)要のWebViewは不具合で開発を進められなかったため、他の機能を開発していくことにしました。待っている間に実装していた昨日は次の通りです。Nativeのバージョンが古い時の方法であったり、パス解決の仕組みがよく分かっておらず、この時は断念しました。後日、最終的にMetroやBabelのモジュールパス解決の方法を組み合わせることで解決することができ、monorepo構成に移行するまでうまく動作しておりました。DevelopersのSlackを定期的に覗く日々でした。様々な人が次のリリースはいつ?のような発言をしていた印象です。いつものようにSlackをのぞいていると、いくつかのIssueを片付けたらリリースできるよと発言がありました。v33があり、インストール可能な状態になっていました。公式アナウンスを待ちきれず試してみると、普通に動くWebViewと対面することができました。未知との遭遇(2019年6月)基本的には動作していたWebViewですが、2つほど問題がありました。挙動に準拠せず、勝手に同一WebViewで開いてしまう。Native側からWebViewでJavaScriptを実行しても実行結果を受け取れない。リンクが存在するか自分で確かめなければなりません。WebViewのJavaScript環境は、ユーザーの端末に依存するため、出来るだけレガシーなJavaScriptを書いてWebViewで動くようにしました。(ブラウザをアップデートしていないユーザーは古い機能しか利用できない)。リンク取得するようにしました。目的のリンクは取得できるようにはなりました。WebViewでJavaScriptを実行しても、実行結果を返すことはありません。一応window.ReactNativeWebView.postMessageを使うことで解決が可能です。Native側に実行結果を送信するのが早いかわからないという問題には、完全に対処できませんでした。worflow"を共存させる試みの失敗(2019年6月-7月)結論から言うとこの試みは失敗しました。最初次の構成にすればうまくいくと考えました。Nativeのアップデートに追従していくためには、こんな複雑な仕組みメンテナンスできないと思い、考え直すことにしました。monorepo構成の導入(2019年7月)しばらく色々試して迷走していましたが、1つのプロジェクトで複数のモジュールを管理できるような仕組みがあれば良いのではと考え、調査したところmonorepoについて知りました。monorepoを実現するツールの一つであるLernaを導入し、試してみました。この構成は現在も使っており導入してよかったと思いました。実行環境の共存も、エントリポイントとなるモジュールを分割することにより別々に実行できるようになりました。実行環境共通で使えないモジュールの解決は、共通interfaceを定義しそれぞれの実行環境ごとに実装したものを、IoCコンテナを通じてアクセスすることによって利用できるようになりました。この辺は前述のIoCコンテナ(スプラッシュ画面の例)に例を載せていますmonorepo構成への完全移行とネイティブIDE/SDKの設定(2019年7月-8月)monorepoへ移行してからも、TypeScriptのpathsを使ったモジュール解決を使っていましたが、エディター上でモジュールをインポートしようとすると、ローカルPCのフルパスでインポートしたり、importの重複が発生したり何かと問題が発生していました。pathsを使ってはいたのですが、そもそも機能ごとにグループ化し擬似モジュールのように扱っていたに過ぎません。モジュールのように扱っていたのであれば、monorepoの中でモジュールとして分割した方が管理しやすくなると考え、pathsで管理していたディレクトリーをそのままモジュールとして切り出すことにしました。これによってモジュールのインポート問題は解決することができました。monorepoでJavaScriptレイヤーの問題は解決することはできましたが、ネイティブ側の設定はnpmのエコシステムに自動的に対応している訳ではありません。最終的に解決はできましたが、様々な問題が発生しました。それに関しては長くなるためここでは省略します。毎回アプリを起動してUI実装するの面倒なためStorybookを導入(2019年8月-9月)基本機能はほぼ出来上がっていましたが、次はUIの微調整が待っていました。毎回アプリを削除して、目的の画面まで遷移して特定の状態にして確認という作業を、繰り返していたため、フラストレーションが溜まっていました。そこで、UIの状態を固定で確認できれば、アプリの実行環境で確認しなくてもいいのでは?と考えStoryboardを導入しました。結果的に、ブラウザ上で素早く確認できるようになりました。Centerを選びました。Nativeアプリの場合、CodePushを使えるのが採用した大きな理由です。配信サービスが決まったので、CircleCIでリリースビルドを作成してみるとなかなか上手くいきません。一回のビルド時間が40分以上かかり確認にも時間がかかります。ここをクリアしないとリリースもできません。絶対にローカルPCでリリースビルドを作るという作業はしたくありません。この作業では、次のような問題が発生しました。13へのアップデート対応で、他アプリの対応もしなくてはならず、なかなか時間が取れませんでしたが、一つ一つ解決していきました。13へのアップデートもひと段落し、やっとリリース準備に漕ぎ着けました。ようにまずは終わらせろの気持ちでいた私ですが、全体を通しての動作確認はしておりません。QAをしなければなりません。QAフェースでも色々問題が発生しました。これは主にAndroidの知識不足が原因でのことです。Nativeのコンポーネントが再生成されるのに、UI周りの再初期化できてない不要な権限をAndroidManifestで消せてないまた、QAを行なっていると、利用しているライブラリに関しても色々と気づくこともあり、修正Pull-Requestを送ったりしました。styleリリース(2019年11月末)まだまだ、改善するところはあったのですが、紆余曲折を経て、リリースすることができました。Storeに再申請するほどの深刻な不具合が発生しなかったことにまずは安心しました。ユーザーに影響のあるものや運用開発環境の考慮漏れなど、いくつかの問題は発生してしまいました。確認不足やAndroidの知識不足に起因するものが多かったです。いくつか上げると次のようなことです。CodePushの設定ミスまとめ今回のプロジェクトでは、本当に多種多様な技術に触れ、大変なことも多かったのですが、様々な人の助言もありなんとか終わらせることができました。長期的な運用やチームでの開発を考えた実装を深く考えられた良い機会でした。Nativeだからネイティブのことを考えなくてよい訳ではなく、ネイティブ起因の様々な問題が発生しました。その時には同じチームのAndroidエンジニアにも度々助けられました。NativeやExpoを取り巻く環境は、2019年の一年間で大幅に変化しそして改善しています。Nativeのことが書かれていました。Nativeを採用するのも悪くない選択肢かなと思います。)の開発チームによるブログです。Groupの大木です。Developerをしている東口です。Groupのマネージャーをしている山田です。12/1から始まっ...Archiveスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。