facebookは今年初めにiOS用のReact Nativeを導入しました。 React Nativeは、ネイティブアプリケーションのスピード、忠実度、感触を維持しながら、web上のReactから開発者が慣れ親しんでいるもの、宣言的な自己完結型UIコンポーネ 本日、React Native for Androidをリリースしました。Facebookでは、React Nativeを本番環境で1年以上使用しています。facebookでは、React Nativeを本番環境で使用しています。 ほぼ正確に一年前、私たちのチームは広告マネージャアプリを開発するために着手しました。 私たちの目標は、Facebook上で広告を掲載する何百万人もの人々が自分のアカウントを管理し、外出先で新しい広告を作成できるようにする新しいアプリを作 これは、Facebookの最初の完全に反応ネイティブアプリだけでなく、最初のクロスプラットフォームのものでもありました。 この記事では、このアプリをどのように構築したか、React Nativeがどのように高速に移動できるようになったか、そして学んだ教訓を共有したいと思います。
React Nativeを選択する
少し前までは、React Nativeはまだ生産で証明されていなかった新しい技術でした。 この技術に基づいて新しいアプリを開発することは、いくつかのリスクを運んだが、それは潜在的な欠点によって上回りました。
まず、三つの製品エンジニアの私たちの最初のチームはすでに反応に精通していました。 第二に、広告形式、タイムゾーン、日付形式、通貨、通貨規則などの違いを正確に処理するために、アプリには多くの複雑なビジネスロジックが必要でした。 これの多くはすでにJavaScriptで書かれていました。 Objective-Cですべてのコードを記述して、後でAndroidバージョンのアプリ用にJavaで記述するという見通しは魅力的ではなく、効率的でもありませんでした。 第三に、React Nativeでは、リスト、テーブル、またはグラフの形で多くのデータを表示する、私たちが構築したいUIサーフェスのほとんどを実装するのは簡単です。 製品エンジニアは、Reactを知っていれば、これらのビューをすぐに実装することができます。
もちろん、この新しいプラットフォームには、広告主が写真をズームしてトリミングできるイメージエディタや、広告主が場所の特定の半径内の人をターゲッ 別の例として、ブレッドクラムナビゲーションがあり、広告主がアカウント内の広告の階層を視覚化するのに役立ちます。 これらは、私たちがプラットフォームをさらに推進する機会を提供しました。
Ios用の広告マネージャーを最初に構築する
私たちのチームは、Ios用に最初に開発されているReact Nativeと非常によく連携したiOSバージョンのアプリを最初に開発することにしました。 私たちは、次のヶ月の間に三人から八人のエンジニアにチームを成長させました。 新入社員はReactに精通しておらず、JavaScriptに精通していない人もいましたが、広告主にとって素晴らしいモバイル体験を構築したいと熱望していました。
React Nativeチームの経験豊富なiOSエンジニアは、電話のカメラロールへのアクセスを提供するなど、React Nativeではまだ利用できなかった機能を橋渡しするのに役 また、認証、分析、クラッシュレポート、ネットワーク、プッシュ通知を実行するために他のFacebookアプリで既に使用されていたFacebookの既存のiOSライブラリの一部 それは私たちのチームが製品だけを構築することに焦点を当ててみました。
前述したように、既存のJavaScriptライブラリの多くを再利用することができました。 そのようなライブラリの1つは、Graphqlを介してReactアプリケーションにデータを配信するためのFacebookのフレームワークであるRelayです。 別のライブラリのセットは、タイムゾーンと通貨が関与しているときにトリッキーなことができ、国際化とローカリゼーションを扱っています。 通常、これらのライブラリは、WEBサイト上のJSONエンドポイントから適切な設定をロードします。 サポートされているすべてのロケールのJSONファイルをエクスポートするスクリプトを作成し、iOSのローカライズされたバンドルを使用してアプリにファイ これにより、私たちのライブラリはほぼ変更されませんでした。
私たちが直面した大きな課題の一つは、ナビゲーションの流れでした。 広告主の既存の広告やキャンペーンをナビゲートするために、ブレッドクラムナビゲーションバーが必要でした。 広告の作成フローには、ウィザードスタイルのナビゲーションバーが必要でした。 その上で、それはそうでなければ、アプリは、ネイティブアプリよりも栄光のモバイルウェブサイトのように感じていただろう、右の遷移アニメーション
私たちの解決策はNavigatorコンポーネントで、Customcomponentsディレクトリの下でReact Nativeとともに利用可能になりました。 本質的には、スタック内の他のReactコンポーネントのセットを追跡するのはReactコンポーネントです。 これらのコンポーネントのいずれかを表示し、ボタンを押すか、タッチジェスチャーに基づいてそれらの間をアニメートすることができます。 また、プラグ可能なナビゲーションバーコンポーネントを備えており、ほとんどの通常のビューにはiOSのようなナビゲーションバー、広告やキャンペーンをナビゲートするためのブレッドクラム、作成フローにはウィザードのようなステッパーを実装できます。 ナビゲーションバーコンポーネントにはアニメーションの進行状況が通知され、一致するように必要なアニ つまり、ビューとナビゲーションバーの両方のすべてのアニメーションはJavaScriptで計算されますが、テストではまだ60fpsで実行できることが示されました。
ナビゲーションアニメーションが吃音する可能性がある唯一の方法があり、それは大きな操作中にJavaScriptスレッドがブロックされたときです。 このシナリオに遭遇したとき、それはほぼ排他的に大量の新しく取得されたデータを処理することによるものでした。 もちろん、新しいビューに移動すると、より多くのデータをロードして処理する必要があることは理にかなっています。 十分に高速なネットワークでは、そのプロセスはまだ進行中のナビゲーションアニメーションを容易に妨害する可能性があります。 ここでの解決策は、React Nativeの一部として同梱されているInteractionManagerコンポーネントを使用して、アニメーションが完了するまでデータ処理を明示的に遅延させること まず、プレースホルダを含むビューにアニメーション化してから、Relayにデータ処理を行わせ、必要なReactコンポーネントを自動的に再レンダリングさせました。
Androidバージョンの出荷
Ios用広告マネージャが出荷に近いとき、私たちは同じアプリのAndroidバージョンの構築を検討し始めました。 AndroidへのReactネイティブポートは、その作業を行うための最良の方法のように思えました。 幸いなことに、React Nativeチームはすでにそれを作成するのに苦労していました。 当然のことながら、できるだけ多くのアプリコードを再利用したいと考えていました。 ビジネスロジックだけでなく、UIコードも、ほとんどのビューがほぼ同じであったため、いくつかのスタイリングを省いています。 もちろん、ナビゲーションや日付ピッカー、スイッチなどのネイティブUI要素の使用など、AndroidのバージョンがiOSのバージョンとは異なる外観と感触を必要とす
幸いなことに、React Native packagerのブロックリスト機能とReactの抽象化メカニズムは、二つのプラットフォーム間でコードの再利用を最大化し、明示的なプラット IOSでは、packagerにで終わるすべてのファイルを無視するように指示しました。アンドロイド…js”を発表した。 Android開発では、で終わるすべてのファイルを無視しました。イオスjs”を発表した。 これで、同じコンポーネントをAndroid用に一度、iOS用に一度実装することができましたが、消費するコードはプラットフォームには気づかないでしょう。 そのため、プラットフォームの明示的なif/elseチェックを導入する代わりに、UIのプラットフォーム固有の部分をAndroidとiOSの実装を持つ別々のコンポーネントに Ads Manager for Androidを出荷した時点で、このアプローチでは約85%のアプリコードの再利用が可能になりました。
私たちが直面した大きな課題は、ソースコードをどのように管理するかでした。 AndroidとiOSのコードベースはFacebookの二つの異なるリポジトリで管理されていました。 IOS版のAds ManagerのソースコードはiOSリポジトリに保存されていましたが、Android版のコードはさまざまな理由でAndroidリポジトリに保存されていました。 たとえば、iOSバージョンと同じように、AndroidリポジトリにあるFacebookのAndroidライブラリのいくつかを利用したいと考えました。 さらに、Androidアプリのすべてのビルドツール、自動化、および継続的な統合がAndroidリポジトリにフックアップされました。 アプリのAndroidポートでは、既存のiOSコードをリファクタリングしてプラットフォーム固有のコンポーネントを独自のファイルに抽象化する必要があるため、本質的には同じコードベースの二つのバージョンを常にフォークしてマージしていたでしょう。 それは私たちにとって容認できない状況のように思えました。
最終的に、私たちはiosリポジトリを真実のソースとして指定することにしました。 私たちは、すべてのJavaScriptコードをiOSからAndroidリポジトリに1日に何度も同期するcronjobを設定しました。 AndroidリポジトリへのJavaScriptのコミットは推奨されず、iosリポジトリへのコミットが付随してフォローアップされた場合にのみ許可されました。 同期スクリプトが不一致を検出した場合は、さらなる調査のためにタスクを提出しました。また、JavaScript packagerサーバーがiOSリポジトリからAndroidコードを実行できるようにしました。 そうすれば、主にJavaScriptに触れ、ネイティブコードを持たない私たちの製品開発者は、iOSリポジトリから直接iOSとAndroidの両方で変更を開発してテストすること しかし、それはまだ彼らがAndroidリポジトリからAndroidアプリのネイティブ部分を構築している必要があり、iOSアプリのために同じ—二つのプラットフォーム上で変更をテストするときに巨大な税。 JavaScriptのみの開発者のためのフローを高速化するために、我々はまた、継続的な統合サーバーから適切なネイティブバイナリをダウンロードしたスクリプトを これにより、ほとんどの開発者はAndroidリポジトリのクローンを保持する必要さえなくなりました。Facebookのウェブスタックよりも速く、または速く、iosリポジトリの真実のソースからすべてのJavaScript開発を行うことができました。
私たちが学んだこと
React Nativeチームは、アプリと一緒にプラットフォームを開発し、それを実現するために必要なネイティブコンポーネントとApiを これらのコンポーネントは、将来的にはアプリを構築するすべての人に利益をもたらすでしょう。 いくつかのコンポーネントを自分で構築しなければならなかったとしても、pure nativeよりもReact Nativeを使用することは価値があったでしょう。 とにかくこれらのコンポーネントを書かなければならなかったでしょうし、おそらく他のチームが再利用することはできませんでした。
私たちが学んだ一つの教訓は、多くのツールや自動化であっても、別々のiOSとAndroidのコードリポジトリで作業することは困難であるということでした。 私たちがアプリを構築していたとき、Facebookはこのモデルを使用し、ビルドの自動化と開発者プロセスのすべてがその周りに設定されました。 しかし、ほとんどの場合、単一の共有JavaScriptコードベースを持つ製品ではうまく機能しません。 幸いなことに、Facebookは両方のプラットフォームのための統一されたリポジトリに移動している—共通のJavaScriptコードの唯一のコピーが必要になり、同期は過去のもの私たちが学んだ別の教訓は、テストを懸念していました。
変更を行う場合、すべてのエンジニアは両方のプラットフォームでテストするように注意する必要があり、プロセスはヒューマンエラー しかし、それは同じコードベースからクロスプラットフォームアプリを開発することの必然的な結果です。 とはいえ、不十分なテストによる時折の事故のコストは、React Nativeを使用し、最初に両方のプラットフォーム間でコードを再利用できることによって得られた開発効率によってはるかに上回っています。 このレッスンは、製品エンジニアだけに適用されるのではなく、Objective-CおよびJavaで作業するReact Native platformエンジニアにも適用されます。 これらのエンジニアが行う作業の多くは、純粋にそれぞれの母国語に限定されるものではありません。 また、コンポーネントApiや部分的に共有された実装など、JavaScriptにも影響を与える可能性があります。 ネイティブのiOSエンジニアは、通常、Android上で変更をテストする必要があることに慣れておらず、その逆はAndroidエンジニアにも当てはまります。 これは主に閉鎖するために時間と労力を要した文化的なギャップであり、その結果、時間の経過とともに、私たちの安定性が高まっています。
また、すべてのリビジョンで実行される統合テストを構築することで、問題に対処しました。 これは、iosと同様にAndroidでiOSの問題をキャッチするためにすぐに機能しましたが、継続的な統合システムはiOSリビジョンでAndroidテストを実行するように設定されておらず、その逆も同様です。 これは解決するための工学的努力を要し、時折アプリを壊すのに十分な誤差が残っています。
すべてが言われ、完了したとき、私たちの賭けは報われました—Facebookの最初の完全に反応するネイティブアプリを二つのプラットフォームに出荷するこ すべてのエンジニアがチームに加わったときにReactに精通していたわけではありませんが、わずか五ヶ月でネイティブのルックアンドフィールでiOSアプリ そして、さらに三ヶ月後、我々はアプリのAndroidバージョンをリリースしました。私たちの言語でより包括的になるために、この投稿を編集して、ブラックリストをブロックリストに置き換えました。