React Nativeの起動プロセスの詳細分析

React Nativeの起動プロセスの詳細分析

はじめに: この記事ではreact-native-cliで作成したサンプル プロジェクト (Android 部分) を例に、React Native の起動プロセスを分析します。

プロジェクト作成の手順については公式ウェブサイトを参照してください。この記事で分析したReact Nativeバージョンはv0.64.2です。

上記のプロジェクトは Android アプリケーションであることがわかっています。 android/ディレクトリのソース コード ファイルを開くと、まずMainApplication.javaMainActivity.javaという 2 つの Java ファイルが作成され、それぞれアプリケーションとメイン アクティビティが定義されていることがわかります。

Android アプリケーションの起動プロセスは次のとおりです。最初のactivityが開始される前に、グローバルに一意のApplicationオブジェクトが作成されます。そこでまずMainApplicationを分析します

メインアプリケーション

パブリッククラス MainApplication は Application を拡張し、ReactApplication を実装します {
  プライベートファイナルReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
    @オーバーライド
        パブリックブール値 getUseDeveloperSupport() {
          BuildConfig.DEBUG を返します。
        }
        @オーバーライド
        保護されたリスト<ReactPackage> getPackages() {
          @SuppressWarnings("不要なローカル変数")
          リスト<ReactPackage> パッケージ = 新しい PackageList(this).getPackages();
          // パッケージに対するその他の操作はパッケージを返します。
        }
        @オーバーライド
        保護された文字列 getJSMainModuleName() {
          「インデックス」を返します。
        }
  }
  @オーバーライド
  パブリックReactNativeHost getReactNativeHost() {
    mReactNativeHost を返します。
  }
  @オーバーライド
  パブリックvoid onCreate() {
    スーパーのonCreate();
    SoLoader.init(this, /* ネイティブ exopackage */ false);
    フリッパーを初期化します(これ、getReactNativeHost().getReactInstanceManager());
  }

MainApplication Application クラスを継承し、 ReactApplicationインターフェースを実装します。やるべきことは次のとおりです:

1. メンバー変数ReactNativeHostのインスタンスを作成し、作成プロセス中に ReactNativeHost クラス メソッドをオーバーライドして、次のようないくつかの構成を挿入します。

  1. getUseDeveloperSupport: デバッグを有効にするかどうかを設定します
  2. getPackages: ロードするモジュールを構成する
  3. getJSMainModuleName: jsモジュールのエントリファイル名を設定します

2. onCreate で:

  1. Soloaer ライブラリを呼び出します。 Soloaderは Facebook がリリースした s​​o ファイル読み込みライブラリです。so ファイルの依存関係を処理できます。react-native では、フレームワーク関連の so ファイルはすべて SoLoader を通じて読み込まれます。
  2. ReactInstanceManagerを介して Flipper を初期化します。 Flipper 、iOS、Android、React Native アプリケーションをデバッグするために Facebook がリリースしたツールです。

ReactNativeHostReactInstanceManagerの簡単な紹介です

リアクトネイティブホスト

ReactNativeHostは抽象クラスであり、開発者はそのメソッドをオーバーライドできます。その主な機能は、アプリケーションでいくつかの割り当て操作を指定して、 ReactInstanceManagerのインスタンスを取得することです。したがって、 ReactNativeHostReactInstanceManagerインスタンスにユーザー定義のパラメータを割り当てるための中継ステーションとして使用できます。コアメソッドはgetReactInstanceManagerです。詳細な分析については以下を参照してください。

Reactインスタンスマネージャー

このクラスはコアクラスであり、主に JS の読み込みの管理、ライフサイクルの維持、JS と C++ 間の相互作用の管理などを担当します。 ReactInstanceManager 、JS と C++ 間の転送ブリッジとして理解できます。

メインアクティビティ

次に、 MainActivity.javaを見てみましょう。

パブリッククラスMainActivityはReactActivityを拡張します{
  @オーバーライド
  保護された文字列 getMainComponentName() {
    「myProject」を返します。
  }
}

MainActivityクラスでは getMainComponentName メソッドのみがオーバーライドされます。このクラスはReactActivityから継承します。そのReactActivityを見てみましょう。

パブリック抽象クラス ReactActivity は AppCompatActivity を拡張します
    DefaultHardwareBackBtnHandler、PermissionAwareActivityを実装します。
  プライベート最終 ReactActivityDelegate mDelegate;
  @オーバーライド
  保護されたvoid onCreate(バンドルsavedInstanceState) {
    super.onCreate(保存されたインスタンス状態);
    mDelegate.onCreate(保存されたインスタンス状態);
  }

ReactActivity onCreateライフサイクルの処理をReactActivityDelegateに完全に委任します。 ReactActivityDelegateonCreateを見てみましょう。

保護されたvoid onCreate(バンドルsavedInstanceState) {
  文字列 mainComponentName = getMainComponentName();
  mReactデリゲート =
      新しいReactDelegate(
          getPlainActivity()、getReactNativeHost()、mainComponentName、getLaunchOptions()) {
        @オーバーライド
        保護されたReactRootView createRootView() {
          ReactActivityDelegate.this.createRootView() を返します。
        }
      };
    mMainComponentName != null の場合 {
      loadApp(メインコンポーネント名);
    }
  }

ここで、ReactDelegate インスタンスが最初に作成されます。次に、 loadAppメソッドを見てみましょう。

保護されたvoid loadApp(String appKey) {
  mReactDelegate.loadApp(appKey);
  getPlainActivity().setContentView(mReactDelegate.getReactRootView());
}

ここから、 ReactDelegateインスタンスのloadAppメソッドに進みます。

パブリック void loadApp(String appKey) {
  mReactRootView が null の場合
    throw new IllegalStateException("アプリがすでに実行中なので、loadApp を実行できません。");
  }
  mReactRootView = createRootView();
  mReactRootView.startReactApplication() を実行します。
      getReactNativeHost().getReactInstanceManager(), appKey, mLaunchOptions);
}

ここでは、rootView ( createRootView ) の作成、ReactInstanceManager ( getReactInstanceManager ) の作成、ReactApplication ( startReactApplication ) の作成という 3 つの処理が行われます。

ルートビューの作成

まず、rootView とは何かを見てみましょう。

パブリッククラス ReactRootView は FrameLayout を拡張し、RootView、ReactRoot を実装します { /* ... */

ReactRootView はFrameLayoutを継承し、 RootViewおよびReactRootインターフェースを実装します。 FrameLayoutは、Android のよりシンプルなレイアウトの 1 つです。インターフェース全体が空白の予備領域として扱われ、すべての要素が左上隅を揃えて積み重ねられます。 ReactRootView はFrameLayoutを継承しており、これも単純なレイアウトとして存在し、 UI 的繪制渲染その上で行われることを示しています。

getReactInstanceManager

ReactInstanceManager 、JS の読み込み、C++ と JS の相互作用、初期化パラメータなどを管理するコア クラスです。最後に、 ReactNativeHostクラスのcreateReactInstanceManagerメソッドが呼び出されます。

保護されたReactInstanceManager createReactInstanceManager() {
  ReactInstanceManagerBuilder ビルダー = /* ... */

  (ReactPackage reactPackage : getPackages()) の場合 {
    ビルダーにパッケージを追加します。
  }

  文字列 jsBundleFile = getJSBundleFile();
  jsBundleFile != null の場合 {
    ビルダーでJSBundleFileを設定します(jsBundleFile);
  } それ以外 {
    バンドルアセット名をアサーションにセットします。
  }
  
  React インスタンスマネージャー reactInstanceManager = builder.build();
  reactInstanceManager を返します。
}

何が起こっているのか、以下に示します。

  • ReactInstanceManagerBuilderインスタンスを作成します。ここでは、 ReactInstanceManagerインスタンスを構築するためにビルダー パターンが使用されているため、最初にコンストラクターを設定するためにパラメーターが渡されます。
  • ReactNativeHostに登録されているすべてのpackagesReactInstanceManagerBuilderインスタンスに追加します。
  • getJSBundleFileが空でない場合は対応するファイルをロードし、そうでない場合はデフォルトのjsBundleFileをロードします。
  • builder.buildメソッドを呼び出します。実際にビルダーを通じてReactInstanceManagerインスタンスを構築する

Reactアプリケーションを起動する

  パブリック void startReactApplication(/* */) {
    // ...
    試す {
      // ...
      mReactInstanceManager.createReactContextInBackground();
    ついに
      // ...
    }
  }

最後に、 ReactInstanceManagercreateReactContextInBackgroundメソッド内で実行が行われます。最終的に、呼び出しチェーンは次のようになります: recreateReactContextInBackgroundInner() -> recreateReactContextInBackgroundFromBundleLoader() -> recreateReactContextInBackground() -> runCreateReactContextOnNewThread()

runCreateReactContextOnNewThread主に次の 2 つのことを行います。

  1. 新しいスレッドを作成し、新しいスレッドでcreateReactContextを通じてReactContextコンテキストを作成します。
  2. コンテキスト環境はsetupReactContextを通じて設定され、最後にAppRegistry.jsが呼び出されてアプリが起動します。

詳細な分析については、別の記事「React Native startReactApplication プロセス分析」に掲載します。

要約する

この記事をまとめると、 react-native-cliで作成したサンプルプロジェクト(Android 部分)を例に、 MainApplicationMainActivity 2 つのクラスの実行フローを辿り、主要なロジックを把握し、最後にReact Nativeの起動からユーザーjsファイルの実行までのプロセスを整理しました。以下が見られます:

MainApplicationの主な機能は、ユーザーの設定を渡し、 soライブラリとアプリケーションdebugツールを初期化することです。

MainActivityの主な機能は次のとおりです。

  1. アプリケーションのrootViewレイアウト コンテナーを作成します。
  2. JS の読み込み、C++ と JS の相互作用、初期化パラメータなどを管理するためのReactInstanceManagerコア クラスを作成します。
  3. ReactContextコンテキストはstartReactApplicationを通じて作成され、最後にAppRegistry.jsが呼び出されてアプリが起動します。

React Native の起動プロセスの簡単な分析に関するこの記事はこれで終わりです。React Native の起動に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React NativeのScrollViewプルダウンリフレッシュ効果
  • React NativeのstartReactApplicationメソッドの簡単な分析
  • React Nativeのカスタムルーティング管理に関する深い理解
  • React NativeプロジェクトでLottieアニメーションを使用する方法

<<:  Mysql一時テーブルの原理と作成方法の分析

>>:  VMWARE で Centos8 仮想マシンをコピーすることによって発生する IP 損失の問題の解決策

推薦する

2019 年に最も役立ち重要なオープンソース ツール トップ 10

Black Duck の 2017 年のオープンソース調査では、回答者の 77% がオープンソース...

Dayjs を使用して Vue で一般的な日付を計算する方法

vue を使用してプロジェクトを開発する場合、フロントエンドでは次のような日付と時刻を計算する必要が...

HTML の div、td、p およびその他のコンテナーでの強制改行と非改行の実装

1. 改行を強制せず、省略記号で終了します。コードをコピーコードは次のとおりです。 <div ...

Vue diffアルゴリズムの完全な分析

目次序文Vue 更新ビューパッチ同じVノードパッチVノード更新子供序文Vue は仮想 DOM を使用...

Node.jsとDenoの比較

目次序文Denoとは何ですか? Node.jsとの比較建築ESモジュール依存関係の管理TypeScr...

シェルスクリプトはNginxのaccess.logのPVを定期的にカウントし、APIに送信してデータベースに保存します。

1. PVとIPの統計一日のPV(ページビュー)をカウントする cat access.log | ...

Vue の基本 MVVM、テンプレート構文、データバインディング

目次1. Vueの概要Vue公式サイトMVVM アーキテクチャ パターンVue の紹介2. Vueを...

Ubuntu システムログで /var/log/messages を設定する方法

1. 問題の説明今日、システム ログ ファイルを確認する必要がありますが、/var/log/mess...

複数の .sql ファイルを MySQL に効率的にインポートする方法の詳細な説明

MySQL には、複数の .sql ファイル (SQL ステートメントを含む) をインポートする方法...

Vue プロジェクトで axios リクエストを使用する方法

目次1. インストール2. カプセル化に問題はない3. ファイルを作成する4. アドレス設定をリクエ...

XHTML言語のデフォルトCSSスタイル

html、アドレス、引用ブロック、本文、dd、div、 dl、dt、フィールドセット、フォーム、フレ...

Linux でシェル スクリプトを使用して jar パッケージ プロジェクトを展開するための完全な手順

1. JDKをインストールする コンピュータの動作桁を確認します。 uname -ar 2017 x...

ブラインドの特殊効果を実現するネイティブJS

この記事では、ネイティブ JS で実装されたブラインドの特殊効果を紹介します。効果は次のとおりです。...

MySQL で指定エンコーディングを実装する際の落とし穴について

前面に書かれた環境: MySQL 5.7+、MySQL データベースの文字エンコードは utf8、テ...

vue-cropper コンポーネントは画像の切り取りとアップロードを実現します

この記事では、画像の切り取りとアップロードを実装するためのvue-cropperコンポーネントの具体...