この記事では、React Native の基本をすでに理解していることを前提とし、ネイティブと JavaScript が通信する際の内部動作に焦点を当てます。 メインスレッド始める前に、React Native には 3 つのメインスレッドがあることを知っておく必要があります。
さらに、一般的に、特に指定がない限り、各ネイティブモジュールには独自のGCDキューがあります(後述)。 *シャドウキューは実際にはスレッドというよりGCDキューに似ています ネイティブモジュールネイティブ モジュールの作成方法がわからない場合は、ドキュメントを読むことをお勧めします。 これは、JavaScript によって呼び出され、JavaScript を呼び出すこともできるネイティブ モジュール Person の例です。 @interface Person : NSObject <RCTBridgeModule> @終わり @implementation ロガー RCT_EXPORT_MODULE() RCT_EXPORT_METHOD(挨拶:(NSString *)名前) { NSLog(@"こんにちは、%@!", 名前); [_bridge.eventDispatcher sendAppEventWithName:@"greeted" 本文:@{ @"name": name }]; } @終わり ここでは、RCT_EXPORT_MODULE と RCT_EXPORT_METHOD という 2 つのマクロに焦点を当て、それらの展開内容、役割、動作について説明します。 RCT_EXPORT_MODULE([js_name])このメソッドの名前が示すように、モジュールをエクスポートしますが、この特定のコンテキストでのエクスポートとはどういう意味でしょうか? これは、ブリッジがモジュールを認識していることを意味します。 その定義は実は非常に単純です。 #RCT_EXPORT_MODULE(js_name) を定義します\ RCT_EXTERN void RCTRegisterModule(クラス); \ + (NSString \*)moduleName { return @#js_name; } \ + (void)ロード{RCTRegisterModule(self);} 次のことを行います:
RCT_EXPORT_METHOD(メソッド)このマクロはさらに興味深いもので、メソッドに何も追加せず、指定されたメソッドを宣言するだけでなく、新しいメソッドも作成します。新しい方法は次のようになります。 + (NSArray *)__rct_export__120 { @[ @"", @"log:(NSString *)message" ] を返します。 } これは、プレフィックス (__rct_export__) とオプションの js_name (この場合は空) を宣言の行番号と __COUNTER__ マクロと組み合わせて構築されます。 このメソッドの目的は、オプションの js_name とメソッド シグネチャを含む配列を返すことです。この js_name の役割は、メソッド名の競合を回避することです。 ランタイムこのセットアップ全体は、ブリッジに情報を提供して、エクスポートされたすべてのモジュールとメソッドを見つけられるようにするためのものですが、これはすべてロード時に行われます。次に、実行時にどのように使用されるかを見てみましょう。 ブリッジが初期化されたときの依存関係グラフは次のとおりです。 初期化モジュールRCTRegisterModule が行うことは、新しいブリッジをインスタンス化するときにクラスが見つかるように、クラスを配列にプッシュすることだけです。ブリッジは、配列内のすべてのモジュールを反復処理し、各モジュールのインスタンスを作成し、ブリッジ側のインスタンスへの参照を格納し、モジュール インスタンスにブリッジへの参照を与え (両側で相互に呼び出すことができるように)、モジュール インスタンスに実行するように指定されたキューがあるかどうかを確認し、ない場合は他のモジュールとは別の新しいキューを与えます。 NSMutableDictionary *modulesByName; // = ... (RCTGetModuleClasses() 内のクラス moduleClass) { // ... モジュール = [モジュールクラス new]; if ([モジュールがSelectorに応答します:@selector(setBridge:)]) { モジュール.bridge = 自己; modulesByName[モジュール名] = モジュール; // ... } 構成モジュールこれらのモジュールを取得したら、バックグラウンド スレッドで各モジュールのすべてのメソッドをリストし、__rct__export__ で始まるメソッドを呼び出して、メソッド シグネチャの文字列を取得します。これは、パラメータの実際の型がわかるので重要です。実行時には、パラメータの1つがIDであることしかわかりませんでしたが、この方法では、IDが実際にはNSStringであることがわかります。 符号なし整数メソッドカウント; メソッド *methods = class_copyMethodList(moduleClass, &methodCount); (符号なし整数 i = 0; i < methodCount; i++) { メソッド method = methods[i]; SELセレクター = method_getName(メソッド); if ([NSStringFromSelector(セレクタ) hasPrefix:@"__rct_export__"]) { IMP imp = method_getImplementation(メソッド); NSArray *エントリ = ((NSArray *(*)(id, SEL))imp)(_moduleClass, セレクタ); //... [moduleMethods addObject:/* メソッドを表すオブジェクト */]; } } JavaScriptエグゼキュータの設定JS エグゼキュータには、バックグラウンド スレッドで JS コードを初期化するなど、より複雑な作業を実行できる -setUp メソッドがあります。これにより、すべてのエグゼキュータではなく、アクティブなエグゼキュータのみが setUp メソッド呼び出しを受け取るため、作業もいくらか節約されます。 JSGlobalContextRef ctx = JSGlobalContextCreate(NULL); _context = [[RCTJavaScriptContext alloc] initWithJSContext:ctx]; JSON設定の挿入JSON 構成には、次の例のように、モジュールのみが含まれます。 この構成情報はJavaScript仮想マシンのグローバル変数として保存されるため、JSサイドブリッジが初期化されるときにこの情報を使用してモジュールを作成できます。 JavaScript コードの読み込みこれは非常に簡単で、指定したプロバイダーからソース コードをロードするだけです。通常、開発中はパッケージャーから、運用中はディスクからロードします。 JavaScriptコードの実行すべての準備が整ったら、アプリケーションのソース コードを JS 仮想マシンに読み込み、コードをコピーして解析し、実行できます。すべての CommonJS モジュールは最初の実行時に登録する必要があり、エントリ ファイルが必要です。 JSValueRef jsError = NULL; JSStringRef execJSString = JSStringCreateWithCFString((__bridge CFStringRef) スクリプト); JSStringRef jsURL = JSStringCreateWithCFString((__bridge CFStringRef)sourceURL.absoluteString); JSValueRef 結果 = JSEvaluateScript(strongSelf->_context.ctx, execJSString, NULL, jsURL, 0, &jsError); JSStringRelease(jsURL); JSStringRelease(execJSString); JavaScript のモジュールJS 側では、 react-native の NativeModules を通じて、以前の JSON 構成情報で構成されるモジュールを取得できるようになりました。 動作の仕組みとしては、メソッドを呼び出すと、モジュール名、メソッド名、すべてのパラメータを含むキューに入れられ、JavsScript 実行の最後にこのキューがネイティブ モジュールに渡されて実行されます。 通話サイクル上記のコードを使用してモジュールを呼び出すと、次のようになります。 呼び出しはネイティブから開始する必要があり、ネイティブが JS を呼び出します (この図は、JS が実行中の特定の瞬間のみをキャプチャしています)。実行プロセス中に、JS が NativeModules のメソッドを呼び出すため、この呼び出しはネイティブ側で実行する必要があるため、この呼び出しをキューに入れます。 JS の実行が完了すると、ネイティブ モジュールはキューに入れられたすべての呼び出しを反復処理し、それらの実行が完了すると、ブリッジを介してコールバックし (ネイティブ モジュールは _bridge インスタンスを介して enqueueJSCall:args: を呼び出すことができます)、再度 JS にコールバックします。 (プロジェクトをフォローしている方ならご存知でしょうが、以前はネイティブ -> JS からの呼び出しキューも存在し、vSYNC ごとにディスパッチされていましたが、起動時間を短縮するために削除されました) パラメータタイプネイティブから JS への呼び出しは簡単で、パラメータは NSArray として渡され、JSON データとしてエンコードされますが、JS からネイティブへの呼び出しではネイティブ型が必要であり、そのためには基本型 (int、float、chars など) をチェックしますが、前述のように、どのオブジェクト (構造体) でも、実行時に NSMthodSignature から十分な情報を取得できないため、型を文字列として保存します。 正規表現を使用してメソッド シグネチャから型を抽出し、RCTConvert クラスを使用して実際にオブジェクトを変換します。デフォルトでは、各型のメソッドが提供され、JSON 入力を必要な型に変換しようとします。 構造体でない限り、objc_msgSend を使用してメソッドを動的に呼び出します。arm64 には objc_msgSend_stret のバージョンがないため、NSInvocation を使用します。 すべてのパラメータを変換した後、別の NSInvocation を使用してターゲット モジュールとメソッドを呼び出します。 例: // 特定のモジュールに次のメソッドがある場合、例: `MyModule` RCT_EXPORT_METHOD(methodWithArray:(NSArray *) size:(CGRect)size) {} // JS から次のように呼び出します: 'NativeModules' が必要です。MyModule.method(['a', 1], { x: 0, y: 0, 幅: 200, 高さ: 100 }); // ネイティブに送信される JS キューは次のようになります。 // ** これは呼び出しのキューなので、すべてのフィールドは配列であることに注意してください ** @[ @[ @0 ], // モジュールID @[ @1 ], // メソッドID @[ // 引数 @[ @[@"a", @1], @{ @"x": @0、@"y": @0、@"幅": @200、@"高さ": @100 } ] ] ]; // これは次の呼び出しに変換されます(疑似コード) NSInvocation呼び出し call[args][0] = GetModuleForId(@0) 呼び出し[args][1] = GetMethodForId(@1) call[args][2] = obj_msgSend(RCTConvert, NSArray, @[@"a", @1]) call[args][3] = NSInvocation(RCTConvert, CGRect, @{ @"x": @0, ... }) 電話() スレッド前述のように、-methodQueue メソッドを実装するか、methodQueue プロパティを有効なキューとマージすることによって実行するキューを指定しない限り、各モジュールにはデフォルトで 1 つの GCD キューがあります。例外は ViewManagers* (RCTViewManager を拡張) で、これはデフォルトで Shadow Queue を使用します。また、特別なターゲット RCTJSThread はスレッドでありキューではないため、単なるプレースホルダーです。 (実際、ビュー マネージャーは例外ではありません。基本クラスがシャドウ キューをターゲット キューとして明示的に指定しているためです) 現在のスレッドルールは次のとおりです。
JS 呼び出しのバッチが受信されると、これらの呼び出しはターゲット キューごとにグループ化され、並列に呼び出されます。 // `buckets` 内の `queue` ごとに `calls` をグループ化します for (バケット内のIDキュー) { ディスパッチブロック_tブロック = ^{ NSOrderedSet *calls = [buckets objectForKey:queue]; for (NSNumber *indexObj 呼び出し内) { // 実際に呼び出す } }; if (キュー == RCTJSThread) { [_javaScriptExecutor は JavaScriptQueue 上でブロックを実行します]; } そうでない場合 (キュー) { キュー、ブロックをdispatch_asyncします。 } } 結論React Native ブリッジングの仕組みについての詳細な概要は以上です。これが、より複雑なモジュールを構築したい人や、コア フレームワークに貢献したい人の役に立つことを願っています。 React Native のコア原則 (React Native Bridge) の詳細な理解に関するこの記事はこれで終わりです。React Native の原則に関するその他のコンテンツについては、123WORDPRESS.COM の以前の記事を検索するか、以下の関連記事を引き続き参照してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。 以下もご興味があるかもしれません:
|
<<: Centos 6.9 に MySQL をインストールするための詳細なチュートリアル
>>: Linux における「!」の知られざる使用法のまとめ
1. キャッシュ - クエリキャッシュ次の図は、MySQL 公式サイトから提供されています: MyS...
この記事では、CentOS 7 に Chrome ブラウザをインストールする方法を紹介します。詳細は...
PHP Linux に XML 拡張機能をインストールする1. PHPインストールソースパッケージを...
導入から始めず、いきなり本題に入りましょう。通常の背景ぼかし効果は次のとおりです。 プロパティを使用...
目次最適化の第一歩: 軽量ベースイメージの使用第2段階の最適化:多段階構築Docker は、ソフトウ...
目次FileReaderはローカルファイルまたはBLOBを読み取ります1. FileReaderの使...
ほとんどのナビゲーション バーは、下の図に示すように水平に配置されていますが、これはどのように実現さ...
通常の開発では、凸型の丸い角、つまり border-radius 属性を使用するのが一般的です。凹角...
Linux のコマンドラインで他のユーザーにメッセージを送信するのは簡単です。これを行うコマンドは多...
MySQL ページング分析の原理と効率改善PERCONA PERFORMANCE CONFERENC...
目次序文指導の基本フック機能フック関数のパラメータ文章使い方とアイデア成し遂げる汎用性を高める要約す...
CSS画像結合技術1. 画像のステッチ画像ステッチング技術は、個々の画像を収集する技術です。画像の多...
序文この記事は主にubantu 16.4 Hadoop完全分散構築に関する関連コンテンツを紹介し、皆...
背景ファイルの作成時刻を取得する必要がある場合があります。例えば: 「xtrabackup スキーマ...
Docker-machineはDockerが公式に提供しているDocker管理ツールです。これは d...