如何在纯 Swift 中创建 React Native Module

How to create React Native Module in pure Swift

提问人:iUrii 提问时间:10/12/2023 更新时间:10/12/2023 访问量:81

问:

我在React Native上有一个项目,它有一堆Native Modules和UI组件。代码主要是用 Swift 编写的,但它也有 Objective-C 代码,用于将我的 swift 的原生类和方法导出到 React Native,因为 Swift 不支持 C 宏,例如:

// Calendar.m

#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(Calendar, NSObject)

RCT_EXTERN_METHOD(createEvent:(NSString *)title location:(NSString* )location)

@end
// Calendar.swift

@objc(Calendar)
class Calendar: NSObject {
  
  @objc
  func createEvent(_ title: String, location: String) {
    print(title, location)
  }
}

每次修改时同时管理 Objective-C 和 Swift 方法接口很不方便,那么有没有办法消除 Objective-C 代码?

swift objective-c react-native-native-module 反应原生 -组件

评论


答:

1赞 iUrii 10/12/2023 #1

如果你研究 React Native 宏等,你会发现它们为 React Native 生成了额外的静态方法来注册你的模块并公开你的方法:RCT_EXTERN_MODULERCT_EXTERN_METHOD

#define RCT_EXPORT_MODULE_NO_LOAD(js_name, objc_name)                           \
  RCT_EXTERN void RCTRegisterModule(Class);                                     \
  +(NSString *)moduleName                                                       \
  {                                                                             \
    return @ #js_name;                                                          \
  }                                                                             \
  __attribute__((constructor)) static void RCT_CONCAT(initialize_, objc_name)() \
  {                                                                             \
    RCTRegisterModule([objc_name class]);                                       \
  }

#define _RCT_EXTERN_REMAP_METHOD(js_name, method, is_blocking_synchronous_method)                            \
  +(const RCTMethodInfo *)RCT_CONCAT(__rct_export__, RCT_CONCAT(js_name, RCT_CONCAT(__LINE__, __COUNTER__))) \
  {                                                                                                          \
    static RCTMethodInfo config = {#js_name, #method, is_blocking_synchronous_method};                       \
    return &config;                                                                                          \
  }

您可以在 Swift 代码中实现以下方法:

import React

class Calendar: NSObject, RCTBridgeModule {
  
  @objc func createEvent(_ title: String, location: String) {
    print(title, location)
  }
  
  @objc static func __rct_export__createEvent() -> UnsafePointer<RCTMethodInfo>? {
    struct Static {
      static let jsName = strdup("createEvent")
      static let objcName = strdup("createEvent:(NSString * _Nonnull)title location:(NSString * _Nonnull)location")
      static var methodInfo = RCTMethodInfo(jsName: jsName, objcName: objcName, isSync: false)
    }
    return withUnsafePointer(to: &Static.methodInfo) {
      $0
    }
  }
  
  @objc class func moduleName() -> String! {
    "\(self)"
  }
}

此外,您需要在应用程序启动时手动注册您的类才能运行:

RCTRegisterModule(Calendar.self)

Swift 宏

正如你所看到的,在纯 Swift 中手动编写一个 React Native 模块是可能的,但它一点也不方便。但是宏已经开始支持 Swift 5.9 (XCode 15),您可以将 ReactBridge swift 宏库用于 React Native 模块和 UI 组件。有了这个库,你的代码就变成了:

import React
import ReactBridge

@ReactModule
class Calendar: NSObject, RCTBridgeModule {
  
  @ReactMethod
  @objc func createEvent(title: String, location: String) {
    print(title, location)
  }
}

0赞 Dustin Forsyth 10/12/2023 #2

如果您愿意使用expo,那么在它们处理所有讨厌的objc内容之前,我已经将其用于本机模块。Expo Modules API

他们希望你把你的模块写进去,但我相信在引擎盖下,他们仍然只是生成你需要的所有objc代码。Kotlin and Swift

Expo Modules API这是一次很棒的经历,特别是如果你想写 swift 代码。我写了一个没有它的原生模块,觉得 objc 的东西很难与 swift 代码保持同步。

https://docs.expo.dev/modules/overview/