React Native JSIはRNとネイティブ通信のサンプルコードを実装します

React Native JSIはRNとネイティブ通信のサンプルコードを実装します

JSIとは

React Native JSI (JavaScript インターフェース) を使用すると、JavaScript とネイティブ モジュール間の通信がより高速かつ簡単になります。これは、React Native の新しいアーキテクチャにおける Fabric UI レイヤーと Turbo モジュールのコア部分でもあります。

JSIの違い

JSI はネイティブ コードと JavaScript コード間のブリッジを削除し、両端が互いに呼び出すときに JSON のシリアル化と逆シリアル化の操作を大幅に節約します。 JSI はネイティブと JS の相互作用に新たな扉を開きます。 JSI の機能の一部を以下に示します。

  1. JavaScript インターフェイスを使用すると、JavaScript ランタイムにメソッドを登録できます。これらのメソッドは、js 環境のグローバル オブジェクトを通じて取得および呼び出すことができます。
  2. これらの登録メソッドを実装するには、iOS では C++ または OC、Android では Java を使用できます。
  3. もともとブリッジ方式を使用して実装されたネイティブ モジュールは、C++ のレイヤーを追加することで、すぐに JSI に変換できます。
  4. C++ と OC を簡単に混在させることができるため、iOS での実装は非常にシンプルです。
  5. Android では、JNI を介して何らかの変換を行う必要があります。
  6. これらのメソッドは完全に同期できるため、非同期は必須ではありません。待つ。

iOS で JSI を使用する

次に、iOS プロジェクトで JSI を使用して、ネイティブと JS の通信を段階的に実現します。
新しいReact Nativeプロジェクトを作成する

npx 反応ネイティブ初期化 jsiDemo

iOS 設定

iOS プロジェクト ディレクトリに C++ ファイル example.h と example.cpp を作成します。
例.h

#ifndef 例_H
#EXAMPLE_H を定義します

名前空間 facebook {
 名前空間 jsi {
  クラス Runtime;
 }
}

名前空間の例 {
 void をインストールします(facebook::jsi::Runtime &jsiRuntime);
}
#endif /* 例_H */

例.m
#include "example.h"
#include <jsi/jsi.h>
名前空間 facebook::jsi を使用します。
名前空間 std を使用します。

名前空間の例 {
 void インストール(ランタイム &jsiRuntime) {  
    自動helloWorld = Function::createFromHostFunction(jsiRuntime,
                                                       PropNameID::forAscii(jsiRuntime,
                                                                            "こんにちは世界")、
                                                       0,
                                                       [](ランタイム &runtime,
                                                          定数値 &thisValue,
                                                          const 値 *引数、
                                                          size_t count) -> 値 {
        文字列 helloworld = "helloworld";
        戻り値(runtime、String::createFromUtf8(runtime、helloworld));
    });
    
    jsiRuntime.global().setProperty(jsiRuntime, "helloWorld", move(helloWorld));
    
 }
}

上記のコードでは、createFromHostFunction メソッドを使用してメソッドを作成し、setProperty メソッドを通じて js ランタイムに登録します。
次に、モジュールを作成し、モジュール内で install メソッドを実行する必要があります。
OCファイルSimpleJsi.h、SimpleJsi.mmを作成します。

シンプルJsi.h

#import <React/RCTBridgeModule.h>
@interface SimpleJsi : NSObject <RCTBridgeModule>
@property (非アトミック、割り当て) BOOL setBridgeOnMainQueue;
@終わり

シンプルJsi.mm

#「SimpleJsi.h」をインポートします
#import <React/RCTBridge+Private.h>
#import <React/RCTUtils.h>
#import <jsi/jsi.h>
#import "example.h"
#import <sys/utsname.h>

名前空間 facebook::jsi を使用します。
名前空間 std を使用します。

@実装 SimpleJsi

@synthesize ブリッジ = _bridge;
メソッドキューを合成します。

RCT_EXPORT_MODULE()

+ (BOOL)MainQueueSetup が必要 {
    
    YESを返します。
}

- (void)setBridge:(RCTBridge *)ブリッジ{
    _bridge = ブリッジ;
    _setBridgeOnMainQueue = RCTIsMainQueue();
    [自己インストールライブラリ];
}

- (void)インストールライブラリ{
    
    RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
    
    cxxBridge.runtime の場合 {
        
        /**
         * これはライブラリをインストールするための回避策です
         * ランタイムが利用可能になり次第、
         * 推奨されません。iOSでランダムクラッシュが発生する場合
         * global.xxx が見つからない場合などにこれを使用します。
         */
        
        ディスパッチ後(ディスパッチ時間(DISPATCH_TIME_NOW、0.001 * NSEC_PER_SEC)、
                       ディスパッチ_get_main_queue()、^{
            /**
             デバッグ中にアプリを更新すると、setBridge
             メソッドが早すぎるタイミングで呼び出されます。ランタイムはまだ準備ができていません
             かなり頻繁に。実行時にすぐにライブラリをインストールする必要がある
             利用可能になります。
             */
            [自己インストールライブラリ];
            
        });
        戻る;
    }
    
    例::install(*(facebook::jsi::Runtime *)cxxBridge.runtime);
}

@終わり

setBridge メソッドでは、example の install メソッドを呼び出してメソッドの登録を完了しました。

RN側の構成

App.js を変更する

'react' から React をインポートします。
'react' から {Node} 型をインポートします。
'react-native' から {Text、View、Button} をインポートします。

const アプリ: () => ノード = () => {
  const [結果、setResult] = React.useState();

  const プレス = () => {
    グローバルなhelloWorld()を設定します。
  };
  戻る (
    // eslint は次の行を無効にする react-native/no-inline-styles
    <表示スタイル={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <表示スタイル={{height: '10%'}} />
      <Button onPress={press} title="ボタン" />
      <Text>{'helloword を呼び出す:' + 結果}</Text>
    </表示>
  );
};

デフォルトのアプリをエクスポートします。

ボタンをクリックすると、結果の値が helloworld であることがわかります。

結果

上記では、パラメータなしでネイティブ呼び出しの js を実装しました。次に、単一のパラメータ呼び出しを実装します。

jsはパラメータ付きのネイティブメソッドを呼び出します

example.cpp の install メソッドに multiply メソッドの登録を追加し、arguments から入力パラメータを取得します。

自動乗算 = Function::createFromHostFunction(jsiRuntime,
                                                     PropNameID::forAscii(jsiRuntime,
                                                                          「掛ける」)、
                                                     2、
                                                     [](ランタイム &runtime,
                                                        定数値 &thisValue,
                                                        const 値 *引数、
                                                        size_t count) -> 値 {
        int x = 引数[0].getNumber();
        int y = 引数[1].getNumber();
        戻り値(x * y); 
    });

jsiRuntime.global().setProperty(jsiRuntime, "multiply", move(multiply));

次にApp.jsを変更します

'react' から React をインポートします。
'react' から {Node} 型をインポートします。
'react-native' から {Text、View、Button} をインポートします。

const アプリ: () => ノード = () => {
  const [結果、setResult] = React.useState();

  const プレス = () => {
    setResult(global.multiply(2, 2));
  };
  戻る (
    // eslint は次の行を無効にする react-native/no-inline-styles
    <表示スタイル={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <表示スタイル={{height: '10%'}} />
      <Button onPress={press} title="ボタン" />
      <テキスト>{'2*2 = ' + 結果}</テキスト>
    </表示>
  );
};

デフォルトのアプリをエクスポートします。

結果

ネイティブコールJS

js のネイティブ呼び出しは、主に jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMethod").call(jsiRuntime); メソッドを通じて実装されます。
まず、js に js メソッドを追加します。 App.js を変更し、jsMethod メソッドを追加します。

'react' から React をインポートします。
'react' から {Node} 型をインポートします。
'react-native' から {Text、View、Button} をインポートします。

const アプリ: () => ノード = () => {
  const [結果、setResult] = React.useState();

  global.jsメソッド = () => {
    アラート('hello jsMethod');
  };

  const プレス = () => {
    setResult(global.multiply(2, 2));
  };
  戻る (
    // eslint は次の行を無効にする react-native/no-inline-styles
    <表示スタイル={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <表示スタイル={{height: '10%'}} />
      <Button onPress={press} title="ボタン" />
      <テキスト>{'2*2 = ' + 結果}</テキスト>
    </表示>
  );
};

デフォルトのアプリをエクスポートします。

ネイティブ側では、アプリケーションに入るときに js メソッドがトリガーされると想定し、AppDelegate の applicationWillEnterForeground メソッドを変更します。

- (void)applicationWillEnterForeground:(UIApplication *)application {
  SimpleJsi *jsi = [self.bridge モジュール名:@"SimpleJsi"];
  [jsi コールjs];
}

moduleForName メソッドを通じて SimpleJsi オブジェクトを取得し、SimpleJsi の calljs メソッドを使用します。

- (void)calljs {
  RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
  ランタイム &jsiRuntime = *(facebook::jsi::Runtime *)cxxBridge.runtime;
  jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMethod").call(jsiRuntime);
}

結果

パラメータ付きのJSメソッドへのネイティブ呼び出し

複数パラメータ呼び出しは、呼び出しメソッドの後にパラメータ リストが追加される点を除いて、ゼロ パラメータ呼び出しと似ています。
まず、js側でメソッドを定義し、app.jsを変更します。

'react' から React をインポートします。
'react' から {Node} 型をインポートします。
'react-native' から {Text、View、Button} をインポートします。

const アプリ: () => ノード = () => {
  const [結果、setResult] = React.useState();

  global.jsメソッド = () => {
    アラート('hello jsMethod');
  };

  global.js乗算 = (x, y) => {
    警告('x * y = ' + x * y);
  };

  const プレス = () => {
    setResult(global.multiply(2, 2));
  };
  戻る (
    // eslint は次の行を無効にする react-native/no-inline-styles
    <表示スタイル={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <表示スタイル={{height: '10%'}} />
      <Button onPress={press} title="ボタン" />
      <テキスト>{'2*2 = ' + 結果}</テキスト>
    </表示>
  );
};

デフォルトのアプリをエクスポートします。

次にネイティブエンドの呼び出しを変更します
アプリデリゲート.m

- (void)applicationWillEnterForeground:(UIApplication *)application {
  SimpleJsi *jsi = [self.bridge モジュール名:@"SimpleJsi"];
// [jsi calljs];
  [jsi callJsMultiply:4 y:4];
}

シンプルJsi.m

- (void)callJsMultiply:(int)xy:(int)y {
  RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
  ランタイム &jsiRuntime = *(facebook::jsi::Runtime *)cxxBridge.runtime;
  jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMultiply").call(jsiRuntime, x, y);
}

結果

ネイティブ側でjs関数パラメータを呼び出す

ネイティブ コードの js パラメータで関数を呼び出すには、 arguments[i].getObject(runtime).getFunction(runtime).call(runtime, value); ; を通じてトリガーする必要があります。

まず、example.cppに新しいメソッドmultiplyWithCallbackを登録します。

自動 multiplyWithCallback = Function::createFromHostFunction(jsiRuntime,
                                                                 PropNameID::forAscii(jsiRuntime,
                                                                                      "multiplyWithCallback")、
                                                                 3、
                                                                 [](ランタイム &runtime,
                                                                    定数値 &thisValue,
                                                                    const 値 *引数、
                                                                    size_t count) -> 値 {
        int x = 引数[0].getNumber();
        int y = 引数[1].getNumber();
        //コールバックを呼び出す
        引数[2].getObject(runtime).getFunction(runtime).call(runtime, x * y);
        
        戻り値();
        
    });
    
    jsiRuntime.global().setProperty(jsiRuntime, "multiplyWithCallback", move(multiplyWithCallback));

js側を呼び出し、app.jsを変更します

'react' から React をインポートします。
'react' から {Node} 型をインポートします。
'react-native' から {Text、View、Button} をインポートします。

const アプリ: () => ノード = () => {
  const [結果、setResult] = React.useState();

  global.jsメソッド = () => {
    アラート('hello jsMethod');
  };

  global.js乗算 = (x, y) => {
    警告('x * y = ' + x * y);
  };

  const プレス = () => {
    // setResult(global.multiply(2, 2));
    グローバル.multiplyWithCallback(4, 5, アラート結果);
  };

  定数アラート結果 = res => {
    アラート(res);
  };

  戻る (
    // eslint は次の行を無効にする react-native/no-inline-styles
    <表示スタイル={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <表示スタイル={{height: '10%'}} />
      <Button onPress={press} title="ボタン" />
      <テキスト>{'2*2 = ' + 結果}</テキスト>
    </表示>
  );
};

デフォルトのアプリをエクスポートします。

ボタンをクリックすると、multiplyWithCallback が呼び出され、alertResult メソッドがネイティブ メソッドに渡されます。

結果

要約する

以上が本記事におけるJSIの紹介です。記事内のコードのGitHubダウンロードアドレスを取得するには、公式アカウントでJSIに返信してください。

質問

RN Debug の場合、global.xx では対応するメソッドが見つからず、わかりません。解決策がございましたら、ご連絡ください。よろしくお願いいたします。

参考文献

https://blog.notesnook.com/getting-started-react-native-jsi/
reactnative.maxieewong.com/
https://github.com/react-native-community/discussions-and-proposals/issues/91
ospfranco.com/

React Native JSI で RN とネイティブ通信を実装するためのサンプルコードに関するこの記事はこれで終わりです。React Native ネイティブ通信に関するより関連性の高いコンテンツについては、123WORDPRESS.COM の過去の記事を検索するか、以下の関連記事を引き続き閲覧してください。今後とも 123WORDPRESS.COM をよろしくお願いいたします。

以下もご興味があるかもしれません:
  • React NativeとAndroidネイティブ通信方式

<<:  MySql 組み込み関数の自習知識ポイントまとめ

>>:  Linuxシステムにmsfをインストールするプロセスの詳細な説明

推薦する

MySQL はパスワード強度の検証をオフにします

パスワード強度検証について: [root@mysql mysql]# mysql -uroot -p...

js 配列エントリ() 反復メソッドを取得する

目次1.entires() メソッドの詳細な構文2.entires() メソッドの一般的な使用法と注...

Linux クラウド サーバーに JDK と Tomcat をインストールするための詳細な手順 (推奨)

JDKをダウンロードしてインストールするステップ 1: まず、公式 Web サイト http://...

vue 要素 el-transfer にドラッグ機能を追加

コア資産管理プロジェクトでは、el-transfer にドラッグ アンド ドロップによる並べ替えと、...

MySQL 8.0.25 解凍版のインストールと設定方法のグラフィックチュートリアル

MySQL 8.0.25解凍版のインストールチュートリアル、参考までに具体的な内容は以下のとおりです...

vue3 における vuex と pinia の落とし穴

目次導入インストールと使用方法文章の相違点と類似点の簡単な比較VuexとPiniaの長所と短所Pin...

ウェブページの要素の検査とソースコードの表示の違いについて

Chrome ブラウザで Web ページを開くと、ページを右クリックすると 2 つの非常によく似たオ...

mysql における mydumper と mysqldump の比較

いくつかのテーブルまたは単一のデータベースのみをバックアップする場合は、innobackup よりも...

Jenkins統合Dockerプラグインの問題を解決するいくつかの方法

目次背景質問1エラー 2エラー 3エラー4要約する背景テスト環境では、docker プラグインを統合...

Vue プロジェクトでの支払い機能の実装 (WeChat 支払いと Alipay 支払い)

目次プロジェクトにおける一般的な支払い方法Alipay決済微信ペイプロジェクトにおける一般的な支払い...

Ubuntu仮想マシンでシリアル通信にcutecomを使用する方法

Ubuntu仮想マシンでのシリアル通信にcutecomを使用する1. cutecomをインストールす...

MySQLデータ内の多数の改行と復帰に対する解決策

目次問題を見つける1. 改行と復帰を削除する方法2. SELECTクエリで「改行と復帰」を無視する方...

検索ボックスと検索ボタンの境界線が重なり合わない問題を解決

今日、Baiduのページで練習していたところ、検索ボックスとボタンの余白とパディングの値が0に設定さ...

JavaScriptの厳密モードが8進数をサポートしていない問題の説明

JavaScript厳密モードが 8 進数をサポートしていないという問題に関して、まず、 Java...

Vueでファジークエリを実装する方法の簡単な例

序文いわゆるファジークエリとは、ユーザーの完全な入力やすべての入力情報がなくてもクエリサービスを提供...