Skip to content

本文概要

大家好我是Joney,在我的职业生涯中 曾经做过RN的开发(从0到1到上架的研发)。深有体会:“如果你不会一些Native的东西,这里的水很深,玩RN建议一定是要懂一些Native的东西(Android/IOS)”。在RN的官方文档中,虽然是说了如何去集成Native的模块,但是!它只说了你要如何如何写,却没有一个完整的示例。本文是一个完整的工程 介绍了 RN 集成 Android Native 的方方面面

重要提示 🚗,本文基于RN 0.70.1, 对于 最新的RN 目前官方还在推他们的新设计,TurboModule 但是还在试验阶段,等它稳定之后我们再去讨论,

文章主要脉络如下

1.工程化工具bod🔧 -->

2.仅仅是集成js部分 --->

3.集成Native的其他模块

4.集成UI组件 --->

重要提醒!:请不要照着文章照抄,建议你先阅读通篇,了解全貌之后再去实践。

本篇是 《一篇搞定!React Native IOS集成 还有人不会制作?》的姊妹篇,所以重复的内容我就不叨叨了 包括 工程脚手架bob 它和ios是一样的,一通百通

我们简单的尝试过后接下来我们将会深入,注意哈我默认你会Java(Android开发)

我会按照下面的知识脉络去介绍

  • 初始化设置
  • 普通的 调用(不需要异步支持)
  • 异步的调用
  • Observer 和广播📢
  • Native组件的生命周期
  • 集成Native UI

初始化设置

  • 对于Native

对于Native 来说,下面的这些步骤是必须的

  1. 创建对应的class文件

image.png

  1. 实现对应的class,只有实现了才能把东西暴露给JS
java
// CalendarModule.java
package com.your-apps-package-name; // replace your-apps-package-name with your app’s package name
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import java.util.Map;
import java.util.HashMap;

public class CalendarModule extends ReactContextBaseJavaModule {
   CalendarModule(ReactApplicationContext context) {
       super(context);
   }

    @Override
    public String getName() {
       return "CalendarModule";
    }
}
  • 对于js
js
// 很简单
const {CalendarModuleFoo} = ReactNative.NativeModules;
  • 依赖和注册相关

Android 需要手动的注册class

java
package com.your-app-name; // replace your-app-name with your app’s name
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 MyAppPackage implements ReactPackage {

   @Override
   public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
       return Collections.emptyList();
   }

   @Override
   public List<NativeModule> createNativeModules(
           ReactApplicationContext reactContext) {
       List<NativeModule> modules = new ArrayList<>();

       modules.add(new CalendarModule(reactContext));

       return modules;
   }

}

注意哈 你写完之后需要按照bob 提供的CLI 进行一定的操作能够关联到 本地RNE项目或者RNP项目中去,具体的方法我在姊妹篇有详细的说明。

以上初始化就完成了

普通的调用

现在我们介绍一下 普通的方法的调用(一般来说我们认为它是同步的,但是RN的通信实际上并不是完全的同步)

  • Native
java


@ReactMethod
public void createCalendarEvent(String name, String location) {
    Log.d("CalendarModule", "Create event called with name: " + name  
    + " and location: " + location);
}

关于同步方法,RN官方还提供了一个 可以实现同步的方法,但是RN不推荐使用。因为同步调用方法可能会带来严重的性能损失,并且会在本机模块中引入与线程相关的 bug。

java
@ReactMethod(isBlockingSynchronousMethod = true)
@ReactMethod
public void createCalendarEvent(String name, String location) {
    Log.d("CalendarModule", "Create event called with name: " + name  
    + " and location: " + location);
}
  • JS
js
import React from 'react';
import {NativeModules, Button} from 'react-native';
const {CalendarModule} = NativeModules;
const NewModuleButton = () => {
    const onPress = () => {
      CalendarModule.createCalendarEvent('testName', 'testLocation');
    };

  return (
    <Button
      title="Click to invoke your native module!"
      color="#841584"
      onPress={onPress}
    />
  );
};

export default NewModuleButton;
  • 关于参数的类型和传递的问题

JS和Native是两种不同的东西,传递参数的时候 就需要注意了这些参数类型是如何转化的

下面是JS到Java/KOTLIN的类型一览图

JAVAKOTLINJAVASCRIPT
BooleanBoolean?boolean
booleanboolean
DoubleDouble?number
doublenumber
StringStringstring
CallbackCallbackFunction
PromisePromisePromise
ReadableMapReadableMapObject
ReadableArrayReadableArrayArray

JS 我们都很熟悉了 我们来唠一下 java 中的一个例子🌰

js
import { NativeModules } from 'react-native';
const {CalendarModule} = NativeModules;
// 调用原生模块的方法,并传递参数
CalendarModule.processData('hello', true, 123, [1, 2, 3], { key: 'value' })
    .then(result => {
        console.log('Received result from native:', result);
    })
    .catch(error => {
        console.error('Error:', error);
    });
java
// CalendarModule.java

package com.yourpackage;

import android.util.Log;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;

public class CalendarModule extends ReactContextBaseJavaModule {

    public CalendarModule(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @Override
    public String getName() {
        return "CalendarModule";
    }

    @ReactMethod
    public void processData(
        String str,
        boolean bool,
        int number,
        ReadableArray array,
        ReadableMap map) {
        // 在这里处理传入的参数
        Log.d("CalendarModule", "Received string: " + str);
        Log.d("CalendarModule", "Received boolean: " + bool);
        Log.d("CalendarModule", "Received number: " + number);
        Log.d("CalendarModule", "Received array: " + array.toString());
        Log.d("CalendarModule", "Received map: " + map.toString());
        
        // 模拟处理并返回结果给 React Native
        WritableMap result = Arguments.createMap();
        result.putString("message", "Data processed successfully");
        promise.resolve(result);
    }
    
    @ReactMethod // 返回数据的时候需要使用 Writable 而不是 Readable
    public void processData(Promise promise) {
        // 构建对象 
        WritableMap map = Arguments.createMap(); map.putString("key", "value");
        // 构建数组
        WritableArray array = Arguments.createArray(); 
        array.pushString("item1");
        array.pushString("item2");
        // 将对象和数组传递给 Promise 的 resolve 方法 
        WritableMap result = Arguments.createMap();     
        result.putMap("object", map);
        result.putArray("array", array);
        promise.resolve(result); }
}

如果你希望获取Native定义的常量 可以这样使用

java
@Override
public Map<String, Object> getConstants() {
   final Map<String, Object> constants = new HashMap<>();
   constants.put("DEFAULT_EVENT_NAME", "New Event");
   return constants;
}
js
const {DEFAULT_EVENT_NAME} = CalendarModule.getConstants();
console.log(DEFAULT_EVENT_NAME);

异步调用

对于 Native 的异步方法, 有两种方式实现,1谁callback 2是promise

  1. callback
java
    @ReactMethod
   public void createCalendarEvent(String name, String location, Callback callBack) {
       Integer eventId = ...
       callBack.invoke(null, eventId);
   }
js
const onPress = () => {
  CalendarModule.createCalendarEventCallback(
    'testName',
    'testLocation',
    (error, eventId) => {
      if (error) {
        console.error(`Error found! ${error}`);
      }
      console.log(`event id ${eventId} returned`);
    },
  );
};

我们还有另一种形式

java
@ReactMethod
public void createCalendarEvent(
    String name,
    String location,
    Callback myFailureCallback,
    Callback mySuccessCallback) {
    // ++++
}
js
const onPress = () => {
  CalendarModule.createCalendarEventCallback(
    'testName',
    'testLocation',
    error => {
      console.error(`Error found! ${error}`);
    },
    eventId => {
      console.log(`event id ${eventId} returned`);
    },
  );
};
  1. promise

这个就比较简单了,我一直在用它

java
import com.facebook.react.bridge.Promise;

@ReactMethod
public void createCalendarEvent(String name, String location, Promise promise) {
    try {
        Integer eventId = ...
        promise.resolve(eventId);
    } catch(Exception e) {
        promise.reject("Create Event Error", e);
    }
}
js
const onSubmit = async () => {
  try {
    const eventId = await CalendarModule.createCalendarEvent(
      'Party',
      'my house',
    );
    console.log(`Created a new event with id ${eventId}`);
  } catch (e) {
    console.error(e);
  }
};

observer和广播

这里描述的是 Native向 JS 发送的广播的具体的实现。比如 通知 消息什么的。

在官方的文档中只有一种,但是实际上有两种。下面我们来看看

  • 模块自己的observer
java
...
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.Arguments;
...
private void sendEvent(ReactContext reactContext,
                      String eventName,
                      @Nullable WritableMap params) {
 reactContext
     .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
     .emit(eventName, params);
}

private int listenerCount = 0;

@ReactMethod
public void addListener(String eventName) {
  if (listenerCount == 0) {
    // Set up any upstream listeners or background tasks as necessary
  }

  listenerCount += 1;
}

@ReactMethod
public void removeListeners(Integer count) {
  listenerCount -= count;
  if (listenerCount == 0) {
    // Remove upstream listeners, stop unnecessary background tasks
  }
}
...
// 在java中某个东西 直接触发 sendEvent 就可以发送广播到js了
WritableMap params = Arguments.createMap();
params.putString("eventProperty", "someValue");
sendEvent(reactContext, "EventReminder", params);
js
import {NativeEventEmitter, NativeModules} from 'react-native';
...
useEffect(() => {
    const eventEmitter = new NativeEventEmitter(NativeModules.ToastExample);
    let eventListener = eventEmitter.addListener('EventReminder', event => {
      console.log(event.eventProperty) // "someValue"
    });

    // Removes the listener once unmounted
    return () => {
      eventListener.remove();
    };
  }, []);
  • 全局的observer

在上述中我们可以看到这样的代码:NativeEventEmitter(NativeModules.ToastExample);; 我们在创建observer 的时候是具体到 某一个模块的。其实RN有一个全局的DeviceEventEmitter

java
// 很简单只需要实现 sendEvent 就可以了 其他的不需要实现
js
import { DeviceEventEmitter } from 'react-native';

DeviceEventEmitter.addListener('EventName', event => {
  console.log('Received event:', event);
});
  • 多线程

你可以开业使用 observer 或者 promise 都可以

java
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;

public class MyThread extends Thread {
    private ReactApplicationContext reactContext;

    public MyThread(ReactApplicationContext context) {
        this.reactContext = context;
    }

    @Override
    public void run() {
        // 在子线程中处理耗时任务
        try {
            Thread.sleep(2000); // 模拟耗时操作
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // 创建一个包含数据的对象
        WritableMap data = Arguments.createMap();
        data.putString("message", "Hello from Android Thread!");

        // 发送消息到 React Native
        reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("AndroidThreadEvent", data);
    }
}

StartActivityForResult get res

如果希望从以 startActivityForResult 启动的活动获得结果,则需要侦听 onActivityResult。

java
public class ImagePickerModule extends ReactContextBaseJavaModule {

  private static final int IMAGE_PICKER_REQUEST = 1;
  private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST";
  private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED";
  private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER";
  private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND";

  private Promise mPickerPromise;

  private final ActivityEventListener mActivityEventListener = new BaseActivityEventListener() {

    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent intent) {
      if (requestCode == IMAGE_PICKER_REQUEST) {
        if (mPickerPromise != null) {
          if (resultCode == Activity.RESULT_CANCELED) {
            mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled");
          } else if (resultCode == Activity.RESULT_OK) {
            Uri uri = intent.getData();

            if (uri == null) {
              mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found");
            } else {
              mPickerPromise.resolve(uri.toString());
            }
          }

          mPickerPromise = null;
        }
      }
    }
  };

  ImagePickerModule(ReactApplicationContext reactContext) {
    super(reactContext);

    // Add the listener for `onActivityResult`
    reactContext.addActivityEventListener(mActivityEventListener);
  }

  @Override
  public String getName() {
    return "ImagePickerModule";
  }

  @ReactMethod
  public void pickImage(final Promise promise) {
    Activity currentActivity = getCurrentActivity();

    if (currentActivity == null) {
      promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist");
      return;
    }

    // Store the promise to resolve/reject when picker returns data
    mPickerPromise = promise;

    try {
      final Intent galleryIntent = new Intent(Intent.ACTION_PICK);

      galleryIntent.setType("image/*");

      final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image");

      currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST);
    } catch (Exception e) {
      mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e);
      mPickerPromise = null;
    }
  }
}

集成 Native UI Component

  • 举例说明 实现一个 ImageView
  1. 创建subclass
java
public class ReactImageManager extends SimpleViewManager<ReactImageView> {

  public static final String REACT_CLASS = "RCTImageView";

  ReactApplicationContext mCallerContext;

  public ReactImageManager(ReactApplicationContext reactContext) {
    mCallerContext = reactContext;
  }
 

  @Override
  public String getName() {
    return REACT_CLASS;
  }
}
  1. 实现createViewInstance
java
  @Override
  public ReactImageView createViewInstance(ThemedReactContext context) {
    return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), null, mCallerContext);
  }
  1. 关于属性的传递

使用@reactprop(或@reactpropgroup)注释来揭示视图属性设置器

java
  @ReactProp(name = "src")
  public void setSrc(ReactImageView view, @Nullable ReadableArray sources) {
    view.setSource(sources);
  }

  @ReactProp(name = "borderRadius", defaultFloat = 0f)
  public void setBorderRadius(ReactImageView view, float borderRadius) {
    view.setBorderRadius(borderRadius);
  }

  @ReactProp(name = ViewProps.RESIZE_MODE)
  public void setResizeMode(ReactImageView view, @Nullable String resizeMode) {
    view.setScaleType(ImageResizeMode.toScaleType(resizeMode));
  }
  1. 注册这个 native ui component

注意啊 这个方法要写到 module package 中去也就是这里

java

public class MyAppPackage implements ReactPackage {

   @Override
   public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
       return Collections.emptyList();
   }

// +++++ 写到这个class 里 createViewManagers 是 ReactPackage的method

}
java
  @Override
  public List<ViewManager> createViewManagers(
                            ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList(
      new ReactImageManager(reactContext)
    );
  }
  1. js中的使用
js
import {requireNativeComponent} from 'react-native';

/**
 * Composes `View`.
 *
 * - src: string
 * - borderRadius: number
 * - resizeMode: 'cover' | 'contain' | 'stretch'
 */
module.exports = requireNativeComponent('RCTImageView');
  1. 对于事件的处理
java
// 我们可以通过 广播的方式 传递 事件出去,但是这效率太低了
class MyCustomView extends View {
   ...
   public void onReceiveNativeEvent() {
      WritableMap event = Arguments.createMap();
      event.putString("message", "MyMessage");
      ReactContext reactContext = (ReactContext)getContext();
      reactContext
          .getJSModule(RCTEventEmitter.class)
          .receiveEvent(getId(), "topChange", event);
    }
}

// 我们选择另一钟方式 把事件 map出去
public class ReactImageManager extends SimpleViewManager<MyCustomView> {
    ...
    public Map getExportedCustomBubblingEventTypeConstants() {
        return MapBuilder.builder().put(
            "topChange",
            MapBuilder.of(
                "phasedRegistrationNames",
                MapBuilder.of("bubbled", "onChange")
            )
        ).build();
    }
}

如此这般 我们就得到了一个 Naive UI Component

tsx
class MyCustomView extends React.Component {
  constructor(props) {
    super(props);
    this._onChange = this._onChange.bind(this);
  }
  _onChange(event) {
    if (!this.props.onChangeMessage) {
      return;
    }
    this.props.onChangeMessage(event.nativeEvent.message);
  }
  render() {
    return <RCTMyCustomView {...this.props} onChange={this._onChange} />;
  }
}
MyCustomView.propTypes = {
  /**
   * Callback that is called continuously when the user is dragging the map.
   */
  onChangeMessage: PropTypes.func,
  ...
};

const RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`);
  • 更多的(比如我想自己集成一个view 而不系统组件img什么的如何做?)
  1. 创建 custom view
java
// replace with your package
package com.mypackage;

import android.content.Context;
import android.graphics.Color;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.NonNull;

public class CustomView extends FrameLayout {
  public CustomView(@NonNull Context context) {
    super(context);
    // set padding and background color
    this.setPadding(16,16,16,16);
    this.setBackgroundColor(Color.parseColor("#5FD3F3"));

    // add default text view
    TextView text = new TextView(context);
    text.setText("Welcome to Android Fragments with React Native.");
    this.addView(text);
  }
}
  1. 创建 fragemt
java
// replace with your package
package com.mypackage;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.fragment.app.Fragment;

// replace with your view's import
import com.mypackage.CustomView;

public class MyFragment extends Fragment {
    CustomView customView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) {
        super.onCreateView(inflater, parent, savedInstanceState);
        customView = new CustomView(this.getContext());
        return customView; // this CustomView could be any view that you want to render
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        // do any logic that should happen in an `onCreate` method, e.g:
        // customView.onCreate(savedInstanceState);
    }

    @Override
    public void onPause() {
        super.onPause();
        // do any logic that should happen in an `onPause` method
        // e.g.: customView.onPause();
    }

    @Override
    public void onResume() {
        super.onResume();
       // do any logic that should happen in an `onResume` method
       // e.g.: customView.onResume();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // do any logic that should happen in an `onDestroy` method
        // e.g.: customView.onDestroy();
    }
}
  1. 创建 viewManager subclass
java
// replace with your package
package com.mypackage;

import android.view.Choreographer;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.annotations.ReactPropGroup;
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.ThemedReactContext;

import java.util.Map;

public class MyViewManager extends ViewGroupManager<FrameLayout> {

  public static final String REACT_CLASS = "MyViewManager";
  public final int COMMAND_CREATE = 1;
  private int propWidth;
  private int propHeight;

  ReactApplicationContext reactContext;

  public MyViewManager(ReactApplicationContext reactContext) {
    this.reactContext = reactContext;
  }

  @Override
  public String getName() {
    return REACT_CLASS;
  }

  /**
   * Return a FrameLayout which will later hold the Fragment
   */
  @Override
  public FrameLayout createViewInstance(ThemedReactContext reactContext) {
    return new FrameLayout(reactContext);
  }

  /**
   * Map the "create" command to an integer
   */
  @Nullable
  @Override
  public Map<String, Integer> getCommandsMap() {
    return MapBuilder.of("create", COMMAND_CREATE);
  }

  /**
   * Handle "create" command (called from JS) and call createFragment method
   */
  @Override
  public void receiveCommand(
    @NonNull FrameLayout root,
    String commandId,
    @Nullable ReadableArray args
  ) {
    super.receiveCommand(root, commandId, args);
    int reactNativeViewId = args.getInt(0);
    int commandIdInt = Integer.parseInt(commandId);

    switch (commandIdInt) {
      case COMMAND_CREATE:
        createFragment(root, reactNativeViewId);
        break;
      default: {}
    }
  }

  @ReactPropGroup(names = {"width", "height"}, customType = "Style")
  public void setStyle(FrameLayout view, int index, Integer value) {
    if (index == 0) {
      propWidth = value;
    }

    if (index == 1) {
      propHeight = value;
    }
  }

  /**
   * Replace your React Native view with a custom fragment
   */
  public void createFragment(FrameLayout root, int reactNativeViewId) {
    ViewGroup parentView = (ViewGroup) root.findViewById(reactNativeViewId);
    setupLayout(parentView);

    final MyFragment myFragment = new MyFragment();
    FragmentActivity activity = (FragmentActivity) reactContext.getCurrentActivity();
    activity.getSupportFragmentManager()
            .beginTransaction()
            .replace(reactNativeViewId, myFragment, String.valueOf(reactNativeViewId))
            .commit();
  }

  public void setupLayout(View view) {
    Choreographer.getInstance().postFrameCallback(new Choreographer.FrameCallback() {
      @Override
      public void doFrame(long frameTimeNanos) {
        manuallyLayoutChildren(view);
        view.getViewTreeObserver().dispatchOnGlobalLayout();
        Choreographer.getInstance().postFrameCallback(this);
      }
    });
  }

  /**
   * Layout all children properly
   */
  public void manuallyLayoutChildren(View view) {
      // propWidth and propHeight coming from react-native props
      int width = propWidth;
      int height = propHeight;

      view.measure(
              View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
              View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY));

      view.layout(0, 0, width, height);
  }
}
  1. 注册 viewManager
java
// replace with your package
package com.mypackage;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.Arrays;
import java.util.List;

public class MyPackage implements ReactPackage {

   @Override
   public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
       return Arrays.<ViewManager>asList(
            new MyViewManager(reactContext)
       );
   }

}
  1. 组册到 packgae中去
java
// MainApplication.java
    @Override
    protected List<ReactPackage> getPackages() {
      List<ReactPackage> packages = new PackageList(this).getPackages();
      ...
      packages.add(new MyPackage());
      return packages;
    }
  1. js参考
tsx
import {requireNativeComponent} from 'react-native';

export const MyViewManager =
  requireNativeComponent('MyViewManager');

import React, {useEffect, useRef} from 'react';
import {
  PixelRatio,
  UIManager,
  findNodeHandle,
} from 'react-native';

import {MyViewManager} from './my-view-manager';

const createFragment = viewId =>
  UIManager.dispatchViewManagerCommand(
    viewId,
    // we are calling the 'create' command
    UIManager.MyViewManager.Commands.create.toString(),
    [viewId],
  );

export const MyView = () => {
  const ref = useRef(null);

  useEffect(() => {
    const viewId = findNodeHandle(ref.current);
    createFragment(viewId);
  }, []);

  return (
    <MyViewManager
      style={{
        // converts dpi to px, provide desired height
        height: PixelRatio.getPixelSizeForLayoutSize(200),
        // converts dpi to px, provide desired width
        width: PixelRatio.getPixelSizeForLayoutSize(200),
      }}
      ref={ref}
    />
  );
};

参考

react-native-builder-bob仓库

RN官方文档

OC文档