中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

怎么用React Native JSI實現RN與原生通信

發布時間:2021-08-24 08:55:38 來源:億速云 閱讀:219 作者:chen 欄目:開發技術

這篇文章主要介紹“怎么用React Native JSI實現RN與原生通信”,在日常操作中,相信很多人在怎么用React Native JSI實現RN與原生通信問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”怎么用React Native JSI實現RN與原生通信”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

目錄
  • 什么是JSI

  • JSI有什么不同

  • 在iOS中使用JSI

    • iOS端配置

    • RN端配置

    • js調用帶參數的原生方法

    • 原生調用JS

    • 原生調用帶參數的JS方法

    • 在原生端調用js的函數參數


什么是JSI

React Native JSI (JavaScript Interface) 可以使 JavaScript 和 原生模塊 更快、更簡單的通信。它也是React Native 新的架構體系中Fabric UI層 和 Turbo 模塊的核心部分。

JSI有什么不同

JSI 移除了原生代碼和JavaScript代碼之間的橋接(bridge),同時也省去了兩端相互調用時大量的JSON序列化和反序列化操作。JSI為原生和JS交互打開了新的大門。下面是一些JSI的特點:

  1. JavaScript Interface 允許我們向JavaScript 運行時注冊方法。這些方法在js環境中可以通過 global對象獲取并調用。

  2. 我們完全可以使用C++或者在iOS里使用OC ,在Android里使用Java實現這些注冊方法。

  3. 原先使用bridge 的方式實現的原生模塊可以通過增加一層C++,快速轉化為通過JSI實現。

  4. 在iOS端實現非常簡單,因為C++和OC 可以方便的實現混編。

  5. 在Android中,我們需要通過JNI 做一些轉化。

  6. 這些方法可以是完全同步的,這意味著不必強制使用async。await。

在iOS中使用JSI

下面我們將一步一步的在iOS工程中使用JSI實現原生與JS的通信。
創建一個新的React Native 項目

npx react-native init jsiDemo

iOS端配置

在iOS項目目錄中創建C++文件,example.h、 example.cpp。
example.h

#ifndef EXAMPLE_H
#define EXAMPLE_H

namespace facebook {
 namespace jsi {
  class Runtime;
 }
}

namespace example {
 void install(facebook::jsi::Runtime &jsiRuntime);
}
#endif /* EXAMPLE_H */

example.m
#include "example.h"
#include <jsi/jsi.h>
using namespace facebook::jsi;
using namespace std;

namespace example {
 void install(Runtime &jsiRuntime) {  
    auto helloWorld = Function::createFromHostFunction(jsiRuntime,
                                                       PropNameID::forAscii(jsiRuntime,
                                                                            "helloWorld"),
                                                       0,
                                                       [](Runtime &runtime,
                                                          const Value &thisValue,
                                                          const Value *arguments,
                                                          size_t count) -> Value {
        string helloworld = "helloworld";
        return Value(runtime, String::createFromUtf8(runtime,helloworld));
    });
    
    jsiRuntime.global().setProperty(jsiRuntime, "helloWorld", move(helloWorld));
    
 }
}

在上面的代碼中,我們使用 createFromHostFunction 方法創建了一個方法,并通過setProperty 方法將其注冊到js運行時。
接下來,我們需要創建一個moudle, 在moudle中執行install 方法。
我們創建OC 文件,SimpleJsi.h , SimpleJsi.mm

SimpleJsi.h

#import <React/RCTBridgeModule.h>
@interface SimpleJsi : NSObject <RCTBridgeModule>
@property (nonatomic, assign) BOOL setBridgeOnMainQueue;
@end

SimpleJsi.mm

#import "SimpleJsi.h"
#import <React/RCTBridge+Private.h>
#import <React/RCTUtils.h>
#import <jsi/jsi.h>
#import "example.h"
#import <sys/utsname.h>

using namespace facebook::jsi;
using namespace std;

@implementation SimpleJsi

@synthesize bridge = _bridge;
@synthesize methodQueue = _methodQueue;

RCT_EXPORT_MODULE()

+ (BOOL)requiresMainQueueSetup {
    
    return YES;
}

- (void)setBridge:(RCTBridge *)bridge {
    _bridge = bridge;
    _setBridgeOnMainQueue = RCTIsMainQueue();
    [self installLibrary];
}

- (void)installLibrary {
    
    RCTCxxBridge *cxxBridge = (RCTCxxBridge *)self.bridge;
    
    if (!cxxBridge.runtime) {
        
        /**
         * This is a workaround to install library
         * as soon as runtime becomes available and is
         * not recommended. If you see random crashes in iOS
         * global.xxx not found etc. use this.
         */
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.001 * NSEC_PER_SEC),
                       dispatch_get_main_queue(), ^{
            /**
             When refreshing the app while debugging, the setBridge
             method is called too soon. The runtime is not ready yet
             quite often. We need to install library as soon as runtime
             becomes available.
             */
            [self installLibrary];
            
        });
        return;
    }
    
    example::install(*(facebook::jsi::Runtime *)cxxBridge.runtime);
}

@end

在 setBridge 方法中,我們調用了 example的 install  方法,完成方法的注冊。

RN端配置

修改App.js

import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';

const App: () => Node = () => {
  const [result, setResult] = React.useState();

  const press = () => {
    setResult(global.helloWorld());
  };
  return (
    // eslint-disable-next-line react-native/no-inline-styles
    <View style={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <View style={{height: '10%'}} />
      <Button onPress={press} title="按鈕" />
      <Text>{'調用helloword:' + result}</Text>
    </View>
  );
};

export default App;

點擊按鈕之后,發現result的值為helloworld。

結果

怎么用React Native JSI實現RN與原生通信

上面我們實現了js 調用原生,但沒有參數,接下來我們實現一個單參數的調用。

js調用帶參數的原生方法

我們在example.cpp  的 install 方法中增加multiply方法的注冊,從arguments 中取出入參。

auto multiply = Function::createFromHostFunction(jsiRuntime,
                                                     PropNameID::forAscii(jsiRuntime,
                                                                          "multiply"),
                                                     2,
                                                     [](Runtime &runtime,
                                                        const Value &thisValue,
                                                        const Value *arguments,
                                                        size_t count) -> Value {
        int x = arguments[0].getNumber();
        int y = arguments[1].getNumber();
        return Value(x * y); 
    });

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

然后修改App.js

import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';

const App: () => Node = () => {
  const [result, setResult] = React.useState();

  const press = () => {
    setResult(global.multiply(2, 2));
  };
  return (
    // eslint-disable-next-line react-native/no-inline-styles
    <View style={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <View style={{height: '10%'}} />
      <Button onPress={press} title="按鈕" />
      <Text>{'2*2 = ' + result}</Text>
    </View>
  );
};

export default App;

結果

怎么用React Native JSI實現RN與原生通信

原生調用JS

原生調用js主要通過jsiRuntime.global().getPropertyAsFunction(jsiRuntime, "jsMethod").call(jsiRuntime);方法實現。
首先我們在js中增加一個js方法。我們修改App.js 在上面增加jsMethod 方法。

import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';

const App: () => Node = () => {
  const [result, setResult] = React.useState();

  global.jsMethod = () => {
    alert('hello jsMethod');
  };

  const press = () => {
    setResult(global.multiply(2, 2));
  };
  return (
    // eslint-disable-next-line react-native/no-inline-styles
    <View style={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <View style={{height: '10%'}} />
      <Button onPress={press} title="按鈕" />
      <Text>{'2*2 = ' + result}</Text>
    </View>
  );
};

export default App;

在原生端,我們假設在進入應用的時候觸發調用js方法,我們修改AppDelegate中的applicationWillEnterForeground 方法。

- (void)applicationWillEnterForeground:(UIApplication *)application {
  SimpleJsi *jsi = [self.bridge moduleForName:@"SimpleJsi"];
  [jsi calljs];
}

通過moduleForName方法獲取SimpleJsi對象, 然后通過SimpleJsi中的calljs 方法。

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

結果

怎么用React Native JSI實現RN與原生通信

原生調用帶參數的JS方法

多參數調用和無參調用類似,只是在call方法后面增加了參數列表。
首先我們先在js側定義方法,修改app.js

import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';

const App: () => Node = () => {
  const [result, setResult] = React.useState();

  global.jsMethod = () => {
    alert('hello jsMethod');
  };

  global.jsMultiply = (x, y) => {
    alert('x * y = ' + x * y);
  };

  const press = () => {
    setResult(global.multiply(2, 2));
  };
  return (
    // eslint-disable-next-line react-native/no-inline-styles
    <View style={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <View style={{height: '10%'}} />
      <Button onPress={press} title="按鈕" />
      <Text>{'2*2 = ' + result}</Text>
    </View>
  );
};

export default App;

然后我們修改原生端的調用
AppDelegate.m

- (void)applicationWillEnterForeground:(UIApplication *)application {
  SimpleJsi *jsi =  [self.bridge moduleForName:@"SimpleJsi"];
//  [jsi calljs];
  [jsi callJsMultiply:4 y:4];
}

SimpleJsi.m

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

結果

怎么用React Native JSI實現RN與原生通信

在原生端調用js的函數參數

在原生中調用js參數中的函數,需要通過arguments[i].getObject(runtime).getFunction(runtime).call(runtime, value);的方式觸發。

首先我們在example.cpp 中新注冊一個方法multiplyWithCallback

auto multiplyWithCallback = Function::createFromHostFunction(jsiRuntime,
                                                                 PropNameID::forAscii(jsiRuntime,
                                                                                      "multiplyWithCallback"),
                                                                 3,
                                                                 [](Runtime &runtime,
                                                                    const Value &thisValue,
                                                                    const Value *arguments,
                                                                    size_t count) -> Value {
        int x = arguments[0].getNumber();
        int y = arguments[1].getNumber();
        //調用callback
        arguments[2].getObject(runtime).getFunction(runtime).call(runtime, x * y);
        
        return Value();
        
    });
    
    jsiRuntime.global().setProperty(jsiRuntime, "multiplyWithCallback", move(multiplyWithCallback));

在js側進行調用, 修改app.js

import React from 'react';
import type {Node} from 'react';
import {Text, View, Button} from 'react-native';

const App: () => Node = () => {
  const [result, setResult] = React.useState();

  global.jsMethod = () => {
    alert('hello jsMethod');
  };

  global.jsMultiply = (x, y) => {
    alert('x * y = ' + x * y);
  };

  const press = () => {
    // setResult(global.multiply(2, 2));
    global.multiplyWithCallback(4, 5, alertResult);
  };

  const alertResult = res => {
    alert(res);
  };

  return (
    // eslint-disable-next-line react-native/no-inline-styles
    <View style={{backgroundColor: '#FFFFFF', height: '100%'}}>
      <View style={{height: '10%'}} />
      <Button onPress={press} title="按鈕" />
      <Text>{'2*2 = ' + result}</Text>
    </View>
  );
};

export default App;

點擊按鈕之后,會調用multiplyWithCallback 將alertResult 方式傳遞給原生。

結果

怎么用React Native JSI實現RN與原生通信

到此,關于“怎么用React Native JSI實現RN與原生通信”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

崇明县| 阿图什市| 益阳市| 涞水县| 桃源县| 西充县| 镇巴县| 青海省| 井研县| 鲁山县| 黄浦区| 武山县| 贵定县| 鄢陵县| 和平区| 大渡口区| 长沙县| 耿马| 宜丰县| 华阴市| 禹州市| 巴中市| 平湖市| 昭觉县| 中宁县| 常熟市| 南岸区| 乌苏市| 木里| 岳普湖县| 安国市| 五家渠市| 牙克石市| 泰安市| 开封县| 淳安县| 新干县| 肃宁县| SHOW| 晋宁县| 海阳市|