React Native iOS Mixed Development Практический курс

внешний интерфейс JavaScript iOS React Native
React Native iOS Mixed Development Практический курс

При разработке RN связь между JS и Native обычно неразрывна, например, когда RN инициализируется, Native передает данные в JS, JS вызывает альбом Native для выбора изображений, JS вызывает модуль Native для выполнения некоторых сложных вычислений, а Native будет некоторые данные (информация GPS, гироскопы, датчики и т. д.) активно передаются в JS и т. д.

В этой статье я познакомлю вас с несколькими способами общения между JS и Native в RN, а также с их принципами и навыками использования;

Далее я расскажу о взаимодействии между JS и Native в различных сценариях.

Несколько сценариев общения:

  • Native передает данные в JS при инициализации RN;
  • Натив отправляет данные в JS;
  • JS отправляет данные в Native;
  • JS отправляет данные в Native, а затем Native возвращает данные в JS;

React-Native-JS-Native-Communication

1. Native передает данные в JS при инициализации RN

init-data-to-js

API RN предоставляет Native способ передачи данных в JS при инициализации страницы JS.Этот способ передачи данных происходит раньше, чем другие способы передачи данных, описанные ниже.

Поскольку информации об этом методе очень мало, может быть много друзей, которые еще не знают этот метод, но это не беда.Далее я покажу вам, как использовать этот метод для передачи данных в JS.

концепция

RN позволяет указать顶级的JS 组件передачаpropsДанные, компонент верхнего уровня можетthis.propsдля получения этих данных.

iOS

[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: self.moduleName //这个"App1"名字一定要和我们在index.js中注册的名字保持一致
                         initialProperties:@{@"params":self.paramsInit}//RN初始化时传递给JS的初始化数据
                             launchOptions: nil];

Далее давайте посмотрим, какiOSВплоть до передачи этих данных инициализации.

iOS передает данные инициализации в RNinitialProperties

RCTRootView от RN обеспечиваетinitWithBundleURLдля рендеринга компонента JS, в этом методе укажите параметр для данных инициализации, передаваемых компоненту JS.

Прототип метода:

- (instancetype)initWithBundleURL:(NSURL *)bundleURL moduleName:(NSString *)moduleName
		initialProperties:(NSDictionary *)initialProperties launchOptions:(NSDictionary *)launchOptions
  • jsCodeLocation: путь к JS-странице RN, которую необходимо отобразить;
  • moduleName: имя загружаемого JS-модуля;
  • initialProperties: для передачи顶级JS组件данные инициализации;
  • launchOptions: в основном используется, когда AppDelegate загружает JS Bundle, просто передайте здесь nil;

Через третий параметр вышеуказанного методаNSDictionaryТип данных, передаваемых в顶级JS组件.

Образец кода:

[[RCTRootView alloc] initWithBundleURL: jsCodeLocation
                                moduleName: self.moduleName
                         initialProperties:@{@"params":@"这是传递给顶级JS组件的数据"}//RN初始化时传递给JS的初始化数据
                             launchOptions: nil];

В приведенном выше коде мы помещаем файл с именемparamsДанные这是传递给顶级JS组件的数据перешел к顶级的JS 组件, затем в顶级的JS 组件Эти данные можно получить следующими методами:

 render() {
        const {params}=this.props;
        return (
            <View style={styles.container}>
                <Text style={styles.data}>来自Native初始化数据:{params}</Text>
            </View>
            );
 }

Кроме того, если вы хотите использовать страницы не верхнего уровня, такие какCommonPageИспользуя эти данные инициализации в , вы можете передать данные вCommonPageстраница:

export default class App extends Component<Props> {
	...
    render() {
        return <CommonPage  {...this.props}/>;
    }
    ...
}

2. Собственная связь с JS (Native отправляет данные в JS)

init-data-to-js

iOS SDK RN предоставляетRCTEventEmitterИнтерфейс, через который мы можем реализовать связь от Native к JS, то есть Native передает данные в JS.

Прототип метода:

- (void)sendEventWithName:(NSString *)name body:(id)body;

Пока мы получаемRCTEventEmitterПримеры могут быть переданы ему с помощью данных JS. чтобы достичьRCTEventEmitterЭкземпляры мы можем наследовать отRCTEventEmitter <RCTBridgeModule>способ достижения:

DataToJSPresenter.h

/**
 * React Native JS Native通信
 * Author: CrazyCodeBoy
 * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702
 * GitHub:https://github.com/crazycodeboy
 * Email:crazycodeboy@gmail.com
 */
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>

@interface DataToJSPresenter : RCTEventEmitter <RCTBridgeModule>

@end

DataToJSPresenter.m

/**
 * React Native JS Native通信
 * Author: CrazyCodeBoy
 * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702
 * GitHub:https://github.com/crazycodeboy
 * Email:crazycodeboy@gmail.com
 */
#import "DataToJSPresenter.h"

@implementation DataToJSPresenter

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents
{
    return @[@"testData"];
}
- (instancetype)init {
    if (self = [super init]) {//在module初始化的时候注册fireData广播
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(fireData:) name:@"fireData" object:nil];
    }
    return self;
}
- (void)fireData:(NSNotification *)notification{//发送数据给RN
    NSString *eventName = notification.object[@"name"];
    NSDictionary *params = notification.object[@"params"];
    [self sendEventWithName:eventName body:params];
}

@end

В приведенном выше методе мы передаемRCTEventEmitterизsendEventWithNameметод будет называтьсяeventNameДанныеparamsперешли на JS.

Подсказка: вDataToJSPresenterв мы достигли(NSArray<NSString *> *)supportedEventsметод, этот метод используется для указания имени события, которое может быть отправлено в JS, поэтому оно отправляется в JS.eventNameОн должен быть настроен в этом методе, иначе он не может быть отправлен.

Шаги, необходимые для реализации связи Native to JS

Далее давайте подытожим шаги, необходимые для реализации связи между Native и JS:

  • первым достичьRCTEventEmitter <RCTBridgeModule>;
  • пройти черезRCTEventEmitterизsendEventWithNameспособ передачи данных в JS;

Выполнив описанные выше шаги, мы можем запустить данные из Native в JS, так как же получить эти данные в JS?

Получить Native pass в JSRCTEventEmitterданные отправлены

В JS вы можете пройтиNativeEventEmitterчтобы получить Native черезRCTEventEmitterПередаваемые данные выглядят следующим образом:

import {NativeEventEmitter} from 'react-native';
export default class CommonPage extends Component<Props> {
    constructor(props) {
        super(props);
        this.state = {
            data: "",
            result: null
        }
    }

    componentWillMount() {
        this.dataToJSPresenter = new NativeEventEmitter(NativeModules.DataToJSPresenter);
        this.dataToJSPresenter.addListener('testData', (e) => {// for iOS
            this.setState({
                data: e.data
            })
        })
	}

    componentWillUnmount() {
        if (this.dataToJSPresenter){
            this.dataToJSPresenter.removeListener('testData');
        }
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={styles.data}>收到Native的数据:{this.state.data}</Text>
            </View>
        );
    }
}

В приведенном выше коде мы передаемNativeEventEmitterизaddListenerДобавлен прослушиватель, который прослушивает имя, отправленное Native.testDataДанные, этоtestDataк вышеизложенномуeventNameЧтобы быть последовательным:

[self sendEventWithName:eventName body:params];

coding.IMO OC.com/lesson/89, Также…Кроме того, не забывайте вовремя удалять прослушиватель, когда компонент JS выгружается.

Вышеизложенный принцип и метод реализации связи между Native и JS в iOS.Далее давайте рассмотрим принцип и метод реализации связи между JS и Native.

3. Связь между JS и Native (JS отправляет данные в Native)

init-data-to-js

Что мы инкапсулируемNativeModuleЭто для JS. Это мост между JS и нативным общением. JS может использовать его для связи с нативом (передача данных, открытие нативных страниц и т. д.). Далее я буду использовать его дляNativeModuleДля реализации связи с JS на Native.

Вы можете узнать и сослаться на то, как реализовать NativeModuleИнкапсуляция нативной модели React Native

Первая реализация JSBridgeModule

Сначала нам нужно реализоватьRCTBridgeModule:

JSBridgeModule.h

/**
 * React Native JS Native通信
 * Author: CrazyCodeBoy
 * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702
 * GitHub:https://github.com/crazycodeboy
 * Email:crazycodeboy@gmail.com
 */
#import <React/RCTBridgeModule.h>
@interface JSBridgeModule : NSObject <RCTBridgeModule>

@end

JSBridgeModule.m

/**
 * React Native JS Native通信
 * Author: CrazyCodeBoy
 * 视频教程:https://coding.imooc.com/lesson/89.html#mid=2702
 * GitHub:https://github.com/crazycodeboy
 * Email:crazycodeboy@gmail.com
 */
#import "JSBridgeModule.h"

@implementation JSBridgeModule

RCT_EXPORT_MODULE();
- (dispatch_queue_t)methodQueue
{
    return dispatch_get_main_queue();//让RN在主线程回调这些方法
}
RCT_EXPORT_METHOD(sendMessage:(NSDictionary*)params){//接受RN发过来的消息
    [[NSNotificationCenter defaultCenter] postNotificationName:@"sendMessage" object:params];
}
@end

Разбор кода

  1. существуетJSBridgeModule, мы реализуемRCT_EXPORT_METHOD(sendMessage:(NSDictionary*)params)метод, который в основном используется для предоставления вызовов JS для передачи данныхparamsна родной;
  2. После получения данных пройтиNSNotificationCenterотправлять данные в виде уведомлений;

JS вызывает JSBridgeModule для отправки данных в Native

import {NativeModules} from 'react-native';

const JSBridge = NativeModules.JSBridgeModule;

JSBridge.sendMessage({text: this.text})

С помощью приведенного выше кода я могу преобразовать данные типа Map{text: this.text}Перешел на родной.

4. JS отправляет данные в Native, а затем Native отправляет данные обратно в JS.

init-data-to-js

через вышеуказанноеJS到Native的通信(JS发送数据给Native), мы реализовали связь с JS на Native, в то время мы использовалиJSBridgeModule, на самом деле его функция этим не ограничивается, с его помощью мы также можем реализовать возврат данных из Native в JS.

Реализация в родном

существуетJSBridgeModuleДобавьте следующий метод в:

RCT_EXPORT_METHOD(doAdd:(NSInteger )num1 num2:(NSInteger )num2 resolver:(RCTPromiseResolveBlock)resolve
                  rejecter:(RCTPromiseRejectBlock)reject)
{
    NSInteger result=num1+num2;
    resolve([NSString stringWithFormat:@"%ld",(long)result]);//回调JS
}

Приведенный выше код предоставляет простую операцию сложения между двумя целыми числами для JS и возвращает результат операции в JS.Здесь мы используемRCTPromiseResolveBlockа такжеRCTPromiseRejectBlockДва типа обратных вызовов, представляющих успех и неудачу соответственно.

Реализация на JS

import {NativeModules} from 'react-native';

const JSBridge = NativeModules.JSBridgeModule;
JSBridge.doAdd(parseInt(this.num1), parseInt(this.num2)).then(e => {
    this.setState({
        result: e
    })
})

В JS мы проходимJSBridge.doAddметод преобразует два целых числаnum1а такжеnum2Перешли на Native, а потом перешлиthenЧтобы контролировать результаты возврата, весь процесс используетPromiseМетод цепного вызова.

Ссылаться на