Fabric 组件
这个文档仍然是实验性的,随着我们的迭代,细节会有变化。欢迎在工作小组内的讨论中分享你的反馈。
此外,它还包含几个手动步骤。请注意新架构尚未稳定下来,最终的开发者体验会继续迭代改善。我们正在努力开发工具、模板和库,以帮助你在新架构上快速入门,而不需要经历整个设置过程。
Fabric 组件是一种使用 Fabric 渲染器渲染并展示在屏幕上的 UI 组件。在新架构中,使用 Fabric 组件替代原生组件具有以下优势:
- 各个平台的强类型接口声明是一致的;
- 您可以使用 C++ 编写组件或迁移其它平台的原生代码,以此避免在跨平台重复实现组件;
- 通过替换 Bridge 为 JSI(使用原生代码编写的 JavaScript 接口),提升 JavaScript 与原生代码的通讯效率。
在开发 Fabric 组件前,您需要先创建一个 JavaScript 接口描述文件。之后 Codegen 会根据这个文件创建一些 C++ 脚手架代码,用于将部分组件逻辑(比如调用原生平台接口能力)与 React Native 结合起来。C++ 代码在各个平台都是一样的,只要组件能够与生成的 C++ 代码连接起来,就可以导入到 App 并运行。
接下来的内容将一步步指导您针对 React Native 0.70.0 创建一个 Fabric 组件。
Fabric 组件仅适用于新架构。若您想了解如何将 App 迁移到新架构,可前往迁移指南。
如何创建 Fabric 组件
若要创建一个 Fabric 组件,您需要遵循以下步骤:
- 声明 JavaScript 接口;
- 配置组件以用于 Codegen 生成统一代码,生成的代码可添加为 App 的依赖;
- 编写所需的原生代码。
完成这些步骤后,组件就可以在 App 里使用了。本指导将向您介绍如何将其添加到 App,并利用自动链接使其能在 JavaScript 代码引用。
1. 目录配置
为了使组件与 App 保持解耦,有个不错的方案是将组件从 App 抽离出来,并添加为 App 的一个依赖。如果您打算开发一个开源的 Fabric 组件,您同样也需要这么做。
在本指导中,您将开发一个用于在屏幕上将文本居中显示的 Fabric 组件。
在与 App 平级的目录,创建名为 RTNCenteredText
的目录。在这个目录中,创建三个子目录:js
、ios
和 android
。创建后的目录结构是这样的:
.
├── MyApp
└── RTNCenteredText
├── android
├── ios
└── js
2. 声明 JavaScript 接口
新架构要求必须使用强类型风格语言声明 JavaScript 接口(Flow 和 TypeScript 皆可)。Codegen
会根据这些接口声明来生成强类型的语言,其中包括 C++、Objective-C 和 Java。
对于声明类型的代码文件必须满足以下两点要求:
- 文件必须使用
<MODULE_NAME>NativeComponent
命名,在使用 Flow 时,以.js
或.jsx
为后缀名;在使用 Typescript 时,以.ts
或.tsx
为后缀名。Codegen 只会找到匹配这些命名规则的文件; - 代码中必须要输出
HostComponent
对象。
以下是使用 Flow 和 TypeScript 声明的 RTNCenteredText
组件。在 js
目录中,创建一个命名为 RTNCenteredText
并带有相应后缀名的文件。
- TypeScript
- Flow
// @flow strict-local
import type {ViewProps} from 'react-native/Libraries/Components/View/ViewPropTypes';
import type {HostComponent} from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
type NativeProps = $ReadOnly<{|
...ViewProps,
text: ?string,
// add other props here
|}>;
export default (codegenNativeComponent<NativeProps>(
'RTNCenteredText',
): HostComponent<NativeProps>);
import type {ViewProps} from 'ViewPropTypes';
import type {HostComponent} from 'react-native';
import codegenNativeComponent from 'react-native/Libraries/Utilities/codegenNativeComponent';
export interface NativeProps extends ViewProps {
text?: string;
// 添加其它 props
}
export default codegenNativeComponent<NativeProps>(
'RTNCenteredText',
) as HostComponent<NativeProps>;
在声明文件的顶部导入了一些内容。以下是开发 Fabric 组件必须要导入的内容:
HostComponent
类型: 导出的组件需要与这个类型保持一致;codegenNativeComponent
函数:负责将组件注册到 JavaScript 运行时。
声明文件的中间部分包含了组件的 props。Props("properties" 的缩写)是用于自定义 React 组件的参数信息。在本例中,您将需要控制组件的 text
属性。
在声明文件的最后部分,导 出了泛型函数 codegenNativeComponent
的返回值,此函数需要传递组件的名称。
当我们在编写 JavaScript 代码时,如果没有配置好对应的模块或依赖安装,就从第三方库导入类型,可能会使的您的 IDE 不能正确载入导入声明,从而显示错误或警告。这些问题会在 Fabric 添加为 App 的依赖后得到解决。
3. 组件配置
接下来,您需要为 Codegen 和自动链接添加一些配置。
有一些配置文件在 iOS 和 Android 平台是通用的,而有的仅能在某一平台使用。
Shared
shared 是 package.json
文件中的一个配置项,它将在 yarn 安装您的模块时被调用,请在 RTNCenteredText
的根目录创建 package.json
文件。
{
"name": "rtn-centered-text",
"version": "0.0.1",
"description": "Showcase a Fabric component with a centered text",
"react-native": "js/index",
"source": "js/index",
"files": [
"js",
"android",
"ios",
"rtn-centered-text.podspec",
"!android/build",
"!ios/build",
"!**/__tests__",
"!**/__fixtures__",
"!**/__mocks__"
],
"keywords": ["react-native", "ios", "android"],
"repository": "https://github.com/<your_github_handle>/rtn-centered-text",
"author": "<Your Name> <your_email@your_provider.com> (https://github.com/<your_github_handle>)",
"license": "MIT",
"bugs": {
"url": "https://github.com/<your_github_handle>/rtn-centered-text/issues"
},
"homepage": "https://github.com/<your_github_handle>/rtn-centered-text#readme",
"devDependencies": {},
"peerDependencies": {
"react": "*",
"react-native": "*"
},
"codegenConfig": {
"name": "RTNCenteredTextSpecs",
"type": "components",
"jsSrcsDir": "js"
}
}
文件上面的内容包含了一些描述性的信息,比如组件名、版本和代码文件。务必记得设置使用 <>
包裹的占位符,如替换所有的<your_github_handle>
、<Your Name>
、<your_email@your_provider.com>
等标记。
接下来是 npm 包的依赖。在本指导中,您会用到 react
和 react-native
。
最后,将 Codegen 的配置声明到 codegenConfig
字段。codegenConfig
是一个用于存放要生成的第三方库的对象数组,每个对象又包含其它三个字段:
name
:第三方库的名称。按照惯例,名称应以Spec
为结尾type
:在这个 npm 包里的模块类型。在本例中,我们开发的是 Fabric 组件,所以值为components
jsSrcsDir
:用于找到js
接口声明文件的相对路径,它将被 Codegen 解析
iOS:创建 podspec
文件
针对 iOS 平台,您需要创建一个 rtn-centered-text.podspec
文件,它将您的模块定义为 App 里的一个依赖。文件要放在 RTNCenteredText
根目录,与 ios
目录处于同一个位置。
文件内容如下:
require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
folly_version = '2021.07.22.00'
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
Pod::Spec.new do |s|
s.name = "rtn-centered-text"
s.version = package["version"]
s.summary = package["description"]
s.description = package["description"]
s.homepage = package["homepage"]
s.license = package["license"]
s.platforms = { :ios => "11.0" }
s.author = package["author"]
s.source = { :git => package["repository"], :tag => "#{s.version}" }
s.source_files = "ios/**/*.{h,m,mm,swift}"
s.dependency "React-Core"
s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
s.pod_target_xcconfig = {
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
"OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
}
s.dependency "React-RCTFabric"
s.dependency "React-Codegen"
s.dependency "RCT-Folly", folly_version
s.dependency "RCTRequired"
s.dependency "RCTTypeSafety"
s.dependency "ReactCommon/turbomodule/core"
end
这个 .podspec
文件需要和 package.json
处于同一个目录,并且它的命名应该取自我们在 package.json
的 name
字段配置的值:rtn-centered-text
。
文件首部分设置了一些在后续会使用到的变量。后面一部分内容是一些用来配置 pod 的信息,比 如命名、版本和功能描述等。其余内容是一些在新架构中必须要配置的依赖。
Android: build.gradle
, AndroidManifest.xml
, ReactPackage
类
若要在 Android 平台运行 Codegen,您需要创建三个文件:
- 带有
Codegen
配置信息的build.gradle
文件 AndroidManifest.xml
- 一个实现
ReactPackage
接口的 Java 类
在文件创建完成后,android
目录文件结构应该是这样的:
android
├── build.gradle
└── src
└── main
├── AndroidManifest.xml
└── java
└── com
└── rtncenteredtext
└── RTNCenteredTextPackage.java
build.gradle
首先,在 android
目录创建 build.gradle
文件,并配置以下内容:
buildscript {
ext.safeExtGet = {prop, fallback ->
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}
repositories {
google()
gradlePluginPortal()
}
dependencies {
classpath("com.android.tools.build:gradle:7.1.1")
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.facebook.react'
android {
compileSdkVersion safeExtGet('compileSdkVersion', 31)
defaultConfig {
minSdkVersion safeExtGet('minSdkVersion', 21)
targetSdkVersion safeExtGet('targetSdkVersion', 31)
buildConfigField("boolean", "IS_NEW_ARCHITECTURE_ENABLED", "true")
}
}
repositories {
maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url "$projectDir/../node_modules/react-native/android"
}
mavenCentral()
google()
}
dependencies {
implementation 'com.facebook.react:react-native:+'
}
AndroidManifest.xml
其次,创建 android/src/main
目录,然后在这个目录内创建 AndroidManifest.xml
文件,并编写以下代码:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.rtncenteredtext">
</manifest>
这个 manifest 文件的用途是声明您开发的模块的 Java 包。
ReactPackage
最后,您需要一个继承 TurboReactPackage
接口的类。在运行 Codegen 前,您不用完整实现这个类。对于 App 而言,一个没有实现接口的空类就已经能当做一个 React Native 依赖,Codegen 会尝试生成其脚手架代码。
创建 android/src/main/java/com/rtncenteredtext
目录,在这个目录内创建 RTNCenteredTextPackage.java
文件
package com.rtncenteredtext;
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.Collections;
import java.util.List;
public class RTNCenteredTextPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
ReactPackage
接口的用途是让 React Native 为使用 App 中的 ViewManager
和 Native Modules
,识别出哪些原生类需要在第三方库里导出。
4. 原生代码
最后一步需要您编写用于 JavaScript 端的组件与原生平台交互的原生代码,这包含两个主要步骤:
- 运行 Codegen 并查看其生成的代码;
- 编写原生代码。
在开发一个使用 Fabric 组件 的 React Native App 时,将由 App 负责使用 Codegen 生成代码。但在开发 Fabric 组件的第三方库时,我们需要引用 Codegen 的生成代码,因此查看生成的代码是很有帮助的。
首先,为生成 iOS 和 Android 平台的代码,本指导将向您展示如何手动执行由 Codegen 生成的脚本,以及生成所需要的平台代码。您可以在这里了解到更多关于 Codegen 的内容。
Codegen 生成的代码不该提交到版本管理系统,React Native 会在 App 构建的时候自动生成代码。这是为了确保在 App 内,所有第三方库都正确使用针对某一 React Native 版本的生成代码。
iOS
iOS 的代码生成
为生成 iOS 平台的代码,您需要在 Terminal 执行以下命令:
cd MyApp
yarn add ../RTNCenteredText
cd ..
node MyApp/node_modules/react-native/scripts/generate-artifacts.js \
--path MyApp/ \
--outputPath RTNCenteredText/generated/
这脚本首先使用 yarn add
将 RTNCenteredText
模块添加到 App。然后通过 generate-artifacts.js
脚本调用 Codegen。
--path
选项用于声明 App 的路径,--outputPath
选项用于声明 Codegen 生成代码的存放路径。
命令执行后将呈现以下目录文件结构:
generated
└── build
└── generated
└── ios
├── FBReactNativeSpec
│ ├── FBReactNativeSpec-generated.mm
│ └── FBReactNativeSpec.h
├── RCTThirdPartyFabricComponentsProvider.h
├── RCTThirdPartyFabricComponentsProvider.mm
└── react
└── renderer
└── components
├── RTNCenteredTextSpecs
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── RCTComponentViewHelpers.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── rncore
├── ComponentDescriptors.h
├── EventEmitters.cpp
├── EventEmitters.h
├── Props.cpp
├── Props.h
├── RCTComponentViewHelpers.h
├── ShadowNodes.cpp
└── ShadowNodes.h
生成的组件的路径为 generated/build/generated/ios/react/renderer/components/RTNCenteredTextSpecs
,此目录包含了您在开发组件时必备的生成代码。
查看 Codegen 章节文档可获得更多文件生成相关细节。
使用 Codegen 生成脚手架代码时,iOS 平台中不会自动清空 build
目录。假如您需要修改接口声明文件的命名,并重新执行了 Codegen,旧的代码会保留下来。如果发生了这种情况,您需要在重新执行 Codegen 之前删除 build
目录。
cd MyApp/ios
rm -rf build
编写 iOS 原生代码
现在脚手架代码已生成完毕,是时候为您的 Fabric 组件编写原生代码了。
您需要在 RTNCenteredText/ios
目录创建三个文件:
RTNCenteredTextManager.mm
:声明组件导出内容的 Objective-C++ 文件上面的内容包含了一些描述性的信息RTNCenteredText.h
:原生视图的头文件RTNCenteredText.mm
:实现原生视图的代码文件
RTNCenteredTextManager.mm
#import <React/RCTLog.h>
#import <React/RCTUIManager.h>
#import <React/RCTViewManager.h>
@interface RTNCenteredTextManager : RCTViewManager
@end
@implementation RTNCenteredTextManager
RCT_EXPORT_MODULE(RTNCenteredText)
RCT_EXPORT_VIEW_PROPERTY(text, NSString)
@end
这个文件是针对 Fabric 组件的 Manager。React Native 运行时使用 Manager 对象来注册模块、属性及方法,使其能在 JavaScript 调用。
调用 RCT_EXPORT_MODULE
是至关重要的,它将导出模块让 Fabric 获取到并进行实例化。
接下来,你需要暴露 text
属性给 Fabric 组件,使用宏定义 RCT_EXPORT_VIEW_PROPERTY
来声明属性名及其类型。
您可以查看 RCTViewManager.h 代码,了解更多用于导出属性、Emitter 及其它结构的宏定义。
RTNCenteredText.h
#import <React/RCTViewComponentView.h>
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface RTNCenteredText : RCTViewComponentView
@end
NS_ASSUME_NONNULL_END
此文件定义了 RTNCenteredText
的视图接口,我们可以在这里添加可被视图触发的方法。在本指引中,我们什么都不用做,所以这个接口是空的。
RTNCenteredText.mm
#import "RTNCenteredText.h"
#import <react/renderer/components/RTNCenteredTextSpecs/ComponentDescriptors.h>
#import <react/renderer/components/RTNCenteredTextSpecs/EventEmitters.h>
#import <react/renderer/components/RTNCenteredTextSpecs/Props.h>
#import <react/renderer/components/RTNCenteredTextSpecs/RCTComponentViewHelpers.h>
#import "RCTFabricComponentsPlugins.h"
using namespace facebook::react;
@interface RTNCenteredText () <RCTRTNCenteredTextViewProtocol>
@end
@implementation RTNCenteredText {
UIView *_view;
UILabel *_label;
}
+ (ComponentDescriptorProvider)componentDescriptorProvider
{
return concreteComponentDescriptorProvider<RTNCenteredTextComponentDescriptor>();
}
- (instancetype)initWithFrame:(CGRect)frame
{
if (self = [super initWithFrame:frame]) {
static const auto defaultProps = std::make_shared<const RTNCenteredTextProps>();
_props = defaultProps;
_view = [[UIView alloc] init];
_view.backgroundColor = [UIColor redColor];
_label = [[UILabel alloc] init];
_label.text = @"Initial value";
[_view addSubview:_label];
_label.translatesAutoresizingMaskIntoConstraints = false;
[NSLayoutConstraint activateConstraints:@[
[_label.leadingAnchor constraintEqualToAnchor:_view.leadingAnchor],
[_label.topAnchor constraintEqualToAnchor:_view.topAnchor],
[_label.trailingAnchor constraintEqualToAnchor:_view.trailingAnchor],
[_label.bottomAnchor constraintEqualToAnchor:_view.bottomAnchor],
]];
_label.textAlignment = NSTextAlignmentCenter;
self.contentView = _view;
}
return self;
}
- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
const auto &oldViewProps = *std::static_pointer_cast<RTNCenteredTextProps const>(_props);
const auto &newViewProps = *std::static_pointer_cast<RTNCenteredTextProps const>(props);
if (oldViewProps.text != newViewProps.text) {
_label.text = [[NSString alloc] initWithCString:newViewProps.text.c_str() encoding:NSASCIIStringEncoding];
}
[super updateProps:props oldProps:oldProps];
}
@end
Class<RCTComponentViewProtocol> RTNCenteredTextCls(void)
{
return RTNCenteredText.class;
}
这个文件包含了视图的实现代码。首先它导入了部分从 Codegen 生成代码。组件必须要遵循由 Codegen 生成的特定协议,在本例中为 RCTRTNCenteredTextViewProtocol
。
接下来定义了静态方法 (ComponentDescriptorProvider)componentDescriptorProvider
,Fabric 将使用此方法来获得组件的 Descriptor Provider,以此实例化组件对象。
之后是视图的构造器 init
方法。在这个方法中,使用 Codegen 生成的 RTNCenteredTextProps
类型创建一个 defaultProps
结构对象特别重要。你需要将其赋值给私有属性 _props
以正确初始化 Fabric 组件。方法的后续部分是标准的 Objective-C 代码,作用是使用 AutoLayout 布局创建 的视图。
最后还有两个方法,分别是 updateProps
和 RTNCenteredTextCls
。
updateProps
会在每次 JavaScript 修改 props 时被 Fabric 调用。通过函数参数传入的 props 会被转换为 RTNCenteredTextProps
类型,而且它们会在必要的时候更新原生代码。请注意,要在此方法的最后调用超类的 [super updateProps]
方法,否则对象 props
和 oldProps
会一直保持相同的值,因此您将无法用它们进行操作或更新组件。
RTNCenteredTextCls
是个另一个静态方法,用于在运行时正确获取实例的类。
与原生组件不同的是,Fabric 组件必须手动实现 updateProps
方法。单单使用宏定义 RCT_EXPORT_XXX
和 RCT_REMAP_XXX
还不足以导出组件的属性。
Android
Android 的操作与 iOS 类似,我们需要先生成代码,然后再编写组件的原生代码。
Android 的代码生成
我们需要手动调用 Codegen 来生成 Android 平台代码。这和我们在 iOS 平台的操作相似:首先向 App 添加 Java 包,然后调用脚本生成代码。
cd MyApp
yarn add ../RTNCenteredText
cd android
./gradlew generateCodegenArtifactsFromSchema
这个脚本会 向 App 添加 Java 包,然后打开 android
目录,创建一个 Gradle 任务来生成代码。
在运行 Codegen 之前,您需要在 Android 中的 App 启动新架构。您可以通过修改 gradle.properties
文件中的 newArchEnabled
属性,将 false
改为 true
。
生成后的代码保存在 MyApp/node_modules/rtn-centered-text/android/build/generated/source/codegen
目录,并呈以下结构:
codegen
├── java
│ └── com
│ └── facebook
│ └── react
│ └── viewmanagers
│ ├── RTNCenteredTextManagerDelegate.java
│ └── RTNCenteredTextManagerInterface.java
├── jni
│ ├── Android.mk
│ ├── CMakeLists.txt
│ ├── RTNCenteredText-generated.cpp
│ ├── RTNCenteredText.h
│ └── react
│ └── renderer
│ └── components
│ └── RTNCenteredText
│ ├── ComponentDescriptors.h
│ ├── EventEmitters.cpp
│ ├── EventEmitters.h
│ ├── Props.cpp
│ ├── Props.h
│ ├── ShadowNodes.cpp
│ └── ShadowNodes.h
└── schema.json
你会发现 codegen/jni/react/renderer/components/RTNCenteredTextSpecs
的内容和 iOS 平台生成的代码差不多。Android.mk
和 CMakeList.txt
在 App 内用于 Fabric 组件配置,而 RTNCenteredTextManagerDelegate.java
和 RTNCenteredTextManagerInterface.java
会用在组件的 Manager。
查看 Codegen 章节文档可获得更多文件生成相关细节。
编写原生代码
Android 平台中 Fabric 组件的原生代码必须包含以下三个部分:
RTNCenteredText.java
用于渲染原生视图RTNCenteredTextManager.java
用于实例化原生视图- 最后,您需要在之前创建的
RTNCenteredTextPackage.java
实现具体的逻辑代码
您的 Android 第三方库目录文件结构应为如下:
android
├── build.gradle
└── src
└── main
├── AndroidManifest.xml
└── java
└── com
└── rtncenteredtext
├── RTNCenteredText.java
├── RTNCenteredTextManager.java
└── RTNCenteredTextPackage.java
RTNCenteredText.java
package com.rtncenteredtext;
import androidx.annotation.Nullable;
import android.content.Context;
import android.util.AttributeSet;
import android.graphics.Color;
import android.widget.TextView;
import android.view.Gravity;
public class RTNCenteredText extends TextView {
public RTNCenteredText(Context context) {
super(context);
this.configureComponent();
}
public RTNCenteredText(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.configureComponent();
}
public RTNCenteredText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.configureComponent();
}
private void configureComponent() {
this.setBackgroundColor(Color.RED);
this.setGravity(Gravity.CENTER_HORIZONTAL);
}
}
这个类表示的是原生视图,将由 Android 渲染到屏幕上。它继承了 TextView
并且调用私有方法 configureComponent()
来配置自身的基本参数。
RTNCenteredTextManager.java
package com.rtncenteredtext;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.module.annotations.ReactModule;
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.RTNCenteredTextManagerInterface;
import com.facebook.react.viewmanagers.RTNCenteredTextManagerDelegate;
@ReactModule(name = RTNCenteredTextManager.NAME)
public class RTNCenteredTextManager extends SimpleViewManager<RTNCenteredText>
implements RTNCenteredTextManagerInterface<RTNCenteredText> {
private final ViewManagerDelegate<RTNCenteredText> mDelegate;
static final String NAME = "RTNCenteredText";
public RTNCenteredTextManager(ReactApplicationContext context) {
mDelegate = new RTNCenteredTextManagerDelegate<>(this);
}
@Nullable
@Override
protected ViewManagerDelegate<RTNCenteredText> getDelegate() {
return mDelegate;
}
@NonNull
@Override
public String getName() {
return RTNCenteredTextManager.NAME;
}
@NonNull
@Override
protected RTNCenteredText createViewInstance(@NonNull ThemedReactContext context) {
return new RTNCenteredText(context);
}
@Override
@ReactProp(name = "text")
public void setText(RTNCenteredText view, @Nullable String text) {
view.setText(text);
}
}
RTNCenteredTextManager
类用于让 React Native 实例化原生组件,它实现了由 Codegen 生成的接口(见 implements
语句的 RTNCenteredTextManagerInterface
接口)并使用了 RTNCenteredTextManagerDelegate
类。
它同时负责导出所有 React Native 所需的内容,例如使用 @ReactModule
注解的 RTNCenteredTextManager
类,及使用 @ReactProp
注解的 setText
方法。
RTNCenteredTextPackage.java
最后,打开 android/src/main/java/com/rtncenteredtext
目录的 RTNCenteredTextPackage.java
,并进行以下修改:
package com.rtncenteredtext;
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.Collections;
import java.util.List;
public class RTNCenteredTextPackage implements ReactPackage {
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
+ return Collections.singletonList(new RTNCenteredTextManager(reactContext));;
}
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
新增的代码实例化了一个 RTNCenteredTextManager
对象,用于让 React Natve 运行时渲染 Fabric 组件。
5. 将 Fabric 组件添加到 App
完成最后这一步,您便能将 Fabric 组件运行在 App 上。
Shared
首先,您需要将包含组件的 NPM 包添加到您的 App。您可以使用以下命令执行此操作:
cd MyApp
yarn add ../RTNCenteredText
此命令会将 RTNCenteredText
模块添加到 App 内的 node_modules
目录。
iOS
接下来,您需要添加新的依赖到您的 iOS 工程,您也可以通过以下命令执行此操作:
cd ios
RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
此命令会查询 iOS 工程里的所有的依赖,并对它们进行安装。RCT_NEW_ARCH_ENABLED=1
的意思是 Cocoapods 在执行 Codegen 前需要一些额外的操作。
在使用 RCT_NEW_ARCH_ENABLED=1
之前,您可能需要先执行一遍 bundle install
。后续除非修改了 Rudy 依赖,您不必再次运行 bundle install
。
Android
在配置 Android 之前,您需要先开启新架构:
- 打开
android/gradle.properties
; - 滑到文件底部,将
newArchEnabled
的值从false
修改为true
。
JavaScript
最后,操作以下步骤,您就可以在 JavaScript 调用组件了。
-
在 js 文件中导入组件。假设您要在
App.js
进行导入,您需要添加这行代码:App.jsimport RTNCenteredText from 'rtn-centered-text/js/RTNCenteredTextNativeComponent';
-
接下来,在 React Native 组件里进行调用。调用的语法和其它组件相同:
App.js// ... other code
const App: () => Node = () => {
// ... other App code ...
return (
// ...other React Native elements...
<RTNCenteredText
text="Hello World!"
style={{width: '100%', height: 30}}
/>
// ...other React Native Elements
);
};
现在,您可以运行 App 并查看在屏幕上显示的组件。