美文网首页
RN与原生模块互调

RN与原生模块互调

作者: 春暖花已开 | 来源:发表于2022-12-19 16:02 被阅读0次
    1、iOS与RN的互调

    相对于Android来说,iOS的两端互调比较简单。先看iOS里 ShowAlert的配置:

    // .h
    #import <React/RCTBridgeModule.h>
    #import <React/RCTEventEmitter.h>
    
    NS_ASSUME_NONNULL_BEGIN
    
    @interface ShowAlert : RCTEventEmitter<RCTBridgeModule>
    
    @end
    
    NS_ASSUME_NONNULL_END
    
    
    // .m
    #import "ShowAlert.h"
    
    @interface ShowAlert ()
    @property (nonatomic, assign) BOOL hasListener;
    @end
    
    static NSString * const EVENT_NAME = @"AlertDismiss";
    
    @implementation ShowAlert
    
    // 如果 RCT_EXPORT_MODULE 里有传参, 则按照传参作为模块名, 否则是类名
    RCT_EXPORT_MODULE(Alert)
    
    // 原生调用RN
    - (NSArray<NSString *> *)supportedEvents {
      return @[EVENT_NAME];
    }
    
    // 在添加第一个监听函数时触发
    - (void)startObserving {
      self.hasListener = YES;
    }
    
    // 当该模块的最后一个监听者被移除, 或者释放的时候 调用
    - (void)stopObserving {
      self.hasListener = NO;
    }
    
    - (void)sendToRNWithInfo:(NSString *)info {
      // 只有在有监听的情况下才发射事件, 防止资源浪费和警告
      if (self.hasListener) {
        [self sendEventWithName:EVENT_NAME body:info];
      }
    }
    
    - (void)in_showAlert:(NSString *)title content:(NSString *) content done:(RCTResponseSenderBlock)done {
      UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:content preferredStyle: UIAlertControllerStyleAlert];
      UIAlertAction *defaultAction = [UIAlertAction actionWithTitle:@"确定" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self sendToRNWithInfo: @"确定"];
      }];
      UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self sendToRNWithInfo: @"取消"];
      }];
      
      [alertVC addAction:defaultAction];
      [alertVC addAction:cancelAction];
      
      [[UIApplication sharedApplication].delegate.window.rootViewController presentViewController:alertVC animated:true completion:^{
        !done ?: done(@[@"已经展示了"]);
      }];
    }
    
    // 暴露的方法名
    RCT_EXPORT_METHOD(showAlert:(NSString *)title content:(NSString *) content done:(RCTResponseSenderBlock)done) {
      [self in_showAlert:title content:content done:done];
    }
    
    // 导出的常量, 取值方式: 模块.key
    - (NSDictionary *)constantsToExport {
      return  @{
        @"one": @"大写的一",
        @"two": @"大写的二"
      };
    }
    
    // 重写constantsToExport, 必须重写此方法
    + (BOOL)requiresMainQueueSetup {
      return true;
    }
    
    // 涉及UI的, 表明初始化的线程, 默认为background线程
    - (dispatch_queue_t)methodQueue{
        return dispatch_get_main_queue();
    }
    
    @end
    

    在 RN 里使用:

    import { Button } from '@ant-design/react-native'
    import { memo, useEffect } from 'react'
    import { NativeEventEmitter, NativeModules, View } from 'react-native'
    
    // 获取模块名
    const { Alert } = NativeModules
    // 原生事件发射器
    const alertEmitter = new NativeEventEmitter(Alert)
    
    export default memo(function HomePage() {
      useEffect(() => {
        // 添加监听, 用于被原生模块调用
        const subscription = alertEmitter.addListener('AlertDismiss', info => {
          console.log('选择的状态info :>> ', info)
        })
    
        return () => {
          // 在组件卸载的时候移除监听
          subscription.remove()
        }
      }, [])
    
      return (
        <View>
          <Button
            onPress={() => {
              // RN调用原生方法
              NativeModules.Alert.showAlert('这是标题', '这是内容', info => {
                console.log('error, events :>> ', info)
              })
            }}>
            调用原生模块
          </Button>
        </View>
      )
    })
    

    2、Android与RN的互调

    a. 编写Module CalendarModule

    package com.zxmall;
    
    import android.util.Log;
    
    import androidx.annotation.NonNull;
    import androidx.annotation.Nullable;
    
    import com.facebook.react.bridge.Callback;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.bridge.ReactContextBaseJavaModule;
    import com.facebook.react.bridge.ReactMethod;
    
    import java.util.HashMap;
    import java.util.Map;
    
    public class CalendarModule extends ReactContextBaseJavaModule {
      CalendarModule(ReactApplicationContext context) {
        super(context);
      }
    
      /**
       * 模块名称
       */
      @NonNull
      @Override
      public String getName() {
        return "CalendarModule";
      }
    
      /**
       * 导出常量, 取值: 模块名.key 的方式
       * @return 暴露给RN的常量
       */
      @Nullable
      @Override
      public Map<String, Object> getConstants() {
        final Map<String, Object> constants = new HashMap<>();
        constants.put("one", "大写的一");
        constants.put("two", "大写的二");
        return constants;
      }
    
      /**
       * 给RN调用的原生方法
       * @param name RN传过来的值
       * @param location RN传过来的值
       * @param cb 回调给RN
       */
      @ReactMethod
      public void createCalendarEvent(String name, String location, Callback cb) {
        Log.i("calendar", name + location);
    
        cb.invoke("已经完成了打印");
      }
    }
    

    b. 编写ReactPackage:CalendarPackage
    在React native中注册原生模块: 将原生模块添加到一个ReactPackage中,并在React native中注册这个ReactPackage。
    在初始化过程中,React Native将遍历所有包,并为每个ReactPackage注册其中的每个原生模块。

    package com.zxmall;
    
    import androidx.annotation.NonNull;
    import com.facebook.react.ReactPackage;
    import com.facebook.react.bridge.NativeModule;
    import com.facebook.react.bridge.ReactApplicationContext;
    import com.facebook.react.uimanager.ViewManager;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class CalendarPackage implements ReactPackage {
    
      @NonNull
      @Override
      public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactApplicationContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new CalendarModule(reactApplicationContext));
        return modules;
      }
    
      @NonNull
      @Override
      public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactApplicationContext) {
        return Collections.emptyList();
      }
    }
    

    c. 在 MainApplication 里注册。

    在 RN 里使用:

    import { Button } from '@ant-design/react-native'
    import { memo } from 'react'
    import { NativeModules, View } from 'react-native'
    
    export default memo(function HomePage() {
      return (
        <View>
          <Button
            onPress={() => {
              NativeModules.CalendarModule.createCalendarEvent(
                '这是标题',
                '这是地点',
                info => {
                  console.log('安卓原生回调信息 :>> ', info)
                }
              )
            }}>
            调用原生模块
          </Button>
        </View>
      )
    })
    

    参考

    Android 原生模块
    iOS 原生模块

    相关文章

      网友评论

          本文标题:RN与原生模块互调

          本文链接:https://www.haomeiwen.com/subject/kojgortx.html