[ReactNative笔记]my-comp适配Fabric

318 阅读1分钟

准备环境

  • volta
$ volta ls
⚡️ Currently active tools:

    Node: v16.20.2 (default)
    Yarn: v1.22.19 (default)
    Tool binaries available:
        nrm (default)
  • nrm
$ nrm ls
* npm ---------- https://registry.npmjs.org/
  yarn --------- https://registry.yarnpkg.com/
  tencent ------ https://mirrors.cloud.tencent.com/npm/
  cnpm --------- https://r.cnpmjs.org/
  taobao ------- https://registry.npmmirror.com/
  npmMirror ---- https://skimdb.npmjs.com/registry/
  • react-native
$ npx react-native info
...
  react-native:
    installed: 0.72.6
...
  • create-react-native-library
$ npx create-react-native-library --version
0.34.2

创建my-comp

  • 创建my-comp
$ npx create-react-native-library my-comp
✔ What is the name of the npm package? … react-native-my-comp
✔ What is the description for the package? … My component
✔ What is the name of package author? … Sunbreak
✔ What is the email address for the package author? … sunbreak.wang@gmail.com
✔ What is the URL for the package author? … https://github.com/Sunbreak
✔ What is the URL for the repository? … https://github.com/Sunbreak/react-native-my-comp
✔ What type of library do you want to develop? › Native view
✔ Which languages do you want to use? › Java & Objective-C
✔ Project created successfully at my-comp!
  • 初始化my-comp
$ cd my-comp
$ yarn
  • Android运行my-comp
$ yarn example start &
$ yarn example android
  • iOS运行my-comp
$ yarn example start &
$ yarn example ios

origin-nofabric.png

开启Fabric

  • 开启Android Fabric
$ yarn example start &
$ yarn example android --extra-params "-PnewArchEnabled=true"
  • 开启iOS Fabric
$ pushd example/ios; RCT_NEW_ARCH_ENABLED=1 pod install; popd
$ yarn example start &
$ yarn example ios

origin-fabric.png

适配Fabric

适配JS/TS

  • 添加MyCompViewNativeComponent.ts到src文件夹
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
import type { ViewProps } from 'react-native';

interface NativeProps extends ViewProps {
  color?: string;
}

export default codegenNativeComponent<NativeProps>('MyCompView');
  • 修改index.tsx
export { default as MyCompView } from './MyCompViewNativeComponent';
export * from './MyCompViewNativeComponent';
  • 添加codegenConfig到package.json
+  },
+  "codegenConfig": {
+    "name": "RNMyCompViewSpec",
+    "type": "components",
+    "jsSrcsDir": "src"
   }
 }

适配Android

  • 修改MyCompViewManager.java
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;

 import com.facebook.react.uimanager.SimpleViewManager;
 import com.facebook.react.uimanager.ThemedReactContext;
+import com.facebook.react.uimanager.ViewManagerDelegate;
 import com.facebook.react.uimanager.annotations.ReactProp;
+import com.facebook.react.viewmanagers.MyCompViewManagerDelegate;
+import com.facebook.react.viewmanagers.MyCompViewManagerInterface;

-public class MyCompViewManager extends SimpleViewManager<View> {
+public class MyCompViewManager extends SimpleViewManager<View> implements MyCompViewManagerInterface<View> {
   public static final String REACT_CLASS = "MyCompView";

+  private final MyCompViewManagerDelegate mDelegate;
+
+  public MyCompViewManager() {
+    mDelegate = new MyCompViewManagerDelegate(this);
+  }
+
+  @Override
+  @Nullable
+  protected ViewManagerDelegate<View> getDelegate() {
+    return mDelegate;
+  }
...
+  @Override
   @ReactProp(name = "color")
   public void setColor(View view, String color) {
     view.setBackgroundColor(Color.parseColor(color));
   }

适配iOS

  • MyCompViewManager.m改名为MyCompViewManager.mm,并修改内容
#import <React/RCTViewManager.h>
#import <React/RCTUIManager.h>
#import "RCTBridge.h"

@interface MyCompViewManager : RCTViewManager
@end

@implementation MyCompViewManager

RCT_EXPORT_MODULE(MyCompView)

RCT_EXPORT_VIEW_PROPERTY(color, NSString)

@end
  • 添加MyCompView.h
// This guard prevent this file to be compiled in the old architecture.
#ifdef RCT_NEW_ARCH_ENABLED
#import <React/RCTViewComponentView.h>
#import <UIKit/UIKit.h>

#ifndef MyCompViewNativeComponent_h
#define MyCompViewNativeComponent_h

NS_ASSUME_NONNULL_BEGIN

@interface MyCompView : RCTViewComponentView
@end

NS_ASSUME_NONNULL_END

#endif /* MyCompViewNativeComponent_h */
#endif /* RCT_NEW_ARCH_ENABLED */
  • 添加MyCompView.mm
#import "MyCompView.h"

#import <react/renderer/components/RNMyCompViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/RNMyCompViewSpec/EventEmitters.h>
#import <react/renderer/components/RNMyCompViewSpec/Props.h>
#import <react/renderer/components/RNMyCompViewSpec/RCTComponentViewHelpers.h>

#import "RCTFabricComponentsPlugins.h"

using namespace facebook::react;

@interface MyCompView () <RCTMyCompViewViewProtocol>

@end

@implementation MyCompView {
    UIView * _view;
}

+ (ComponentDescriptorProvider)componentDescriptorProvider
{
    return concreteComponentDescriptorProvider<MyCompViewComponentDescriptor>();
}

- (instancetype)initWithFrame:(CGRect)frame
{
  if (self = [super initWithFrame:frame]) {
    static const auto defaultProps = std::make_shared<const MyCompViewProps>();
    _props = defaultProps;

    _view = [[UIView alloc] init];

    self.contentView = _view;
  }

  return self;
}

- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
    const auto &oldViewProps = *std::static_pointer_cast<MyCompViewProps const>(_props);
    const auto &newViewProps = *std::static_pointer_cast<MyCompViewProps const>(props);

    if (oldViewProps.color != newViewProps.color) {
        NSString * colorToConvert = [[NSString alloc] initWithUTF8String: newViewProps.color.c_str()];
        [_view setBackgroundColor:[self hexStringToColor:colorToConvert]];
    }

    [super updateProps:props oldProps:oldProps];
}

Class<RCTComponentViewProtocol> MyCompViewCls(void)
{
    return MyCompView.class;
}

- hexStringToColor:(NSString *)stringToConvert
{
    NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
    NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
    
    unsigned hex;
    if (![stringScanner scanHexInt:&hex]) return nil;
    int r = (hex >> 16) & 0xFF;
    int g = (hex >> 8) & 0xFF;
    int b = (hex) & 0xFF;
    
    return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
}

@end

测试适配结果

参考“开启Fabric”