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をインストールするプロセスの詳細な説明

推薦する

Vue で手ぶれ補正を実装するためのサンプルコード

手ぶれ防止: 繰り返しのクリックによるイベントのトリガーを防止まず、揺れとは何でしょうか? 震えるの...

SSH経由でローカルLinux仮想マシンに接続するプロセスを記録する

実験環境:物理マシン Windows 10 x64物理NIC情報IPv4 アドレス: 192.168...

JavaScript の querySelector メソッドと getElementById メソッドの違いを分析する

目次1. 概要1.1 querySelector() と querySelectorAll() の使...

MySQLはbinlogを通じてデータを復元する

目次MySQL ログファイルバイナリログBinlogログがオンになっていますログ記録を有効にする方法...

MySQL 外部キー制約 (FOREIGN KEY) ケースの説明

MySQL 外部キー制約 (FOREIGN KEY) はテーブルの特別なフィールドであり、主キー制約...

星のきらめき効果を実現するネイティブ js

この記事の例では、星のきらめき効果を実現するためのjsの具体的なコードを共有しています。具体的な内容...

デザイン理論: なぜ私たちは間違った場所を見ているのでしょうか?

数日前、バスで仕事に行きました。バスのカードリーダーの実際の使用シーンを実際に見て、カードリーダーの...

Nexusプライベートサーバー構築原理とチュートリアル分析

1つ。 Nexus プライベート サーバーを構築する理由は何ですか?社内の開発メンバーは全員外部ネッ...

CCS におけるマージン: トップ崩壊問題を解決する

HTML 構造は次のとおりです。 CCS 構造は次のとおりです。 ページ効果図は次のとおりです。 こ...

mysql init_connect に関するいくつかの重要なポイントの要約

init_connectの役割init_connect は通常、接続が来たときに、自動コミットを 0...

DockerでSpringbootプロジェクトを実行する方法

1. IDEAの下にあるターミナルをクリックし、mvn clean installと入力します。 次...

ユーザーエクスペリエンスの概要

最近では、ソフトウェアやウェブサイトのいずれの作業であっても、設計時に「ユーザー エクスペリエンス」...

CSSは2つの要素をブレンドする効果(スティッキー効果)を実現します。

数年前、Taobaoのモバイル版の左下隅に面白い丸いボタンがあったことを覚えています。それをクリック...

MySQL 8.0.12 の詳細なインストールおよびアンインストール チュートリアル

1. MySQL 8.0.12 バージョンのインストール手順。 1. ダウンロードhttps://d...