[ReactNative翻译]使用 React Native 轻松创建 iOS 棕地应用程序

219 阅读5分钟

我们先来回答一个问题:什么是棕地应用?

所谓 "棕地",是指利用现有元素建造的东西。棕地 "一词最初用于城市规划,描述可以重新利用的区域,后来被移动应用开发所采用。棕地应用程序基本上是指并非从零开始构建的应用程序。

它的实际含义是什么?这意味着我们希望将 React Native 应用程序作为已使用 Java、Kotlin、Objective-C 或 Swift 等技术开发的本地应用程序的一部分来运行。换句话说,我们希望将 React Native 集成到现有的应用程序中

它是如何工作的?

‍ 假设我们有一个原生 iOS 应用程序,我们想使用已经实现的 React Native 应用程序创建一个新的屏幕。该屏幕将导航到 react-native 应用程序中的另一个屏幕。

1.gif

为了让它正常工作,我们需要做几件事。

在项目中添加 React Native:

首先,我们需要将 React Native 应用程序添加到现有的本地项目中。我们需要确定要集成 React Native 框架的哪些部分。为此,我们将使用 CocoaPods。让我们在原生项目中编辑或创建 Podfile,添加 React 和所有需要的子规范,并将路径指向 node_modules,然后运行 pod install 命令

platform :ios, '9.0'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
 
target 'NativeExample' do
  pod 'React', :path => '../node_modules/react-native/'
  pod 'React-Core', :path => '../node_modules/react-native/React'
  pod 'React-DevSupport', :path => '../node_modules/react-native/React'
  pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS'
  pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation'
  pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob'
  pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image'
  pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS'
  pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network'
  pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings'
  pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text'
  pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration'
  pod 'React-RCTWebSocket', :path => '../node_modules/react-native/Libraries/WebSocket'
 
  pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec'
  pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec'
  pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec'
 
  pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact'
  pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi'
  pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor'
  pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector'
  pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga'
 
  use_native_modules!('../..')
 
end

运行 React Native 应用程序:

  • 当 React Native 应用程序正确链接到原生应用程序时,我们需要创建一个实现 RCTBridgeDelegate 的类,至少需要 sourceURLForBridge 方法来指定使用哪个 JS 捆绑程序。
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge {
    return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
}
  • 然后创建一个 React Native 桥接实例 ( RCTBridge ),并将先前实现的类作为委托和启动选项字典(如需要)。
bridge = [[RCTBridge alloc] initWithDelegate:delegate launchOptions:launchOptions];
  • 创建 ViewController,将 react-native 应用程序的 rootView 设置为视图属性。
    RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"MainComponent" initialProperties:nil] 
    UIViewController *vc = [[UIViewController alloc] init];
    vc.view = rootView;
  • 最后,我们可以将 react-native 视图控制器推送到堆栈中
[self presentViewController:vc animated:YES completion:nil];

其他步骤:

注意:在调试模式下,我们需要打包程序来提供 JS 捆绑包。但是,Apple 已阻止隐式明文 HTTP 资源加载。因此,我们需要在项目的 Info.plist 文件(或类似文件)中添加以下内容。

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>localhost</key>
        <dict>
            <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

此外,我们还可以在构建阶段添加脚本,这些脚本将为我们构建 react-native bundle 和图片

image.png

运行打包程序的脚本

image.png

export RCT_METRO_PORT="${RCT_METRO_PORT:=8081}"
echo "export RCT_METRO_PORT=${RCT_METRO_PORT}" > "${SRCROOT}/../node_modules/react-native/scripts/.packager.env"
if [ -z "${RCT_NO_LAUNCH_PACKAGER+xxx}" ] ; then
  if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then
    if ! curl -s "http://localhost:${RCT_METRO_PORT}/status" | grep -q "packager-status:running" ; then
echo "Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly"
exit 2
    fi
  else
    open "$SRCROOT/../node_modules/react-native/scripts/launchPackager.command" || echo "Can't start packager automatically"
  fi
fi

导航问题:

我们现在已经设置好了一切,但在轻扫返回功能方面存在问题。我们无法通过轻扫手势或 "返回 "按钮返回原生屏幕。我们需要一种机制,让我们可以从 react-native 向原生部分表示,我们想回到原生屏幕,或者我们想启用/禁用原生 PopGestureRecognizer。这可以通过一个 react-native 原生模块来解决,该模块将通过 NSNotificationCenter 发送通知。

但等等... 就不能用更简单的方法吗?我们真的需要处理 RCTBridgeDelegate、RCTBridge 和 RCTRootView 吗?

当然,这可能更简单:) 我们可以使用 react-native-brownfield 软件包,它可以帮助我们解决导航问题,并提供运行 react-native 应用程序的良好 API。

如何使用 React Native brownfield?

我们想要实现与之前完全相同的效果,但我们将使用 react-native-brownfield 库。

1.gif

在项目中添加 React Native:

理论与我在本文前一部分中描述的相同,但增加了一些功能。为了使用 react-native-brownfield 在原生环境中运行 React Native 应用程序,我们需要将该软件包作为依赖项添加到 package.json 中:

npm install @callstack/react-native-brownfield

‍ 或

yarn add @callstack/react-native-brownfield

接下来,我们需要添加 React Native 应用程序,就像在使用 CocoaPods 将 react-native 添加到项目点时所做的那样。

运行 React Native 应用程序:

现在好戏开始了) 我们可以使用 ReactNativeBrownfield 软件包来代替自己创建桥接器。

导入 ReactNativeBrownfield 软件包,并以入口文件名创建实例。

ReactNativeBrownfield *reactNativeBrownfieldManager = [ReactNativeBrownfield shared];
reactNativeBrownfieldManager.entryFile = @"index"

我们可以使用 reactNativeBrownfieldManager 的 startReactNative 方法运行 react-native 应用程序了

[reactNativeBrownfieldManager startReactNative:^(void){
        NSLog(@"React Native started");
}];

就是这样。我们可以通过用户友好的 API 将 react-native 应用程序视图控制器推送到导航栈。

[[self navigationController] pushViewController:[[ReactNativeViewController alloc] initWithModuleName:@"MainComponent"] animated:YES];

附加步骤:

还需要在此处添加所有其他步骤

  • 编辑 Info.plist 文件,允许连接到打包程序
  • 在 Build Phases 中添加脚本以运行打包程序
  • 为 BuildPhases 添加脚本以捆绑 JS 代码和资产

导航问题:

react-native-brownfield 为上述问题提供了解决方案。它提供了两种方法,可用于在 JS 代码中切换手势和弹出到原生屏幕。

  • ReactNativeBrownfield.setNativeBackGestureAndButtonEnabled - 用于切换 iOS 原生返回手势
  • ReactNativeBrownfield.popToNative - 弹出到原生屏幕

就是这样!我们已经准备就绪)

总结:

在现有的原生应用程序中使用 React Native 是一件很流行的事情,尤其是在有多个团队为多个平台开发同一应用程序的大型组织中。有了 React Native brownfield,集成变得更加简单、愉快,而且每个 React Native brownfield 应用程序中都存在的一些问题也得到了解决:)

使用 react-native-brownfield 的工作示例位于示例目录中。

作为 React Native Show 的一部分,我们发布了一个播客,专门介绍使用 React Native 进行棕地开发的未来。


www.deepl.com 翻译