Spec TypeScript giống ví dụ Kotlin (NativeCalculator.ts).
Bước 1 — Header Obj-C bridging (ios/Calculator/RNCalculator.h):
#import <Foundation/Foundation.h>
#import "RNCalculatorSpec.h" // generated by Codegen
NS_ASSUME_NONNULL_BEGIN
@interface RNCalculator : NSObject <NativeCalculatorSpec>
@end
NS_ASSUME_NONNULL_ENDBước 2 — Implementation Swift (ios/Calculator/RNCalculator.swift):
import Foundation
@objc(RNCalculator)
class RNCalculator: NSObject, NativeCalculatorSpec {
func add(_ a: NSNumber, b: NSNumber) -> NSNumber {
return NSNumber(value: a.doubleValue + b.doubleValue)
}
func fetchUser(_ id: String, resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
resolve(["name": "Alice"])
}
static func moduleName() -> String { "Calculator" }
}Bước 3 — Bridging header (ios/RNCalculator-Bridging-Header.h):
#import <React/RCTBridgeModule.h>Bước 4 — Module entry Obj-C++ (ios/Calculator/RNCalculator.mm):
#import "RNCalculator.h"
#import "MyApp-Swift.h"
@implementation RNCalculator
RCT_EXPORT_MODULE(Calculator)
@endBước 5 — Calculator.podspec:
Pod::Spec.new do |s|
s.name = 'Calculator'
s.source_files = "Calculator/**/*.{swift,h,m,mm}"
s.dependency 'React-Core'
install_modules_dependencies(s)
endBước 6 — pod install trong ios/. Codegen chạy → RNCalculatorSpec.h/.mm generate. Build pnpm ios.
Lưu ý:
- Swift class phải @objc để Codegen + Obj-C++ thấy.
- Method async dùng RCTPromiseResolveBlock/RCTPromiseRejectBlock.
- Param type: NSNumber cho number, NSString cho string, NSDictionary cho object — Swift Codegen tự bridge.
The TypeScript spec is the same as the Kotlin example (NativeCalculator.ts).
Step 1 — Obj-C bridging header (ios/Calculator/RNCalculator.h):
#import <Foundation/Foundation.h>
#import "RNCalculatorSpec.h" // generated by Codegen
NS_ASSUME_NONNULL_BEGIN
@interface RNCalculator : NSObject <NativeCalculatorSpec>
@end
NS_ASSUME_NONNULL_ENDStep 2 — Swift implementation (ios/Calculator/RNCalculator.swift):
import Foundation
@objc(RNCalculator)
class RNCalculator: NSObject, NativeCalculatorSpec {
func add(_ a: NSNumber, b: NSNumber) -> NSNumber {
return NSNumber(value: a.doubleValue + b.doubleValue)
}
func fetchUser(_ id: String, resolve: @escaping RCTPromiseResolveBlock,
reject: @escaping RCTPromiseRejectBlock) {
resolve(["name": "Alice"])
}
static func moduleName() -> String { "Calculator" }
}Step 3 — bridging header (ios/RNCalculator-Bridging-Header.h):
#import <React/RCTBridgeModule.h>Step 4 — Obj-C++ module entry (ios/Calculator/RNCalculator.mm):
#import "RNCalculator.h"
#import "MyApp-Swift.h"
@implementation RNCalculator
RCT_EXPORT_MODULE(Calculator)
@endStep 5 — Calculator.podspec:
Pod::Spec.new do |s|
s.name = 'Calculator'
s.source_files = "Calculator/**/*.{swift,h,m,mm}"
s.dependency 'React-Core'
install_modules_dependencies(s)
endStep 6 — pod install in ios/. Codegen runs → RNCalculatorSpec.h/.mm is generated. Build with pnpm ios.
Pitfalls:
- The Swift class must be @objc so Codegen + Obj-C++ can see it.
- Async methods use RCTPromiseResolveBlock/RCTPromiseRejectBlock.
- Parameter types: NSNumber for numbers, NSString for strings, NSDictionary for objects — Swift Codegen handles the bridging.